@enclavemoney/enclave-wallet-sdk
Version:
A simple enclave wallet SDK for React applications
818 lines (748 loc) • 22.4 kB
text/typescript
const API_BASE_URL =
typeof window !== "undefined" &&
window.location.href.includes("stage.enclave.money")
? "https://enclave-b2b-api-stage-160004845895.asia-south1.run.app"
: "https://hyperapp.in";
// Import necessary types from services.ts
import { QuoteType, QuoteChoice } from "./services";
// Define action interface
export interface IAction {
action:
| string
| {
encodedData: string;
targetContractAddress: string;
value: string;
}[];
}
// API request interfaces
export interface getSourceTokensFromIdentifierRequest {
body: {
chainId: number;
tokenAddress: string;
};
}
export interface CalculateQuoteAmountInRequest {
body: {
username: string;
fromTokens: UserBalance[];
toToken: {
tokenAddress: string;
chainId: number;
};
quoteType: QuoteType;
action?: IAction["action"];
};
}
export interface CalculateQuoteAmountOutRequest {
body: {
username: string;
fromTokens: getSourceTokensFromIdentifierRequest["body"][];
toToken: {
tokenAddress: string;
chainId: number;
outputAmount: string;
};
quoteType: QuoteType;
action?: IAction["action"];
};
}
// Add interfaces for calculateQuoteAmountInWithAction function
export interface UserBalance {
chainId: number;
address: string;
balance: string;
}
export interface CalculateQuoteAmountInInput {
fromTokens: UserBalance[];
toToken: {
tokenAddress: string;
chainId: number;
};
action: IAction["action"];
}
export interface CalculateQuoteAmountInParams {
username: string;
fromTokens: UserBalance[];
toToken: {
tokenAddress: string;
chainId: number;
};
quoteType: QuoteType;
action?: IAction["action"];
}
export interface ModifiedSpendPlan {
total_fees: string;
spend_distribution: Record<string, string>;
total_withdrawn: string;
remaining_balance: string;
enclave_fee_distribution: Record<string, string>;
enclave_fee: string;
}
export interface QuoteDetailsWithAction {
success: boolean;
provider: string;
fees: string;
estimatedTime: number;
inputDetails: {
amount: string;
amountUsd: string | number;
};
outputDetails: {
amount: string;
amountFormatted: string;
amountUsd: string;
minimumAmount: string;
};
rate: string;
modifiedSpendPlan: ModifiedSpendPlan;
}
export interface CalculateQuoteResponse {
success: boolean;
bestQuote: QuoteDetailsWithAction;
fastestQuote: QuoteDetailsWithAction;
}
// Add interfaces for calculateQuoteAmountOut function
export interface CalculateQuoteAmountOutInput {
fromTokens: getSourceTokensFromIdentifierRequest["body"][];
toToken: {
tokenAddress: string;
chainId: number;
outputAmount: string;
};
quoteType: QuoteType;
action?: IAction["action"];
}
export interface CalculateQuoteAmountOutParams {
username: string;
fromTokens: getSourceTokensFromIdentifierRequest["body"][];
toToken: {
tokenAddress: string;
chainId: number;
outputAmount: string;
};
quoteType: QuoteType;
action?: IAction["action"];
}
// Add interfaces for executeSwapAmountIn function
export interface ExecuteSwapAmountInRequest {
body: {
username: string;
fromTokens: UserBalance[];
toToken: {
tokenAddress: string;
chainId: number;
};
isHeadless: boolean;
quoteChoice: QuoteChoice;
quoteType: QuoteType;
quoteId?: string;
action?: IAction["action"];
};
}
export interface ExecuteSwapAmountInInput {
fromTokens: UserBalance[];
toToken: {
tokenAddress: string;
chainId: number;
};
isHeadless: boolean;
quoteChoice: QuoteChoice;
quoteType: QuoteType;
quoteId?: string;
action?: IAction["action"];
}
export interface ExecuteSwapAmountInParams {
username: string;
fromTokens: UserBalance[];
toToken: {
tokenAddress: string;
chainId: number;
};
isHeadless: boolean;
quoteChoice: QuoteChoice;
quoteType: QuoteType;
quoteId?: string;
action?: IAction["action"];
}
export interface ExecuteSwapAmountInResponse {
success: boolean;
transactionDetails?: {
multiTransactionId: string;
overallStatus: string;
};
// Add other response fields as needed
}
// Add interfaces for executeSwapAmountOut function
export interface ExecuteSwapAmountOutRequest {
body: {
username: string;
fromTokens: getSourceTokensFromIdentifierRequest["body"][];
toToken: {
tokenAddress: string;
chainId: number;
outputAmount: string;
};
isHeadless: boolean;
quoteChoice: QuoteChoice;
quoteType: QuoteType;
quoteId?: string;
action?: IAction["action"];
};
}
export interface ExecuteSwapAmountOutInput {
fromTokens: UserBalance[];
toToken: {
tokenAddress: string;
chainId: number;
outputAmount: string;
};
isHeadless: boolean;
quoteChoice: QuoteChoice;
quoteType: QuoteType;
quoteId?: string;
action?: IAction["action"];
}
export interface ExecuteSwapAmountOutParams {
username: string;
fromTokens: getSourceTokensFromIdentifierRequest["body"][];
toToken: {
tokenAddress: string;
chainId: number;
outputAmount: string;
};
isHeadless: boolean;
quoteChoice: QuoteChoice;
quoteType: QuoteType;
quoteId?: string;
action?: IAction["action"];
}
export interface ExecuteSwapAmountOutResponse {
success: boolean;
transactionDetails?: {
multiTransactionId: string;
overallStatus: string;
};
// Add other response fields as needed
}
// Unified interface for calculateQuote function
export interface CalculateQuoteInput {
fromTokens: UserBalance[];
toToken: {
tokenAddress: string;
chainId: number;
outputAmount?: string; // Optional for AMOUNT_IN, required for AMOUNT_OUT
};
quoteType: QuoteType;
action?: IAction["action"];
}
export interface CalculateQuoteParams {
username: string;
fromTokens: UserBalance[] | getSourceTokensFromIdentifierRequest["body"][];
toToken: {
tokenAddress: string;
chainId: number;
outputAmount?: string;
};
quoteType: QuoteType;
action?: IAction["action"];
}
// Unified interface for executeSwap function
export interface ExecuteSwapInput {
fromTokens: UserBalance[];
toToken: {
tokenAddress: string;
chainId: number;
outputAmount?: string; // Optional for AMOUNT_IN, required for AMOUNT_OUT
};
isHeadless: boolean;
quoteChoice: QuoteChoice;
quoteType: QuoteType;
quoteId?: string;
action?: IAction["action"];
}
export interface ExecuteSwapParams {
username: string;
fromTokens: UserBalance[] | getSourceTokensFromIdentifierRequest["body"][];
toToken: {
tokenAddress: string;
chainId: number;
outputAmount?: string;
};
isHeadless: boolean;
quoteChoice: QuoteChoice;
quoteType: QuoteType;
quoteId?: string;
action?: IAction["action"];
}
export type ExecuteSwapResponse =
| ExecuteSwapAmountInResponse
| ExecuteSwapAmountOutResponse;
// Add interfaces for getQuoteForActionAmountOut function
export interface CalculateQuoteForActionAmountOutRequest {
body: {
username: string;
fromTokens?: getSourceTokensFromIdentifierRequest["body"][];
toToken: {
tokenAddress: string;
chainId: number;
};
outputAmount: string;
quoteType: QuoteType;
action?: IAction["action"];
};
}
export interface GetQuoteForActionInput {
fromTokens?: getSourceTokensFromIdentifierRequest["body"][];
toToken: {
tokenAddress: string;
chainId: number;
};
outputAmount: string;
quoteType: QuoteType;
action?: IAction["action"];
}
export interface GetQuoteForActionParams {
username: string;
fromTokens?: getSourceTokensFromIdentifierRequest["body"][];
toToken: {
tokenAddress: string;
chainId: number;
};
outputAmount: string;
quoteType: QuoteType;
action?: IAction["action"];
}
export interface GetQuoteForActionResponse {
success: boolean;
bestQuote: QuoteDetailsWithAction;
fastestQuote: QuoteDetailsWithAction;
}
// Add interfaces for executeAction function
export interface ExecuteActionAmountOutRequest {
body: {
quoteChoice: QuoteChoice;
quoteId: string;
};
}
export interface ExecuteActionInput {
quoteChoice: QuoteChoice;
quoteId: string;
username: string;
fromTokens?: getSourceTokensFromIdentifierRequest["body"][];
toToken?: {
tokenAddress: string;
chainId: number;
};
outputAmount?: string;
action?: IAction["action"];
}
export interface ExecuteActionParams {
quoteChoice: QuoteChoice;
quoteId: string;
username: string;
fromTokens?: getSourceTokensFromIdentifierRequest["body"][];
toToken?: {
tokenAddress: string;
chainId: number;
};
outputAmount?: string;
action?: IAction["action"];
}
export interface ExecuteActionResponse {
success: boolean;
transactionDetails?: {
multiTransactionId: string;
overallStatus: string;
};
// Add other response fields as needed
}
/**
* Calculates quote amount in with action
* @param params The request parameters
* @param apiKey The wallet SDK key for authorization
* @returns The calculate quote amount in with action response
*/
export const calculateQuoteAmountIn = async (
params: CalculateQuoteAmountInParams,
apiKey: string
): Promise<CalculateQuoteResponse | null> => {
try {
// Construct the request body in the format expected by the API
const requestBody: CalculateQuoteAmountInRequest = {
body: {
username: params.username,
fromTokens: params.fromTokens,
toToken: params.toToken,
quoteType: params.quoteType,
...(params.action && { action: params.action }),
},
};
const response = await fetch(`${API_BASE_URL}/sdk/calculateQuoteAmountIn`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: apiKey,
},
body: JSON.stringify(requestBody),
});
if (!response.ok) {
throw new Error("Failed to calculate quote amount in");
}
const data = await response.json();
return data;
} catch (error) {
console.error("Error calculating quote amount in:", error);
return null;
}
};
/**
* Calculates quote amount out
* @param params The request parameters
* @param apiKey The wallet SDK key for authorization
* @returns The calculate quote amount out response
*/
export const calculateQuoteAmountOut = async (
params: CalculateQuoteAmountOutParams,
apiKey: string
): Promise<CalculateQuoteResponse | null> => {
try {
// Use the appropriate endpoint based on whether action is provided
const endpoint = params.action
? `${API_BASE_URL}/sdk/calculateQuoteAmountOutWithAction`
: `${API_BASE_URL}/sdk/calculateQuoteAmountOut`;
// Construct the request body in the format expected by the API
const requestBody: CalculateQuoteAmountOutRequest = {
body: {
username: params.username,
fromTokens: params.fromTokens,
toToken: params.toToken,
quoteType: params.quoteType,
...(params.action && { action: params.action }),
},
};
const response = await fetch(endpoint, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: apiKey,
},
body: JSON.stringify(requestBody),
});
if (!response.ok) {
throw new Error("Failed to calculate quote amount out");
}
const data = await response.json();
return data;
} catch (error) {
console.error("Error calculating quote amount out:", error);
return null;
}
};
/**
* Executes swap amount in
* @param params The request parameters
* @param apiKey The wallet SDK key for authorization
* @returns The execute swap amount in response
*/
export const executeSwapAmountIn = async (
params: ExecuteSwapAmountInParams,
apiKey: string
): Promise<ExecuteSwapAmountInResponse | null> => {
try {
// Get userSession from SDK instance
const sdkInstance = (window as any).__walletSDKInstance;
const userSession =
sdkInstance?.getUserSession?.() || sdkInstance?.userSession;
// Determine auth type based on userSession
const authType = userSession?.authMethod || "passkey";
const authToken = userSession?.token;
// Construct the request body in the format expected by the API
const requestBody: ExecuteSwapAmountInRequest = {
body: {
username: params.username,
fromTokens: params.fromTokens,
toToken: params.toToken,
isHeadless: params.isHeadless,
quoteChoice: params.quoteChoice,
quoteType: params.quoteType,
...(params.quoteId && { quoteId: params.quoteId }),
...(params.action && { action: params.action }),
},
};
const response = await fetch(`${API_BASE_URL}/sdk/executeSwapAmountIn`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-user-auth": authType,
"x-user-authToken": authToken,
Authorization: apiKey,
},
body: JSON.stringify(requestBody),
});
if (!response.ok) {
throw new Error("Failed to execute swap amount in");
}
const data = await response.json();
return data;
} catch (error) {
console.error("Error executing swap amount in:", error);
return null;
}
};
/**
* Executes swap amount out
* @param params The request parameters
* @param apiKey The wallet SDK key for authorization
* @returns The execute swap amount out response
*/
export const executeSwapAmountOut = async (
params: ExecuteSwapAmountOutParams,
apiKey: string
): Promise<ExecuteSwapAmountOutResponse | null> => {
try {
// Get userSession from SDK instance
const sdkInstance = (window as any).__walletSDKInstance;
const userSession =
sdkInstance?.getUserSession?.() || sdkInstance?.userSession;
// Determine auth type based on userSession
const authType = userSession?.authMethod || "passkey";
const authToken = userSession?.token;
// Construct the request body in the format expected by the API
const requestBody: ExecuteSwapAmountOutRequest = {
body: {
username: params.username,
fromTokens: params.fromTokens,
toToken: params.toToken,
isHeadless: params.isHeadless,
quoteChoice: params.quoteChoice,
quoteType: params.quoteType,
...(params.quoteId && { quoteId: params.quoteId }),
...(params.action && { action: params.action }),
},
};
const response = await fetch(`${API_BASE_URL}/sdk/executeSwapAmountOut`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-user-auth": authType,
"x-user-authToken": authToken,
Authorization: apiKey,
},
body: JSON.stringify(requestBody),
});
if (!response.ok) {
throw new Error("Failed to execute swap amount out");
}
const data = await response.json();
return data;
} catch (error) {
console.error("Error executing swap amount out:", error);
return null;
}
};
/**
* Unified execute swap function that routes to appropriate endpoint based on quoteType
* @param params The request parameters
* @param apiKey The wallet SDK key for authorization
* @returns The execute swap response
*/
export const executeSwapQuote = async (
params: ExecuteSwapParams,
apiKey: string
): Promise<ExecuteSwapResponse | null> => {
try {
if (params.quoteType === QuoteType.AMOUNT_IN) {
// For AMOUNT_IN, use executeSwapAmountIn
const amountInParams: ExecuteSwapAmountInParams = {
username: params.username,
fromTokens: params.fromTokens as UserBalance[],
toToken: {
tokenAddress: params.toToken.tokenAddress,
chainId: params.toToken.chainId,
},
isHeadless: params.isHeadless,
quoteChoice: params.quoteChoice,
quoteType: params.quoteType,
quoteId: params.quoteId,
action: params.action,
};
return await executeSwapAmountIn(amountInParams, apiKey);
} else if (params.quoteType === QuoteType.AMOUNT_OUT) {
// For AMOUNT_OUT, use executeSwapAmountOut
if (!params.toToken.outputAmount) {
throw new Error("outputAmount is required for AMOUNT_OUT quote type");
}
const amountOutParams: ExecuteSwapAmountOutParams = {
username: params.username,
fromTokens:
Array.isArray(params.fromTokens) &&
params.fromTokens.length > 0 &&
"balance" in params.fromTokens[0]
? (params.fromTokens as UserBalance[]).map((token) => ({
chainId: token.chainId,
tokenAddress: token.address,
}))
: (params.fromTokens as getSourceTokensFromIdentifierRequest["body"][]),
toToken: {
tokenAddress: params.toToken.tokenAddress,
chainId: params.toToken.chainId,
outputAmount: params.toToken.outputAmount,
},
isHeadless: params.isHeadless,
quoteChoice: params.quoteChoice,
quoteType: params.quoteType,
quoteId: params.quoteId,
action: params.action,
};
return await executeSwapAmountOut(amountOutParams, apiKey);
} else {
throw new Error(`Unsupported quote type: ${params.quoteType}`);
}
} catch (error) {
console.error("Error executing swap:", error);
return null;
}
};
/**
* Unified calculate quote function that routes to appropriate endpoint based on quoteType
* @param params The request parameters
* @param apiKey The wallet SDK key for authorization
* @returns The calculate quote response
*/
export const calculateQuote = async (
params: CalculateQuoteParams,
apiKey: string
): Promise<CalculateQuoteResponse | null> => {
try {
if (params.quoteType === QuoteType.AMOUNT_IN) {
// For AMOUNT_IN, use calculateQuoteAmountIn
const amountInParams: CalculateQuoteAmountInParams = {
username: params.username,
fromTokens: params.fromTokens as UserBalance[],
toToken: {
tokenAddress: params.toToken.tokenAddress,
chainId: params.toToken.chainId,
},
quoteType: params.quoteType,
action: params.action,
};
return await calculateQuoteAmountIn(amountInParams, apiKey);
} else if (params.quoteType === QuoteType.AMOUNT_OUT) {
// For AMOUNT_OUT, use calculateQuoteAmountOut
if (!params.toToken.outputAmount) {
throw new Error("outputAmount is required for AMOUNT_OUT quote type");
}
const amountOutParams: CalculateQuoteAmountOutParams = {
username: params.username,
fromTokens:
Array.isArray(params.fromTokens) &&
params.fromTokens.length > 0 &&
"balance" in params.fromTokens[0]
? (params.fromTokens as UserBalance[]).map((token) => ({
chainId: token.chainId,
tokenAddress: token.address,
}))
: (params.fromTokens as getSourceTokensFromIdentifierRequest["body"][]),
toToken: {
tokenAddress: params.toToken.tokenAddress,
chainId: params.toToken.chainId,
outputAmount: params.toToken.outputAmount,
},
quoteType: params.quoteType,
action: params.action,
};
return await calculateQuoteAmountOut(amountOutParams, apiKey);
} else {
throw new Error(`Unsupported quote type: ${params.quoteType}`);
}
} catch (error) {
console.error("Error calculating quote:", error);
return null;
}
};
/**
* Gets quote for action amount out
* @param params The request parameters
* @param apiKey The wallet SDK key for authorization
* @returns The get quote for action response
*/
export const getQuoteForActionAmountOut = async (
params: GetQuoteForActionParams,
apiKey: string
): Promise<GetQuoteForActionResponse | null> => {
try {
// Construct the request body in the format expected by the API
const requestBody: CalculateQuoteForActionAmountOutRequest = {
body: {
username: params.username,
...(params.fromTokens && { fromTokens: params.fromTokens }),
toToken: params.toToken,
outputAmount: params.outputAmount,
quoteType: params.quoteType,
...(params.action && { action: params.action }),
},
};
const response = await fetch(
`${API_BASE_URL}/sdk/getQuoteForActionAmountOut`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: apiKey,
},
body: JSON.stringify(requestBody),
}
);
if (!response.ok) {
throw new Error("Failed to get quote for action amount out");
}
const data = await response.json();
return data;
} catch (error) {
console.error("Error getting quote for action amount out:", error);
return null;
}
};
/**
* Executes action amount out
* @param params The request parameters
* @param apiKey The wallet SDK key for authorization
* @returns The execute action response
*/
export const executeActionAmountOut = async (
params: ExecuteActionParams,
apiKey: string
): Promise<ExecuteActionResponse | null> => {
try {
// Get userSession from SDK instance
const sdkInstance = (window as any).__walletSDKInstance;
const userSession =
sdkInstance?.getUserSession?.() || sdkInstance?.userSession;
// Determine auth type based on userSession
const authType = userSession?.authMethod || "passkey";
const authToken = userSession?.token;
// Construct the request body in the format expected by the API
const requestBody: ExecuteActionAmountOutRequest = {
body: params,
};
const response = await fetch(`${API_BASE_URL}/sdk/executeActionAmountOut`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-user-auth": authType,
"x-user-authToken": authToken,
Authorization: apiKey,
},
body: JSON.stringify(requestBody),
});
if (!response.ok) {
throw new Error("Failed to execute action amount out");
}
const data = await response.json();
return data;
} catch (error) {
console.error("Error executing action amount out:", error);
return null;
}
};