import { createWalletClient, http, encodeFunctionData, parseUnits } from "viem";
import { privateKeyToAccount } from "viem/accounts";
const SINGLE_DEFAULT_MODE =
"0x0000000000000000000000000000000000000000000000000000000000000000";
const DELEGATION_MANAGER_ABI = [
{
type: "function",
name: "redeemDelegations",
inputs: [
{ name: "permissionContexts", type: "bytes[]" },
{ name: "modes", type: "bytes32[]" },
{ name: "executionCallDatas", type: "bytes[]" },
],
outputs: [],
stateMutability: "nonpayable",
},
];
function encodeSingleExecution(execution: {
target: `0x${string}`;
value: bigint;
callData: `0x${string}`;
}) {
const target = execution.target.slice(2).toLowerCase().padStart(40, "0");
const value = execution.value.toString(16).padStart(64, "0");
const data = execution.callData.slice(2);
return `0x${target}${value}${data}` as `0x${string}`;
}
async function redeemErc20Transfer(
grant: PermissionResponse,
payee: `0x${string}`,
humanAmount: string,
rpcUrl: string,
) {
const sessionAccount = privateKeyToAccount(
process.env.SESSION_PRIVATE_KEY as `0x${string}`,
);
if (sessionAccount.address.toLowerCase() !== grant.to.toLowerCase()) {
throw new Error("Session 地址与授权 to 不一致");
}
const decimals = 18; // 需要根据实际 ERC-20 合约读取 decimals
const amount = parseUnits(humanAmount, decimals);
const tokenAddress = grant.permission.data.tokenAddress as `0x${string}`;
const executionCallData = encodeSingleExecution({
target: tokenAddress,
value: 0n,
callData: encodeFunctionData({
abi: [
{
type: "function",
name: "transfer",
inputs: [{ type: "address" }, { type: "uint256" }],
outputs: [{ type: "bool" }],
stateMutability: "nonpayable",
},
],
functionName: "transfer",
args: [payee, amount],
}),
});
const data = encodeFunctionData({
abi: DELEGATION_MANAGER_ABI,
functionName: "redeemDelegations",
args: [[grant.context], [SINGLE_DEFAULT_MODE], [executionCallData]],
});
const chainId = parseInt(grant.chainId, 16);
const client = createWalletClient({
account: sessionAccount,
chain: {
id: chainId,
name: `Chain ${chainId}`,
nativeCurrency: { name: "Native", symbol: "Native", decimals: 18 },
rpcUrls: { default: { http: [rpcUrl] } },
},
transport: http(rpcUrl),
});
return client.sendTransaction({
to: grant.delegationManager,
value: 0n,
data,
});
}