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.
468 lines (467 loc) ⢠25.9 kB
JavaScript
#!/usr/bin/env node
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const prompts_1 = require("@inquirer/prompts");
const ethers_1 = require("ethers");
const axie_1 = require("./lib/axie");
const access_token_1 = require("./lib/marketplace/access-token");
const transfers_1 = require("./lib/transfers");
const utils_1 = require("./lib/utils");
const approve_1 = require("./lib/marketplace/approve");
const settle_order_1 = __importDefault(require("./lib/marketplace/settle-order"));
const cancel_order_1 = __importDefault(require("./lib/marketplace/cancel-order"));
const create_order_1 = __importDefault(require("./lib/marketplace/create-order"));
const atia_1 = require("./lib/atia");
const delegation_1 = require("./lib/atia/delegation");
const graphql_1 = require("./lib/atia/graphql");
require("dotenv/config");
async function main() {
// Check for PRIVATE_KEY before the main loop
let privateKey = process.env.PRIVATE_KEY;
if (!privateKey) {
privateKey = await (0, prompts_1.password)({
message: "š Enter your private key:",
validate: (value) => {
if (!value)
return false;
// Private keys are 32 bytes (64 characters) + optional "0x" prefix
return (0, ethers_1.isHexString)(value, 32) || (0, ethers_1.isHexString)(`0x${value}`, 32);
},
});
// Ensure "0x" prefix
privateKey = privateKey.startsWith("0x") ? privateKey : `0x${privateKey}`;
}
// Initialize provider with a reliable RPC endpoint
const provider = new ethers_1.JsonRpcProvider("https://api.roninchain.com/rpc");
// Initialize wallet with the previously obtained private key
const wallet = new ethers_1.Wallet(privateKey, provider);
const address = await wallet.getAddress();
while (true) {
try {
const action = await (0, prompts_1.select)({
message: "What would you like to do?",
choices: [
{ name: "Get account info", value: "account" },
{ name: "Refresh access token", value: "refresh-token" },
{ name: "Approve WETH", value: "approve-weth" },
{ name: "Approve marketplace", value: "approve-marketplace" },
{ name: "Buy axie", value: "buy" },
{ name: "Delist axie", value: "delist" },
{ name: "Delist multiple axies", value: "delist-all" },
{ name: "List axie", value: "list" },
{ name: "List multiple axies", value: "list-all" },
{ name: "Transfer axie", value: "transfer" },
{ name: "Transfer multiple axies", value: "transfer-all" },
{ name: "Delegate axie", value: "delegate-axie" },
{ name: "Revoke axie delegation", value: "revoke-delegation-axie" },
{ name: "Delegate multiple axies", value: "batch-delegate" },
{ name: "Revoke multiple delegations", value: "batch-revoke" },
{ name: "Check Atia blessing status", value: "check-blessing" },
{ name: "Pray for Atia blessing", value: "pray-blessing" },
{ name: "Create Atia Blessing delegation", value: "delegate" },
{ name: "List Atia Blessing delegations", value: "list-delegations" },
{ name: "Revoke Atia Blessing delegation", value: "revoke-delegation" },
],
});
switch (action) {
case "account": {
const info = await (0, utils_1.getAccountInfo)(address, provider);
console.log(`š¬ Address: ${info.address}`);
console.log("š° RON Balance:", info.ronBalance);
console.log("š° WETH Balance:", info.wethBalance);
console.log("š° USDC Balance:", info.usdcBalance);
console.log("š Marketplace WETH allowance:", info.allowance !== 0n ? "ā
Granted" : "ā Not granted");
console.log("š Marketplace approval for Axies:", info.isApprovedForAll ? "ā
Approved" : "ā Not approved");
console.log(`š¾ Number of Axies: ${info.axieIds.length}`);
if (info.axieIds.length > 0) {
console.log(`š Axie IDs: ${info.axieIds.join(", ")}`);
}
break;
}
case "refresh-token": {
let refreshTokenValue = process.env.MARKETPLACE_REFRESH_TOKEN;
if (!refreshTokenValue) {
refreshTokenValue = await (0, prompts_1.input)({
message: "Enter refresh token",
validate: (value) => value.length > 0,
});
}
const result = await (0, access_token_1.refreshToken)(refreshTokenValue);
console.log("New access token:", result.newAccessToken);
console.log("New refresh token:", result.newRefreshToken);
process.env.MARKETPLACE_ACCESS_TOKEN = result.newAccessToken;
process.env.MARKETPLACE_REFRESH_TOKEN = result.newRefreshToken;
break;
}
case "approve-weth": {
await (0, approve_1.approveWETH)(wallet);
break;
}
case "approve-marketplace": {
await (0, approve_1.approveMarketplaceContract)(wallet);
break;
}
case "buy": {
const token = await (0, utils_1.ensureMarketplaceToken)();
const axieId = await (0, utils_1.getAxieId)();
if (!axieId)
break;
await (0, approve_1.approveWETH)(wallet);
const receipt = await (0, settle_order_1.default)(axieId, wallet, token);
if (receipt) {
console.log("š Transaction successful! Hash:", receipt.hash);
console.log(`š View transaction: https://app.roninchain.com/tx/${receipt.hash}`);
}
break;
}
case "list": {
const axieId = await (0, utils_1.getAxieId)();
if (!axieId)
break;
const token = await (0, utils_1.ensureMarketplaceToken)();
const basePrice = await (0, prompts_1.input)({
message: "Enter base price in ETH",
validate: (value) => (0, ethers_1.parseEther)(value) > 0n,
});
await (0, approve_1.approveMarketplaceContract)(wallet);
const currentBlock = await provider.getBlock("latest");
const startedAt = currentBlock?.timestamp ?? Math.floor(Date.now() / 1000);
const expiredAt = startedAt + 15634800; // ~6 months
const orderData = {
address,
axieId: axieId.toString(),
basePrice: (0, ethers_1.parseEther)(basePrice).toString(),
endedPrice: "0",
startedAt,
endedAt: 0,
expiredAt,
};
const result = await (0, create_order_1.default)(orderData, token, wallet);
if (result === null || result.errors || !result.data) {
console.error("ā Error:", result?.errors?.[0]?.message || "Unknown error");
break;
}
console.log(`ā
Listed Axie ${axieId}! Current price in USD: ${result.data.createOrder.currentPriceUsd}`);
break;
}
case "list-all": {
const token = await (0, utils_1.ensureMarketplaceToken)();
const basePrice = await (0, prompts_1.input)({
message: "Enter base price in ETH (for all Axies)",
validate: (value) => (0, ethers_1.parseEther)(value) > 0n,
});
await (0, approve_1.approveMarketplaceContract)(wallet);
let axieIds = await (0, axie_1.getAxieIdsFromAccount)(address, provider);
if (axieIds.length > 100) {
console.log("ā ļø Warning: Can only list up to 100 Axies at once, only listing the first 100");
axieIds = axieIds.slice(0, 100);
}
const currentBlock = await provider.getBlock("latest");
const startedAt = currentBlock?.timestamp ?? Math.floor(Date.now() / 1000);
const expiredAt = startedAt + 15634800; // ~6 months
for (const axieId of axieIds) {
const orderData = {
address,
axieId: axieId.toString(),
basePrice: (0, ethers_1.parseEther)(basePrice).toString(),
endedPrice: "0",
startedAt,
endedAt: 0,
expiredAt,
};
const result = await (0, create_order_1.default)(orderData, token, wallet);
if (result === null || result.errors || !result.data) {
console.error(`ā Error listing Axie ${axieId}:`, result?.errors?.[0]?.message || "Unknown error");
continue;
}
console.log(`ā
Listed Axie ${axieId}! Current price in USD: ${result.data.createOrder.currentPriceUsd}`);
}
break;
}
case "delist": {
const axieId = await (0, utils_1.getAxieId)();
if (!axieId)
break;
const receipt = await (0, cancel_order_1.default)(axieId, wallet);
if (receipt) {
console.log("ā
Axie delisted! Transaction hash:", receipt.hash);
console.log(`š View transaction: https://app.roninchain.com/tx/${receipt.hash}`);
}
break;
}
case "delist-all": {
const axieIdsInput = await (0, prompts_1.input)({
message: "Enter comma-separated Axie IDs to delist (e.g. 123, 456, 789)",
validate: (value) => {
const ids = value.split(",").map(id => id.trim());
return ids.length > 0 && ids.every(id => !Number.isNaN(Number(id)));
},
});
let axieIds = axieIdsInput.split(",").map(id => id.trim());
if (axieIds.length > 100) {
console.log("ā ļø Warning: Can only delist up to 100 Axies at once, only delisting the first 100");
axieIds = axieIds.slice(0, 100);
}
const receipt = await (0, transfers_1.batchTransferAxies)(wallet, await wallet.getAddress(), axieIds);
if (receipt) {
console.log("ā
Axies delisted! Transaction hash:", receipt.hash);
console.log(`š View transaction: https://app.roninchain.com/tx/${receipt.hash}`);
}
else {
console.log("ā Error delisting Axies");
}
break;
}
case "transfer": {
const axieId = await (0, utils_1.getAxieId)();
if (!axieId)
break;
const address = await (0, prompts_1.input)({
message: "Enter recipient address",
validate: (value) => value.length > 0,
});
const receipt = await (0, transfers_1.transferAxie)(wallet, address, axieId);
if (receipt) {
console.log("ā
Axie transferred! Transaction hash:", receipt.hash);
}
break;
}
case "transfer-all": {
const axieIdsInput = await (0, prompts_1.input)({
message: "Enter comma-separated Axie IDs (e.g. 123, 456, 789)",
validate: (value) => {
const ids = value.split(",").map(id => id.trim());
return ids.length > 0 && ids.every(id => !Number.isNaN(Number(id)));
},
});
let axieIds = axieIdsInput.split(",").map(id => id.trim());
if (axieIds.length > 100) {
console.log("ā ļø Warning: Can only transfer up to 100 Axies at once, only transferring the first 100");
axieIds = axieIds.slice(0, 100);
}
const address = await (0, prompts_1.input)({
message: "Enter recipient address",
validate: (value) => value.length > 0,
});
const receipt = await (0, transfers_1.batchTransferAxies)(wallet, address, axieIds);
if (receipt) {
console.log("ā
Axies transferred! Transaction hash:", receipt.hash);
}
break;
}
case "delegate-axie": {
const axieId = await (0, utils_1.getAxieId)();
if (!axieId)
break;
const address = await (0, prompts_1.input)({
message: "Enter delegatee address",
validate: (value) => value.length > 0,
});
const receipt = await (0, axie_1.delegateAxie)(wallet, axieId, address);
if (receipt) {
console.log("ā
Axie delegated! Transaction hash:", receipt.hash);
console.log(`š View transaction: https://app.roninchain.com/tx/${receipt.hash}`);
}
break;
}
case "revoke-delegation-axie": {
const axieId = await (0, utils_1.getAxieId)();
if (!axieId)
break;
console.log("š Starting delegation revocation process (this requires multiple transactions)...");
const receipt = await (0, axie_1.revokeDelegation)(wallet, axieId);
if (receipt) {
console.log("ā
Axie delegation fully revoked! Final transaction hash:", receipt.hash);
console.log(`š View transaction: https://app.roninchain.com/tx/${receipt.hash}`);
}
break;
}
case "batch-delegate": {
const axieIdsInput = await (0, prompts_1.input)({
message: "Enter comma-separated Axie IDs to delegate (e.g. 123, 456, 789)",
validate: (value) => {
const ids = value.split(",").map(id => id.trim());
return ids.length > 0 && ids.every(id => !Number.isNaN(Number(id)));
},
});
let axieIds = axieIdsInput.split(",").map(id => id.trim());
if (axieIds.length === 0) {
console.log("ā No Axie IDs provided");
break;
}
if (axieIds.length > 100) {
console.log("ā ļø Warning: Can only delegate up to 100 Axies at once, only delegating the first 100");
axieIds = axieIds.slice(0, 100);
}
const address = await (0, prompts_1.input)({
message: "Enter delegatee address",
validate: (value) => value.length > 0,
});
console.log("\nš Starting batch delegation process...");
try {
const receipt = await (0, axie_1.batchDelegateAxies)(wallet, axieIds, address);
if (receipt) {
console.log("\nā
Batch operation completed! Final transaction hash:", receipt.hash);
console.log(`š View transaction: https://app.roninchain.com/tx/${receipt.hash}`);
}
}
catch (error) {
console.log("\nā Some operations failed. Check the logs above for details.");
}
break;
}
case "batch-revoke": {
const axieIdsInput = await (0, prompts_1.input)({
message: "Enter comma-separated Axie IDs to revoke delegation (e.g. 123, 456, 789)",
validate: (value) => {
const ids = value.split(",").map(id => id.trim());
return ids.length > 0 && ids.every(id => !Number.isNaN(Number(id)));
},
});
let axieIds = axieIdsInput.split(",").map(id => id.trim());
if (axieIds.length === 0) {
console.log("ā No Axie IDs provided");
break;
}
if (axieIds.length > 100) {
console.log("ā ļø Warning: Can only revoke up to 100 Axies at once, only revoking the first 100");
axieIds = axieIds.slice(0, 100);
}
console.log("\nš Starting batch revocation process...");
console.log("This will:");
console.log("1. Check and approve delegation contract if needed");
console.log("2. Request detachment for each Axie");
console.log("3. Perform the revocation\n");
try {
const receipt = await (0, axie_1.batchRevokeDelegations)(wallet, axieIds);
if (receipt) {
console.log("\nā
Batch operation completed! Final transaction hash:", receipt.hash);
console.log(`š View transaction: https://app.roninchain.com/tx/${receipt.hash}`);
}
}
catch (error) {
console.log("\nā Some operations failed. Check the logs above for details.");
}
break;
}
case "check-blessing": {
const address = await (0, prompts_1.input)({
message: "Enter address to check blessing status (press Enter to use your address)",
validate: () => true,
});
const targetAddress = address || wallet.address;
const { status, streak } = await (0, atia_1.isActivated)(targetAddress, provider);
if (status) {
console.log(`ā
Address ${targetAddress.slice(-4)} has already prayed today (Current streak: ${streak})`);
}
else {
console.log(`ā Address ${targetAddress.slice(-4)} has not prayed today (Current streak: ${streak})`);
}
break;
}
case "pray-blessing": {
const token = await (0, utils_1.ensureMarketplaceToken)();
await (0, atia_1.checkBlessings)(wallet, token);
break;
}
case "delegate": {
const token = await (0, utils_1.ensureMarketplaceToken)();
if (!token) {
console.log("ā No marketplace token available. Please refresh token first.");
break;
}
const toAddress = await (0, prompts_1.input)({
message: "Enter delegatee address:",
validate: (value) => (0, ethers_1.isAddress)(value),
});
const percentage = await (0, prompts_1.input)({
message: "Enter delegator slips percentage (default: 100):",
validate: (value) => {
if (value === "")
return true;
const num = Number.parseInt(value);
return !Number.isNaN(num) && num > 0 && num <= 100;
},
default: "100"
});
const delegatedAt = Math.floor(Date.now() / 1000);
console.log("\nš Creating delegation signature...");
const { message, signature } = await (0, delegation_1.signDelegation)(wallet, toAddress, delegatedAt, Number.parseInt(percentage));
console.log("ā
Signature created!");
console.log("\nš Message:", message);
console.log("āļø Signature:", signature);
console.log("\nš Submitting delegation...");
const success = await (0, graphql_1.delegateAtiaBlessing)(token, signature, wallet.address, toAddress, delegatedAt, Number.parseInt(percentage));
if (success) {
console.log("ā
Delegation submitted successfully!");
}
else {
console.log("ā Failed to submit delegation");
}
break;
}
case "revoke-delegation": {
const token = await (0, utils_1.ensureMarketplaceToken)();
if (!token) {
console.log("ā No marketplace token available. Please refresh token first.");
break;
}
const toAddress = await (0, prompts_1.input)({
message: "Enter delegatee address to revoke:",
validate: (value) => (0, ethers_1.isAddress)(value),
});
console.log("\nš Revoking delegation...");
const success = await (0, graphql_1.revokeAtiaBlessingDelegation)(token, wallet.address, // userAddress
toAddress, wallet.address // fromAddress
);
if (success) {
console.log("ā
Delegation revoked successfully!");
}
else {
console.log("ā Failed to revoke delegation");
}
break;
}
case "list-delegations": {
const token = await (0, utils_1.ensureMarketplaceToken)();
if (!token) {
console.log("ā No marketplace token available. Please refresh token first.");
break;
}
console.log("\nš Checking delegations...");
const delegations = await (0, graphql_1.getAtiaBlessingDelegations)(token, wallet.address);
if (delegations.length === 0) {
console.log("ā¹ļø No delegations found");
break;
}
console.log("\nš Delegations:");
for (const delegation of delegations) {
const fromName = delegation.fromProfile?.name || delegation.fromAddress.slice(-4);
const toName = delegation.toProfile?.name || delegation.toAddress.slice(-4);
console.log(`\nš From: ${fromName} (${delegation.fromAddress})`);
console.log(` To: ${toName} (${delegation.toAddress})`);
console.log(` Percentage: ${delegation.delegatorSlipsPercent}%`);
console.log(` Last Prayed: ${delegation.lastPrayedAt ? new Date(delegation.lastPrayedAt).toLocaleString() : 'Never'}`);
console.log(` Delegated At: ${new Date(delegation.delegatedAt * 1000).toLocaleString()}`);
}
break;
}
}
}
catch (error) {
if (error instanceof Error) {
console.error("ā Error:", error.message);
}
else {
console.error("ā Error:", error);
}
}
finally {
await (0, utils_1.askToContinue)();
}
}
}
main();