four-flap-meme-sdk
Version:
SDK for Flap bonding curve and four.meme TokenManager
68 lines (67 loc) • 2.66 kB
JavaScript
import { Wallet, AbiCoder, Contract, JsonRpcProvider } from 'ethers';
import { FLAP_PORTAL_ADDRESSES } from './constants.js';
import { CHAIN } from '../utils/constants.js';
/**
* 构建 Permit Piggyback 数据
* 自动签名并使用正确的 Portal 代理地址
*
* @param chain 链名称
* @param privateKey 用户私钥
* @param tokenAddress ERC20 代币地址(需要支持 EIP-2612 Permit)
* @param value 授权金额
* @param deadline 截止时间戳
* @param nonce Permit nonce(通常从代币合约的 nonces(owner) 获取)
* @returns Permit Piggyback 编码数据(Hex string)
*/
export async function buildPermitPiggybackAuto(chain, privateKey, tokenAddress, value, deadline, nonce, opts) {
const spender = FLAP_PORTAL_ADDRESSES[chain];
if (!spender) {
throw new Error(`Flap Portal not deployed on ${chain}`);
}
// 创建钱包
const wallet = new Wallet(privateKey);
const owner = wallet.address;
// 获取 chainId
const chainId = CHAIN[chain].chainId;
// 读取代币 name(优先 override,其次链上查询,不可用时回退为空字符串)
let tokenName = opts?.tokenNameOverride ?? '';
if (!tokenName && opts?.rpcUrl) {
try {
const erc20 = new Contract(tokenAddress, ['function name() view returns (string)'], new JsonRpcProvider(opts.rpcUrl));
tokenName = await erc20.name();
}
catch { }
}
// 构建 EIP-2612 Permit 消息(name 可能为空字符串,符合部分实现)
const domain = {
name: tokenName,
version: '1',
chainId,
verifyingContract: tokenAddress,
};
const types = {
Permit: [
{ name: 'owner', type: 'address' },
{ name: 'spender', type: 'address' },
{ name: 'value', type: 'uint256' },
{ name: 'nonce', type: 'uint256' },
{ name: 'deadline', type: 'uint256' },
],
};
const message = {
owner,
spender,
value: value.toString(),
nonce: nonce.toString(),
deadline: deadline.toString(),
};
// 签名
const signature = await wallet.signTypedData(domain, types, message);
// 解析签名为 v, r, s
const r = `0x${signature.slice(2, 66)}`;
const s = `0x${signature.slice(66, 130)}`;
const v = parseInt(signature.slice(130, 132), 16);
// 使用 ethers AbiCoder 编码 Permit Piggyback 数据
const abiCoder = AbiCoder.defaultAbiCoder();
return abiCoder.encode(['address', 'address', 'uint256', 'uint256', 'uint8', 'bytes32', 'bytes32'], [owner, spender, value, deadline, v, r, s]);
}