@biconomy/abstractjs
Version:
SDK for Biconomy integration with support for account abstraction, smart accounts, ERC-4337.
142 lines • 5.62 kB
JavaScript
import { parseAbi } from "abitype";
import { encodeFunctionData, erc20Abi } from "viem";
import { arbitrumSepolia, baseSepolia, optimismSepolia, sepolia } from "viem/chains";
import { createHttpClient } from "../../clients/createHttpClient.js";
const TESTNET_IDS = [
sepolia.id,
baseSepolia.id,
optimismSepolia.id,
arbitrumSepolia.id
];
// Create HTTP client instance
const acrossClient = createHttpClient("https://app.across.to/api");
const testnetAcrossClient = createHttpClient("https://testnet.across.to/api");
/**
* Fetches suggested fees from Across bridge API
* @param {AcrossSuggestedFeesParams} params - Parameters for fee calculation
* @param {Address} params.inputToken - Source token address
* @param {Address} params.outputToken - Destination token address
* @param {number} params.originChainId - Source chain ID
* @param {number} params.destinationChainId - Destination chain ID
* @param {bigint} params.amount - Amount to bridge
* @returns {Promise<AcrossRelayFeeResponse>} Suggested fees and related information
*/
const acrossGetSuggestedFees = async ({ inputToken, outputToken, originChainId, destinationChainId, amount }) => {
const client = TESTNET_IDS.includes(originChainId)
? testnetAcrossClient
: acrossClient;
return client.request({
path: "suggested-fees",
method: "GET",
params: {
inputToken,
outputToken,
originChainId: originChainId.toString(),
destinationChainId: destinationChainId.toString(),
amount: amount.toString()
}
});
};
/**
* Encodes a bridging operation for the Across protocol into a user operation
* @param {BridgingUserOpParams} params - Parameters for the bridge operation
* @param {bigint} params.bridgingAmount - Amount to bridge
* @param {number} params.fromChainId - Source chain ID
* @param {Address} params.depositor - Depositor address
* @param {Address} params.recipient - Recipient address
* @param {number} params.toChainId - Destination chain ID
* @param {TokenMapping} params.tokenMapping - Token address mapping across chains
* @returns {Promise<BridgingPluginResult>} Encoded user operation and bridging details
* @throws {Error} When depositor or recipient address cannot be found
*/
export const acrossEncodeBridgingUserOp = async (params) => {
const { bridgingAmount, fromChainId, depositor, recipient, toChainId, tokenMapping } = params;
const inputToken = tokenMapping.on(fromChainId);
const outputToken = tokenMapping.on(toChainId);
const suggestedFees = await acrossGetSuggestedFees({
amount: bridgingAmount,
destinationChainId: toChainId,
inputToken: inputToken,
outputToken: outputToken,
originChainId: fromChainId
});
const depositV3abi = parseAbi([
"function depositV3(address depositor, address recipient, address inputToken, address outputToken, uint256 inputAmount, uint256 outputAmount, uint256 destinationChainId, address exclusiveRelayer, uint32 quoteTimestamp, uint32 fillDeadline, uint32 exclusivityDeadline, bytes message) external"
]);
const outputAmount = BigInt(bridgingAmount) - BigInt(suggestedFees.totalRelayFee.total);
const fillDeadlineBuffer = 18000;
const fillDeadline = Math.round(Date.now() / 1000) + fillDeadlineBuffer;
const approveCall = {
to: inputToken,
gasLimit: 100000n,
data: encodeFunctionData({
abi: erc20Abi,
functionName: "approve",
args: [suggestedFees.spokePoolAddress, bridgingAmount]
})
};
const depositCall = {
to: suggestedFees.spokePoolAddress,
gasLimit: 1500n,
data: encodeFunctionData({
abi: depositV3abi,
args: [
depositor,
recipient,
inputToken,
outputToken,
bridgingAmount,
outputAmount,
BigInt(toChainId),
suggestedFees.exclusiveRelayer,
Number.parseInt(suggestedFees.timestamp),
fillDeadline,
Number.parseInt(suggestedFees.exclusivityDeadline),
"0x" // message
]
})
};
const userOp = {
calls: [approveCall, depositCall],
chainId: fromChainId,
metadata: [
{
type: "BRIDGE",
fromAddress: depositor,
toAddress: recipient,
fromTokenAddress: inputToken,
toTokenAddress: outputToken,
amount: bridgingAmount,
fromChainId: fromChainId,
toChainId: toChainId,
protocolNames: ["Across"]
}
]
};
return {
userOp,
receivedAtDestination: outputAmount,
bridgingDurationExpectedMs: undefined
};
};
/**
* Creates an Across bridging plugin instance
* @returns {BridgingPlugin} Plugin instance implementing the Across bridge protocol
*
* @example
* const acrossPlugin = toAcrossPlugin()
* const bridgeResult = await acrossPlugin.encodeBridgeUserOp({
* bridgingAmount: 1000000n,
* fromChainId: 11155111,
* toChainId: 84532,
* depositor: "0x00000000000000000000000000000000000a11ce",
* recipient: "0x00000000000000000000000000000000000a11ce",
* tokenMapping: tokens
* })
*/
export const toAcrossPlugin = () => ({
encodeBridgeUserOp: async (params) => {
return await acrossEncodeBridgingUserOp(params);
}
});
//# sourceMappingURL=toAcrossPlugin.js.map