@robertprp/intents-sdk
Version:
Shogun Network Intent-based cross-chain swaps SDK
123 lines (108 loc) • 4.16 kB
text/typescript
import { type Address } from 'viem';
import { type SupportedEvmChain } from '../../chains.js';
import type { EVMConfig } from '../../config.js';
import { SINGLE_CHAIN_GUARD_ADDRESSES, CROSS_CHAIN_GUARD_ADDRESSES, MAX_UINT_32 } from '../../constants.js';
import { getEVMCrossChainOrderTypedData, getEVMSingleChainOrderTypedData } from './order-signature.js';
import { type CrossChainPermitTransferFrom, type SingleChainPermitTransferFrom, type TransferData } from './permit2.js';
import { ChainProvider } from './chain-provider.js';
import type { CrossChainOrder } from '../orders/cross-chain.js';
import type { SingleChainOrder } from '../orders/single-chain.js';
import type { CrossChainOrderPrepared, SingleChainOrderPrepared } from '../../types/intent.js';
export class EVMIntentProvider {
provider: ChainProvider;
constructor(config: EVMConfig) {
this.provider = new ChainProvider(config);
}
async prepareSingleChainOrder(order: SingleChainOrder): Promise<SingleChainOrderPrepared> {
const { orderTypedData: dataToSign, nonce } = await getEVMSingleChainOrderTypedData(order);
const signature = await this.provider.walletClient.signTypedData({
message: dataToSign.message,
primaryType: dataToSign.primaryType,
types: dataToSign.types,
domain: dataToSign.domain,
account: this.provider.getAccount(),
});
return {
order,
preparedData: {
nonce: nonce.toString(),
signature: signature.slice(2),
},
};
}
async prepareCrossChainOrder(order: CrossChainOrder): Promise<CrossChainOrderPrepared> {
const { orderTypedData: dataToSign, nonce } = await getEVMCrossChainOrderTypedData(order);
const signature = await this.provider.walletClient.signTypedData({
message: dataToSign.message,
primaryType: dataToSign.primaryType,
types: dataToSign.types,
domain: dataToSign.domain,
account: this.provider.getAccount(),
});
return {
order,
preparedData: {
nonce: nonce.toString(),
signature: signature.slice(2),
},
};
}
static getCrossChainPermissionMessage(order: CrossChainOrder, nonce: bigint): CrossChainPermitTransferFrom {
const spender = CROSS_CHAIN_GUARD_ADDRESSES[order.sourceChainId as SupportedEvmChain] as Address;
return {
permitted: {
token: order.sourceTokenAddress as Address,
amount: order.sourceTokenAmount,
},
spender,
nonce,
deadline: BigInt(order.deadline),
witness: {
user: order.user as Address,
tokenIn: order.sourceTokenAddress as Address,
srcChainId: order.sourceChainId,
deadline: order.deadline,
amountIn: order.sourceTokenAmount,
minStablecoinsAmount: order.minStablecoinAmount,
nonce,
executionDetailsHash: order.getExecutionDetailsHash(),
},
};
}
static getSingleChainLimitPermissionMessage(order: SingleChainOrder, nonce: bigint): SingleChainPermitTransferFrom {
const spender = SINGLE_CHAIN_GUARD_ADDRESSES[order.chainId as SupportedEvmChain] as Address;
const requestedOutput: TransferData = {
token: order.tokenOut as Address,
receiver: order.destinationAddress as Address,
amount: order.amountOutMin,
};
const extraTransfers: TransferData[] =
order.extraTransfers?.map((transfer) => ({
token: transfer.token as Address,
receiver: transfer.receiver as Address,
amount: transfer.amount,
})) || [];
return {
permitted: {
token: order.tokenIn as Address,
amount: order.amountIn,
},
spender,
nonce,
deadline: BigInt(order.deadline),
witness: {
user: order.user as Address,
tokenIn: order.tokenIn as Address,
amountIn: order.amountIn,
requestedOutput,
encodedExternalCallData: '0x', // TODO: Update when external call data is supported
extraTransfers,
deadline: order.deadline,
nonce,
},
};
}
static getRandomNonce(): bigint {
return BigInt(Math.floor(Math.random() * Number(MAX_UINT_32)));
}
}