@biconomy/abstractjs
Version:
SDK for Biconomy integration with support for account abstraction, smart accounts, ERC-4337.
103 lines • 4 kB
JavaScript
import { concatHex, encodeAbiParameters, zeroAddress } from "viem";
import { encodeFunctionData } from "viem";
import { FORWARDER_ADDRESS } from "../../../constants/index.js";
import { ForwarderAbi } from "../../../constants/abi/ForwarderAbi.js";
export const FUSION_NATIVE_TRANSFER_PREFIX = "0x150b7a02";
export const ON_CHAIN_PREFIX = "0x177eee01";
/**
* Generates a trigger call from a trigger
* @private
*/
const generateTriggerCallFromTrigger = async ({ account, trigger, recipient, scaAddress }) => {
let triggerCall;
// build custom call
if (trigger.call) {
triggerCall = trigger.call;
}
else if (trigger.tokenAddress === zeroAddress) {
// If the token address is zero address, we need to send eth via the ETH forwarder
const forwardCalldata = encodeFunctionData({
abi: ForwarderAbi,
functionName: "forward",
args: [recipient]
});
const [{ calls: [ethForwardCall] }] = await account.build({
type: "default",
data: {
calls: [
{
to: FORWARDER_ADDRESS,
data: forwardCalldata,
value: trigger.amount
}
],
chainId: trigger.chainId
}
});
triggerCall = ethForwardCall;
}
else {
// erc20 trigger
// check if we have an explicit `approvalAmount` set and error if it's smaller than the trigger amount
if (trigger.approvalAmount &&
trigger.amount !== undefined &&
trigger.approvalAmount < trigger.amount) {
throw new Error(`Approval amount must be bigger or equal with the amount from the trigger (triggerAmount: ${trigger.amount} amount: ${trigger.approvalAmount})`);
}
const amount = trigger.approvalAmount ?? trigger.amount;
const [{ calls: [approveCall] }] = await account.build({
type: "approve",
data: {
spender: scaAddress,
tokenAddress: trigger.tokenAddress,
chainId: trigger.chainId,
amount
}
});
triggerCall = approveCall;
}
return triggerCall;
};
/**
* Signs a fusion quote with a tx send client side.
*
* @param client - The Mee client to use
* @param params - The parameters for the fusion quote
* @returns The signed quote
* @example
* const signedQuote = await signOnChainQuote(meeClient, {
* quote: quotePayload,
* account: smartAccount
* })
*/
export const signOnChainQuote = async (client, params) => {
const { confirmations = 2, companionAccount: account_ = client.account, fusionQuote: { quote, trigger } } = params;
const chainId = trigger.chainId;
const { chain, walletClient, address: scaAddress } = account_.deploymentOn(chainId, true);
// By default the trigger amount will be deposited to sca account.
// if a custom recipient is defined ? It will deposit to the recipient address
const recipient = trigger.recipientAddress || scaAddress;
const triggerCall = await generateTriggerCallFromTrigger({
account: account_,
trigger,
recipient,
scaAddress
});
// This will be always a non composable transaction, so don't worry about the composability
const dataOrPrefix = triggerCall?.data ?? FUSION_NATIVE_TRANSFER_PREFIX;
const call = { ...triggerCall, data: concatHex([dataOrPrefix, quote.hash]) };
// @ts-ignore
const hash = await walletClient.sendTransaction(call);
// @ts-ignore
await walletClient.waitForTransactionReceipt({ hash, confirmations });
const signature = concatHex([
ON_CHAIN_PREFIX,
encodeAbiParameters([{ type: "bytes32" }, { type: "uint256" }], [hash, BigInt(chain.id)])
]);
return {
...quote,
signature
};
};
export default signOnChainQuote;
//# sourceMappingURL=signOnChainQuote.js.map