From 748f71da3f395611b7cf06e65e456e7144805614 Mon Sep 17 00:00:00 2001 From: Bot Date: Mon, 31 Aug 2026 02:52:16 +0800 Subject: [PATCH] chore(scripts): add real on-chain trade verification script (approve -> mint -> redeem) --- scripts/real_trade_test.js | 97 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 scripts/real_trade_test.js diff --git a/scripts/real_trade_test.js b/scripts/real_trade_test.js new file mode 100644 index 0000000..6ccfaf7 --- /dev/null +++ b/scripts/real_trade_test.js @@ -0,0 +1,97 @@ +// 真实链上交易验证:授权 -> 买入 OT -> 卖出 OT +// 用法: npx hardhat run scripts/real_trade_test.js --network robinhoodTestnet +const hre = require("hardhat"); +const { ethers } = hre; + +const MARKET = "0x048E9a90C25ba2c4410425D282b19A472e076039"; +const CURVE = "0xF0E189974c413506098AFB6Bc6Bf4C6715fBf7B1"; +const COLLATERAL = "0xe776e957953EA69b7Eaa9d7d4098aBC076bDD5E7"; + +const marketAbi = [ + "function mintCollateralToExactOt(address receiver, uint256 tokenId, uint256 otDeltaOut, bytes dataSwap) returns (uint256 collateralIn)", + "function redeemExactOtToCollateral(address receiver, uint256 tokenId, uint256 otDeltaIn, bytes dataSwap) returns (uint256 collateralOut)", + "function balanceOf(address owner, uint256 id) view returns (uint256)", + "function readMarketState() view returns (tuple(address market, address curve, uint128 timestampStart, uint256 totalMarketCap, address treasury, uint256 numOutcomes, uint128 timestampEnd, uint256 answer, bool isFinalised))", +]; +const curveAbi = [ + "function calMarginalPrice(address market, uint256 tokenId) view returns (uint256)", + "function calMintCostByOtDelta(address market, uint256 tokenId, uint256 otDelta, bytes data) view returns (uint256 collateralFromUser, uint256 collateralToTreasury)", + "function calRedeemValueByOtDelta(address market, uint256 tokenId, uint256 otDelta, bytes data) view returns (uint256 collateralToUser, uint256 collateralToTreasury)", +]; +const erc20Abi = [ + "function balanceOf(address) view returns (uint256)", + "function allowance(address owner, address spender) view returns (uint256)", + "function approve(address spender, uint256 amount) returns (bool)", + "function mint(address to, uint256 amount) external", +]; + +const OT = 1000n * 10n ** 18n; // 买 1000 OT +const OUTCOME = 1; // tokenId = 1 << 0 = 1 (YES) + +async function main() { + const provider = hre.ethers.provider; + const [signer] = await hre.ethers.getSigners(); + console.log("Signer:", signer.address); + console.log("Block:", await provider.getBlockNumber()); + + const market = new hre.ethers.Contract(MARKET, marketAbi, signer); + const curve = new hre.ethers.Contract(CURVE, curveAbi, provider); + const wusd = new hre.ethers.Contract(COLLATERAL, erc20Abi, signer); + + // 1) 水龙头: 余额不足则 mint 100_000 WUSD + const bal = await wusd.balanceOf(signer.address); + console.log("WUSD balance:", ethers.formatEther(bal)); + if (bal < ethers.parseEther("10000")) { + console.log("> minting 100000 WUSD..."); + const tx = await wusd.mint(signer.address, ethers.parseEther("100000")); + await tx.wait(); + console.log(" minted, tx:", tx.hash); + } + + // 2) 授权 + const allowance = await wusd.allowance(signer.address, MARKET); + console.log("allowance -> market:", ethers.formatEther(allowance)); + if (allowance < ethers.parseEther("100000")) { + console.log("> approve MaxUint256 to market..."); + const tx = await wusd.approve(MARKET, ethers.MaxUint256); + await tx.wait(); + console.log(" approved, tx:", tx.hash); + } + + // 3) 价格与成本 + const price = await curve.calMarginalPrice(MARKET, OUTCOME); + console.log("marginalPrice:", ethers.formatEther(price), "WUSD/OT"); + const [cost, treasury] = await curve.calMintCostByOtDelta(MARKET, OUTCOME, OT, "0x"); + console.log("cost for 1000 OT:", ethers.formatEther(cost), "+ treasury fee", ethers.formatEther(treasury)); + + // 4) 真实买入 + console.log("> mintCollateralToExactOt(1000 OT, tokenId=1)..."); + try { + const tx = await market.mintCollateralToExactOt(signer.address, OUTCOME, OT, "0x", { gasLimit: 2000000 }); + const receipt = await tx.wait(); + console.log(" BUY SUCCESS tx:", tx.hash, "status:", receipt.status); + console.log(" gasUsed:", receipt.gasUsed.toString()); + } catch (e) { + console.log(" BUY FAILED:", e.shortMessage || e.message); + process.exitCode = 1; + return; + } + + // 5) 检查 OT 余额并真实卖出 + const otBal = await market.balanceOf(signer.address, OUTCOME); + console.log("OT balance:", ethers.formatEther(otBal)); + console.log("> redeemExactOtToCollateral(1000 OT)..."); + try { + const tx = await market.redeemExactOtToCollateral(signer.address, OUTCOME, OT, "0x", { gasLimit: 2000000 }); + const receipt = await tx.wait(); + console.log(" SELL SUCCESS tx:", tx.hash, "status:", receipt.status); + } catch (e) { + console.log(" SELL FAILED:", e.shortMessage || e.message); + process.exitCode = 1; + } +} + +main().catch((e) => { + console.error(e); + process.exitCode = 1; +});