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
JavaScript
"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;