UNPKG

anchor-sdk

Version:

TypeScript SDK for interacting with Anchor ecosystem - badge minting, payment processing, and ERC1155 token management

302 lines (301 loc) 12.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.AnchorERC1155Client = void 0; const viem_1 = require("viem"); const AnchorERC1155_1 = require("./abi/AnchorERC1155"); const typechain_1 = require("./typechain"); /** * AnchorERC1155 客户端 * 用于与 AnchorERC1155 合约交互 */ class AnchorERC1155Client { /** * 创建 AnchorERC1155 客户端 * @param publicClient 公共客户端(只读操作) * @param network 网络配置 * @param walletClient 钱包客户端(写入操作) * @param account 账户(可选,如果不提供则使用只读模式) */ constructor(publicClient, network, walletClient, account, contracts) { this.publicClient = publicClient; this.network = network; this.walletClient = walletClient; this.account = account; this.contracts = contracts || {}; } /** * 获取代币 URI * @param tokenId 代币 ID * @returns 代币 URI */ async getTokenURI(tokenId) { if (!this.contracts?.anchorERC1155) { throw new Error("AnchorERC1155 contract address not set, please check network configuration"); } return (await this.publicClient.readContract({ address: this.contracts.anchorERC1155, abi: AnchorERC1155_1.AnchorERC1155ABI, functionName: "uri", args: [tokenId], })); } /** * 获取代币名称 * @returns 代币名称 */ async getName() { if (!this.contracts?.anchorERC1155) { throw new Error("AnchorERC1155 contract address not set, please check network configuration"); } return (await this.publicClient.readContract({ address: this.contracts.anchorERC1155, abi: AnchorERC1155_1.AnchorERC1155ABI, functionName: "name", })); } /** * 获取代币符号 * @returns 代币符号 */ async getSymbol() { if (!this.contracts?.anchorERC1155) { throw new Error("AnchorERC1155 contract address not set, please check network configuration"); } return (await this.publicClient.readContract({ address: this.contracts.anchorERC1155, abi: AnchorERC1155_1.AnchorERC1155ABI, functionName: "symbol", })); } /** * 使用签名铸造代币(免费代币) * @param signedRequest 签名铸造请求 * @param options 选项,可以控制是否直接发送交易 * @returns 如果直接发送交易,返回交易收据;否则返回交易数据 */ async mintWithSignature(signedRequest, anchorERC1155Address, options) { if (BigInt(signedRequest.request.price) !== 0n) { throw new Error("mintWithSignature method can only be used to mint free tokens"); } const contractAddress = anchorERC1155Address || this.contracts?.anchorERC1155; // 用 typechain encodeFunctionData,参数断言为 any 以兼容类型 const data = typechain_1.AnchorERC1155__factory.createInterface().encodeFunctionData("mintWithSignature", [ this.formatMintRequest(signedRequest.request), signedRequest.signature, ]); // const data = encodeFunctionData({ // abi: AnchorERC1155ABI, // functionName: "mintWithSignature", // args: [ // this.formatMintRequest(signedRequest.request), // signedRequest.signature as `0x${string}`, // ], // }); console.log(data, "data"); if (options?.sendTransaction === false) { return { to: contractAddress, data, value: 0n, }; } if (!this.walletClient || !this.account) { throw new Error("Wallet client and account are required to send transactions"); } // 估算 gas 和费用 const { maxFeePerGas, maxPriorityFeePerGas } = await this.publicClient.estimateFeesPerGas(); const gas = await this.publicClient.estimateGas({ to: contractAddress, data: data, value: 0n, account: this.account, }); const txHash = await this.walletClient.writeContract({ account: this.account, address: contractAddress, abi: typechain_1.AnchorERC1155__factory.abi, functionName: "mintWithSignature", args: [ this.formatMintRequest(signedRequest.request), signedRequest.signature, ], chain: this.publicClient.chain, maxFeePerGas, maxPriorityFeePerGas, gas, }); const receipt = await this.publicClient.waitForTransactionReceipt({ hash: txHash, }); return receipt; } /** * 编码签名铸造请求(用于通过 AnchorPay 支付) * @param signedRequest 签名铸造请求 * @returns 编码后的数据 */ encodeTokenReceivedData(signedRequest) { // 计算接口哈希 - AnchorERC1155 接口标识 const interfaceHash = (0, viem_1.keccak256)((0, viem_1.stringToHex)("AnchorERC1155")); // 准备签名数据 const signature = signedRequest.signature.startsWith("0x") ? signedRequest.signature : `0x${signedRequest.signature}`; // 格式化请求数据 const formattedRequest = this.formatMintRequest(signedRequest.request); console.log("Formatted request data:", JSON.stringify(formattedRequest, (_, v) => typeof v === "bigint" ? v.toString() : v)); console.log("Signature:", signature); // 编码tokenReceived函数调用 // tokenReceived(address token, address from, address to, uint256 amount, bytes calldata userData) // 其中userData是通过abi.encode(MintRequest, signature)编码的 // 1. 首先编码userData - 这是合约中通过abi.decode解码的部分 const userData = (0, viem_1.encodeAbiParameters)([ { components: [ { name: "to", type: "address" }, { name: "tokenId", type: "uint256" }, { name: "quantity", type: "uint256" }, { name: "price", type: "uint256" }, { name: "currency", type: "address" }, { name: "validityStartTimestamp", type: "uint128" }, { name: "validityEndTimestamp", type: "uint128" }, { name: "uid", type: "bytes32" }, { name: "chainId", type: "uint256" }, { name: "projectHandle", type: "bytes32" }, ], name: "req", type: "tuple", }, { name: "signature", type: "bytes" }, ], [formattedRequest, signature]); console.log("Encoded userData:", userData); // 返回完整的编码数据 return (0, viem_1.concat)([interfaceHash, userData]); } /** * 编码签名铸造请求(用于通过 AnchorPay 支付),使用空接口字符串 * @param signedRequest 签名铸造请求 * @returns 编码后的数据 */ encodeTokenReceivedDataWithEmptyInterface(signedRequest) { // 计算接口哈希 - 使用空字符串 const interfaceHash = (0, viem_1.keccak256)((0, viem_1.stringToHex)("")); // 准备签名数据 const signature = signedRequest.signature.startsWith("0x") ? signedRequest.signature : `0x${signedRequest.signature}`; // 格式化请求数据 const formattedRequest = this.formatMintRequest(signedRequest.request); console.log("Formatted request data (empty interface):", JSON.stringify(formattedRequest, (_, v) => typeof v === "bigint" ? v.toString() : v)); console.log("Signature:", signature); // 编码userData - 与标准方法相同,只是接口哈希不同 const userData = (0, viem_1.encodeAbiParameters)([ { components: [ { name: "to", type: "address" }, { name: "tokenId", type: "uint256" }, { name: "quantity", type: "uint256" }, { name: "price", type: "uint256" }, { name: "currency", type: "address" }, { name: "validityStartTimestamp", type: "uint128" }, { name: "validityEndTimestamp", type: "uint128" }, { name: "uid", type: "bytes32" }, { name: "chainId", type: "uint256" }, { name: "projectHandle", type: "bytes32" }, ], name: "req", type: "tuple", }, { name: "signature", type: "bytes" }, ], [formattedRequest, signature]); console.log("Encoded userData (empty interface):", userData); // 返回完整的编码数据 return (0, viem_1.concat)([interfaceHash, userData]); } /** * multicall 方法,用于批量执行交易 * @param data 编码后的交易数据数组 * @param options 选项,可以控制是否直接发送交易 * @returns 如果直接发送交易,返回交易收据;否则返回交易数据 */ async multicall(data, options) { if (!this.contracts?.anchorERC1155) { throw new Error("AnchorERC1155 contract address not set, please check network configuration"); } const contractAddress = this.contracts.anchorERC1155; const calldata = (0, viem_1.encodeFunctionData)({ abi: AnchorERC1155_1.AnchorERC1155ABI, functionName: "multicall", args: [data], }); if (options?.sendTransaction === false) { return { to: contractAddress, data: calldata, value: 0n, }; } if (!this.walletClient || !this.account) { throw new Error("Wallet client and account are required to send transactions"); } const { maxFeePerGas, maxPriorityFeePerGas } = await this.publicClient.estimateFeesPerGas(); const gas = await this.publicClient.estimateGas({ to: contractAddress, data: calldata, value: 0n, account: this.account, }); const txHash = await this.walletClient.writeContract({ account: this.account, address: contractAddress, abi: AnchorERC1155_1.AnchorERC1155ABI, functionName: "multicall", args: [data], chain: this.publicClient.chain, maxFeePerGas, maxPriorityFeePerGas, gas, }); return await this.publicClient.waitForTransactionReceipt({ hash: txHash }); } /** * 格式化铸造请求,将 bigint 转换为字符串 * @param request 铸造请求 * @returns 格式化后的铸造请求 */ formatMintRequest(request) { let uid; if (typeof request.uid === "string") { if (request.uid.startsWith("0x")) { uid = request.uid; } else { uid = (0, viem_1.keccak256)((0, viem_1.stringToHex)(request.uid)); } } else { uid = request.uid; } // 计算当前时间戳(秒) const currentTimestamp = BigInt(Math.floor(Date.now() / 1000)); return { to: request.to, tokenId: BigInt(request.tokenId), quantity: BigInt(request.quantity), price: BigInt(request.price), currency: request.currency, validityStartTimestamp: request.validityStartTimestamp ? BigInt(request.validityStartTimestamp) : currentTimestamp, validityEndTimestamp: request.validityEndTimestamp ? BigInt(request.validityEndTimestamp) : request.validUntil ? BigInt(request.validUntil) : currentTimestamp + 3600n, // 默认1小时后过期 uid: uid, chainId: BigInt(request.chainId || this.network.id), projectHandle: request.projectHandle, }; } } exports.AnchorERC1155Client = AnchorERC1155Client;