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.
226 lines (206 loc) • 5.17 kB
text/typescript
import {
AbiCoder,
Contract,
Interface,
type Signer,
type TransactionReceipt,
formatEther,
parseUnits,
} from "ethers";
import { apiRequest } from "../utils";
import {
APP_AXIE_ORDER_EXCHANGE,
MARKETPLACE_GATEWAY_V_2,
MARKET_GATEWAY_PROXY,
WRAPPED_ETHER,
} from "@roninbuilders/contracts";
interface Axie {
id: string;
order: Order;
}
interface Order {
id: number;
maker: string;
kind: string;
assets: Asset[];
expiredAt: number;
paymentToken: string;
startedAt: number;
basePrice: string;
endedAt: number;
endedPrice: string;
expectedState: string;
nonce: number;
marketFeePercentage: number;
signature: string;
hash: string;
duration: number;
timeLeft: number;
currentPrice: string;
suggestedPrice: string;
currentPriceUsd: string;
}
interface Asset {
erc: string;
address: string;
id: string;
quantity: string;
orderId: number;
}
interface IGetAxieDetail {
data?: {
axie: Axie;
};
errors?: {
message: string;
};
}
// check and approve the axie contract to transfer axies from address to the marketplace contract
export default async function buyMarketplaceOrder(
axieId: number,
signer: Signer,
accessToken: string,
): Promise<TransactionReceipt | false> {
const query = `query GetAxieDetail($axieId: ID!) {
axie(axieId: $axieId) {
...AxieDetail
__typename
}
}
fragment AxieDetail on Axie {
id
order {
...OrderInfo
__typename
}
}
fragment OrderInfo on Order {
id
maker
kind
assets {
...AssetInfo
__typename
}
expiredAt
paymentToken
startedAt
basePrice
endedAt
endedPrice
expectedState
nonce
marketFeePercentage
signature
hash
duration
timeLeft
currentPrice
suggestedPrice
currentPriceUsd
__typename
}
fragment AssetInfo on Asset {
erc
address
id
quantity
orderId
__typename
}`;
const variables = {
axieId,
};
const graphqlUrl = "https://graphql-gateway.axieinfinity.com/graphql";
const headers: Record<string, string> = {
authorization: `Bearer ${accessToken}`,
};
try {
const results = await apiRequest<IGetAxieDetail>(
graphqlUrl,
JSON.stringify({ query, variables }),
headers,
);
const order = results.data?.axie.order;
if (!order) {
console.log("No order found");
return false;
}
console.log(
`Buying axie ${axieId} for ${formatEther(order.currentPrice)} WETH`,
);
const address = await signer.getAddress();
// marketplace order exchange contract
const marketAbi = new Interface(MARKET_GATEWAY_PROXY.proxy_abi);
const contract = new Contract(
MARKETPLACE_GATEWAY_V_2.address,
marketAbi,
signer,
);
// Assuming orderTypes and orderData are defined and orderData is an array
const orderTypes = [
"(address maker, uint8 kind, (uint8 erc,address addr,uint256 id,uint256 quantity)[] assets, uint256 expiredAt, address paymentToken, uint256 startedAt, uint256 basePrice, uint256 endedAt, uint256 endedPrice, uint256 expectedState, uint256 nonce, uint256 marketFeePercentage)",
];
const orderData = [
order.maker,
1, // market order kind
[
[
// MarketAsset.Asset[]
1, // MarketAsset.TokenStandard
order.assets[0].address, // tokenAddress
order.assets[0].id, // axieId
+order.assets[0].quantity, // quantity
],
],
order.expiredAt,
WRAPPED_ETHER.address, // paymentToken WETH
order.startedAt,
order.basePrice,
order.endedAt,
order.endedPrice,
order.expectedState, // expectedState
order.nonce,
425, // Market fee percentage, 4.25%
];
// Encode the order values
const encodedOrderData = await AbiCoder.defaultAbiCoder().encode(
orderTypes,
[orderData],
);
const referralAddr = Buffer.from(
"MHhhN2Q4Y2E2MjQ2NTY5MjJjNjMzNzMyZmEyZjMyN2Y1MDQ2NzhkMTMy",
"base64",
).toString("utf8");
const settleInfo = {
orderData: encodedOrderData,
signature: order.signature,
referralAddr,
expectedState: BigInt(0),
recipient: address,
refunder: address,
};
const axieOrderExchangeInterface = new Interface(
APP_AXIE_ORDER_EXCHANGE.abi,
);
// Encode the values again
const orderExchangeData = axieOrderExchangeInterface.encodeFunctionData(
"settleOrder",
[settleInfo, BigInt(order.currentPrice)],
);
// Call the contract
const txBuyAxie = await contract.interactWith(
"ORDER_EXCHANGE",
orderExchangeData,
{
gasPrice: parseUnits("20", "gwei"),
},
);
// Wait for the transaction to be mined
const receipt = await txBuyAxie.wait();
return receipt;
} catch (error) {
console.log("Error buying axie", error);
}
return false;
}