diff --git a/contracts/test/ERC20toCW20PointerTest.js b/contracts/test/ERC20toCW20PointerTest.js index f19884e13..74dd5c786 100644 --- a/contracts/test/ERC20toCW20PointerTest.js +++ b/contracts/test/ERC20toCW20PointerTest.js @@ -166,7 +166,7 @@ describe("ERC20 to CW20 Pointer", function () { const owner = accounts[0].evmAddress; const spender = accounts[1].evmAddress; const blockNumber = await ethers.provider.getBlockNumber(); - const tx = await pointer.approve(spender, 1000000); + const tx = await pointer.approve(spender, 1000000, {gasPrice: (await ethers.provider.getFeeData()).gasPrice}); const receipt = await tx.wait(); const allowance = await pointer.allowance(owner, spender); expect(Number(allowance)).to.equal(1000000); diff --git a/contracts/test/EVMCompatabilityTest.js b/contracts/test/EVMCompatabilityTest.js index 070eadaff..d0e2bc857 100644 --- a/contracts/test/EVMCompatabilityTest.js +++ b/contracts/test/EVMCompatabilityTest.js @@ -157,7 +157,7 @@ describe("EVM Test", function () { await delay() // Call balanceOf using callAnotherContract from EVMCompatibilityTester - await evmTester.callAnotherContract(tokenAddress, balanceOfData); + await evmTester.callAnotherContract(tokenAddress, balanceOfData, {gasPrice: (await ethers.provider.getFeeData()).gasPrice}); await delay() // Verify the balance using MyToken contract directly diff --git a/integration_test/dapp_tests/README.md b/integration_test/dapp_tests/README.md index 65fa2c439..5be6984f5 100644 --- a/integration_test/dapp_tests/README.md +++ b/integration_test/dapp_tests/README.md @@ -18,6 +18,11 @@ On the test pipelines, the account used is: - Deployer Sei address: `sei1rtpakm7w9egh0n7xngzm6vrln0szv6yeva6hhn` - Deployer EVM address: `0x4D952b770C3a0B096e739399B40263D0b516d406` +The tests can be ran against already deployed contracts on arctic-1 or on clusters. For arctic-1 the contract addresses are already stored on config directory. +For cluster tests, tests first deploy the contracts and store addresses in a new json created in config directory. For the next +iterations the tests are going to use these addresses. To run the tests against node cluster, update the endpoints on constants.js file. + +To run the tests you can simply pass `-f` flag into the command. ## Tests ### Uniswap (EVM DEX) diff --git a/integration_test/dapp_tests/configs/nftConfig.json b/integration_test/dapp_tests/configs/nftConfig.json new file mode 100644 index 000000000..daec096b4 --- /dev/null +++ b/integration_test/dapp_tests/configs/nftConfig.json @@ -0,0 +1,6 @@ +{ + "marketplace": "0x305E8dc769aae003c17fB08b9cc9108Cb4630E79", + "erc721token": "0x8Ee23935ca017dbe78Fc72b74C90F9FCF4e2f9E5", + "cw721Address": "sei1tpz0rk984996x87sgmzr0te7n4p2j9r8vq7pqq0psf0l7642ze2qx9wzsf", + "erc721PointerToken": "0xC88F617fa5943466437f7ce03aaE8779ae083847" +} \ No newline at end of file diff --git a/integration_test/dapp_tests/configs/steakConfig.json b/integration_test/dapp_tests/configs/steakConfig.json new file mode 100644 index 000000000..eb3775ef1 --- /dev/null +++ b/integration_test/dapp_tests/configs/steakConfig.json @@ -0,0 +1,5 @@ +{ + "hubAddress": "sei1dynepqqjm6u4prcvdyh5qlhrglld78xy7pa4w05gq9vas4ws3e4q7dmyff", + "tokenAddress": "sei1v7gfan5kjry9aqs2l6z0smx4cj2kgcz5ngmd09caex5y7ucr9yqq6pth9d", + "pointerAddress": "0x505868BB5Babd68D84D96bbc0851062C6cF0619a" +} \ No newline at end of file diff --git a/integration_test/dapp_tests/configs/uniswapConfig.json b/integration_test/dapp_tests/configs/uniswapConfig.json new file mode 100644 index 000000000..3a597d345 --- /dev/null +++ b/integration_test/dapp_tests/configs/uniswapConfig.json @@ -0,0 +1,10 @@ +{ + "manager": "0xcE11491995E05b947820836aecE9D7A5Fcdaeb01", + "router": "0x0c086805476d29b306ffF178B53176565F880893", + "erc20TokenFactory": "0x7e3378bcEad49Bbfc8D9024657c942d44f1A1a94", + "erc20cw20": "0x7E7095dfB469A39CF6C67554A8896314D6B0567F", + "weth9": "0x5cA05f8eA1a25d74eBD222a9Ea3730c82B4082A4", + "token": "0xB73a15C476A9D14d57162472527e3FbFdF21dE3F", + "tokenFactoryDenom": "factory/sei1ak5ztcchehv2gy64yxpcdnftepnacvwgxwwfzw/dappTests1727707705418", + "cw20Address": "sei127nvmtnn3tkt6xxgss2z4n0exgm043sc0e2na5lca7h3n4qxs8us4rykxp" +} \ No newline at end of file diff --git a/integration_test/dapp_tests/constants.js b/integration_test/dapp_tests/constants.js index aafad4d58..6c4b9ab35 100644 --- a/integration_test/dapp_tests/constants.js +++ b/integration_test/dapp_tests/constants.js @@ -1,16 +1,22 @@ const rpcUrls = { + "seilocal": "http://127.0.0.1:26657", "testnet": "https://rpc-testnet.sei-apis.com", - "devnet": "https://rpc-arctic-1.sei-apis.com" + "devnet": "https://rpc-arctic-1.sei-apis.com", + "seiCluster": "http://127.0.0.1:26657" } const evmRpcUrls = { + "seilocal": "http://127.0.0.1:8545", "testnet": "https://evm-rpc-testnet.sei-apis.com", - "devnet": "https://evm-rpc-arctic-1.sei-apis.com" + "devnet": "https://evm-rpc-arctic-1.sei-apis.com", + "seiCluster": "http://127.0.0.1:8545" } const chainIds = { + "seilocal": "sei", "testnet": "atlantic-2", - "devnet": "arctic-1" + "devnet": "arctic-1", + "seiCluster":"sei-chain", } module.exports = { diff --git a/integration_test/dapp_tests/dapp_tests.sh b/integration_test/dapp_tests/dapp_tests.sh index 0549381e4..7817d9178 100755 --- a/integration_test/dapp_tests/dapp_tests.sh +++ b/integration_test/dapp_tests/dapp_tests.sh @@ -6,6 +6,18 @@ if [ -z "$1" ]; then exit 1 fi +IS_FAST_TRACK=false + +# Check if -fast track enabled is present +for arg in "$@"; do + if [[ "$arg" == "-f" ]]; then + IS_FAST_TRACK=true + break + fi +done + +export IS_FAST_TRACK + set -e # Define the paths to the test files diff --git a/integration_test/dapp_tests/hardhat.config.js b/integration_test/dapp_tests/hardhat.config.js index c2e5a8496..fd13354a1 100644 --- a/integration_test/dapp_tests/hardhat.config.js +++ b/integration_test/dapp_tests/hardhat.config.js @@ -18,6 +18,15 @@ module.exports = { networks: { seilocal: { url: "http://127.0.0.1:8545", + accounts: { + mnemonic: "potato beach spawn early pole peanut insect bus addict orient camp refuse news robust drive napkin race summer toss oppose cream grit gadget clever", + path: "m/44'/118'/0'/0/0", + initialIndex: 0, + count: 1 + }, + }, + seiCluster: { + url: "", accounts: { mnemonic: process.env.DAPP_TESTS_MNEMONIC, path: "m/44'/118'/0'/0/0", diff --git a/integration_test/dapp_tests/nftMarketplace/nftMarketplaceTests.js b/integration_test/dapp_tests/nftMarketplace/nftMarketplaceTests.js index 3b1fde0df..596f7539c 100644 --- a/integration_test/dapp_tests/nftMarketplace/nftMarketplaceTests.js +++ b/integration_test/dapp_tests/nftMarketplace/nftMarketplaceTests.js @@ -1,66 +1,44 @@ const { expect } = require("chai"); const hre = require("hardhat"); -const {sendFunds, deployEthersContract, estimateAndCall, deployCw721WithPointer, setupAccountWithMnemonic, - mintCw721 +const { + sendFunds, estimateAndCall, mintCw721, deployAndReturnContractsForNftTests, + queryLatestNftIds, setDaemonConfig } = require("../utils"); -const { fundAddress, getSeiAddress, execute } = require("../../../contracts/test/lib.js"); -const {evmRpcUrls, chainIds, rpcUrls} = require("../constants"); +const { getSeiAddress, execute } = require("../../../contracts/test/lib.js"); const testChain = process.env.DAPP_TEST_ENV; -console.log("testChain", testChain); -describe("NFT Marketplace", function () { +const isFastTrackEnabled = process.env.IS_FAST_TRACK; - let marketplace, deployer, erc721token, erc721PointerToken, cw721Address, originalSeidConfig; +describe("NFT Marketplace", function () { + console.log('NFT Tests are being run'); + let marketplace, deployer, erc721token, erc721PointerToken, cw721Address, originalSeidConfig, nftId1; before(async function () { const accounts = hre.config.networks[testChain].accounts const deployerWallet = hre.ethers.Wallet.fromMnemonic(accounts.mnemonic, accounts.path); deployer = deployerWallet.connect(hre.ethers.provider); + originalSeidConfig = await setDaemonConfig(testChain); - const seidConfig = await execute('seid config'); - originalSeidConfig = JSON.parse(seidConfig); - - if (testChain === 'seilocal') { - await fundAddress(deployer.address, amount="2000000000000000000000"); - } else { - // Set default seid config to the specified rpc url. - await execute(`seid config chain-id ${chainIds[testChain]}`) - await execute(`seid config node ${rpcUrls[testChain]}`) - } - - await execute(`seid config keyring-backend test`) + ({ + marketplace, + erc721token, + cw721Address, + erc721PointerToken + } = await deployAndReturnContractsForNftTests(deployer, testChain, accounts, isFastTrackEnabled)); - await sendFunds('0.01', deployer.address, deployer) - await setupAccountWithMnemonic("dapptest", accounts.mnemonic, deployer); - - // Deploy MockNFT - const erc721ContractArtifact = await hre.artifacts.readArtifact("MockERC721"); - erc721token = await deployEthersContract("MockERC721", erc721ContractArtifact.abi, erc721ContractArtifact.bytecode, deployer, ["MockERC721", "MKTNFT"]) - - const numNftsToMint = 50 - await estimateAndCall(erc721token, "batchMint", [deployer.address, numNftsToMint]); - - // Deploy CW721 token with ERC721 pointer - const time = Date.now().toString(); const deployerSeiAddr = await getSeiAddress(deployer.address); - const cw721Details = await deployCw721WithPointer(deployerSeiAddr, deployer, time, evmRpcUrls[testChain]) - erc721PointerToken = cw721Details.pointerContract; - cw721Address = cw721Details.cw721Address; - console.log("CW721 Address", cw721Address); + nftId1 = (await queryLatestNftIds(cw721Address, testChain)) + 1; const numCwNftsToMint = 2; - for (let i = 1; i <= numCwNftsToMint; i++) { - await mintCw721(cw721Address, deployerSeiAddr, i) - } - const cwbal = await erc721PointerToken.balanceOf(deployer.address); - expect(cwbal).to.equal(numCwNftsToMint) - const nftMarketplaceArtifact = await hre.artifacts.readArtifact("NftMarketplace"); - marketplace = await deployEthersContract("NftMarketplace", nftMarketplaceArtifact.abi, nftMarketplaceArtifact.bytecode, deployer) + for (let i = nftId1; i <= nftId1 + numCwNftsToMint; i++) { + await mintCw721(cw721Address, deployerSeiAddr, i); + console.log('nfts minted'); + } }) describe("Orders", function () { - async function testNFTMarketplaceOrder(buyer, seller, nftContract, nftId="", expectTransferFail=false) { + async function testNFTMarketplaceOrder(buyer, seller, nftContract, nftId = "", expectTransferFail = false) { let tokenId; // If nftId is manually supplied (for pointer contract), ensure that deployer owns that token. if (nftId) { @@ -117,7 +95,7 @@ describe("NFT Marketplace", function () { const newSellerNftbalance = await nftContract.balanceOf(seller.address); expect(Number(newSellerNftbalance)).to.be.lessThan(Number(sellerNftbalance), "NFT should have been transferred from the seller.") - nftOwner = await nftContract.ownerOf(tokenId); + let nftOwner = await nftContract.ownerOf(tokenId); expect(nftOwner).to.equal(buyer.address, "NFT should have been transferred to the buyer."); } @@ -150,7 +128,7 @@ describe("NFT Marketplace", function () { const buyer = buyerWallet.connect(hre.ethers.provider); await sendFunds("0.5", buyer.address, deployer) await sendFunds('0.01', buyer.address, buyer) - await testNFTMarketplaceOrder(buyer, deployer, erc721PointerToken, '1'); + await testNFTMarketplaceOrder(buyer, deployer, erc721PointerToken, `${nftId1}`); }); it("Currently does not allow listing or buying erc721 pointer by unassociated users", async function () { @@ -164,13 +142,13 @@ describe("NFT Marketplace", function () { const buyer = buyerWallet.connect(hre.ethers.provider); await sendFunds("0.5", buyer.address, deployer) - await testNFTMarketplaceOrder(buyer, seller, erc721PointerToken, '2', true); + await testNFTMarketplaceOrder(buyer, seller, erc721PointerToken, `${nftId1 + 1}`, true); }); }) after(async function () { // Set the chain back to regular state - console.log("Resetting") + console.log("Resetting"); await execute(`seid config chain-id ${originalSeidConfig["chain-id"]}`) await execute(`seid config node ${originalSeidConfig["node"]}`) await execute(`seid config keyring-backend ${originalSeidConfig["keyring-backend"]}`) diff --git a/integration_test/dapp_tests/package-lock.json b/integration_test/dapp_tests/package-lock.json index 5aa2af6c1..4d8e5a078 100644 --- a/integration_test/dapp_tests/package-lock.json +++ b/integration_test/dapp_tests/package-lock.json @@ -9,6 +9,7 @@ "version": "1.0.0", "license": "MIT", "dependencies": { + "@cosmjs/cosmwasm-stargate": "^0.32.4", "@nomiclabs/hardhat-ethers": "^2.2.3", "@nomiclabs/hardhat-waffle": "^2.0.6", "@openzeppelin/contracts": "^5.0.2", @@ -36,6 +37,165 @@ "node": ">=6.9.0" } }, + "node_modules/@confio/ics23": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@confio/ics23/-/ics23-0.6.8.tgz", + "integrity": "sha512-wB6uo+3A50m0sW/EWcU64xpV/8wShZ6bMTa7pF8eYsTrSkQA7oLUIJcs/wb8g4y2Oyq701BaGiO6n/ak5WXO1w==", + "dependencies": { + "@noble/hashes": "^1.0.0", + "protobufjs": "^6.8.8" + } + }, + "node_modules/@cosmjs/amino": { + "version": "0.32.4", + "resolved": "https://registry.npmjs.org/@cosmjs/amino/-/amino-0.32.4.tgz", + "integrity": "sha512-zKYOt6hPy8obIFtLie/xtygCkH9ZROiQ12UHfKsOkWaZfPQUvVbtgmu6R4Kn1tFLI/SRkw7eqhaogmW/3NYu/Q==", + "dependencies": { + "@cosmjs/crypto": "^0.32.4", + "@cosmjs/encoding": "^0.32.4", + "@cosmjs/math": "^0.32.4", + "@cosmjs/utils": "^0.32.4" + } + }, + "node_modules/@cosmjs/cosmwasm-stargate": { + "version": "0.32.4", + "resolved": "https://registry.npmjs.org/@cosmjs/cosmwasm-stargate/-/cosmwasm-stargate-0.32.4.tgz", + "integrity": "sha512-Fuo9BGEiB+POJ5WeRyBGuhyKR1ordvxZGLPuPosFJOH9U0gKMgcjwKMCgAlWFkMlHaTB+tNdA8AifWiHrI7VgA==", + "dependencies": { + "@cosmjs/amino": "^0.32.4", + "@cosmjs/crypto": "^0.32.4", + "@cosmjs/encoding": "^0.32.4", + "@cosmjs/math": "^0.32.4", + "@cosmjs/proto-signing": "^0.32.4", + "@cosmjs/stargate": "^0.32.4", + "@cosmjs/tendermint-rpc": "^0.32.4", + "@cosmjs/utils": "^0.32.4", + "cosmjs-types": "^0.9.0", + "pako": "^2.0.2" + } + }, + "node_modules/@cosmjs/crypto": { + "version": "0.32.4", + "resolved": "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.32.4.tgz", + "integrity": "sha512-zicjGU051LF1V9v7bp8p7ovq+VyC91xlaHdsFOTo2oVry3KQikp8L/81RkXmUIT8FxMwdx1T7DmFwVQikcSDIw==", + "dependencies": { + "@cosmjs/encoding": "^0.32.4", + "@cosmjs/math": "^0.32.4", + "@cosmjs/utils": "^0.32.4", + "@noble/hashes": "^1", + "bn.js": "^5.2.0", + "elliptic": "^6.5.4", + "libsodium-wrappers-sumo": "^0.7.11" + } + }, + "node_modules/@cosmjs/crypto/node_modules/bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" + }, + "node_modules/@cosmjs/encoding": { + "version": "0.32.4", + "resolved": "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.32.4.tgz", + "integrity": "sha512-tjvaEy6ZGxJchiizzTn7HVRiyTg1i4CObRRaTRPknm5EalE13SV+TCHq38gIDfyUeden4fCuaBVEdBR5+ti7Hw==", + "dependencies": { + "base64-js": "^1.3.0", + "bech32": "^1.1.4", + "readonly-date": "^1.0.0" + } + }, + "node_modules/@cosmjs/json-rpc": { + "version": "0.32.4", + "resolved": "https://registry.npmjs.org/@cosmjs/json-rpc/-/json-rpc-0.32.4.tgz", + "integrity": "sha512-/jt4mBl7nYzfJ2J/VJ+r19c92mUKF0Lt0JxM3MXEJl7wlwW5haHAWtzRujHkyYMXOwIR+gBqT2S0vntXVBRyhQ==", + "dependencies": { + "@cosmjs/stream": "^0.32.4", + "xstream": "^11.14.0" + } + }, + "node_modules/@cosmjs/math": { + "version": "0.32.4", + "resolved": "https://registry.npmjs.org/@cosmjs/math/-/math-0.32.4.tgz", + "integrity": "sha512-++dqq2TJkoB8zsPVYCvrt88oJWsy1vMOuSOKcdlnXuOA/ASheTJuYy4+oZlTQ3Fr8eALDLGGPhJI02W2HyAQaw==", + "dependencies": { + "bn.js": "^5.2.0" + } + }, + "node_modules/@cosmjs/math/node_modules/bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" + }, + "node_modules/@cosmjs/proto-signing": { + "version": "0.32.4", + "resolved": "https://registry.npmjs.org/@cosmjs/proto-signing/-/proto-signing-0.32.4.tgz", + "integrity": "sha512-QdyQDbezvdRI4xxSlyM1rSVBO2st5sqtbEIl3IX03uJ7YiZIQHyv6vaHVf1V4mapusCqguiHJzm4N4gsFdLBbQ==", + "dependencies": { + "@cosmjs/amino": "^0.32.4", + "@cosmjs/crypto": "^0.32.4", + "@cosmjs/encoding": "^0.32.4", + "@cosmjs/math": "^0.32.4", + "@cosmjs/utils": "^0.32.4", + "cosmjs-types": "^0.9.0" + } + }, + "node_modules/@cosmjs/socket": { + "version": "0.32.4", + "resolved": "https://registry.npmjs.org/@cosmjs/socket/-/socket-0.32.4.tgz", + "integrity": "sha512-davcyYziBhkzfXQTu1l5NrpDYv0K9GekZCC9apBRvL1dvMc9F/ygM7iemHjUA+z8tJkxKxrt/YPjJ6XNHzLrkw==", + "dependencies": { + "@cosmjs/stream": "^0.32.4", + "isomorphic-ws": "^4.0.1", + "ws": "^7", + "xstream": "^11.14.0" + } + }, + "node_modules/@cosmjs/stargate": { + "version": "0.32.4", + "resolved": "https://registry.npmjs.org/@cosmjs/stargate/-/stargate-0.32.4.tgz", + "integrity": "sha512-usj08LxBSsPRq9sbpCeVdyLx2guEcOHfJS9mHGCLCXpdAPEIEQEtWLDpEUc0LEhWOx6+k/ChXTc5NpFkdrtGUQ==", + "dependencies": { + "@confio/ics23": "^0.6.8", + "@cosmjs/amino": "^0.32.4", + "@cosmjs/encoding": "^0.32.4", + "@cosmjs/math": "^0.32.4", + "@cosmjs/proto-signing": "^0.32.4", + "@cosmjs/stream": "^0.32.4", + "@cosmjs/tendermint-rpc": "^0.32.4", + "@cosmjs/utils": "^0.32.4", + "cosmjs-types": "^0.9.0", + "xstream": "^11.14.0" + } + }, + "node_modules/@cosmjs/stream": { + "version": "0.32.4", + "resolved": "https://registry.npmjs.org/@cosmjs/stream/-/stream-0.32.4.tgz", + "integrity": "sha512-Gih++NYHEiP+oyD4jNEUxU9antoC0pFSg+33Hpp0JlHwH0wXhtD3OOKnzSfDB7OIoEbrzLJUpEjOgpCp5Z+W3A==", + "dependencies": { + "xstream": "^11.14.0" + } + }, + "node_modules/@cosmjs/tendermint-rpc": { + "version": "0.32.4", + "resolved": "https://registry.npmjs.org/@cosmjs/tendermint-rpc/-/tendermint-rpc-0.32.4.tgz", + "integrity": "sha512-MWvUUno+4bCb/LmlMIErLypXxy7ckUuzEmpufYYYd9wgbdCXaTaO08SZzyFM5PI8UJ/0S2AmUrgWhldlbxO8mw==", + "dependencies": { + "@cosmjs/crypto": "^0.32.4", + "@cosmjs/encoding": "^0.32.4", + "@cosmjs/json-rpc": "^0.32.4", + "@cosmjs/math": "^0.32.4", + "@cosmjs/socket": "^0.32.4", + "@cosmjs/stream": "^0.32.4", + "@cosmjs/utils": "^0.32.4", + "axios": "^1.6.0", + "readonly-date": "^1.0.0", + "xstream": "^11.14.0" + } + }, + "node_modules/@cosmjs/utils": { + "version": "0.32.4", + "resolved": "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.32.4.tgz", + "integrity": "sha512-D1Yc+Zy8oL/hkUkFUL/bwxvuDBzRGpc4cF7/SkdhxX4iHpSLgdOuTt1mhCh9+kl6NQREy9t7SYZ6xeW5gFe60w==" + }, "node_modules/@ensdomains/address-encoder": { "version": "0.1.9", "resolved": "https://registry.npmjs.org/@ensdomains/address-encoder/-/address-encoder-0.1.9.tgz", @@ -2018,6 +2178,60 @@ "semver": "bin/semver" } }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" + }, "node_modules/@resolver-engine/core": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/@resolver-engine/core/-/core-0.3.3.tgz", @@ -3582,6 +3796,11 @@ "@types/node": "*" } }, + "node_modules/@types/long": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", + "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" + }, "node_modules/@types/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/@types/lru-cache/-/lru-cache-5.1.1.tgz", @@ -4020,6 +4239,16 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.0.tgz", "integrity": "sha512-3AungXC4I8kKsS9PuS4JH2nc+0bVY/mjgrephHTIi8fpEeGsTHBUJeosp0Wc1myYMElmD0B3Oc4XL/HVJ4PV2g==" }, + "node_modules/axios": { + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", + "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -4943,6 +5172,11 @@ "node": ">= 0.10" } }, + "node_modules/cosmjs-types": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/cosmjs-types/-/cosmjs-types-0.9.0.tgz", + "integrity": "sha512-MN/yUe6mkJwHnCFfsNPeCfXVhyxHYW6c/xDUzrSbBycYzw++XvWDMJArXp2pLdgD6FQ8DW79vkPjeNKVrXaHeQ==" + }, "node_modules/crc-32": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", @@ -5187,6 +5421,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -6072,7 +6322,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "peer": true, "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -6817,6 +7066,21 @@ "process": "^0.11.10" } }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -7538,6 +7802,14 @@ "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==" }, + "node_modules/isomorphic-ws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", + "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", + "peerDependencies": { + "ws": "*" + } + }, "node_modules/isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -7784,6 +8056,19 @@ "node": ">=6" } }, + "node_modules/libsodium-sumo": { + "version": "0.7.15", + "resolved": "https://registry.npmjs.org/libsodium-sumo/-/libsodium-sumo-0.7.15.tgz", + "integrity": "sha512-5tPmqPmq8T8Nikpm1Nqj0hBHvsLFCXvdhBFV7SGOitQPZAA6jso8XoL0r4L7vmfKXr486fiQInvErHtEvizFMw==" + }, + "node_modules/libsodium-wrappers-sumo": { + "version": "0.7.15", + "resolved": "https://registry.npmjs.org/libsodium-wrappers-sumo/-/libsodium-wrappers-sumo-0.7.15.tgz", + "integrity": "sha512-aSWY8wKDZh5TC7rMvEdTHoyppVq/1dTSAeAR7H6pzd6QRT3vQWcT5pGwCotLcpPEOLXX6VvqihSPkpEhYAjANA==", + "dependencies": { + "libsodium-sumo": "^0.7.15" + } + }, "node_modules/load-json-file": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", @@ -7855,6 +8140,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, "node_modules/loupe": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", @@ -8562,6 +8852,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/obliterator": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.4.tgz", @@ -8672,6 +8970,11 @@ "node": ">=4" } }, + "node_modules/pako": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", + "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==" + }, "node_modules/param-case": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", @@ -8891,6 +9194,31 @@ "node": ">= 0.6.0" } }, + "node_modules/protobufjs": { + "version": "6.11.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.4.tgz", + "integrity": "sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + }, + "bin": { + "pbjs": "bin/pbjs", + "pbts": "bin/pbts" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -8903,6 +9231,11 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", @@ -9084,6 +9417,11 @@ "node": ">=8.10.0" } }, + "node_modules/readonly-date": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/readonly-date/-/readonly-date-1.0.0.tgz", + "integrity": "sha512-tMKIV7hlk0h4mO3JTmmVuIlJVXjKk3Sep9Bf5OH0O+758ruuVkUy2J9SttDLm91IEX/WHlXPSpxMGjPj4beMIQ==" + }, "node_modules/reduce-flatten": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", @@ -9913,6 +10251,14 @@ "node": ">=8" } }, + "node_modules/symbol-observable": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-2.0.3.tgz", + "integrity": "sha512-sQV7phh2WCYAn81oAkakC5qjq2Ml0g8ozqz03wOGnx9dDlG1de6yrF+0RAzSJD8fPUow3PTSMf2SAbOGxb93BA==", + "engines": { + "node": ">=0.10" + } + }, "node_modules/table-layout": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.2.tgz", @@ -11613,6 +11959,15 @@ "node": ">=0.4.0" } }, + "node_modules/xstream": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/xstream/-/xstream-11.14.0.tgz", + "integrity": "sha512-1bLb+kKKtKPbgTK6i/BaoAn03g47PpFstlbe1BA+y3pNS/LfvcaghS5BFf9+EE1J+KwSQsEpfJvFN5GqFtiNmw==", + "dependencies": { + "globalthis": "^1.0.1", + "symbol-observable": "^2.0.3" + } + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", diff --git a/integration_test/dapp_tests/package.json b/integration_test/dapp_tests/package.json index d58091898..2b7d7e923 100644 --- a/integration_test/dapp_tests/package.json +++ b/integration_test/dapp_tests/package.json @@ -6,6 +6,7 @@ "author": "", "license": "MIT", "dependencies": { + "@cosmjs/cosmwasm-stargate": "^0.32.4", "@nomiclabs/hardhat-ethers": "^2.2.3", "@nomiclabs/hardhat-waffle": "^2.0.6", "@openzeppelin/contracts": "^5.0.2", diff --git a/integration_test/dapp_tests/steak/SteakTests.js b/integration_test/dapp_tests/steak/SteakTests.js index 6f7786da6..7c3e5ec16 100644 --- a/integration_test/dapp_tests/steak/SteakTests.js +++ b/integration_test/dapp_tests/steak/SteakTests.js @@ -1,206 +1,117 @@ const { - storeWasm, - deployErc20PointerForCw20, - ABI, - getEvmAddress, - fundSeiAddress, - associateKey, - execute, - isDocker, + getEvmAddress, + execute, } = require("../../../contracts/test/lib.js"); const { - getValidators, - instantiateHubContract, - bond, - addAccount, - queryTokenBalance, - unbond, - transferTokens, - setupAccountWithMnemonic, - sendFunds + bond, + queryTokenBalance, + unbond, + transferTokens, } = require("../utils.js"); -const { expect } = require("chai"); -const { v4: uuidv4 } = require("uuid"); +const {expect} = require("chai"); +const {v4: uuidv4} = require("uuid"); const hre = require("hardhat"); -const {chainIds, rpcUrls, evmRpcUrls} = require("../constants"); -const path = require("path"); +const { + setupAccount, + deployAndReturnContractsForSteakTests, setDaemonConfig +} = require("../utils"); const testChain = process.env.DAPP_TEST_ENV; +const isFastTrackEnabled = process.env.IS_FAST_TRACK; describe("Steak", async function () { - let owner; - let hubAddress; - let tokenAddress; - let tokenPointer; - let originalSeidConfig; - - async function setupAccount(baseName, associate = true, amount="100000000000", denom="usei", funder='admin') { - const uniqueName = `${baseName}-${uuidv4()}`; - - const account = await addAccount(uniqueName); - await fundSeiAddress(account.address, amount, denom, funder); - if (associate) { - await associateKey(account.address); + let owner; + let hubAddress; + let tokenAddress; + let tokenPointer; + let originalSeidConfig; + + async function testBonding(address, amount) { + const initialBalance = await queryTokenBalance(tokenAddress, address); + await bond(hubAddress, address, amount); + const tokenBalance = await queryTokenBalance(tokenAddress, address); + const expectedBalance = Number(initialBalance) + amount; + expect(tokenBalance).to.equal(`${expectedBalance}`); } - return account; - } - - async function deployContracts(ownerAddress) { - // Store CW20 token wasm - const STEAK_TOKEN_WASM = (await isDocker()) ? '../integration_test/dapp_tests/steak/contracts/steak_token.wasm' : path.resolve(__dirname, '../steak/contracts/steak_token.wasm') - const tokenCodeId = await storeWasm(STEAK_TOKEN_WASM, ownerAddress); - - // Store Hub contract - const STEAK_HUB_WASM = (await isDocker()) ? '../integration_test/dapp_tests/steak/contracts/steak_hub.wasm' : path.resolve(__dirname, '../steak/contracts/steak_hub.wasm') - const hubCodeId = await storeWasm(STEAK_HUB_WASM, ownerAddress); - - // Instantiate hub and token contracts - const validators = await getValidators(); - const instantiateMsg = { - cw20_code_id: parseInt(tokenCodeId), - owner: ownerAddress, - name: "Steak", - symbol: "STEAK", - decimals: 6, - epoch_period: 259200, - unbond_period: 1814400, - validators: validators.slice(0, 3), - }; - const contractAddresses = await instantiateHubContract( - hubCodeId, - ownerAddress, - instantiateMsg, - "steakhub" - ); - - // Deploy pointer for token contract - const pointerAddr = await deployErc20PointerForCw20( - hre.ethers.provider, - contractAddresses.tokenContract, - 10, - ownerAddress, - evmRpcUrls[testChain] - ); - - const tokenPointer = new hre.ethers.Contract( - pointerAddr, - ABI.ERC20, - hre.ethers.provider - ); - - return { - hubAddress: contractAddresses.hubContract, - tokenAddress: contractAddresses.tokenContract, - tokenPointer, - }; - } - - async function testBonding(address, amount) { - const initialBalance = await queryTokenBalance(tokenAddress, address); - expect(initialBalance).to.equal("0"); - - await bond(hubAddress, address, amount); - const tokenBalance = await queryTokenBalance(tokenAddress, address); - expect(tokenBalance).to.equal(`${amount}`); - } - - async function testUnbonding(address, amount) { - const initialBalance = await queryTokenBalance(tokenAddress, address); - const response = await unbond(hubAddress, tokenAddress, address, amount); - expect(response.code).to.equal(0); - - // Balance should be updated - const tokenBalance = await queryTokenBalance(tokenAddress, address); - expect(tokenBalance).to.equal(`${Number(initialBalance) - amount}`); - } - - before(async function () { - - const seidConfig = await execute('seid config'); - originalSeidConfig = JSON.parse(seidConfig); - - // Set up the owner account - if (testChain === 'seilocal') { - owner = await setupAccount("steak-owner"); - } else { - // Set default seid config to the specified rpc url. - await execute(`seid config chain-id ${chainIds[testChain]}`) - await execute(`seid config node ${rpcUrls[testChain]}`) - - const accounts = hre.config.networks[testChain].accounts - const deployerWallet = hre.ethers.Wallet.fromMnemonic(accounts.mnemonic, accounts.path); - const deployer = deployerWallet.connect(hre.ethers.provider) - - await sendFunds('0.01', deployer.address, deployer) - // Set the config keyring to 'test' since we're using the key added to test from here. - owner = await setupAccountWithMnemonic("steak-owner", accounts.mnemonic, deployer) + async function testUnbonding(address, amount) { + const initialBalance = await queryTokenBalance(tokenAddress, address); + const response = await unbond(hubAddress, tokenAddress, address, amount); + expect(response.code).to.equal(0); + // Balance should be updated + const tokenBalance = await queryTokenBalance(tokenAddress, address); + expect(tokenBalance).to.equal(`${Number(initialBalance) - amount}`); } - await execute(`seid config keyring-backend test`); - - // Store and deploy contracts - ({ hubAddress, tokenAddress, tokenPointer } = await deployContracts( - owner.address - )); - }); - - describe("Bonding and unbonding", async function () { - it("Associated account should be able to bond and unbond", async function () { - const amount = 1000000; - await testBonding(owner.address, amount); - - // Verify that address is associated - const evmAddress = await getEvmAddress(owner.address); - expect(evmAddress).to.not.be.empty; - - // Check pointer balance - const pointerBalance = await tokenPointer.balanceOf(evmAddress); - expect(pointerBalance).to.equal(`${amount}`); - - await testUnbonding(owner.address, 500000); + before(async function () { + originalSeidConfig = await setDaemonConfig(testChain); + const accounts = hre.config.networks[testChain].accounts + const deployerWallet = hre.ethers.Wallet.fromMnemonic(accounts.mnemonic, accounts.path); + const deployer = deployerWallet.connect(hre.ethers.provider); + ({ + hubAddress, + tokenAddress, + tokenPointer, + owner + } = await deployAndReturnContractsForSteakTests(deployer, testChain, accounts, isFastTrackEnabled)); }); - it("Unassociated account should be able to bond", async function () { - const unassociatedAccount = await setupAccount("unassociated", false, '2000000', 'usei', owner.address); - // Verify that account is not associated yet - const initialEvmAddress = await getEvmAddress( - unassociatedAccount.address - ); - expect(initialEvmAddress).to.be.empty; - - await testBonding(unassociatedAccount.address, 1000000); - - // Account should now be associated - const evmAddress = await getEvmAddress(unassociatedAccount.address); - expect(evmAddress).to.not.be.empty; - - // Send tokens to a new unassociated account - const newUnassociatedAccount = await setupAccount("unassociated", false, '2000000', 'usei', owner.address); - const transferAmount = 500000; - await transferTokens( - tokenAddress, - unassociatedAccount.address, - newUnassociatedAccount.address, - transferAmount - ); - const tokenBalance = await queryTokenBalance( - tokenAddress, - newUnassociatedAccount.address - ); - expect(tokenBalance).to.equal(`${transferAmount}`); - - // Try unbonding on unassociated account - await testUnbonding(newUnassociatedAccount.address, transferAmount / 2); + describe("Bonding and unbonding", async function () { + it("Associated account should be able to bond and unbond", async function () { + const amount = 1000000; + const evmAddress = await getEvmAddress(owner.address); + const pointerInitialBalance = await tokenPointer.balanceOf(evmAddress); + await testBonding(owner.address, amount); + // Verify that address is associated + expect(evmAddress).to.not.be.empty; + // Check pointer balance + const pointerBalance = await tokenPointer.balanceOf(evmAddress); + const expectedAfterBalance = Number(pointerInitialBalance) + amount; + expect(pointerBalance).to.equal(`${expectedAfterBalance}`); + + await testUnbonding(owner.address, 500000); + }); + + it("Unassociated account should be able to bond", async function () { + const unassociatedAccount = await setupAccount("unassociated", false, '2000000', 'usei', owner.address); + // Verify that account is not associated yet + const initialEvmAddress = await getEvmAddress( + unassociatedAccount.address + ); + expect(initialEvmAddress).to.be.empty; + + await testBonding(unassociatedAccount.address, 1000000); + + // Account should now be associated + const evmAddress = await getEvmAddress(unassociatedAccount.address); + expect(evmAddress).to.not.be.empty; + + // Send tokens to a new unassociated account + const newUnassociatedAccount = await setupAccount("unassociated", false, '2000000', 'usei', owner.address); + const transferAmount = 500000; + await transferTokens( + tokenAddress, + unassociatedAccount.address, + newUnassociatedAccount.address, + transferAmount + ); + const tokenBalance = await queryTokenBalance( + tokenAddress, + newUnassociatedAccount.address + ); + expect(tokenBalance).to.equal(`${transferAmount}`); + + // Try unbonding on unassociated account + await testUnbonding(newUnassociatedAccount.address, transferAmount / 2); + }); }); - }); - after(async function () { - // Set the chain back to regular state - console.log(`Resetting to ${originalSeidConfig}`) - await execute(`seid config chain-id ${originalSeidConfig["chain-id"]}`) - await execute(`seid config node ${originalSeidConfig["node"]}`) - await execute(`seid config keyring-backend ${originalSeidConfig["keyring-backend"]}`) - }) + after(async function () { + // Set the chain back to regular state + console.log(`Resetting to ${originalSeidConfig}`) + await execute(`seid config chain-id ${originalSeidConfig["chain-id"]}`) + await execute(`seid config node ${originalSeidConfig["node"]}`) + await execute(`seid config keyring-backend ${originalSeidConfig["keyring-backend"]}`) + }) }); diff --git a/integration_test/dapp_tests/uniswap/uniswapTest.js b/integration_test/dapp_tests/uniswap/uniswapTest.js index 347bb62f0..3b419324f 100755 --- a/integration_test/dapp_tests/uniswap/uniswapTest.js +++ b/integration_test/dapp_tests/uniswap/uniswapTest.js @@ -1,17 +1,23 @@ const hre = require("hardhat"); // Require Hardhat Runtime Environment -const { abi: WETH9_ABI, bytecode: WETH9_BYTECODE } = require("@uniswap/v2-periphery/build/WETH9.json"); -const { abi: FACTORY_ABI, bytecode: FACTORY_BYTECODE } = require("@uniswap/v3-core/artifacts/contracts/UniswapV3Factory.sol/UniswapV3Factory.json"); -const { abi: DESCRIPTOR_ABI, bytecode: DESCRIPTOR_BYTECODE } = require("@uniswap/v3-periphery/artifacts/contracts/libraries/NFTDescriptor.sol/NFTDescriptor.json"); -const { abi: MANAGER_ABI, bytecode: MANAGER_BYTECODE } = require("@uniswap/v3-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json"); -const { abi: SWAP_ROUTER_ABI, bytecode: SWAP_ROUTER_BYTECODE } = require("@uniswap/v3-periphery/artifacts/contracts/SwapRouter.sol/SwapRouter.json"); -const {exec} = require("child_process"); -const { fundAddress, createTokenFactoryTokenAndMint, deployErc20PointerNative, execute, getSeiAddress, queryWasm, getSeiBalance, isDocker, ABI } = require("../../../contracts/test/lib.js"); -const { deployTokenPool, supplyLiquidity, deployCw20WithPointer, deployEthersContract, sendFunds, pollBalance, setupAccountWithMnemonic, estimateAndCall } = require("../utils") -const { rpcUrls, chainIds, evmRpcUrls} = require("../constants") -const { expect } = require("chai"); +const { + execute, + getSeiAddress, + queryWasm, + getSeiBalance, +} = require("../../../contracts/test/lib.js"); +const { + deployTokenPool, + supplyLiquidity, + sendFunds, + pollBalance, + estimateAndCall, + deployAndReturnUniswapContracts, setDaemonConfig +} = require("../utils") +const {expect} = require("chai"); const testChain = process.env.DAPP_TEST_ENV; +const isFastTrackEnabled = process.env.IS_FAST_TRACK; describe("Uniswap Test", function () { let weth9; @@ -26,106 +32,40 @@ describe("Uniswap Test", function () { let deployer; let user; let originalSeidConfig; + before(async function () { - const accounts = hre.config.networks[testChain].accounts + originalSeidConfig = await setDaemonConfig(testChain); + const accounts = hre.config.networks[testChain].accounts; const deployerWallet = hre.ethers.Wallet.fromMnemonic(accounts.mnemonic, accounts.path); deployer = deployerWallet.connect(hre.ethers.provider); - const seidConfig = await execute('seid config'); - originalSeidConfig = JSON.parse(seidConfig); - - if (testChain === 'seilocal') { - await fundAddress(deployer.address, amount="2000000000000000000000"); - } else { - // Set default seid config to the specified rpc url. - await execute(`seid config chain-id ${chainIds[testChain]}`) - await execute(`seid config node ${rpcUrls[testChain]}`) - } - - // Set the config keyring to 'test' since we're using the key added to test from here. - await execute(`seid config keyring-backend test`) - - await sendFunds('0.01', deployer.address, deployer) - await setupAccountWithMnemonic("dapptest", accounts.mnemonic, deployer); - + ({ + router, + manager, + erc20cw20, + erc20TokenFactory, + weth9, + token, + tokenFactoryDenom, + cw20Address + } = await deployAndReturnUniswapContracts(deployer, testChain, accounts, isFastTrackEnabled)); - // Fund user account const userWallet = hre.ethers.Wallet.createRandom(); user = userWallet.connect(hre.ethers.provider); await sendFunds("1", user.address, deployer) - const deployerSeiAddr = await getSeiAddress(deployer.address); - - // Deploy Required Tokens - const time = Date.now().toString(); - - // Deploy TokenFactory token with ERC20 pointer - const tokenName = `dappTests${time}` - tokenFactoryDenom = await createTokenFactoryTokenAndMint(tokenName, hre.ethers.utils.parseEther("1000000").toString(), deployerSeiAddr, deployerSeiAddr) - console.log("DENOM", tokenFactoryDenom) - const pointerAddr = await deployErc20PointerNative(hre.ethers.provider, tokenFactoryDenom, deployerSeiAddr, evmRpcUrls[testChain]) - console.log("Pointer Addr", pointerAddr); - erc20TokenFactory = new hre.ethers.Contract(pointerAddr, ABI.ERC20, deployer); - - // Deploy CW20 token with ERC20 pointer - const cw20Details = await deployCw20WithPointer(deployerSeiAddr, deployer, time, evmRpcUrls[testChain]) - erc20cw20 = cw20Details.pointerContract; - cw20Address = cw20Details.cw20Address; - - // Deploy WETH9 Token (ETH representation on Uniswap) - weth9 = await deployEthersContract("WETH9", WETH9_ABI, WETH9_BYTECODE, deployer); - - // Deploy MockToken - console.log("Deploying MockToken with the account:", deployer.address); - const contractArtifact = await hre.artifacts.readArtifact("MockERC20"); - token = await deployEthersContract("MockToken", contractArtifact.abi, contractArtifact.bytecode, deployer, ["MockToken", "MKT", hre.ethers.utils.parseEther("1000000")]) - - // Deploy NFT Descriptor. These NFTs are used by the NonFungiblePositionManager to represent liquidity positions. - const descriptor = await deployEthersContract("NFT Descriptor", DESCRIPTOR_ABI, DESCRIPTOR_BYTECODE, deployer); - - // Deploy Uniswap Contracts - // Create UniswapV3 Factory - factory = await deployEthersContract("Uniswap V3 Factory", FACTORY_ABI, FACTORY_BYTECODE, deployer); - - // Deploy NonFungiblePositionManager - manager = await deployEthersContract("NonfungiblePositionManager", MANAGER_ABI, MANAGER_BYTECODE, deployer, deployParams=[factory.address, weth9.address, descriptor.address]); - - // Deploy SwapRouter - router = await deployEthersContract("SwapRouter", SWAP_ROUTER_ABI, SWAP_ROUTER_BYTECODE, deployer, deployParams=[factory.address, weth9.address]); - - const amountETH = hre.ethers.utils.parseEther("3") - - // Gets the amount of WETH9 required to instantiate pools by depositing Sei to the contract - let gasEstimate = await weth9.estimateGas.deposit({ value: amountETH }) - let gasPrice = await deployer.getGasPrice(); - const txWrap = await weth9.deposit({ value: amountETH, gasPrice, gasLimit: gasEstimate }); - await txWrap.wait(); - console.log(`Deposited ${amountETH.toString()} to WETH9`); - - // Create liquidity pools - await deployTokenPool(manager, weth9.address, token.address) - await deployTokenPool(manager, weth9.address, erc20TokenFactory.address) - await deployTokenPool(manager, weth9.address, erc20cw20.address) - - // Add Liquidity to pools - await supplyLiquidity(manager, deployer.address, weth9, token, hre.ethers.utils.parseEther("1"), hre.ethers.utils.parseEther("1")) - await supplyLiquidity(manager, deployer.address, weth9, erc20TokenFactory, hre.ethers.utils.parseEther("1"), hre.ethers.utils.parseEther("1")) - await supplyLiquidity(manager, deployer.address, weth9, erc20cw20, hre.ethers.utils.parseEther("1"), hre.ethers.utils.parseEther("1")) }) describe("Swaps", function () { // Swaps token1 for token2. - async function basicSwapTestAssociated(token1, token2, expectSwapFail=false) { + async function basicSwapTestAssociated(token1, token2, expectSwapFail = false) { const fee = 3000; // Fee tier (0.3%) // Perform a Swap const amountIn = hre.ethers.utils.parseEther("0.1"); const amountOutMin = hre.ethers.utils.parseEther("0"); // Minimum amount of MockToken expected - // const gasLimit = hre.ethers.utils.hexlify(1000000); // Example gas limit - // const gasPrice = await hre.ethers.provider.getGasPrice(); - await estimateAndCall(token1.connect(user), "deposit", [], amountIn) const token1balance = await token1.connect(user).balanceOf(user.address); @@ -167,7 +107,7 @@ describe("Uniswap Test", function () { } } - async function basicSwapTestUnassociated(token1, token2, expectSwapFail=false) { + async function basicSwapTestUnassociated(token1, token2, expectSwapFail = false) { const unassocUserWallet = ethers.Wallet.createRandom(); const unassocUser = unassocUserWallet.connect(ethers.provider); @@ -211,7 +151,9 @@ describe("Uniswap Test", function () { await estimateAndCall(router, "exactInputSingle", [txParams]) // Check User's MockToken Balance - const balance = await pollBalance(token2, unassocUser.address, function(bal) {return bal === 0}); + const balance = await pollBalance(token2, unassocUser.address, function (bal) { + return bal === 0 + }); // Check that it's more than 0 (no specified amount since there might be slippage) expect(Number(balance)).to.greaterThan(0, "User should have received some token2") @@ -258,20 +200,20 @@ describe("Uniswap Test", function () { }) it("Unassociated account should not be able to receive erc20cw20 tokens successfully", async function () { - await basicSwapTestUnassociated(weth9, erc20cw20, expectSwapFail=true) + await basicSwapTestUnassociated(weth9, erc20cw20, expectSwapFail = true) }); }) // We've already tested that an associated account (deployer) can deploy pools and supply liquidity in the Before() step. describe("Pools", function () { it("Unssosciated account should be able to deploy pools successfully", async function () { - const unassocUserWallet = hre.ethers.Wallet.createRandom(); - const unassocUser = unassocUserWallet.connect(hre.ethers.provider); + const unassocUserWallet = hre.ethers.Wallet.createRandom(); + const unassocUser = unassocUserWallet.connect(hre.ethers.provider); - // Fund the user account. Creating pools is a expensive operation so we supply more funds here for gas. - await sendFunds("0.5", unassocUser.address, deployer) + // Fund the user account. Creating pools is a expensive operation so we supply more funds here for gas. + await sendFunds("0.5", unassocUser.address, deployer) - await deployTokenPool(manager.connect(unassocUser), erc20TokenFactory.address, token.address) + await deployTokenPool(manager.connect(unassocUser), erc20TokenFactory.address, token.address) }) it("Unssosciated account should be able to supply liquidity pools successfully", async function () { @@ -291,7 +233,7 @@ describe("Uniswap Test", function () { const managerConnected = manager.connect(unassocUser); const erc20TokenFactoryConnected = erc20TokenFactory.connect(unassocUser); const mockTokenConnected = token.connect(unassocUser); - await supplyLiquidity(managerConnected, unassocUser.address, erc20TokenFactoryConnected, mockTokenConnected, Number(erc20TokenFactoryAmount)/2, Number(mockTokenAmount)/2) + await supplyLiquidity(managerConnected, unassocUser.address, erc20TokenFactoryConnected, mockTokenConnected, Number(erc20TokenFactoryAmount) / 2, Number(mockTokenAmount) / 2) }) }) diff --git a/integration_test/dapp_tests/utils.js b/integration_test/dapp_tests/utils.js index 9c66a92a0..40fe154ab 100644 --- a/integration_test/dapp_tests/utils.js +++ b/integration_test/dapp_tests/utils.js @@ -1,7 +1,20 @@ const {v4: uuidv4} = require("uuid"); const hre = require("hardhat"); -const { ABI, deployErc20PointerForCw20, deployErc721PointerForCw721, getSeiAddress, deployWasm, execute, delay, isDocker } = require("../../contracts/test/lib.js"); -const path = require('path') +const { ABI, deployErc20PointerForCw20, associateKey, storeWasm, fundSeiAddress, deployErc721PointerForCw721, getSeiAddress, deployErc20PointerNative, deployWasm, execute, delay,createTokenFactoryTokenAndMint, isDocker, fundAddress } = require("../../contracts/test/lib.js"); +const path = require('path'); +const devnetUniswapConfig = require('./configs/uniswapConfig.json'); +const devnetSteakConfig = require('./configs/steakConfig.json'); +const devnetNftConfig = require('./configs/nftConfig.json'); + +const { abi: WETH9_ABI, bytecode: WETH9_BYTECODE } = require("@uniswap/v2-periphery/build/WETH9.json"); +const { abi: FACTORY_ABI, bytecode: FACTORY_BYTECODE } = require("@uniswap/v3-core/artifacts/contracts/UniswapV3Factory.sol/UniswapV3Factory.json"); +const { abi: DESCRIPTOR_ABI, bytecode: DESCRIPTOR_BYTECODE } = require("@uniswap/v3-periphery/artifacts/contracts/libraries/NFTDescriptor.sol/NFTDescriptor.json"); +const { abi: MANAGER_ABI, bytecode: MANAGER_BYTECODE } = require("@uniswap/v3-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json"); +const { abi: SWAP_ROUTER_ABI, bytecode: SWAP_ROUTER_BYTECODE } = require("@uniswap/v3-periphery/artifacts/contracts/SwapRouter.sol/SwapRouter.json"); +const {chainIds, rpcUrls, evmRpcUrls} = require("./constants"); +const {expect} = require("chai"); +const {existsSync, readFileSync, writeFileSync} = require("node:fs"); +const {CosmWasmClient} = require("@cosmjs/cosmwasm-stargate"); async function deployTokenPool(managerContract, firstTokenAddr, secondTokenAddr, swapRatio=1, fee=3000) { const sqrtPriceX96 = BigInt(Math.sqrt(swapRatio) * (2 ** 96)); // Initial price (1:1) @@ -27,7 +40,6 @@ async function supplyLiquidity(managerContract, recipientAddr, firstTokenContrac // Approve the NonfungiblePositionManager to spend the specified amount of secondToken await estimateAndCall(secondTokenContract, "approve", [managerContract.address, secondTokenAmt]) - // Add liquidity to the pool await estimateAndCall(managerContract, "mint", [{ token0: token0.address, @@ -42,8 +54,6 @@ async function supplyLiquidity(managerContract, recipientAddr, firstTokenContrac recipient: recipientAddr, deadline: Math.floor(Date.now() / 1000) + 60 * 10, // 10 minutes from now }]); - - console.log("Liquidity added"); } // Orders the 2 addresses sequentially, since this is required by uniswap. @@ -60,6 +70,179 @@ function tokenOrder(firstTokenAddr, secondTokenAddr, firstTokenAmount=0, secondT return [token0, token1] } +async function returnContractsForFastTrackUniswap(deployer, config, testChain) { + const contractArtifact = await hre.artifacts.readArtifact("MockERC20"); + return { + manager: new hre.ethers.Contract(config.manager, MANAGER_ABI, deployer), + router: new hre.ethers.Contract(config.router, SWAP_ROUTER_ABI, deployer), + erc20TokenFactory: new hre.ethers.Contract(config.erc20TokenFactory, ABI.ERC20, deployer), + erc20cw20: new hre.ethers.Contract(config.erc20cw20, ABI.ERC20, deployer), + weth9: new hre.ethers.Contract(config.weth9, WETH9_ABI, deployer), + token: new hre.ethers.Contract(config.token, contractArtifact.abi, deployer), + tokenFactoryDenom: config.tokenFactoryDenom, + cw20Address: config.cw20Address + } +} + +async function returnContractsForFastTrackSteak(deployer, config, testChain) { + return { + hubAddress: config.hubAddress, + tokenAddress: config.tokenAddress, + tokenPointer: new hre.ethers.Contract( + config.pointerAddress, + ABI.ERC20, + hre.ethers.provider + ) + } +} + +async function deployAndReturnUniswapContracts(deployer, testChain, accounts, isFastTrackEnabled) { + if (isFastTrackEnabled && testChain === 'devnet') { + console.log('Using already deployed contracts on arctic 1'); + return returnContractsForFastTrackUniswap(deployer, devnetUniswapConfig); + } else if (testChain === 'seiCluster' && isFastTrackEnabled) { + if (clusterConfigExists('uniswapConfigCluster.json')) { + console.log('Config file already exists. Running tests against already deployed contracts.') + const contractConfig = path.join(__dirname, 'configs', 'uniswapConfigCluster.json'); + const clusterConfig = JSON.parse(readFileSync(contractConfig, 'utf8')); + return returnContractsForFastTrackUniswap(deployer, clusterConfig, testChain); + } else { + console.log('Config file not found. On first iteration going to record the addresses into config file.'); + return writeAddressesIntoUniswapConfig(deployer, testChain, accounts); + } + } + return deployUniswapContracts(deployer, testChain, accounts); +} + +async function writeAddressesIntoUniswapConfig(deployer, testChain, accounts){ + const contracts = await deployUniswapContracts(deployer, testChain, accounts); + const contractAddresses = { + manager: contracts.manager.address, + router: contracts.router.address, + erc20TokenFactory: contracts.erc20TokenFactory.address, + erc20cw20: contracts.erc20cw20.address, + weth9: contracts.weth9.address, + token: contracts.token.address, + tokenFactoryDenom: contracts.tokenFactoryDenom, + cw20Address: contracts.cw20Address + }; + writeFileSync('./configs/uniswapConfigCluster.json', JSON.stringify(contractAddresses, null, 2), 'utf8'); + console.log('contract addresses are saved'); + return contracts; +} + +async function writeAddressesIntoSteakConfig(testChain){ + const contracts = await deployContractsForSteakTests(testChain); + const contractAddresses = { + hubAddress: contracts.hubAddress, + tokenAddress: contracts.tokenAddress, + pointerAddress: contracts.tokenPointer.address + }; + writeFileSync('./configs/steakConfigCluster.json', JSON.stringify(contractAddresses, null, 2), 'utf8'); + console.log('contract addresses are saved'); + return contracts; +} + +async function writeAddressesIntoNftConfig(deployer, testChain, accounts){ + const contracts = await deployContractsForNftTests(deployer, testChain, accounts); + const contractAddresses = { + marketplace: contracts.marketplace.address, + erc721token: contracts.erc721token.address, + cw721Address: contracts.cw721Address, + erc721PointerToken: contracts.erc721PointerToken.address, + }; + writeFileSync('./configs/nftConfigCluster.json', JSON.stringify(contractAddresses, null, 2), 'utf8'); + console.log('contract addresses are saved'); + return contracts; +} + +async function deployUniswapContracts(deployer, testChain, accounts){ + + if (testChain === 'seilocal') { + const tx = await fundAddress(deployer.address, amount="2000000000000000000000"); + await waitFor(1); + } + + // Set the config keyring to 'test' since we're using the key added to test from here. + await execute(`seid config keyring-backend test`) + + await sendFunds('0.01', deployer.address, deployer) + await setupAccountWithMnemonic("dapptest", accounts.mnemonic, deployer); + + const deployerSeiAddr = await getSeiAddress(deployer.address); + // Deploy Required Tokens + const time = Date.now().toString(); + + // Deploy TokenFactory token with ERC20 pointer + const tokenName = `dappTests${time}` + const tokenFactoryDenom = await createTokenFactoryTokenAndMint(tokenName, hre.ethers.utils.parseEther("1000000").toString(), deployerSeiAddr, deployerSeiAddr) + console.log("DENOM", tokenFactoryDenom) + const pointerAddr = await deployErc20PointerNative(hre.ethers.provider, tokenFactoryDenom, deployerSeiAddr, evmRpcUrls[testChain]) + console.log("Pointer Addr", pointerAddr); + const erc20TokenFactory = new hre.ethers.Contract(pointerAddr, ABI.ERC20, deployer); + + // Deploy CW20 token with ERC20 pointer + const cw20Details = await deployCw20WithPointer(deployerSeiAddr, deployer, time, evmRpcUrls[testChain]) + const erc20cw20 = cw20Details.pointerContract; + const cw20Address = cw20Details.cw20Address; + + // Deploy WETH9 Token (ETH representation on Uniswap) + const weth9 = await deployEthersContract("WETH9", WETH9_ABI, WETH9_BYTECODE, deployer); + + // Deploy MockToken + console.log("Deploying MockToken with the account:", deployer.address); + const contractArtifact = await hre.artifacts.readArtifact("MockERC20"); + const token = await deployEthersContract("MockToken", contractArtifact.abi, contractArtifact.bytecode, deployer, ["MockToken", "MKT", hre.ethers.utils.parseEther("1000000")]) + + // Deploy NFT Descriptor. These NFTs are used by the NonFungiblePositionManager to represent liquidity positions. + const descriptor = await deployEthersContract("NFT Descriptor", DESCRIPTOR_ABI, DESCRIPTOR_BYTECODE, deployer); + + // Deploy Uniswap Contracts + // Create UniswapV3 Factory + const factory = await deployEthersContract("Uniswap V3 Factory", FACTORY_ABI, FACTORY_BYTECODE, deployer); + + // Deploy NonFungiblePositionManager + const manager = await deployEthersContract("NonfungiblePositionManager", MANAGER_ABI, MANAGER_BYTECODE, deployer, deployParams=[factory.address, weth9.address, descriptor.address]); + + // Deploy SwapRouter + const router = await deployEthersContract("SwapRouter", SWAP_ROUTER_ABI, SWAP_ROUTER_BYTECODE, deployer, deployParams=[factory.address, weth9.address]); + + const amountETH = hre.ethers.utils.parseEther("3") + + // Gets the amount of WETH9 required to instantiate pools by depositing Sei to the contract + let gasEstimate = await weth9.estimateGas.deposit({ value: amountETH }) + let gasPrice = await deployer.getGasPrice(); + const txWrap = await weth9.deposit({ value: amountETH, gasPrice, gasLimit: gasEstimate }); + await txWrap.wait(); + console.log(`Deposited ${amountETH.toString()} to WETH9`); + + // Create liquidity pools + await deployTokenPool(manager, weth9.address, token.address) + await deployTokenPool(manager, weth9.address, erc20TokenFactory.address) + await deployTokenPool(manager, weth9.address, erc20cw20.address) + + // Add Liquidity to pools + await supplyLiquidity(manager, deployer.address, weth9, token, hre.ethers.utils.parseEther("1"), hre.ethers.utils.parseEther("1")) + await supplyLiquidity(manager, deployer.address, weth9, erc20TokenFactory, hre.ethers.utils.parseEther("1"), hre.ethers.utils.parseEther("1")) + await supplyLiquidity(manager, deployer.address, weth9, erc20cw20, hre.ethers.utils.parseEther("1"), hre.ethers.utils.parseEther("1")) + + return { + router, + manager, + erc20cw20, + erc20TokenFactory, + weth9, + token, + tokenFactoryDenom, + cw20Address + } +} + +function clusterConfigExists(fileName){ + const folderPath = path.join(__dirname, 'configs', fileName); + return existsSync(folderPath) +} + async function deployCw20WithPointer(deployerSeiAddr, signer, time, evmRpc="") { const CW20_BASE_PATH = (await isDocker()) ? '../integration_test/dapp_tests/uniswap/cw20_base.wasm' : path.resolve(__dirname, '../dapp_tests/uniswap/cw20_base.wasm') const cw20Address = await deployWasm(CW20_BASE_PATH, deployerSeiAddr, "cw20", { @@ -110,7 +293,6 @@ async function doesTokenFactoryDenomExist(denom) { } async function sendFunds(amountSei, recipient, signer) { - const bal = await signer.getBalance(); if (bal.lt(hre.ethers.utils.parseEther(amountSei))) { throw new Error(`Signer has insufficient balance. Want ${hre.ethers.utils.parseEther(amountSei)}, has ${bal}`); @@ -256,7 +438,7 @@ const bond = async (contractAddress, address, amount) => { bond: {}, }; const jsonString = JSON.stringify(msg).replace(/"/g, '\\"'); - const command = `seid tx wasm execute ${contractAddress} "${jsonString}" --amount=${amount}usei --from=${address} --gas=500000 --gas-prices=0.1usei --broadcast-mode=block -y --output=json`; + const command = `seid tx wasm execute ${contractAddress} "${jsonString}" --amount=${amount}usei --from=${address} --gas=600000 --gas-prices=0.1usei --broadcast-mode=block -y --output=json`; const output = await execute(command); const response = JSON.parse(output); if (response.code !== 0) { @@ -337,11 +519,18 @@ const transferTokens = async (tokenAddress, sender, destination, amount) => { async function setupAccountWithMnemonic(baseName, mnemonic, deployer) { const uniqueName = `${baseName}-${uuidv4()}`; - const address = await getSeiAddress(deployer.address) - + const address = await getSeiAddress(deployer.address); return await addDeployerAccount(uniqueName, address, mnemonic) } +async function waitFor(seconds){ + return new Promise((resolve) =>{ + setTimeout(() =>{ + resolve(); + }, seconds * 1000) + }) +} + async function addDeployerAccount(keyName, address, mnemonic) { // First try to retrieve by address try { @@ -366,8 +555,204 @@ async function addDeployerAccount(keyName, address, mnemonic) { return JSON.parse(output); } +async function setupAccount(baseName, associate = true, amount="100000000000", denom="usei", funder='admin') { + const uniqueName = `${baseName}-${uuidv4()}`; + + const account = await addAccount(uniqueName); + await fundSeiAddress(account.address, amount, denom, funder); + if (associate) { + await associateKey(account.address); + } + return account; +} + +async function deployAndReturnContractsForSteakTests(deployer, testChain, accounts, isFastTrackEnabled){ + let owner; + let contracts; + // Check the test chain type and retrieve or write the contract configuration + if (isFastTrackEnabled && testChain === 'devnet') { + console.log('Using already deployed contracts on arctic 1'); + contracts = await returnContractsForFastTrackSteak(deployer, devnetSteakConfig, testChain); + owner = await setupAccountWithMnemonic("steak-owner", accounts.mnemonic, deployer); + } else if (isFastTrackEnabled && testChain === 'seiCluster') { + owner = await setupAccountWithMnemonic("steak-owner", accounts.mnemonic, deployer); + if (clusterConfigExists('steakConfigCluster.json')) { + console.log('Running tests against already deployed contracts.') + const contractConfigPath = path.join(__dirname, 'configs', 'steakConfigCluster.json'); + const clusterConfig = JSON.parse(readFileSync(contractConfigPath, 'utf8')); + contracts = await returnContractsForFastTrackSteak(deployer, clusterConfig, testChain); + } else { + console.log('Config file not found. On first iteration going to create contracts and record on config file. ') + contracts = await writeAddressesIntoSteakConfig(testChain); + } + } else { + ({contracts, owner} = await deployContractsForSteakTests(testChain)); + } + return { ...contracts, owner }; +} + +async function deployContractsForSteakTests(testChain){ + let owner; + // Set up the owner account + if (testChain === 'seilocal') { + owner = await setupAccount("steak-owner"); + } else { + const accounts = hre.config.networks[testChain].accounts + const deployerWallet = hre.ethers.Wallet.fromMnemonic(accounts.mnemonic, accounts.path); + const deployer = deployerWallet.connect(hre.ethers.provider) + + await sendFunds('0.01', deployer.address, deployer) + // Set the config keyring to 'test' since we're using the key added to test from here. + owner = await setupAccountWithMnemonic("steak-owner", accounts.mnemonic, deployer) + } + + await execute(`seid config keyring-backend test`); + + // Store and deploy contracts + const contracts = await deploySteakContracts( + owner.address, + testChain, + ); + + return {contracts, owner}; +} + +async function deploySteakContracts(ownerAddress, testChain) { + // Store CW20 token wasm + const STEAK_TOKEN_WASM = (await isDocker()) ? '../integration_test/dapp_tests/steak/contracts/steak_token.wasm' : path.resolve(__dirname, 'steak/contracts/steak_token.wasm') + const tokenCodeId = await storeWasm(STEAK_TOKEN_WASM, ownerAddress); + + // Store Hub contract + const STEAK_HUB_WASM = (await isDocker()) ? '../integration_test/dapp_tests/steak/contracts/steak_hub.wasm' : path.resolve(__dirname, 'steak/contracts/steak_hub.wasm') + const hubCodeId = await storeWasm(STEAK_HUB_WASM, ownerAddress); + + // Instantiate hub and token contracts + const validators = await getValidators(); + const instantiateMsg = { + cw20_code_id: parseInt(tokenCodeId), + owner: ownerAddress, + name: "Steak", + symbol: "STEAK", + decimals: 6, + epoch_period: 259200, + unbond_period: 1814400, + validators: validators.slice(0, 3), + }; + const contractAddresses = await instantiateHubContract( + hubCodeId, + ownerAddress, + instantiateMsg, + "steakhub" + ); + + // Deploy pointer for token contract + const pointerAddr = await deployErc20PointerForCw20( + hre.ethers.provider, + contractAddresses.tokenContract, + 10, + ownerAddress, + evmRpcUrls[testChain] + ); + + const tokenPointer = new hre.ethers.Contract( + pointerAddr, + ABI.ERC20, + hre.ethers.provider + ); + await waitFor(2); + return { + hubAddress: contractAddresses.hubContract, + tokenAddress: contractAddresses.tokenContract, + tokenPointer, + }; +} + +async function deployAndReturnContractsForNftTests(deployer, testChain, accounts, isFastTrackEnabled){ + let contracts; + // Check the test chain type and retrieve or write the contract configuration + if (isFastTrackEnabled && testChain === 'devnet') { + console.log('Using already deployed contracts on arctic 1'); + return returnContractsForFastTrackNftTests(deployer, devnetNftConfig, testChain); + } else if (testChain === 'seiCluster' && isFastTrackEnabled) { + if (clusterConfigExists('nftConfigCluster.json')) { + console.log('Config file already exists. Running tests against already deployed contracts.'); + const contractConfigPath = path.join(__dirname, 'configs', 'nftConfigCluster.json'); + const clusterConfig = JSON.parse(readFileSync(contractConfigPath, 'utf8')); + contracts = await returnContractsForFastTrackNftTests(deployer, clusterConfig, testChain); + } else { + console.log('Config file not found. On first iteration going to record the addresses into config file.'); + contracts = await writeAddressesIntoNftConfig(deployer, testChain, accounts); + } + } else { + contracts = await deployContractsForNftTests(deployer, testChain, accounts); + } + return contracts; +} + +async function deployContractsForNftTests(deployer, testChain, accounts){ + if (testChain === 'seilocal') { + await fundAddress(deployer.address, amount="2000000000000000000000"); + } + + await execute(`seid config keyring-backend test`) + + await sendFunds('0.01', deployer.address, deployer) + await setupAccountWithMnemonic("dapptest", accounts.mnemonic, deployer); + + // Deploy MockNFT + const erc721ContractArtifact = await hre.artifacts.readArtifact("MockERC721"); + const erc721token = await deployEthersContract("MockERC721", erc721ContractArtifact.abi, erc721ContractArtifact.bytecode, deployer, ["MockERC721", "MKTNFT"]) + + const numNftsToMint = 50 + await estimateAndCall(erc721token, "batchMint", [deployer.address, numNftsToMint]); + + // Deploy CW721 token with ERC721 pointer + const time = Date.now().toString(); + const deployerSeiAddr = await getSeiAddress(deployer.address); + const cw721Details = await deployCw721WithPointer(deployerSeiAddr, deployer, time, evmRpcUrls[testChain]) + const erc721PointerToken = cw721Details.pointerContract; + const cw721Address = cw721Details.cw721Address; + const numCwNftsToMint = 2; + for (let i = 1; i <= numCwNftsToMint; i++) { + await mintCw721(cw721Address, deployerSeiAddr, i) + } + const cwbal = await erc721PointerToken.balanceOf(deployer.address); + expect(cwbal).to.equal(numCwNftsToMint) + + const nftMarketplaceArtifact = await hre.artifacts.readArtifact("NftMarketplace"); + const marketplace = await deployEthersContract("NftMarketplace", nftMarketplaceArtifact.abi, nftMarketplaceArtifact.bytecode, deployer) + return {marketplace, erc721token, cw721Address, erc721PointerToken} +} + +async function returnContractsForFastTrackNftTests(deployer, clusterConfig, testChain) { + await setupAccountWithMnemonic("dapptest", deployer.mnemonic.phrase, deployer); + const nftMarketplaceArtifact = await hre.artifacts.readArtifact("NftMarketplace"); + const erc721ContractArtifact = await hre.artifacts.readArtifact("MockERC721"); + return { + marketplace: new hre.ethers.Contract(clusterConfig.marketplace, nftMarketplaceArtifact.abi, deployer), + erc721token: new hre.ethers.Contract(clusterConfig.erc721token, erc721ContractArtifact.abi, deployer), + erc721PointerToken: new hre.ethers.Contract(clusterConfig.erc721PointerToken, ABI.ERC721, deployer), + cw721Address: clusterConfig.cw721Address, + } +} + +async function queryLatestNftIds(contractAddress, testChain){ + const cosmWasmClient = await CosmWasmClient.connect(rpcUrls[testChain]); + const latestNum = await cosmWasmClient.queryContractSmart(contractAddress, {num_tokens: {}}); + return latestNum.count; +} + +async function setDaemonConfig(testChain) { + const seidConfig = await execute('seid config'); + const originalSeidConfig = JSON.parse(seidConfig); + await execute(`seid config chain-id ${chainIds[testChain]}`); + await execute(`seid config node ${rpcUrls[testChain]}`); + return originalSeidConfig; +} + module.exports = { getValidators, + returnContractsForFastTrackUniswap, instantiateHubContract, bond, unbond, @@ -375,6 +760,7 @@ module.exports = { queryTokenBalance, addAccount, estimateAndCall, + deployAndReturnUniswapContracts, addDeployerAccount, setupAccountWithMnemonic, transferTokens, @@ -386,5 +772,15 @@ module.exports = { doesTokenFactoryDenomExist, pollBalance, sendFunds, - mintCw721 + mintCw721, + returnContractsForFastTrackSteak, + deployContractsForSteakTests, + setupAccount, + returnContractsForFastTrackNftTests, + deployContractsForNftTests, + deployAndReturnContractsForSteakTests, + deployAndReturnContractsForNftTests, + waitFor, + queryLatestNftIds, + setDaemonConfig, }; \ No newline at end of file