axie-tools
Version:
TypeScript library and CLI tool for interacting with Axie Infinity marketplace and NFTs on Ronin network. Features marketplace operations (buy/sell/delist), batch transfers, and wallet information.
239 lines (238 loc) • 10.7 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.getAxieIdsFromAccount = getAxieIdsFromAccount;
exports.delegateAxie = delegateAxie;
exports.batchDelegateAxies = batchDelegateAxies;
exports.batchRevokeDelegations = batchRevokeDelegations;
exports.revokeDelegation = revokeDelegation;
const ethers_1 = require("ethers");
const contracts_1 = require("./contracts");
// Delegation context hash
const ctxHash = "0xfa4914198408a3840a0a751c221614143f885428607953c71fa37ad0dd52f940";
async function approveAxieDelegation(signer) {
const axieContract = (0, contracts_1.getAxieContract)(signer);
const delegationContract = (0, contracts_1.getAxieDelegationContract)(signer);
const delegationAddress = await delegationContract.getAddress();
// Check if already approved
const isApproved = await axieContract.isApprovedForAll(await signer.getAddress(), delegationAddress);
if (!isApproved) {
console.log("Approving Axie delegation contract...");
const tx = await axieContract.setApprovalForAll(delegationAddress, true);
await tx.wait();
console.log("✅ Delegation contract approved");
}
}
async function getAxieIdsFromAccount(address, provider) {
// get axie contract
const axieContract = (0, contracts_1.getAxieContract)(provider);
// get axies balance for the address
const axiesBalance = await axieContract.balanceOf(address);
// get axie ids
const axieIds = [];
for (let i = 0; i < axiesBalance; i++) {
try {
const axieId = await axieContract.tokenOfOwnerByIndex(address, i);
axieIds.push(Number(axieId));
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : "Unknown error";
console.error(`Error fetching axie id at index ${i}: ${errorMessage}`);
}
}
return axieIds;
}
async function delegateAxie(signer, tokenId, delegatee) {
const axieContract = (0, contracts_1.getAxieContract)(signer);
const delegationContract = (0, contracts_1.getAxieDelegationContract)(signer);
// Format token ID
const formattedTokenId = typeof tokenId === "string" ? tokenId : tokenId.toString();
try {
// Check if context is already attached
const context = await axieContract.contextOf(formattedTokenId);
if (context === ctxHash) {
console.log(`ℹ️ Context already attached for Axie ${formattedTokenId}`);
}
else {
// If context exists but is different, we need to attach the correct one
console.log(`Attaching context for Axie ${formattedTokenId}`);
const tx1 = await axieContract.attachContext(ctxHash, formattedTokenId, "0x", {
gasPrice: (0, ethers_1.parseUnits)("20", "gwei"),
});
await tx1.wait();
console.log(`✅ Context attached for Axie ${formattedTokenId}`);
}
}
catch (error) {
// If error contains "execution reverted", context is already attached
if (error instanceof Error && error.message.includes('execution reverted')) {
console.log(`ℹ️ Context already attached for Axie ${formattedTokenId}`);
}
else {
// If any other error, try to attach context
try {
console.log(`Attaching context for Axie ${formattedTokenId}`);
const tx1 = await axieContract.attachContext(ctxHash, formattedTokenId, "0x", {
gasPrice: (0, ethers_1.parseUnits)("20", "gwei"),
});
await tx1.wait();
console.log(`✅ Context attached for Axie ${formattedTokenId}`);
}
catch (attachError) {
if (attachError instanceof Error && attachError.message.includes('execution reverted')) {
console.log(`ℹ️ Context already attached for Axie ${formattedTokenId}`);
}
else {
throw attachError;
}
}
}
}
// Calculate expiry timestamp (1 year from now)
const oneYearFromNow = Math.floor(Date.now() / 1000) + (365 * 24 * 60 * 60);
// Format the delegatee address
const cleanDelegatee = delegatee.replace("ronin:", "0x").toLowerCase();
console.log(`Delegating Axie ${formattedTokenId} to ${cleanDelegatee}`);
try {
// Call delegate function with standard method call
const tx2 = await delegationContract.delegate(formattedTokenId, cleanDelegatee, oneYearFromNow, 1, // permissionBitMap as uint64
{
gasPrice: (0, ethers_1.parseUnits)("20", "gwei"),
});
const receipt = await tx2.wait();
return receipt;
}
catch (error) {
console.error("Delegation error:", error);
throw error;
}
}
async function batchDelegateAxies(signer, axieIds, delegatee) {
const axieContract = (0, contracts_1.getAxieContract)(signer);
const delegationContract = (0, contracts_1.getAxieDelegationContract)(signer);
// Format token IDs and delegatee address
const tokenIds = axieIds.map(id => {
try {
return BigInt(id.toString().replace(/[^0-9]/g, ''));
}
catch (e) {
throw new Error(`Invalid Axie ID format: ${id}`);
}
});
// Format the delegatee address
const formattedDelegatee = delegatee.replace("ronin:", "0x").toLowerCase();
// Check and attach contexts individually
console.log(`Checking/attaching context for ${tokenIds.length} Axies`);
for (const tokenId of tokenIds) {
try {
// Check if context is already attached
const context = await axieContract.contextOf(tokenId.toString());
if (context === ctxHash) {
console.log(`ℹ️ Context already attached for Axie ${tokenId}`);
}
else {
console.log(`- Attaching context for Axie ${tokenId}`);
const tx1 = await axieContract.attachContext(ctxHash, tokenId.toString(), "0x");
await tx1.wait();
console.log(`✅ Context attached for Axie ${tokenId}`);
}
}
catch (error) {
// If error contains "execution reverted", context is already attached
if (error instanceof Error && error.message.includes('execution reverted')) {
console.log(`ℹ️ Context already attached for Axie ${tokenId}`);
}
else {
try {
console.log(`- Attaching context for Axie ${tokenId}`);
const tx1 = await axieContract.attachContext(ctxHash, tokenId.toString(), "0x");
await tx1.wait();
console.log(`✅ Context attached for Axie ${tokenId}`);
}
catch (attachError) {
if (attachError instanceof Error && attachError.message.includes('execution reverted')) {
console.log(`ℹ️ Context already attached for Axie ${tokenId}`);
}
else {
console.log(`❌ Failed to attach context for Axie ${tokenId}`, attachError);
throw attachError;
}
}
}
}
}
// Calculate expiry timestamp (1 year from now)
const oneYearFromNow = BigInt(Math.floor(Date.now() / 1000) + (365 * 24 * 60 * 60));
const permissionBitMap = 1n;
// Now do the bulk delegation
console.log(`\nDelegating ${tokenIds.length} Axies to ${delegatee}`);
try {
const tx2 = await delegationContract.bulkDelegate(tokenIds, Array(tokenIds.length).fill(formattedDelegatee), Array(tokenIds.length).fill(oneYearFromNow), Array(tokenIds.length).fill(permissionBitMap));
const receipt = await tx2.wait();
return receipt;
}
catch (error) {
// If bulk delegation fails, try individual delegations
console.log("\n⚠️ Bulk delegation failed:", error);
console.log("Falling back to individual delegations...\n");
for (const tokenId of tokenIds) {
try {
const tx = await delegationContract.delegate(tokenId, formattedDelegatee, oneYearFromNow, permissionBitMap);
await tx.wait();
console.log(`✅ Successfully delegated Axie ${tokenId}`);
}
catch (err) {
console.log(`❌ Failed to delegate Axie ${tokenId}`, err);
}
}
}
}
async function batchRevokeDelegations(signer, axieIds) {
const delegationContract = (0, contracts_1.getAxieDelegationContract)(signer);
// Format token IDs - ensure they are clean numeric strings
const tokenIds = axieIds.map(id => id.toString().replace(/[^0-9]/g, ''));
// Then do the bulk revocation
console.log(`\nRevoking delegations for ${tokenIds.length} Axies`);
try {
const tx2 = await delegationContract.bulkRevokeDelegations(tokenIds);
const receipt = await tx2.wait();
return receipt;
}
catch (error) {
console.log("\n⚠️ Bulk revocation failed:", error);
console.log("Falling back to individual revocations...\n");
for (const tokenId of tokenIds) {
try {
const tx = await delegationContract.revokeDelegation(tokenId);
await tx.wait();
console.log(`✅ Successfully revoked delegation for Axie ${tokenId}`);
}
catch (err) {
console.log(`❌ Failed to revoke delegation for Axie ${tokenId}`, err);
}
}
}
}
async function revokeDelegation(signer, tokenId) {
// // First approve the delegation contract if needed
// await approveAxieDelegation(signer);
// const axieContract = getAxieContract(signer);
const delegationContract = (0, contracts_1.getAxieDelegationContract)(signer);
// // First request detachment
// console.log(`Requesting detachment for Axie ${Number(tokenId)}...`);
// const tx1 = await axieContract.requestDetachContext(
// ctxHash,
// Number(tokenId),
// "0x",
// {
// gasPrice: parseUnits("20", "gwei"),
// }
// );
// await tx1.wait();
// Then revoke the delegation
console.log(`Revoking delegation for Axie ${Number(tokenId)}`);
const tx2 = await delegationContract.revokeDelegation(Number(tokenId), {
gasPrice: (0, ethers_1.parseUnits)("20", "gwei"),
});
const receipt = await tx2.wait();
return receipt;
}