Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@stringpay/sdk",
"version": "0.2.2",
"version": "0.2.3",
"license": "Apache-2.0",
"description": "String Checkout SDK",
"author": "string.xyz",
Expand Down
2 changes: 1 addition & 1 deletion src/lib/StringPay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ export class StringPay {
// Create iframe in dom
const iframe = document.createElement("iframe");
iframe.style.width = "100vh";
iframe.style.height = "700px";
iframe.style.height = "900px";
iframe.style.overflow = "none";
iframe.src = this._IFRAME_URL;

Expand Down
39 changes: 32 additions & 7 deletions src/lib/services/apiClient.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,17 @@ export function createApiClient({ baseUrl, apiKey }: ApiClientOptions): ApiClien
}
}

async function getQuote(payload: TransactionRequest) {
async function getSavedCards() {
try {
const { data } = await httpClient.get(`/cards`);
return data;
} catch (e: any) {
const error = _getErrorFromAxiosError(e);
throw error;
}
}

async function getQuote(payload: ExecutionRequest) {
try {
const request = () => httpClient.post(`/quotes`, payload);
const { data } = await authInterceptor<{ data: Quote }>(request);
Expand All @@ -214,7 +224,7 @@ export function createApiClient({ baseUrl, apiKey }: ApiClientOptions): ApiClien
}
}

async function transact(payload: ExecutionRequest) {
async function transact(payload: TransactionRequest) {
try {
const request = () => httpClient.post(`/transactions`, payload);
const { data } = await authInterceptor<{
Expand Down Expand Up @@ -270,6 +280,7 @@ export function createApiClient({ baseUrl, apiKey }: ApiClientOptions): ApiClien
getUserStatus,
getDeviceStatus,
getUserEmailPreview,
getSavedCards,
getQuote,
transact,
setWalletAddress,
Expand All @@ -288,8 +299,9 @@ export interface ApiClient {
getUserStatus: (userId: string) => Promise<{ status: string }>;
getDeviceStatus: (nonce: string, signature: string, visitor: VisitorData) => Promise<{ status: string }>;
getUserEmailPreview: (nonce: string, signature: string) => Promise<{ email: string }>;
getQuote: (request: TransactionRequest) => Promise<Quote>;
transact: (request: ExecutionRequest) => Promise<TransactionResponse>;
getSavedCards: () => Promise<SavedCardResponse[]>;
getQuote: (request: ExecutionRequest) => Promise<Quote>;
transact: (request: TransactionRequest) => Promise<TransactionResponse>;
setWalletAddress: (walletAddress: string) => void;
}

Expand Down Expand Up @@ -335,7 +347,7 @@ export interface VisitorData {
requestId?: string;
}

export interface TransactionRequest {
export interface ExecutionRequest {
userAddress: string;
assetName: string;
chainID: number;
Expand All @@ -357,7 +369,7 @@ export interface Estimate {
}

export interface Quote {
transactionRequest: TransactionRequest;
request: ExecutionRequest;
estimate: Estimate;
signature: string;
}
Expand All @@ -366,16 +378,29 @@ export interface PaymentInfo {
cardToken?: string;
cardId?: string;
cvv?: string;
saveCard?: boolean;
}

export interface ExecutionRequest {
export interface TransactionRequest {
quote: Quote;
paymentInfo: PaymentInfo;
}

export interface TransactionResponse {
txID: string;
txUrl: string;
txTimestamp: string;
}

export interface SavedCardResponse {
type: string;
id: string;
scheme: string;
last4: string;
expiryMonth: number;
expiryYear: number;
expired: boolean;
cardType: string;
}

export interface ApiClientOptions {
Expand Down
6 changes: 3 additions & 3 deletions src/lib/services/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export function createAuthService({ apiClient, locationService, bypassDeviceChec
}
}

const getPreviousSignature = async () => {
const getPreviousLogin = async () => {
// TODO: Use refresh token instead
// TODO: Modify refresh token endpoint to verify visitor data
if (!previousAttempt.signature) throw { code: "UNAUTHORIZED" };
Expand Down Expand Up @@ -82,7 +82,7 @@ export function createAuthService({ apiClient, locationService, bypassDeviceChec
loginOrCreateUser,
fetchLoggedInUser,
requestSignature,
getPreviousSignature,
getPreviousLogin,
logout
};
}
Expand All @@ -97,6 +97,6 @@ export interface AuthService {
loginOrCreateUser: (walletAddress: string) => Promise<{ user: User }>;
fetchLoggedInUser: (walletAddress: string) => Promise<User | null>;
requestSignature: (userAddress: string, encodedMessage: string) => Promise<string>;
getPreviousSignature: () => Promise<{nonce: string, signature: string, visitor: VisitorData}>;
getPreviousLogin: () => Promise<{nonce: string, signature: string, visitor: VisitorData}>;
logout: () => Promise<any>;
}
34 changes: 23 additions & 11 deletions src/lib/services/events.service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { StringPay, StringPayload } from "../StringPay";
import type { ApiClient, ExecutionRequest, TransactionRequest, Quote, PaymentInfo, User, UserUpdate } from "./apiClient.service";
import type { ApiClient, ExecutionRequest, Quote, User, UserUpdate, TransactionRequest } from "./apiClient.service";
import type { LocationService } from "./location.service";
import type { QuoteService } from "./quote.service";
import type { AuthService } from "./auth.service";
Expand All @@ -21,6 +21,8 @@ export enum Events {
RECEIVE_EMAIL_PREVIEW = "receive_email_preview",
REQUEST_DEVICE_VERIFICATION = "request_device_verification",
RECEIVE_DEVICE_VERIFICATION = "receive_device_verification",
REQUEST_SAVED_CARDS = "request_saved_cards",
RECEIVE_SAVED_CARDS = "receive_saved_cards",
REQUEST_CONFIRM_TRANSACTION = "request_confirm_transaction",
RECEIVE_CONFIRM_TRANSACTION = "receive_confirm_transaction",
REQUEST_QUOTE_START = "request_quote_start",
Expand Down Expand Up @@ -100,6 +102,7 @@ export function createEventsService(iframeUrl: string, authService: AuthService,
eventHandlers[Events.REQUEST_EMAIL_VERIFICATION] = onEmailVerification;
eventHandlers[Events.REQUEST_EMAIL_PREVIEW] = onEmailPreview;
eventHandlers[Events.REQUEST_DEVICE_VERIFICATION] = onDeviceVerification;
eventHandlers[Events.REQUEST_SAVED_CARDS] = onRequestSavedCards;
eventHandlers[Events.REQUEST_QUOTE_START] = onQuoteStart;
eventHandlers[Events.REQUEST_QUOTE_STOP] = onQuoteStop;
eventHandlers[Events.REQUEST_CONFIRM_TRANSACTION] = onConfirmTransaction;
Expand Down Expand Up @@ -200,20 +203,22 @@ export function createEventsService(iframeUrl: string, authService: AuthService,
let nonce: string;
let signature: string;

const previous = await authService.getPreviousSignature();
const previous = await authService.getPreviousLogin();
nonce = previous.nonce;
signature = previous.signature;

const visitor = previous.visitor;

if (!previous.signature) {
nonce = (await apiClient.requestLogin(data.walletAddress)).nonce;
signature = await authService.requestSignature(data.walletAddress, nonce);
}

await apiClient.requestDeviceVerification(nonce, signature, previous.visitor);
await apiClient.requestDeviceVerification(nonce, signature, visitor);

clearInterval(deviceCheckInterval);
deviceCheckInterval = setInterval(async () => {
const { status } = await apiClient.getDeviceStatus(nonce, signature, previous.visitor);
const { status } = await apiClient.getDeviceStatus(nonce, signature, visitor);
if (status == "verified") {
sendEvent(frame, Events.RECEIVE_DEVICE_VERIFICATION, { status });
clearInterval(deviceCheckInterval);
Expand All @@ -233,7 +238,7 @@ export function createEventsService(iframeUrl: string, authService: AuthService,
let nonce: string;
let signature: string;

const previous = await authService.getPreviousSignature();
const previous = await authService.getPreviousLogin();
nonce = previous.nonce;
signature = previous.signature;

Expand All @@ -250,10 +255,21 @@ export function createEventsService(iframeUrl: string, authService: AuthService,
}
}

async function onRequestSavedCards(event: StringEvent, { frame }: StringPay) {
if (!frame) throw new Error("Iframe not ready");

try {
const cards = await apiClient.getSavedCards();

sendEvent(frame, Events.RECEIVE_SAVED_CARDS, { cards });
} catch (error: any) {
sendEvent(frame, Events.RECEIVE_SAVED_CARDS, {}, error);
}
}
async function onQuoteStart(event: StringEvent, { frame, payload }: StringPay) {
if (!frame) throw new Error("Iframe not ready");

const quotePayload = <TransactionRequest>payload;
const quotePayload = <ExecutionRequest>payload;

const callback = (quote: Quote | null, err: any) => sendEvent(frame, Events.QUOTE_CHANGED, { quote, err });
quoteService.startQuote(quotePayload, callback);
Expand All @@ -267,11 +283,7 @@ export function createEventsService(iframeUrl: string, authService: AuthService,
if (!stringPay.frame) throw new Error("Iframe not ready");

try {
const paymentInfo = <PaymentInfo>{};
paymentInfo.cardToken = event.data.cardToken;

const data = <ExecutionRequest>event.data;
data.paymentInfo = paymentInfo;
const data = <TransactionRequest>event.data;

const txRes = await apiClient.transact(data);
sendEvent(stringPay.frame, Events.RECEIVE_CONFIRM_TRANSACTION, txRes);
Expand Down
8 changes: 4 additions & 4 deletions src/lib/services/quote.service.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { ApiClient, TransactionRequest, Quote } from './apiClient.service';
import type { ApiClient, Quote, ExecutionRequest } from './apiClient.service';

export function createQuoteService(apiClient: ApiClient): QuoteService {
let interval: NodeJS.Timer | undefined;

async function startQuote(payload: TransactionRequest, callback: (quote: Quote | null, err: any) => void) {
async function startQuote(payload: ExecutionRequest, callback: (quote: Quote | null, err: any) => void) {
_refreshQuote(payload, callback);

if (interval) {
Expand All @@ -18,7 +18,7 @@ export function createQuoteService(apiClient: ApiClient): QuoteService {
interval = undefined;
}

async function _refreshQuote(payload: TransactionRequest, callback: (quote: Quote | null, err: any) => void) {
async function _refreshQuote(payload: ExecutionRequest, callback: (quote: Quote | null, err: any) => void) {
try {
const quote = await apiClient.getQuote(payload);
callback(quote, null);
Expand All @@ -35,6 +35,6 @@ export function createQuoteService(apiClient: ApiClient): QuoteService {
}

export interface QuoteService {
startQuote: (payload: TransactionRequest, callback: (quote: Quote | null, err: any) => void) => Promise<void>;
startQuote: (payload: ExecutionRequest, callback: (quote: Quote | null, err: any) => void) => Promise<void>;
stopQuote: () => void;
}
Loading