four-flap-meme-sdk
Version:
SDK for Flap bonding curve and four.meme TokenManager
177 lines (176 loc) • 8.1 kB
JavaScript
import { Contract, JsonRpcProvider, Wallet } from 'ethers';
import TM2Abi from '../abis/TokenManager2.json' with { type: 'json' };
import Helper3Abi from '../abis/TokenManagerHelper3.json' with { type: 'json' };
import { Contract as EContract } from 'ethers';
import { ADDRESSES } from '../utils/constants.js';
import { TM1 } from './tm1.js';
import { TM2 } from './tm2.js';
export async function createTokenOnChain(params) {
const { chain, rpcUrl, signerPrivateKey, args, signature, valueWei } = params;
const provider = new JsonRpcProvider(rpcUrl);
const signer = new Wallet(signerPrivateKey, provider);
// 使用 Four.meme 平台原始合约地址(API 签名是给原始合约的)
const FOUR_ORIGINAL_TM2 = '0x5c952063c7fc8610FFDB798152D69F0B9550762b';
const tm2 = new Contract(FOUR_ORIGINAL_TM2, TM2Abi, signer);
const tx = await tm2.createToken(args, signature, { value: valueWei ?? 0n });
const receipt = await tx.wait();
// 解析 TokenCreate 事件获取代币地址
let tokenAddress;
if (receipt && receipt.logs) {
for (const log of receipt.logs) {
try {
const parsed = tm2.interface.parseLog({ topics: log.topics, data: log.data });
if (parsed && parsed.name === 'TokenCreate') {
tokenAddress = parsed.args.token;
break;
}
}
catch (e) {
// 忽略无法解析的日志
}
}
}
return { receipt, tokenAddress };
}
export async function tryBuy(chain, rpcUrl, token, amount, funds, proxyAddressOverride) {
const helper3Addresses = {
BSC: ADDRESSES.BSC.TokenManagerHelper3,
BASE: ADDRESSES.BASE.TokenManagerHelper3,
ARBITRUM_ONE: ADDRESSES.ARBITRUM_ONE.TokenManagerHelper3,
};
const provider = new JsonRpcProvider(rpcUrl);
// 优先用代理预览(若提供)
if (proxyAddressOverride) {
const proxyAbi = [
'function previewBuy(address token, uint256 funds) view returns (uint256)',
];
const proxy = new EContract(proxyAddressOverride, proxyAbi, provider);
const estimatedAmount = await proxy.previewBuy(token, funds);
return {
tokenManager: 'proxy',
quote: '0x0000000000000000000000000000000000000000',
estimatedAmount,
estimatedCost: funds,
estimatedFee: 0n,
amountMsgValue: funds,
amountApproval: 0n,
amountFunds: funds,
};
}
const helper = new Contract(helper3Addresses[chain], Helper3Abi, provider);
const r = await helper.tryBuy(token, amount, funds);
return {
tokenManager: r.tokenManager,
quote: r.quote,
estimatedAmount: r.estimatedAmount,
estimatedCost: r.estimatedCost,
estimatedFee: r.estimatedFee,
amountMsgValue: r.amountMsgValue,
amountApproval: r.amountApproval,
amountFunds: r.amountFunds,
};
}
export async function trySell(chain, rpcUrl, token, amount, proxyAddressOverride) {
const helper3Addresses = {
BSC: ADDRESSES.BSC.TokenManagerHelper3,
BASE: ADDRESSES.BASE.TokenManagerHelper3,
ARBITRUM_ONE: ADDRESSES.ARBITRUM_ONE.TokenManagerHelper3,
};
const provider = new JsonRpcProvider(rpcUrl);
// 优先用代理预览(若提供)
if (proxyAddressOverride) {
const proxyAbi = [
'function previewSell(address token, uint256 amount) view returns (uint256)',
];
const proxy = new EContract(proxyAddressOverride, proxyAbi, provider);
const funds = await proxy.previewSell(token, amount);
return {
tokenManager: 'proxy',
quote: '0x0000000000000000000000000000000000000000',
funds,
fee: 0n,
};
}
const helper = new Contract(helper3Addresses[chain], Helper3Abi, provider);
const r = await helper.trySell(token, amount);
return {
tokenManager: r.tokenManager,
quote: r.quote,
funds: r.funds,
fee: r.fee,
};
}
export async function buyTokenWithFunds(chain, rpcUrl, signerPrivateKey, token, funds, minAmount, to, origin = 0n) {
const provider = new JsonRpcProvider(rpcUrl);
const signer = new Wallet(signerPrivateKey, provider);
const tm2 = new Contract(ADDRESSES[chain].TokenManagerV2, TM2Abi, signer);
if (to) {
const tx = await tm2.buyTokenAMAP(origin, token, to, funds, minAmount, { value: funds });
return await tx.wait();
}
else {
const tx = await tm2.buyTokenAMAP(token, funds, minAmount, { value: funds });
return await tx.wait();
}
}
export async function sellToken(chain, rpcUrl, signerPrivateKey, token, amount, minFunds, origin = 0n) {
const provider = new JsonRpcProvider(rpcUrl);
const signer = new Wallet(signerPrivateKey, provider);
const tm2 = new Contract(ADDRESSES[chain].TokenManagerV2, TM2Abi, signer);
// 使用明确的函数签名避免歧义
const tx = await tm2['sellToken(uint256,address,uint256,uint256)'](origin, token, amount, minFunds);
return await tx.wait();
}
// 统一路由:根据 Helper3.getTokenInfo.version 选择 V1 或 V2
export async function tradeBuy(chain, rpcUrl, token, params) {
const helper3Addresses = {
BSC: ADDRESSES.BSC.TokenManagerHelper3,
BASE: ADDRESSES.BASE.TokenManagerHelper3,
ARBITRUM_ONE: ADDRESSES.ARBITRUM_ONE.TokenManagerHelper3,
};
const provider = new JsonRpcProvider(rpcUrl);
const helper = new Contract(helper3Addresses[chain], Helper3Abi, provider);
const info = await helper.getTokenInfo(token);
const version = info.version;
if (version === 1n) {
if (chain !== 'BSC')
throw new Error('TokenManager V1 only supported on BSC');
const tm1 = TM1.connectByChain('BSC', rpcUrl);
if (params.type === 'funds')
return await tm1.purchaseTokenAMAP(token, params.funds, params.minAmount, params.origin, params.to);
return await tm1.purchaseToken(token, params.amount, params.maxFunds, params.origin, params.to);
}
if (chain !== 'BSC')
throw new Error('TokenManager V2 only supported on BSC');
const tm2 = TM2.connectByChain('BSC', rpcUrl);
if (params.type === 'funds')
return await tm2.buyTokenAMAP(params.origin ?? 0n, token, params.to ?? undefined, params.funds, params.minAmount);
return await tm2.buyToken(params.origin ?? 0n, token, params.to ?? undefined, params.amount, params.maxFunds);
}
export async function tradeSell(chain, rpcUrl, token, params) {
const helper3Addresses = {
BSC: ADDRESSES.BSC.TokenManagerHelper3,
BASE: ADDRESSES.BASE.TokenManagerHelper3,
ARBITRUM_ONE: ADDRESSES.ARBITRUM_ONE.TokenManagerHelper3,
};
const provider = new JsonRpcProvider(rpcUrl);
const helper = new Contract(helper3Addresses[chain], Helper3Abi, provider);
const info = await helper.getTokenInfo(token);
const version = info.version;
if (version === 1n) {
if (chain !== 'BSC')
throw new Error('TokenManager V1 only supported on BSC');
const tm1 = TM1.connectByChain('BSC', rpcUrl);
if (params.type === 'router' && params.from)
return await tm1.saleToken(token, params.amount, params.origin, params.from, params.minFunds, params.feeRate, params.feeRecipient);
return await tm1.saleToken(token, params.amount, params.origin, undefined, params.minFunds);
}
if (chain !== 'BSC')
throw new Error('TokenManager V2 only supported on BSC');
const tm2 = TM2.connectByChain('BSC', rpcUrl);
if (params.type === 'router')
return await tm2.sellTokenFrom(params.origin ?? 0n, token, params.from, params.amount, params.minFunds, params.feeRate, params.feeRecipient);
if (params.minFunds !== undefined)
return await tm2.sellToken(params.origin ?? 0n, token, params.amount, params.minFunds);
return await tm2.sellToken(token, params.amount);
}