From 033a8b58241c264fd1ada76d3d2fa552bdd1b5cd Mon Sep 17 00:00:00 2001 From: Jeremy Wei Date: Fri, 2 Aug 2024 16:51:25 -0400 Subject: [PATCH 01/38] [EVM] Tune configs (#1800) * increase min gas price from 1gwei to 333gwei * fixes * fixes * fix * fetch depth 0 * try to install docker compose * fixes --- .github/workflows/integration-test.yml | 6 +++++ app/receipt_test.go | 4 +-- contracts/test/ERC20toNativePointerTest.js | 10 +++++--- contracts/test/EVMCompatabilityTest.js | 25 ++++++++++--------- precompiles/distribution/distribution_test.go | 8 +++--- precompiles/ibc/ibc_test.go | 6 ++--- x/evm/integration_test.go | 8 +++--- x/evm/module_test.go | 2 +- x/evm/types/params.go | 2 +- 9 files changed, 41 insertions(+), 30 deletions(-) diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml index 406742264..239fd7d27 100644 --- a/.github/workflows/integration-test.yml +++ b/.github/workflows/integration-test.yml @@ -143,6 +143,12 @@ jobs: with: go-version: 1.21 + - name: Install Docker Compose + run: | + sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose + sudo chmod +x /usr/local/bin/docker-compose + docker-compose --version + - name: Start 4 node docker cluster run: make clean && INVARIANT_CHECK_INTERVAL=10 ${{matrix.test.env}} make docker-cluster-start & diff --git a/app/receipt_test.go b/app/receipt_test.go index d1ce00052..935031cef 100644 --- a/app/receipt_test.go +++ b/app/receipt_test.go @@ -87,7 +87,7 @@ func TestEvmEventsForCw20(t *testing.T) { wasmAddr := common.HexToAddress(wasmd.WasmdAddress) txData := ethtypes.LegacyTx{ Nonce: 0, - GasPrice: big.NewInt(1000000000), + GasPrice: big.NewInt(333000000000), Gas: 1000000, To: &wasmAddr, Data: data, @@ -202,7 +202,7 @@ func TestEvmEventsForCw721(t *testing.T) { wasmAddr := common.HexToAddress(wasmd.WasmdAddress) txData := ethtypes.LegacyTx{ Nonce: 0, - GasPrice: big.NewInt(1000000000), + GasPrice: big.NewInt(333000000000), Gas: 1000000, To: &wasmAddr, Data: data, diff --git a/contracts/test/ERC20toNativePointerTest.js b/contracts/test/ERC20toNativePointerTest.js index c6c024380..f878e1eeb 100644 --- a/contracts/test/ERC20toNativePointerTest.js +++ b/contracts/test/ERC20toNativePointerTest.js @@ -1,5 +1,6 @@ const {setupSigners, deployErc20PointerNative, getAdmin, createTokenFactoryTokenAndMint, ABI, generateWallet, - fundAddress, getSeiAddress + fundAddress, getSeiAddress, + delay } = require("./lib"); const {expect} = require("chai"); @@ -89,10 +90,13 @@ describe("ERC20 to Native Pointer", function () { expect(await pointer.balanceOf(recipient)).to.equal(amount); // fund address so it can transact - await fundAddress(recipient) + await fundAddress(recipient, "1000000000000000000000") + await delay() // unlinked wallet can send balance back to sender (becomes linked at this moment) - await (await pointer.connect(recipientWallet).transfer(sender.evmAddress, amount)).wait() + await (await pointer.connect(recipientWallet).transfer(sender.evmAddress, amount, { + gasPrice: ethers.parseUnits('333', 'gwei') + })).wait() expect(await pointer.balanceOf(recipient)).to.equal(BigInt(0)); expect(await pointer.balanceOf(sender.evmAddress)).to.equal(startBal); diff --git a/contracts/test/EVMCompatabilityTest.js b/contracts/test/EVMCompatabilityTest.js index 8ab8220ec..bbf1dbc7d 100644 --- a/contracts/test/EVMCompatabilityTest.js +++ b/contracts/test/EVMCompatabilityTest.js @@ -497,24 +497,24 @@ describe("EVM Test", function () { describe("EIP-1559", async function() { const zero = ethers.parseUnits('0', 'ether') - const twoGwei = ethers.parseUnits("2", "gwei"); - const oneGwei = ethers.parseUnits("1", "gwei"); + const highgp = ethers.parseUnits("400", "gwei"); + const gp = ethers.parseUnits("333", "gwei"); const testCases = [ - ["No truncation from max priority fee", oneGwei, oneGwei], - ["With truncation from max priority fee", oneGwei, twoGwei], - ["With complete truncation from max priority fee", zero, twoGwei] + ["No truncation from max priority fee", gp, gp], + ["With truncation from max priority fee", gp, highgp], + ["With complete truncation from max priority fee", zero, highgp] ]; it("Should be able to send many EIP-1559 txs", async function () { - const oneGwei = ethers.parseUnits("1", "gwei"); + const gp = ethers.parseUnits("333", "gwei"); const zero = ethers.parseUnits('0', 'ether') for (let i = 0; i < 10; i++) { const txResponse = await owner.sendTransaction({ to: owner.address, value: zero, - maxPriorityFeePerGas: oneGwei, - maxFeePerGas: oneGwei, + maxPriorityFeePerGas: gp, + maxFeePerGas: gp, type: 2 }); await txResponse.wait(); @@ -617,8 +617,8 @@ describe("EVM Test", function () { it("Should retrieve a transaction receipt", async function () { const txResponse = await evmTester.setBoolVar(false, { type: 2, // force it to be EIP-1559 - maxPriorityFeePerGas: ethers.parseUnits('100', 'gwei'), // set gas high just to get it included - maxFeePerGas: ethers.parseUnits('100', 'gwei') + maxPriorityFeePerGas: ethers.parseUnits('400', 'gwei'), // set gas high just to get it included + maxFeePerGas: ethers.parseUnits('400', 'gwei') }); await txResponse.wait(); const receipt = await ethers.provider.getTransactionReceipt(txResponse.hash); @@ -1093,6 +1093,7 @@ describe("EVM Validations ", function() { await setupSigners(await hre.ethers.getSigners()) signer = generateWallet() await fundAddress(await signer.getAddress()) + await sleep(3000) }) it("should prevent wrong chainId for eip-155 txs", async function() { @@ -1104,9 +1105,9 @@ describe("EVM Validations ", function() { chainId: "0x12345", type: 2, nonce: nonce, - maxPriorityFeePerGas: 21000, + maxPriorityFeePerGas: 400000000000, gasLimit: 21000, - maxFeePerGas:10000000000}) + maxFeePerGas: 400000000000}) const nodeUrl = 'http://localhost:8545'; const response = await axios.post(nodeUrl, { diff --git a/precompiles/distribution/distribution_test.go b/precompiles/distribution/distribution_test.go index cc7f0c770..1a7e071d3 100644 --- a/precompiles/distribution/distribution_test.go +++ b/precompiles/distribution/distribution_test.go @@ -148,7 +148,7 @@ func TestWithdraw(t *testing.T) { res, err = msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), req) require.Nil(t, err) require.Empty(t, res.VmError) - require.Equal(t, uint64(68682), res.GasUsed) + require.Equal(t, uint64(68688), res.GasUsed) // reinitialized d, found = testApp.StakingKeeper.GetDelegation(ctx, seiAddr, val) @@ -301,7 +301,7 @@ func setWithdrawAddressAndWithdraw( res, err = msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), r) require.Nil(t, err) require.Empty(t, res.VmError) - require.Equal(t, uint64(152848), res.GasUsed) + require.Equal(t, uint64(152854), res.GasUsed) // reinitialized for _, val := range vals { @@ -1051,7 +1051,7 @@ func TestPrecompile_RunAndCalculateGas_Rewards(t *testing.T) { suppliedGas: uint64(1000000), }, wantRet: emptyCasePackedOutput, - wantRemainingGas: 994319, + wantRemainingGas: 994313, wantErr: false, }, { @@ -1067,7 +1067,7 @@ func TestPrecompile_RunAndCalculateGas_Rewards(t *testing.T) { suppliedGas: uint64(1000000), }, wantRet: happyPathPackedOutput, - wantRemainingGas: 994319, + wantRemainingGas: 994313, wantErr: false, }, } diff --git a/precompiles/ibc/ibc_test.go b/precompiles/ibc/ibc_test.go index da56d0f93..feccfb150 100644 --- a/precompiles/ibc/ibc_test.go +++ b/precompiles/ibc/ibc_test.go @@ -106,7 +106,7 @@ func TestPrecompile_Run(t *testing.T) { fields: fields{transferKeeper: &MockTransferKeeper{}}, args: commonArgs, wantBz: packedTrue, - wantRemainingGas: 994319, + wantRemainingGas: 994313, wantErr: false, }, { @@ -235,7 +235,7 @@ func TestPrecompile_Run(t *testing.T) { value: nil, }, wantBz: packedTrue, - wantRemainingGas: 994319, + wantRemainingGas: 994313, wantErr: false, }, { @@ -255,7 +255,7 @@ func TestPrecompile_Run(t *testing.T) { value: nil, }, wantBz: packedTrue, - wantRemainingGas: 994319, + wantRemainingGas: 994313, wantErr: false, }, } diff --git a/x/evm/integration_test.go b/x/evm/integration_test.go index 577fbcb46..bb03ee0ae 100644 --- a/x/evm/integration_test.go +++ b/x/evm/integration_test.go @@ -75,7 +75,7 @@ func TestERC2981PointerToCW2981(t *testing.T) { require.Nil(t, err) txData := ethtypes.LegacyTx{ Nonce: 0, - GasPrice: big.NewInt(1000000000), + GasPrice: big.NewInt(333000000000), Gas: 5000000, To: &to, Data: data, @@ -108,7 +108,7 @@ func TestERC2981PointerToCW2981(t *testing.T) { require.Nil(t, err) txData = ethtypes.LegacyTx{ Nonce: 1, - GasPrice: big.NewInt(1000000000), + GasPrice: big.NewInt(333000000000), Gas: 1000000, To: &pointerAddr, Data: data, @@ -158,7 +158,7 @@ func TestCW2981PointerToERC2981(t *testing.T) { require.Nil(t, err) txData := ethtypes.LegacyTx{ Nonce: 0, - GasPrice: big.NewInt(1000000000), + GasPrice: big.NewInt(333000000000), Gas: 5000000, To: nil, Data: append(bz, data...), @@ -193,7 +193,7 @@ func TestCW2981PointerToERC2981(t *testing.T) { to := common.HexToAddress(receipt.ContractAddress) txData = ethtypes.LegacyTx{ Nonce: 1, - GasPrice: big.NewInt(1000000000), + GasPrice: big.NewInt(333000000000), Gas: 1000000, To: &to, Data: data, diff --git a/x/evm/module_test.go b/x/evm/module_test.go index 8f12f0e42..32e30c279 100644 --- a/x/evm/module_test.go +++ b/x/evm/module_test.go @@ -53,7 +53,7 @@ func TestModuleExportGenesis(t *testing.T) { module := evm.NewAppModule(nil, k) jsonMsg := module.ExportGenesis(ctx, types.ModuleCdc) jsonStr := string(jsonMsg) - assert.Equal(t, "{\"params\":{\"priority_normalizer\":\"1.000000000000000000\",\"base_fee_per_gas\":\"0.000000000000000000\",\"minimum_fee_per_gas\":\"1000000000.000000000000000000\",\"whitelisted_cw_code_hashes_for_delegate_call\":[]},\"address_associations\":[{\"sei_address\":\"sei17xpfvakm2amg962yls6f84z3kell8c5la4jkdu\",\"eth_address\":\"0x27F7B8B8B5A4e71E8E9aA671f4e4031E3773303F\"}],\"codes\":[],\"states\":[],\"nonces\":[],\"serialized\":[{\"prefix\":\"Fg==\",\"key\":\"AwAC\",\"value\":\"AAAAAAAAAAM=\"},{\"prefix\":\"Fg==\",\"key\":\"BAAG\",\"value\":\"AAAAAAAAAAQ=\"}]}", jsonStr) + assert.Equal(t, "{\"params\":{\"priority_normalizer\":\"1.000000000000000000\",\"base_fee_per_gas\":\"0.000000000000000000\",\"minimum_fee_per_gas\":\"333000000000.000000000000000000\",\"whitelisted_cw_code_hashes_for_delegate_call\":[]},\"address_associations\":[{\"sei_address\":\"sei17xpfvakm2amg962yls6f84z3kell8c5la4jkdu\",\"eth_address\":\"0x27F7B8B8B5A4e71E8E9aA671f4e4031E3773303F\"}],\"codes\":[],\"states\":[],\"nonces\":[],\"serialized\":[{\"prefix\":\"Fg==\",\"key\":\"AwAC\",\"value\":\"AAAAAAAAAAM=\"},{\"prefix\":\"Fg==\",\"key\":\"BAAG\",\"value\":\"AAAAAAAAAAQ=\"}]}", jsonStr) } func TestConsensusVersion(t *testing.T) { diff --git a/x/evm/types/params.go b/x/evm/types/params.go index faff9e9ec..485782dc0 100644 --- a/x/evm/types/params.go +++ b/x/evm/types/params.go @@ -23,7 +23,7 @@ var DefaultPriorityNormalizer = sdk.NewDec(1) // burnt rather than go to validators (similar to base fee on // Ethereum). var DefaultBaseFeePerGas = sdk.NewDec(0) -var DefaultMinFeePerGas = sdk.NewDec(1000000000) +var DefaultMinFeePerGas = sdk.NewDec(333000000000) var DefaultWhitelistedCwCodeHashesForDelegateCall = generateDefaultWhitelistedCwCodeHashesForDelegateCall() From 4fed1a0808a2164522e1439f272983ef0ca14703 Mon Sep 17 00:00:00 2001 From: mj Date: Tue, 6 Aug 2024 21:17:17 -0400 Subject: [PATCH 02/38] Add dApp Tests (#1802) * draft * draft * working protoype * poc fix * import * imports issue * use fund address * amount * expect * working tests * put package.json in dapp_tests * dont commit artifacts * no build * run ci * update package json --- .github/workflows/integration-test.yml | 6 + .gitignore | 3 + .../dapp_tests/contracts/MockERC20.sol | 14 + integration_test/dapp_tests/dapp_tests.sh | 14 + integration_test/dapp_tests/hardhat.config.js | 25 + integration_test/dapp_tests/package-lock.json | 11680 ++++++++++++++++ integration_test/dapp_tests/package.json | 20 + .../dapp_tests/uniswap/uniswapTest.js | 253 + 8 files changed, 12015 insertions(+) create mode 100644 integration_test/dapp_tests/contracts/MockERC20.sol create mode 100755 integration_test/dapp_tests/dapp_tests.sh create mode 100644 integration_test/dapp_tests/hardhat.config.js create mode 100644 integration_test/dapp_tests/package-lock.json create mode 100644 integration_test/dapp_tests/package.json create mode 100755 integration_test/dapp_tests/uniswap/uniswapTest.js diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml index 239fd7d27..d0f5f8339 100644 --- a/.github/workflows/integration-test.yml +++ b/.github/workflows/integration-test.yml @@ -121,6 +121,12 @@ jobs: "./integration_test/evm_module/scripts/evm_interoperability_tests.sh" ] }, + { + name: "dApp Tests", + scripts: [ + "./integration_test/dapp_tests/dapp_tests.sh" + ] + }, ] steps: - uses: actions/checkout@v3 diff --git a/.gitignore b/.gitignore index ada3dc4f6..1af6db532 100644 --- a/.gitignore +++ b/.gitignore @@ -52,3 +52,6 @@ example/cosmwasm/cw721/target # Solidity contracts artifacts contracts/artifacts + +# Integration tests build artifacts +integration_test/dapp_tests/artifacts diff --git a/integration_test/dapp_tests/contracts/MockERC20.sol b/integration_test/dapp_tests/contracts/MockERC20.sol new file mode 100644 index 000000000..58989ad89 --- /dev/null +++ b/integration_test/dapp_tests/contracts/MockERC20.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +contract MockERC20 is ERC20 { + constructor(string memory name, string memory symbol, uint256 initialSupply) ERC20(name, symbol) { + _mint(msg.sender, initialSupply); + } + + function mint(address to, uint256 amount) public { + _mint(to, amount); + } +} \ No newline at end of file diff --git a/integration_test/dapp_tests/dapp_tests.sh b/integration_test/dapp_tests/dapp_tests.sh new file mode 100755 index 000000000..a824b88dd --- /dev/null +++ b/integration_test/dapp_tests/dapp_tests.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +set -e + +# Build contacts repo first since we rely on that for lib.js +cd contracts +npm ci + +cd ../integration_test/dapp_tests +npm ci + +npx hardhat compile + +npx hardhat test --network seilocal uniswap/uniswapTest.js diff --git a/integration_test/dapp_tests/hardhat.config.js b/integration_test/dapp_tests/hardhat.config.js new file mode 100644 index 000000000..55f4f7935 --- /dev/null +++ b/integration_test/dapp_tests/hardhat.config.js @@ -0,0 +1,25 @@ +require("@nomiclabs/hardhat-waffle"); +require("@nomiclabs/hardhat-ethers"); + +/** @type import('hardhat/config').HardhatUserConfig */ +module.exports = { + solidity: { + version: "0.8.20", + settings: { + optimizer: { + enabled: true, + runs: 1000, + }, + }, + }, + mocha: { + timeout: 100000000, + }, + networks: { + seilocal: { + url: "http://127.0.0.1:8545", + address: ["0xF87A299e6bC7bEba58dbBe5a5Aa21d49bCD16D52", "0x70997970C51812dc3A010C7d01b50e0d17dc79C8"], + accounts: ["0x57acb95d82739866a5c29e40b0aa2590742ae50425b7dd5b5d279a986370189e", "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d"], + }, + }, +}; diff --git a/integration_test/dapp_tests/package-lock.json b/integration_test/dapp_tests/package-lock.json new file mode 100644 index 000000000..584964141 --- /dev/null +++ b/integration_test/dapp_tests/package-lock.json @@ -0,0 +1,11680 @@ +{ + "name": "uniswapv3-deployment", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "uniswapv3-deployment", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@nomiclabs/hardhat-ethers": "^2.2.3", + "@nomiclabs/hardhat-waffle": "^2.0.6", + "@openzeppelin/contracts": "^5.0.2", + "@openzeppelin/test-helpers": "^0.5.16", + "@uniswap/v2-periphery": "^1.1.0-beta.0", + "@uniswap/v3-core": "^1.0.1", + "@uniswap/v3-periphery": "^1.4.4", + "chai": "^4.2.0", + "ethers": "^5.7.2", + "hardhat": "^2.22.6" + } + }, + "node_modules/@babel/runtime": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz", + "integrity": "sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@ensdomains/address-encoder": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/@ensdomains/address-encoder/-/address-encoder-0.1.9.tgz", + "integrity": "sha512-E2d2gP4uxJQnDu2Kfg1tHNspefzbLT8Tyjrm5sEuim32UkU2sm5xL4VXtgc2X33fmPEw9+jUMpGs4veMbf+PYg==", + "dependencies": { + "bech32": "^1.1.3", + "blakejs": "^1.1.0", + "bn.js": "^4.11.8", + "bs58": "^4.0.1", + "crypto-addr-codec": "^0.1.7", + "nano-base32": "^1.0.1", + "ripemd160": "^2.0.2" + } + }, + "node_modules/@ensdomains/ens": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/@ensdomains/ens/-/ens-0.4.5.tgz", + "integrity": "sha512-JSvpj1iNMFjK6K+uVl4unqMoa9rf5jopb8cya5UGBWz23Nw8hSNT7efgUx4BTlAPAgpNlEioUfeTyQ6J9ZvTVw==", + "deprecated": "Please use @ensdomains/ens-contracts", + "dependencies": { + "bluebird": "^3.5.2", + "eth-ens-namehash": "^2.0.8", + "solc": "^0.4.20", + "testrpc": "0.0.1", + "web3-utils": "^1.0.0-beta.31" + } + }, + "node_modules/@ensdomains/ens/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@ensdomains/ens/node_modules/camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@ensdomains/ens/node_modules/cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha512-0yayqDxWQbqk3ojkYqUKqaAQ6AfNKeKWRNA8kR0WXzAsdHpP4BIaOmMAG87JGuO6qcobyW4GjxHd9PmhEd+T9w==", + "dependencies": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + } + }, + "node_modules/@ensdomains/ens/node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@ensdomains/ens/node_modules/fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==", + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" + } + }, + "node_modules/@ensdomains/ens/node_modules/get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==" + }, + "node_modules/@ensdomains/ens/node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@ensdomains/ens/node_modules/jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@ensdomains/ens/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/@ensdomains/ens/node_modules/solc": { + "version": "0.4.26", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.4.26.tgz", + "integrity": "sha512-o+c6FpkiHd+HPjmjEVpQgH7fqZ14tJpXhho+/bQXlXbliLIS/xjXb42Vxh+qQY1WCSTMQ0+a5vR9vi0MfhU6mA==", + "dependencies": { + "fs-extra": "^0.30.0", + "memorystream": "^0.3.1", + "require-from-string": "^1.1.0", + "semver": "^5.3.0", + "yargs": "^4.7.1" + }, + "bin": { + "solcjs": "solcjs" + } + }, + "node_modules/@ensdomains/ens/node_modules/string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@ensdomains/ens/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@ensdomains/ens/node_modules/wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==", + "dependencies": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@ensdomains/ens/node_modules/y18n": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz", + "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==" + }, + "node_modules/@ensdomains/ens/node_modules/yargs": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", + "integrity": "sha512-LqodLrnIDM3IFT+Hf/5sxBnEGECrfdC1uIbgZeJmESCSo4HoCAaKEus8MylXHAkdacGc0ye+Qa+dpkuom8uVYA==", + "dependencies": { + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "lodash.assign": "^4.0.3", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.1", + "which-module": "^1.0.0", + "window-size": "^0.2.0", + "y18n": "^3.2.1", + "yargs-parser": "^2.4.1" + } + }, + "node_modules/@ensdomains/ens/node_modules/yargs-parser": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz", + "integrity": "sha512-9pIKIJhnI5tonzG6OnCFlz/yln8xHYcGl+pn3xR0Vzff0vzN1PbNRaelgfgRUwZ3s4i3jvxT9WhmUGL4whnasA==", + "dependencies": { + "camelcase": "^3.0.0", + "lodash.assign": "^4.0.6" + } + }, + "node_modules/@ensdomains/ensjs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@ensdomains/ensjs/-/ensjs-2.1.0.tgz", + "integrity": "sha512-GRbGPT8Z/OJMDuxs75U/jUNEC0tbL0aj7/L/QQznGYKm/tiasp+ndLOaoULy9kKJFC0TBByqfFliEHDgoLhyog==", + "dependencies": { + "@babel/runtime": "^7.4.4", + "@ensdomains/address-encoder": "^0.1.7", + "@ensdomains/ens": "0.4.5", + "@ensdomains/resolver": "0.2.4", + "content-hash": "^2.5.2", + "eth-ens-namehash": "^2.0.8", + "ethers": "^5.0.13", + "js-sha3": "^0.8.0" + } + }, + "node_modules/@ensdomains/resolver": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@ensdomains/resolver/-/resolver-0.2.4.tgz", + "integrity": "sha512-bvaTH34PMCbv6anRa9I/0zjLJgY4EuznbEMgbV77JBCQ9KNC46rzi0avuxpOfu+xDjPEtSFGqVEOr5GlUSGudA==", + "deprecated": "Please use @ensdomains/ens-contracts" + }, + "node_modules/@ethereum-waffle/chai": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/@ethereum-waffle/chai/-/chai-4.0.10.tgz", + "integrity": "sha512-X5RepE7Dn8KQLFO7HHAAe+KeGaX/by14hn90wePGBhzL54tq4Y8JscZFu+/LCwCl6TnkAAy5ebiMoqJ37sFtWw==", + "peer": true, + "dependencies": { + "@ethereum-waffle/provider": "4.0.5", + "debug": "^4.3.4", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=10.0" + }, + "peerDependencies": { + "ethers": "*" + } + }, + "node_modules/@ethereum-waffle/compiler": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@ethereum-waffle/compiler/-/compiler-4.0.3.tgz", + "integrity": "sha512-5x5U52tSvEVJS6dpCeXXKvRKyf8GICDwiTwUvGD3/WD+DpvgvaoHOL82XqpTSUHgV3bBq6ma5/8gKUJUIAnJCw==", + "peer": true, + "dependencies": { + "@resolver-engine/imports": "^0.3.3", + "@resolver-engine/imports-fs": "^0.3.3", + "@typechain/ethers-v5": "^10.0.0", + "@types/mkdirp": "^0.5.2", + "@types/node-fetch": "^2.6.1", + "mkdirp": "^0.5.1", + "node-fetch": "^2.6.7" + }, + "engines": { + "node": ">=10.0" + }, + "peerDependencies": { + "ethers": "*", + "solc": "*", + "typechain": "^8.0.0" + } + }, + "node_modules/@ethereum-waffle/ens": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@ethereum-waffle/ens/-/ens-4.0.3.tgz", + "integrity": "sha512-PVLcdnTbaTfCrfSOrvtlA9Fih73EeDvFS28JQnT5M5P4JMplqmchhcZB1yg/fCtx4cvgHlZXa0+rOCAk2Jk0Jw==", + "peer": true, + "engines": { + "node": ">=10.0" + }, + "peerDependencies": { + "@ensdomains/ens": "^0.4.4", + "@ensdomains/resolver": "^0.2.4", + "ethers": "*" + } + }, + "node_modules/@ethereum-waffle/mock-contract": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@ethereum-waffle/mock-contract/-/mock-contract-4.0.4.tgz", + "integrity": "sha512-LwEj5SIuEe9/gnrXgtqIkWbk2g15imM/qcJcxpLyAkOj981tQxXmtV4XmQMZsdedEsZ/D/rbUAOtZbgwqgUwQA==", + "peer": true, + "engines": { + "node": ">=10.0" + }, + "peerDependencies": { + "ethers": "*" + } + }, + "node_modules/@ethereum-waffle/provider": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@ethereum-waffle/provider/-/provider-4.0.5.tgz", + "integrity": "sha512-40uzfyzcrPh+Gbdzv89JJTMBlZwzya1YLDyim8mVbEqYLP5VRYWoGp0JMyaizgV3hMoUFRqJKVmIUw4v7r3hYw==", + "peer": true, + "dependencies": { + "@ethereum-waffle/ens": "4.0.3", + "@ganache/ethereum-options": "0.1.4", + "debug": "^4.3.4", + "ganache": "7.4.3" + }, + "engines": { + "node": ">=10.0" + }, + "peerDependencies": { + "ethers": "*" + } + }, + "node_modules/@ethereumjs/block": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@ethereumjs/block/-/block-3.6.3.tgz", + "integrity": "sha512-CegDeryc2DVKnDkg5COQrE0bJfw/p0v3GBk2W5/Dj5dOVfEmb50Ux0GLnSPypooLnfqjwFaorGuT9FokWB3GRg==", + "peer": true, + "dependencies": { + "@ethereumjs/common": "^2.6.5", + "@ethereumjs/tx": "^3.5.2", + "ethereumjs-util": "^7.1.5", + "merkle-patricia-tree": "^4.2.4" + } + }, + "node_modules/@ethereumjs/block/node_modules/@ethereumjs/common": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-2.6.5.tgz", + "integrity": "sha512-lRyVQOeCDaIVtgfbowla32pzeDv2Obr8oR8Put5RdUBNRGr1VGPGQNGP6elWIpgK3YdpzqTOh4GyUGOureVeeA==", + "peer": true, + "dependencies": { + "crc-32": "^1.2.0", + "ethereumjs-util": "^7.1.5" + } + }, + "node_modules/@ethereumjs/block/node_modules/@ethereumjs/tx": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.5.2.tgz", + "integrity": "sha512-gQDNJWKrSDGu2w7w0PzVXVBNMzb7wwdDOmOqczmhNjqFxFuIbhVJDwiGEnxFNC2/b8ifcZzY7MLcluizohRzNw==", + "peer": true, + "dependencies": { + "@ethereumjs/common": "^2.6.4", + "ethereumjs-util": "^7.1.5" + } + }, + "node_modules/@ethereumjs/block/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==", + "peer": true + }, + "node_modules/@ethereumjs/block/node_modules/ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "peer": true, + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@ethereumjs/blockchain": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/@ethereumjs/blockchain/-/blockchain-5.5.3.tgz", + "integrity": "sha512-bi0wuNJ1gw4ByNCV56H0Z4Q7D+SxUbwyG12Wxzbvqc89PXLRNR20LBcSUZRKpN0+YCPo6m0XZL/JLio3B52LTw==", + "peer": true, + "dependencies": { + "@ethereumjs/block": "^3.6.2", + "@ethereumjs/common": "^2.6.4", + "@ethereumjs/ethash": "^1.1.0", + "debug": "^4.3.3", + "ethereumjs-util": "^7.1.5", + "level-mem": "^5.0.1", + "lru-cache": "^5.1.1", + "semaphore-async-await": "^1.5.1" + } + }, + "node_modules/@ethereumjs/blockchain/node_modules/@ethereumjs/common": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-2.6.5.tgz", + "integrity": "sha512-lRyVQOeCDaIVtgfbowla32pzeDv2Obr8oR8Put5RdUBNRGr1VGPGQNGP6elWIpgK3YdpzqTOh4GyUGOureVeeA==", + "peer": true, + "dependencies": { + "crc-32": "^1.2.0", + "ethereumjs-util": "^7.1.5" + } + }, + "node_modules/@ethereumjs/blockchain/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==", + "peer": true + }, + "node_modules/@ethereumjs/blockchain/node_modules/ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "peer": true, + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@ethereumjs/common": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-2.6.0.tgz", + "integrity": "sha512-Cq2qS0FTu6O2VU1sgg+WyU9Ps0M6j/BEMHN+hRaECXCV/r0aI78u4N6p52QW/BDVhwWZpCdrvG8X7NJdzlpNUA==", + "peer": true, + "dependencies": { + "crc-32": "^1.2.0", + "ethereumjs-util": "^7.1.3" + } + }, + "node_modules/@ethereumjs/common/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==", + "peer": true + }, + "node_modules/@ethereumjs/common/node_modules/ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "peer": true, + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@ethereumjs/ethash": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/ethash/-/ethash-1.1.0.tgz", + "integrity": "sha512-/U7UOKW6BzpA+Vt+kISAoeDie1vAvY4Zy2KF5JJb+So7+1yKmJeJEHOGSnQIj330e9Zyl3L5Nae6VZyh2TJnAA==", + "peer": true, + "dependencies": { + "@ethereumjs/block": "^3.5.0", + "@types/levelup": "^4.3.0", + "buffer-xor": "^2.0.1", + "ethereumjs-util": "^7.1.1", + "miller-rabin": "^4.0.0" + } + }, + "node_modules/@ethereumjs/ethash/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==", + "peer": true + }, + "node_modules/@ethereumjs/ethash/node_modules/buffer-xor": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-2.0.2.tgz", + "integrity": "sha512-eHslX0bin3GB+Lx2p7lEYRShRewuNZL3fUl4qlVJGGiwoPGftmt8JQgk2Y9Ji5/01TnVDo33E5b5O3vUB1HdqQ==", + "peer": true, + "dependencies": { + "safe-buffer": "^5.1.1" + } + }, + "node_modules/@ethereumjs/ethash/node_modules/ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "peer": true, + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@ethereumjs/rlp": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@ethereumjs/rlp/-/rlp-4.0.1.tgz", + "integrity": "sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw==", + "bin": { + "rlp": "bin/rlp" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@ethereumjs/tx": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.4.0.tgz", + "integrity": "sha512-WWUwg1PdjHKZZxPPo274ZuPsJCWV3SqATrEKQP1n2DrVYVP1aZIYpo/mFaA0BDoE0tIQmBeimRCEA0Lgil+yYw==", + "peer": true, + "dependencies": { + "@ethereumjs/common": "^2.6.0", + "ethereumjs-util": "^7.1.3" + } + }, + "node_modules/@ethereumjs/tx/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==", + "peer": true + }, + "node_modules/@ethereumjs/tx/node_modules/ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "peer": true, + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@ethereumjs/util": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/util/-/util-8.1.0.tgz", + "integrity": "sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA==", + "dependencies": { + "@ethereumjs/rlp": "^4.0.1", + "ethereum-cryptography": "^2.0.0", + "micro-ftch": "^0.3.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@ethereumjs/util/node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/util/node_modules/@scure/bip32": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", + "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", + "dependencies": { + "@noble/curves": "~1.4.0", + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/util/node_modules/@scure/bip39": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", + "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", + "dependencies": { + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/util/node_modules/ethereum-cryptography": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", + "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", + "dependencies": { + "@noble/curves": "1.4.2", + "@noble/hashes": "1.4.0", + "@scure/bip32": "1.4.0", + "@scure/bip39": "1.3.0" + } + }, + "node_modules/@ethereumjs/vm": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/vm/-/vm-5.6.0.tgz", + "integrity": "sha512-J2m/OgjjiGdWF2P9bj/4LnZQ1zRoZhY8mRNVw/N3tXliGI8ai1sI1mlDPkLpeUUM4vq54gH6n0ZlSpz8U/qlYQ==", + "peer": true, + "dependencies": { + "@ethereumjs/block": "^3.6.0", + "@ethereumjs/blockchain": "^5.5.0", + "@ethereumjs/common": "^2.6.0", + "@ethereumjs/tx": "^3.4.0", + "async-eventemitter": "^0.2.4", + "core-js-pure": "^3.0.1", + "debug": "^2.2.0", + "ethereumjs-util": "^7.1.3", + "functional-red-black-tree": "^1.0.1", + "mcl-wasm": "^0.7.1", + "merkle-patricia-tree": "^4.2.2", + "rustbn.js": "~0.2.0" + } + }, + "node_modules/@ethereumjs/vm/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==", + "peer": true + }, + "node_modules/@ethereumjs/vm/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "peer": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/@ethereumjs/vm/node_modules/ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "peer": true, + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@ethereumjs/vm/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "peer": true + }, + "node_modules/@ethersproject/abi": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz", + "integrity": "sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/abstract-provider": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz", + "integrity": "sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0" + } + }, + "node_modules/@ethersproject/abstract-signer": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz", + "integrity": "sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "node_modules/@ethersproject/address": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz", + "integrity": "sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/rlp": "^5.7.0" + } + }, + "node_modules/@ethersproject/base64": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz", + "integrity": "sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.7.0" + } + }, + "node_modules/@ethersproject/basex": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.7.0.tgz", + "integrity": "sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "node_modules/@ethersproject/bignumber": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz", + "integrity": "sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "bn.js": "^5.2.1" + } + }, + "node_modules/@ethersproject/bignumber/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==", + "license": "MIT" + }, + "node_modules/@ethersproject/bytes": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz", + "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/constants": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz", + "integrity": "sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bignumber": "^5.7.0" + } + }, + "node_modules/@ethersproject/contracts": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.7.0.tgz", + "integrity": "sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/abi": "^5.7.0", + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0" + } + }, + "node_modules/@ethersproject/hash": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz", + "integrity": "sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/hdnode": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.7.0.tgz", + "integrity": "sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/basex": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "node_modules/@ethersproject/json-wallets": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz", + "integrity": "sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hdnode": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "aes-js": "3.0.0", + "scrypt-js": "3.0.1" + } + }, + "node_modules/@ethersproject/keccak256": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz", + "integrity": "sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "js-sha3": "0.8.0" + } + }, + "node_modules/@ethersproject/logger": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz", + "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT" + }, + "node_modules/@ethersproject/networks": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.1.tgz", + "integrity": "sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/pbkdf2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz", + "integrity": "sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/sha2": "^5.7.0" + } + }, + "node_modules/@ethersproject/properties": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz", + "integrity": "sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/providers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.7.2.tgz", + "integrity": "sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/basex": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0", + "bech32": "1.1.4", + "ws": "7.4.6" + } + }, + "node_modules/@ethersproject/providers/node_modules/ws": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@ethersproject/random": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.7.0.tgz", + "integrity": "sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/rlp": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz", + "integrity": "sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/sha2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.7.0.tgz", + "integrity": "sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "hash.js": "1.1.7" + } + }, + "node_modules/@ethersproject/signing-key": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz", + "integrity": "sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "bn.js": "^5.2.1", + "elliptic": "6.5.4", + "hash.js": "1.1.7" + } + }, + "node_modules/@ethersproject/signing-key/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==", + "license": "MIT" + }, + "node_modules/@ethersproject/signing-key/node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "license": "MIT", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/@ethersproject/signing-key/node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "license": "MIT" + }, + "node_modules/@ethersproject/solidity": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz", + "integrity": "sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/strings": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz", + "integrity": "sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/transactions": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz", + "integrity": "sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0" + } + }, + "node_modules/@ethersproject/units": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.7.0.tgz", + "integrity": "sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/wallet": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.7.0.tgz", + "integrity": "sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/hdnode": "^5.7.0", + "@ethersproject/json-wallets": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "node_modules/@ethersproject/web": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz", + "integrity": "sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/wordlists": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.7.0.tgz", + "integrity": "sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@fastify/busboy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/@ganache/ethereum-address": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@ganache/ethereum-address/-/ethereum-address-0.1.4.tgz", + "integrity": "sha512-sTkU0M9z2nZUzDeHRzzGlW724xhMLXo2LeX1hixbnjHWY1Zg1hkqORywVfl+g5uOO8ht8T0v+34IxNxAhmWlbw==", + "peer": true, + "dependencies": { + "@ganache/utils": "0.1.4" + } + }, + "node_modules/@ganache/ethereum-options": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@ganache/ethereum-options/-/ethereum-options-0.1.4.tgz", + "integrity": "sha512-i4l46taoK2yC41FPkcoDlEVoqHS52wcbHPqJtYETRWqpOaoj9hAg/EJIHLb1t6Nhva2CdTO84bG+qlzlTxjAHw==", + "peer": true, + "dependencies": { + "@ganache/ethereum-address": "0.1.4", + "@ganache/ethereum-utils": "0.1.4", + "@ganache/options": "0.1.4", + "@ganache/utils": "0.1.4", + "bip39": "3.0.4", + "seedrandom": "3.0.5" + } + }, + "node_modules/@ganache/ethereum-utils": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@ganache/ethereum-utils/-/ethereum-utils-0.1.4.tgz", + "integrity": "sha512-FKXF3zcdDrIoCqovJmHLKZLrJ43234Em2sde/3urUT/10gSgnwlpFmrv2LUMAmSbX3lgZhW/aSs8krGhDevDAg==", + "peer": true, + "dependencies": { + "@ethereumjs/common": "2.6.0", + "@ethereumjs/tx": "3.4.0", + "@ethereumjs/vm": "5.6.0", + "@ganache/ethereum-address": "0.1.4", + "@ganache/rlp": "0.1.4", + "@ganache/utils": "0.1.4", + "emittery": "0.10.0", + "ethereumjs-abi": "0.6.8", + "ethereumjs-util": "7.1.3" + } + }, + "node_modules/@ganache/ethereum-utils/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==", + "peer": true + }, + "node_modules/@ganache/ethereum-utils/node_modules/ethereumjs-util": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.3.tgz", + "integrity": "sha512-y+82tEbyASO0K0X1/SRhbJJoAlfcvq8JbrG4a5cjrOks7HS/36efU/0j2flxCPOUM++HFahk33kr/ZxyC4vNuw==", + "peer": true, + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@ganache/options": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@ganache/options/-/options-0.1.4.tgz", + "integrity": "sha512-zAe/craqNuPz512XQY33MOAG6Si1Xp0hCvfzkBfj2qkuPcbJCq6W/eQ5MB6SbXHrICsHrZOaelyqjuhSEmjXRw==", + "peer": true, + "dependencies": { + "@ganache/utils": "0.1.4", + "bip39": "3.0.4", + "seedrandom": "3.0.5" + } + }, + "node_modules/@ganache/rlp": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@ganache/rlp/-/rlp-0.1.4.tgz", + "integrity": "sha512-Do3D1H6JmhikB+6rHviGqkrNywou/liVeFiKIpOBLynIpvZhRCgn3SEDxyy/JovcaozTo/BynHumfs5R085MFQ==", + "peer": true, + "dependencies": { + "@ganache/utils": "0.1.4", + "rlp": "2.2.6" + } + }, + "node_modules/@ganache/rlp/node_modules/rlp": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.6.tgz", + "integrity": "sha512-HAfAmL6SDYNWPUOJNrM500x4Thn4PZsEy5pijPh40U9WfNk0z15hUYzO9xVIMAdIHdFtD8CBDHd75Td1g36Mjg==", + "peer": true, + "dependencies": { + "bn.js": "^4.11.1" + }, + "bin": { + "rlp": "bin/rlp" + } + }, + "node_modules/@ganache/utils": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@ganache/utils/-/utils-0.1.4.tgz", + "integrity": "sha512-oatUueU3XuXbUbUlkyxeLLH3LzFZ4y5aSkNbx6tjSIhVTPeh+AuBKYt4eQ73FFcTB3nj/gZoslgAh5CN7O369w==", + "peer": true, + "dependencies": { + "emittery": "0.10.0", + "keccak": "3.0.1", + "seedrandom": "3.0.5" + }, + "optionalDependencies": { + "@trufflesuite/bigint-buffer": "1.1.9" + } + }, + "node_modules/@ganache/utils/node_modules/keccak": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.1.tgz", + "integrity": "sha512-epq90L9jlFWCW7+pQa6JOnKn2Xgl2mtI664seYR6MHskvI9agt7AnDqmAlp9TqU4/caMYbA08Hi5DMZAl5zdkA==", + "hasInstallScript": true, + "peer": true, + "dependencies": { + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@metamask/eth-sig-util": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@metamask/eth-sig-util/-/eth-sig-util-4.0.1.tgz", + "integrity": "sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ==", + "license": "ISC", + "dependencies": { + "ethereumjs-abi": "^0.6.8", + "ethereumjs-util": "^6.2.1", + "ethjs-util": "^0.1.6", + "tweetnacl": "^1.0.3", + "tweetnacl-util": "^0.15.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@noble/curves": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", + "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", + "dependencies": { + "@noble/hashes": "1.4.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/curves/node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz", + "integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT" + }, + "node_modules/@noble/secp256k1": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", + "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT" + }, + "node_modules/@nomicfoundation/edr": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr/-/edr-0.5.0.tgz", + "integrity": "sha512-nAUyjGhxntXje/1AkDX9POfH+pqUxdi4XHzIhaf/dJYs7fgAFxL3STBK1OYcA3LR7vtiylLHMz7wxjqLzlLGKg==", + "license": "MIT", + "dependencies": { + "@nomicfoundation/edr-darwin-arm64": "0.5.0", + "@nomicfoundation/edr-darwin-x64": "0.5.0", + "@nomicfoundation/edr-linux-arm64-gnu": "0.5.0", + "@nomicfoundation/edr-linux-arm64-musl": "0.5.0", + "@nomicfoundation/edr-linux-x64-gnu": "0.5.0", + "@nomicfoundation/edr-linux-x64-musl": "0.5.0", + "@nomicfoundation/edr-win32-x64-msvc": "0.5.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-darwin-arm64": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.5.0.tgz", + "integrity": "sha512-G6OX/PESdfU4ZOyJ4MDh4eevW0wt2mduuxA+thXtTcStOiQTtPuV205h4kLOR5wRB1Zz6Zy0LedTMax7TzOtGw==", + "license": "MIT", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-darwin-x64": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.5.0.tgz", + "integrity": "sha512-fI7uHfHqPtdPZjkFUTpotc/F5gGv41ws+jSZy9+2AR9RDMOAIXMEArOx9rGLBcevWu8SFnyH/l/77kG/5FXbDw==", + "license": "MIT", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-linux-arm64-gnu": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.5.0.tgz", + "integrity": "sha512-eMC3sWPkBZILg2/YB4Xv6IR0nggCLt5hS8K8jjHeGEeUs9pf8poBF2Oy+G4lSu0YLLjexGzHypz9/P+pIuxZHw==", + "license": "MIT", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-linux-arm64-musl": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.5.0.tgz", + "integrity": "sha512-yPK0tKjYRxe5ktggFr8aBHH0DCI9uafuaD8QuzyrQAfSf/m/ebTdgthROdbYp6eRk5mJyfAQT/45fM3tnlYsWw==", + "license": "MIT", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-linux-x64-gnu": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.5.0.tgz", + "integrity": "sha512-Hds8CRYi4DEyuErjcwUNSvNpMzmOYUihW4qYCoKgSBUVS5saX1PyPYvFYuYpeU5J8/T2iMk6yAPVLCxtKbgnKg==", + "license": "MIT", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-linux-x64-musl": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.5.0.tgz", + "integrity": "sha512-1hXMDSzdyh5ojwO3ZSRbt7t5KKYycGUlFdC3lgJRZ7gStB8xjb7RA3hZn2csn9OydS950Ne4nh+puNq91iXApw==", + "license": "MIT", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-win32-x64-msvc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.5.0.tgz", + "integrity": "sha512-CFagD423400xXkRmACIR13FoocN48qi4ogRnuFQIvBDtEE3aMEajfFj4bycmQQDqnqChsZy/jwD4OxbX6oaNJw==", + "license": "MIT", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/ethereumjs-common": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.4.tgz", + "integrity": "sha512-9Rgb658lcWsjiicr5GzNCjI1llow/7r0k50dLL95OJ+6iZJcVbi15r3Y0xh2cIO+zgX0WIHcbzIu6FeQf9KPrg==", + "license": "MIT", + "dependencies": { + "@nomicfoundation/ethereumjs-util": "9.0.4" + } + }, + "node_modules/@nomicfoundation/ethereumjs-rlp": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.4.tgz", + "integrity": "sha512-8H1S3s8F6QueOc/X92SdrA4RDenpiAEqMg5vJH99kcQaCy/a3Q6fgseo75mgWlbanGJXSlAPtnCeG9jvfTYXlw==", + "license": "MPL-2.0", + "bin": { + "rlp": "bin/rlp.cjs" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@nomicfoundation/ethereumjs-tx": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.4.tgz", + "integrity": "sha512-Xjv8wAKJGMrP1f0n2PeyfFCCojHd7iS3s/Ab7qzF1S64kxZ8Z22LCMynArYsVqiFx6rzYy548HNVEyI+AYN/kw==", + "license": "MPL-2.0", + "dependencies": { + "@nomicfoundation/ethereumjs-common": "4.0.4", + "@nomicfoundation/ethereumjs-rlp": "5.0.4", + "@nomicfoundation/ethereumjs-util": "9.0.4", + "ethereum-cryptography": "0.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "c-kzg": "^2.1.2" + }, + "peerDependenciesMeta": { + "c-kzg": { + "optional": true + } + } + }, + "node_modules/@nomicfoundation/ethereumjs-util": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.4.tgz", + "integrity": "sha512-sLOzjnSrlx9Bb9EFNtHzK/FJFsfg2re6bsGqinFinH1gCqVfz9YYlXiMWwDM4C/L4ywuHFCYwfKTVr/QHQcU0Q==", + "license": "MPL-2.0", + "dependencies": { + "@nomicfoundation/ethereumjs-rlp": "5.0.4", + "ethereum-cryptography": "0.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "c-kzg": "^2.1.2" + }, + "peerDependenciesMeta": { + "c-kzg": { + "optional": true + } + } + }, + "node_modules/@nomicfoundation/solidity-analyzer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer/-/solidity-analyzer-0.1.2.tgz", + "integrity": "sha512-q4n32/FNKIhQ3zQGGw5CvPF6GTvDCpYwIf7bEY/dZTZbgfDsHyjJwURxUJf3VQuuJj+fDIFl4+KkBVbw4Ef6jA==", + "license": "MIT", + "engines": { + "node": ">= 12" + }, + "optionalDependencies": { + "@nomicfoundation/solidity-analyzer-darwin-arm64": "0.1.2", + "@nomicfoundation/solidity-analyzer-darwin-x64": "0.1.2", + "@nomicfoundation/solidity-analyzer-linux-arm64-gnu": "0.1.2", + "@nomicfoundation/solidity-analyzer-linux-arm64-musl": "0.1.2", + "@nomicfoundation/solidity-analyzer-linux-x64-gnu": "0.1.2", + "@nomicfoundation/solidity-analyzer-linux-x64-musl": "0.1.2", + "@nomicfoundation/solidity-analyzer-win32-x64-msvc": "0.1.2" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-darwin-arm64": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.2.tgz", + "integrity": "sha512-JaqcWPDZENCvm++lFFGjrDd8mxtf+CtLd2MiXvMNTBD33dContTZ9TWETwNFwg7JTJT5Q9HEecH7FA+HTSsIUw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-darwin-x64": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-x64/-/solidity-analyzer-darwin-x64-0.1.2.tgz", + "integrity": "sha512-fZNmVztrSXC03e9RONBT+CiksSeYcxI1wlzqyr0L7hsQlK1fzV+f04g2JtQ1c/Fe74ZwdV6aQBdd6Uwl1052sw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-gnu": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-gnu/-/solidity-analyzer-linux-arm64-gnu-0.1.2.tgz", + "integrity": "sha512-3d54oc+9ZVBuB6nbp8wHylk4xh0N0Gc+bk+/uJae+rUgbOBwQSfuGIbAZt1wBXs5REkSmynEGcqx6DutoK0tPA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-musl": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-musl/-/solidity-analyzer-linux-arm64-musl-0.1.2.tgz", + "integrity": "sha512-iDJfR2qf55vgsg7BtJa7iPiFAsYf2d0Tv/0B+vhtnI16+wfQeTbP7teookbGvAo0eJo7aLLm0xfS/GTkvHIucA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-gnu": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-gnu/-/solidity-analyzer-linux-x64-gnu-0.1.2.tgz", + "integrity": "sha512-9dlHMAt5/2cpWyuJ9fQNOUXFB/vgSFORg1jpjX1Mh9hJ/MfZXlDdHQ+DpFCs32Zk5pxRBb07yGvSHk9/fezL+g==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-musl": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-musl/-/solidity-analyzer-linux-x64-musl-0.1.2.tgz", + "integrity": "sha512-GzzVeeJob3lfrSlDKQw2bRJ8rBf6mEYaWY+gW0JnTDHINA0s2gPR4km5RLIj1xeZZOYz4zRw+AEeYgLRqB2NXg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-win32-x64-msvc": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-x64-msvc/-/solidity-analyzer-win32-x64-msvc-0.1.2.tgz", + "integrity": "sha512-Fdjli4DCcFHb4Zgsz0uEJXZ2K7VEO+w5KVv7HmT7WO10iODdU9csC2az4jrhEsRtiR9Gfd74FlG0NYlw1BMdyA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@nomiclabs/hardhat-ethers": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-ethers/-/hardhat-ethers-2.2.3.tgz", + "integrity": "sha512-YhzPdzb612X591FOe68q+qXVXGG2ANZRvDo0RRUtimev85rCrAlv/TLMEZw5c+kq9AbzocLTVX/h2jVIFPL9Xg==", + "license": "MIT", + "peerDependencies": { + "ethers": "^5.0.0", + "hardhat": "^2.0.0" + } + }, + "node_modules/@nomiclabs/hardhat-waffle": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-waffle/-/hardhat-waffle-2.0.6.tgz", + "integrity": "sha512-+Wz0hwmJGSI17B+BhU/qFRZ1l6/xMW82QGXE/Gi+WTmwgJrQefuBs1lIf7hzQ1hLk6hpkvb/zwcNkpVKRYTQYg==", + "license": "MIT", + "peerDependencies": { + "@nomiclabs/hardhat-ethers": "^2.0.0", + "@types/sinon-chai": "^3.2.3", + "ethereum-waffle": "*", + "ethers": "^5.0.0", + "hardhat": "^2.0.0" + } + }, + "node_modules/@openzeppelin/contract-loader": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@openzeppelin/contract-loader/-/contract-loader-0.6.3.tgz", + "integrity": "sha512-cOFIjBjwbGgZhDZsitNgJl0Ye1rd5yu/Yx5LMgeq3u0ZYzldm4uObzHDFq4gjDdoypvyORjjJa3BlFA7eAnVIg==", + "dependencies": { + "find-up": "^4.1.0", + "fs-extra": "^8.1.0" + } + }, + "node_modules/@openzeppelin/contract-loader/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@openzeppelin/contract-loader/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/@openzeppelin/contract-loader/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@openzeppelin/contract-loader/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@openzeppelin/contract-loader/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@openzeppelin/contract-loader/node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@openzeppelin/contract-loader/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@openzeppelin/contracts": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-5.0.2.tgz", + "integrity": "sha512-ytPc6eLGcHHnapAZ9S+5qsdomhjo6QBHTDRRBFfTxXIpsicMhVPouPgmUPebZZZGX7vt9USA+Z+0M0dSVtSUEA==", + "license": "MIT" + }, + "node_modules/@openzeppelin/test-helpers": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/@openzeppelin/test-helpers/-/test-helpers-0.5.16.tgz", + "integrity": "sha512-T1EvspSfH1qQO/sgGlskLfYVBbqzJR23SZzYl/6B2JnT4EhThcI85UpvDk0BkLWKaDScQTabGHt4GzHW+3SfZg==", + "dependencies": { + "@openzeppelin/contract-loader": "^0.6.2", + "@truffle/contract": "^4.0.35", + "ansi-colors": "^3.2.3", + "chai": "^4.2.0", + "chai-bn": "^0.2.1", + "ethjs-abi": "^0.2.1", + "lodash.flatten": "^4.4.0", + "semver": "^5.6.0", + "web3": "^1.2.5", + "web3-utils": "^1.2.5" + } + }, + "node_modules/@openzeppelin/test-helpers/node_modules/ansi-colors": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", + "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@openzeppelin/test-helpers/node_modules/chai-bn": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/chai-bn/-/chai-bn-0.2.2.tgz", + "integrity": "sha512-MzjelH0p8vWn65QKmEq/DLBG1Hle4WeyqT79ANhXZhn/UxRWO0OogkAxi5oGGtfzwU9bZR8mvbvYdoqNVWQwFg==", + "peerDependencies": { + "bn.js": "^4.11.0", + "chai": "^4.0.0" + } + }, + "node_modules/@openzeppelin/test-helpers/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/@resolver-engine/core": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@resolver-engine/core/-/core-0.3.3.tgz", + "integrity": "sha512-eB8nEbKDJJBi5p5SrvrvILn4a0h42bKtbCTri3ZxCGt6UvoQyp7HnGOfki944bUjBSHKK3RvgfViHn+kqdXtnQ==", + "peer": true, + "dependencies": { + "debug": "^3.1.0", + "is-url": "^1.2.4", + "request": "^2.85.0" + } + }, + "node_modules/@resolver-engine/core/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "peer": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/@resolver-engine/fs": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@resolver-engine/fs/-/fs-0.3.3.tgz", + "integrity": "sha512-wQ9RhPUcny02Wm0IuJwYMyAG8fXVeKdmhm8xizNByD4ryZlx6PP6kRen+t/haF43cMfmaV7T3Cx6ChOdHEhFUQ==", + "peer": true, + "dependencies": { + "@resolver-engine/core": "^0.3.3", + "debug": "^3.1.0" + } + }, + "node_modules/@resolver-engine/fs/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "peer": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/@resolver-engine/imports": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@resolver-engine/imports/-/imports-0.3.3.tgz", + "integrity": "sha512-anHpS4wN4sRMwsAbMXhMfOD/y4a4Oo0Cw/5+rue7hSwGWsDOQaAU1ClK1OxjUC35/peazxEl8JaSRRS+Xb8t3Q==", + "peer": true, + "dependencies": { + "@resolver-engine/core": "^0.3.3", + "debug": "^3.1.0", + "hosted-git-info": "^2.6.0", + "path-browserify": "^1.0.0", + "url": "^0.11.0" + } + }, + "node_modules/@resolver-engine/imports-fs": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@resolver-engine/imports-fs/-/imports-fs-0.3.3.tgz", + "integrity": "sha512-7Pjg/ZAZtxpeyCFlZR5zqYkz+Wdo84ugB5LApwriT8XFeQoLwGUj4tZFFvvCuxaNCcqZzCYbonJgmGObYBzyCA==", + "peer": true, + "dependencies": { + "@resolver-engine/fs": "^0.3.3", + "@resolver-engine/imports": "^0.3.3", + "debug": "^3.1.0" + } + }, + "node_modules/@resolver-engine/imports-fs/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "peer": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/@resolver-engine/imports/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "peer": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/@scure/base": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.7.tgz", + "integrity": "sha512-PPNYBslrLNNUQ/Yad37MHYsNQtK67EhWb6WtSvNLLPo7SdVZgkUjD6Dg+5On7zNwmskf8OX7I7Nx5oN+MIWE0g==", + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip32": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.5.tgz", + "integrity": "sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.2.0", + "@noble/secp256k1": "~1.7.0", + "@scure/base": "~1.1.0" + } + }, + "node_modules/@scure/bip39": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.1.tgz", + "integrity": "sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.2.0", + "@scure/base": "~1.1.0" + } + }, + "node_modules/@sentry/core": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.30.0.tgz", + "integrity": "sha512-TmfrII8w1PQZSZgPpUESqjB+jC6MvZJZdLtE/0hZ+SrnKhW3x5WlYLvTXZpcWePYBku7rl2wn1RZu6uT0qCTeg==", + "license": "BSD-3-Clause", + "dependencies": { + "@sentry/hub": "5.30.0", + "@sentry/minimal": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/hub": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.30.0.tgz", + "integrity": "sha512-2tYrGnzb1gKz2EkMDQcfLrDTvmGcQPuWxLnJKXJvYTQDGLlEvi2tWz1VIHjunmOvJrB5aIQLhm+dcMRwFZDCqQ==", + "license": "BSD-3-Clause", + "dependencies": { + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/minimal": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.30.0.tgz", + "integrity": "sha512-BwWb/owZKtkDX+Sc4zCSTNcvZUq7YcH3uAVlmh/gtR9rmUvbzAA3ewLuB3myi4wWRAMEtny6+J/FN/x+2wn9Xw==", + "license": "BSD-3-Clause", + "dependencies": { + "@sentry/hub": "5.30.0", + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/node": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-5.30.0.tgz", + "integrity": "sha512-Br5oyVBF0fZo6ZS9bxbJZG4ApAjRqAnqFFurMVJJdunNb80brh7a5Qva2kjhm+U6r9NJAB5OmDyPkA1Qnt+QVg==", + "license": "BSD-3-Clause", + "dependencies": { + "@sentry/core": "5.30.0", + "@sentry/hub": "5.30.0", + "@sentry/tracing": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "cookie": "^0.4.1", + "https-proxy-agent": "^5.0.0", + "lru_map": "^0.3.3", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/tracing": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-5.30.0.tgz", + "integrity": "sha512-dUFowCr0AIMwiLD7Fs314Mdzcug+gBVo/+NCMyDw8tFxJkwWAKl7Qa2OZxLQ0ZHjakcj1hNKfCQJ9rhyfOl4Aw==", + "license": "MIT", + "dependencies": { + "@sentry/hub": "5.30.0", + "@sentry/minimal": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/types": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.30.0.tgz", + "integrity": "sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/utils": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.30.0.tgz", + "integrity": "sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww==", + "license": "BSD-3-Clause", + "dependencies": { + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "dependencies": { + "defer-to-connect": "^2.0.1" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/@truffle/abi-utils": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@truffle/abi-utils/-/abi-utils-1.0.3.tgz", + "integrity": "sha512-AWhs01HCShaVKjml7Z4AbVREr/u4oiWxCcoR7Cktm0mEvtT04pvnxW5xB/cI4znRkrbPdFQlFt67kgrAjesYkw==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dependencies": { + "change-case": "3.0.2", + "fast-check": "3.1.1", + "web3-utils": "1.10.0" + }, + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "node_modules/@truffle/abi-utils/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/@truffle/abi-utils/node_modules/ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@truffle/abi-utils/node_modules/web3-utils": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.0.tgz", + "integrity": "sha512-kSaCM0uMcZTNUSmn5vMEhlo02RObGNRRCkdX0V9UTAU0+lrvn0HSaudyCo6CQzuXUsnuY2ERJGCGPfeWmv19Rg==", + "dependencies": { + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereumjs-util": "^7.1.0", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/blockchain-utils": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/@truffle/blockchain-utils/-/blockchain-utils-0.1.9.tgz", + "integrity": "sha512-RHfumgbIVo68Rv9ofDYfynjnYZIfP/f1vZy4RoqkfYAO+fqfc58PDRzB1WAGq2U6GPuOnipOJxQhnqNnffORZg==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "node_modules/@truffle/codec": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@truffle/codec/-/codec-0.17.3.tgz", + "integrity": "sha512-Ko/+dsnntNyrJa57jUD9u4qx9nQby+H4GsUO6yjiCPSX0TQnEHK08XWqBSg0WdmCH2+h0y1nr2CXSx8gbZapxg==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dependencies": { + "@truffle/abi-utils": "^1.0.3", + "@truffle/compile-common": "^0.9.8", + "big.js": "^6.0.3", + "bn.js": "^5.1.3", + "cbor": "^5.2.0", + "debug": "^4.3.1", + "lodash": "^4.17.21", + "semver": "^7.5.4", + "utf8": "^3.0.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "node_modules/@truffle/codec/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/@truffle/codec/node_modules/ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@truffle/codec/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@truffle/codec/node_modules/web3-utils": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.0.tgz", + "integrity": "sha512-kSaCM0uMcZTNUSmn5vMEhlo02RObGNRRCkdX0V9UTAU0+lrvn0HSaudyCo6CQzuXUsnuY2ERJGCGPfeWmv19Rg==", + "dependencies": { + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereumjs-util": "^7.1.0", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/compile-common": { + "version": "0.9.8", + "resolved": "https://registry.npmjs.org/@truffle/compile-common/-/compile-common-0.9.8.tgz", + "integrity": "sha512-DTpiyo32t/YhLI1spn84D3MHYHrnoVqO+Gp7ZHrYNwDs86mAxtNiH5lsVzSb8cPgiqlvNsRCU9nm9R0YmKMTBQ==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dependencies": { + "@truffle/error": "^0.2.2", + "colors": "1.4.0" + }, + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "node_modules/@truffle/contract": { + "version": "4.6.31", + "resolved": "https://registry.npmjs.org/@truffle/contract/-/contract-4.6.31.tgz", + "integrity": "sha512-s+oHDpXASnZosiCdzu+X1Tx5mUJUs1L1CYXIcgRmzMghzqJkaUFmR6NpNo7nJYliYbO+O9/aW8oCKqQ7rCHfmQ==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dependencies": { + "@ensdomains/ensjs": "^2.1.0", + "@truffle/blockchain-utils": "^0.1.9", + "@truffle/contract-schema": "^3.4.16", + "@truffle/debug-utils": "^6.0.57", + "@truffle/error": "^0.2.2", + "@truffle/interface-adapter": "^0.5.37", + "bignumber.js": "^7.2.1", + "debug": "^4.3.1", + "ethers": "^4.0.32", + "web3": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-promievent": "1.10.0", + "web3-eth-abi": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "node_modules/@truffle/contract-schema": { + "version": "3.4.16", + "resolved": "https://registry.npmjs.org/@truffle/contract-schema/-/contract-schema-3.4.16.tgz", + "integrity": "sha512-g0WNYR/J327DqtJPI70ubS19K1Fth/1wxt2jFqLsPmz5cGZVjCwuhiie+LfBde4/Mc9QR8G+L3wtmT5cyoBxAg==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dependencies": { + "ajv": "^6.10.0", + "debug": "^4.3.1" + }, + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "node_modules/@truffle/contract/node_modules/@ethereumjs/common": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-2.5.0.tgz", + "integrity": "sha512-DEHjW6e38o+JmB/NO3GZBpW4lpaiBpkFgXF6jLcJ6gETBYpEyaA5nTimsWBUJR3Vmtm/didUEbNjajskugZORg==", + "dependencies": { + "crc-32": "^1.2.0", + "ethereumjs-util": "^7.1.1" + } + }, + "node_modules/@truffle/contract/node_modules/@ethereumjs/tx": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.3.2.tgz", + "integrity": "sha512-6AaJhwg4ucmwTvw/1qLaZUX5miWrwZ4nLOUsKyb/HtzS3BMw/CasKhdi1ims9mBKeK9sOJCH4qGKOBGyJCeeog==", + "dependencies": { + "@ethereumjs/common": "^2.5.0", + "ethereumjs-util": "^7.1.2" + } + }, + "node_modules/@truffle/contract/node_modules/@types/node": { + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==" + }, + "node_modules/@truffle/contract/node_modules/bignumber.js": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-7.2.1.tgz", + "integrity": "sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ==", + "engines": { + "node": "*" + } + }, + "node_modules/@truffle/contract/node_modules/cross-fetch": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", + "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "node_modules/@truffle/contract/node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/@truffle/contract/node_modules/eth-lib": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.8.tgz", + "integrity": "sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw==", + "dependencies": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "xhr-request-promise": "^0.1.2" + } + }, + "node_modules/@truffle/contract/node_modules/ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/ethereumjs-util/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/@truffle/contract/node_modules/ethers": { + "version": "4.0.49", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.49.tgz", + "integrity": "sha512-kPltTvWiyu+OktYy1IStSO16i2e7cS9D9OxZ81q2UUaiNPVrm/RTcbxamCXF9VUSKzJIdJV68EAIhTEVBalRWg==", + "dependencies": { + "aes-js": "3.0.0", + "bn.js": "^4.11.9", + "elliptic": "6.5.4", + "hash.js": "1.1.3", + "js-sha3": "0.5.7", + "scrypt-js": "2.0.4", + "setimmediate": "1.0.4", + "uuid": "2.0.1", + "xmlhttprequest": "1.8.0" + } + }, + "node_modules/@truffle/contract/node_modules/hash.js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", + "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==" + }, + "node_modules/@truffle/contract/node_modules/scrypt-js": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.4.tgz", + "integrity": "sha512-4KsaGcPnuhtCZQCxFxN3GVYIhKFPTdLd8PLC552XwbMndtD0cjRFAhDuuydXQ0h08ZfPgzqe6EKHozpuH74iDw==" + }, + "node_modules/@truffle/contract/node_modules/setimmediate": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.4.tgz", + "integrity": "sha512-/TjEmXQVEzdod/FFskf3o7oOAsGhHf2j1dZqRFbDzq4F3mvvxflIIi4Hd3bLQE9y/CpwqfSQam5JakI/mi3Pog==" + }, + "node_modules/@truffle/contract/node_modules/uuid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", + "integrity": "sha512-nWg9+Oa3qD2CQzHIP4qKUqwNfzKn8P0LtFhotaCTFchsV7ZfDhAybeip/HZVeMIpZi9JgY1E3nUlwaCmZT1sEg==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details." + }, + "node_modules/@truffle/contract/node_modules/web3": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3/-/web3-1.10.0.tgz", + "integrity": "sha512-YfKY9wSkGcM8seO+daR89oVTcbu18NsVfvOngzqMYGUU0pPSQmE57qQDvQzUeoIOHAnXEBNzrhjQJmm8ER0rng==", + "hasInstallScript": true, + "dependencies": { + "web3-bzz": "1.10.0", + "web3-core": "1.10.0", + "web3-eth": "1.10.0", + "web3-eth-personal": "1.10.0", + "web3-net": "1.10.0", + "web3-shh": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-bzz": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.10.0.tgz", + "integrity": "sha512-o9IR59io3pDUsXTsps5pO5hW1D5zBmg46iNc2t4j2DkaYHNdDLwk2IP9ukoM2wg47QILfPEJYzhTfkS/CcX0KA==", + "hasInstallScript": true, + "dependencies": { + "@types/node": "^12.12.6", + "got": "12.1.0", + "swarm-js": "^0.1.40" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.10.0.tgz", + "integrity": "sha512-fWySwqy2hn3TL89w5TM8wXF1Z2Q6frQTKHWmP0ppRQorEK8NcHJRfeMiv/mQlSKoTS1F6n/nv2uyZsixFycjYQ==", + "dependencies": { + "@types/bn.js": "^5.1.1", + "@types/node": "^12.12.6", + "bignumber.js": "^9.0.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-requestmanager": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-core-method": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.10.0.tgz", + "integrity": "sha512-4R700jTLAMKDMhQ+nsVfIXvH6IGJlJzGisIfMKWAIswH31h5AZz7uDUW2YctI+HrYd+5uOAlS4OJeeT9bIpvkA==", + "dependencies": { + "@ethersproject/transactions": "^5.6.2", + "web3-core-helpers": "1.10.0", + "web3-core-promievent": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-core-requestmanager": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.10.0.tgz", + "integrity": "sha512-3z/JKE++Os62APml4dvBM+GAuId4h3L9ckUrj7ebEtS2AR0ixyQPbrBodgL91Sv7j7cQ3Y+hllaluqjguxvSaQ==", + "dependencies": { + "util": "^0.12.5", + "web3-core-helpers": "1.10.0", + "web3-providers-http": "1.10.0", + "web3-providers-ipc": "1.10.0", + "web3-providers-ws": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-core-subscriptions": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.10.0.tgz", + "integrity": "sha512-HGm1PbDqsxejI075gxBc5OSkwymilRWZufIy9zEpnWKNmfbuv5FfHgW1/chtJP6aP3Uq2vHkvTDl3smQBb8l+g==", + "dependencies": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-core/node_modules/bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", + "engines": { + "node": "*" + } + }, + "node_modules/@truffle/contract/node_modules/web3-eth": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.10.0.tgz", + "integrity": "sha512-Z5vT6slNMLPKuwRyKGbqeGYC87OAy8bOblaqRTgg94CXcn/mmqU7iPIlG4506YdcdK3x6cfEDG7B6w+jRxypKA==", + "dependencies": { + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-eth-abi": "1.10.0", + "web3-eth-accounts": "1.10.0", + "web3-eth-contract": "1.10.0", + "web3-eth-ens": "1.10.0", + "web3-eth-iban": "1.10.0", + "web3-eth-personal": "1.10.0", + "web3-net": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-eth-accounts": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.10.0.tgz", + "integrity": "sha512-wiq39Uc3mOI8rw24wE2n15hboLE0E9BsQLdlmsL4Zua9diDS6B5abXG0XhFcoNsXIGMWXVZz4TOq3u4EdpXF/Q==", + "dependencies": { + "@ethereumjs/common": "2.5.0", + "@ethereumjs/tx": "3.3.2", + "eth-lib": "0.2.8", + "ethereumjs-util": "^7.1.5", + "scrypt-js": "^3.0.1", + "uuid": "^9.0.0", + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-eth-accounts/node_modules/scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==" + }, + "node_modules/@truffle/contract/node_modules/web3-eth-accounts/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@truffle/contract/node_modules/web3-eth-contract": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.10.0.tgz", + "integrity": "sha512-MIC5FOzP/+2evDksQQ/dpcXhSqa/2hFNytdl/x61IeWxhh6vlFeSjq0YVTAyIzdjwnL7nEmZpjfI6y6/Ufhy7w==", + "dependencies": { + "@types/bn.js": "^5.1.1", + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-promievent": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-eth-abi": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-eth-ens": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.10.0.tgz", + "integrity": "sha512-3hpGgzX3qjgxNAmqdrC2YUQMTfnZbs4GeLEmy8aCWziVwogbuqQZ+Gzdfrym45eOZodk+lmXyLuAdqkNlvkc1g==", + "dependencies": { + "content-hash": "^2.5.2", + "eth-ens-namehash": "2.0.8", + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-promievent": "1.10.0", + "web3-eth-abi": "1.10.0", + "web3-eth-contract": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-eth-personal": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.10.0.tgz", + "integrity": "sha512-anseKn98w/d703eWq52uNuZi7GhQeVjTC5/svrBWEKob0WZ5kPdo+EZoFN0sp5a5ubbrk/E0xSl1/M5yORMtpg==", + "dependencies": { + "@types/node": "^12.12.6", + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-net": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-net": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.10.0.tgz", + "integrity": "sha512-NLH/N3IshYWASpxk4/18Ge6n60GEvWBVeM8inx2dmZJVmRI6SJIlUxbL8jySgiTn3MMZlhbdvrGo8fpUW7a1GA==", + "dependencies": { + "web3-core": "1.10.0", + "web3-core-method": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-providers-http": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.10.0.tgz", + "integrity": "sha512-eNr965YB8a9mLiNrkjAWNAPXgmQWfpBfkkn7tpEFlghfww0u3I0tktMZiaToJVcL2+Xq+81cxbkpeWJ5XQDwOA==", + "dependencies": { + "abortcontroller-polyfill": "^1.7.3", + "cross-fetch": "^3.1.4", + "es6-promise": "^4.2.8", + "web3-core-helpers": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-providers-ipc": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.10.0.tgz", + "integrity": "sha512-OfXG1aWN8L1OUqppshzq8YISkWrYHaATW9H8eh0p89TlWMc1KZOL9vttBuaBEi96D/n0eYDn2trzt22bqHWfXA==", + "dependencies": { + "oboe": "2.1.5", + "web3-core-helpers": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-providers-ws": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.10.0.tgz", + "integrity": "sha512-sK0fNcglW36yD5xjnjtSGBnEtf59cbw4vZzJ+CmOWIKGIR96mP5l684g0WD0Eo+f4NQc2anWWXG74lRc9OVMCQ==", + "dependencies": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.10.0", + "websocket": "^1.0.32" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-shh": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.10.0.tgz", + "integrity": "sha512-uNUUuNsO2AjX41GJARV9zJibs11eq6HtOe6Wr0FtRUcj8SN6nHeYIzwstAvJ4fXA53gRqFMTxdntHEt9aXVjpg==", + "hasInstallScript": true, + "dependencies": { + "web3-core": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-net": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-utils": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.0.tgz", + "integrity": "sha512-kSaCM0uMcZTNUSmn5vMEhlo02RObGNRRCkdX0V9UTAU0+lrvn0HSaudyCo6CQzuXUsnuY2ERJGCGPfeWmv19Rg==", + "dependencies": { + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereumjs-util": "^7.1.0", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-utils/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/@truffle/debug-utils": { + "version": "6.0.57", + "resolved": "https://registry.npmjs.org/@truffle/debug-utils/-/debug-utils-6.0.57.tgz", + "integrity": "sha512-Q6oI7zLaeNLB69ixjwZk2UZEWBY6b2OD1sjLMGDKBGR7GaHYiw96GLR2PFgPH1uwEeLmV4N78LYaQCrDsHbNeA==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dependencies": { + "@truffle/codec": "^0.17.3", + "@trufflesuite/chromafi": "^3.0.0", + "bn.js": "^5.1.3", + "chalk": "^2.4.2", + "debug": "^4.3.1", + "highlightjs-solidity": "^2.0.6" + }, + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "node_modules/@truffle/debug-utils/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@truffle/debug-utils/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/@truffle/debug-utils/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@truffle/debug-utils/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@truffle/debug-utils/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/@truffle/debug-utils/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@truffle/debug-utils/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@truffle/error": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@truffle/error/-/error-0.2.2.tgz", + "integrity": "sha512-TqbzJ0O8DHh34cu8gDujnYl4dUl6o2DE4PR6iokbybvnIm/L2xl6+Gv1VC+YJS45xfH83Yo3/Zyg/9Oq8/xZWg==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "node_modules/@truffle/interface-adapter": { + "version": "0.5.37", + "resolved": "https://registry.npmjs.org/@truffle/interface-adapter/-/interface-adapter-0.5.37.tgz", + "integrity": "sha512-lPH9MDgU+7sNDlJSClwyOwPCfuOimqsCx0HfGkznL3mcFRymc1pukAR1k17zn7ErHqBwJjiKAZ6Ri72KkS+IWw==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dependencies": { + "bn.js": "^5.1.3", + "ethers": "^4.0.32", + "web3": "1.10.0" + }, + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/@ethereumjs/common": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-2.5.0.tgz", + "integrity": "sha512-DEHjW6e38o+JmB/NO3GZBpW4lpaiBpkFgXF6jLcJ6gETBYpEyaA5nTimsWBUJR3Vmtm/didUEbNjajskugZORg==", + "dependencies": { + "crc-32": "^1.2.0", + "ethereumjs-util": "^7.1.1" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/@ethereumjs/tx": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.3.2.tgz", + "integrity": "sha512-6AaJhwg4ucmwTvw/1qLaZUX5miWrwZ4nLOUsKyb/HtzS3BMw/CasKhdi1ims9mBKeK9sOJCH4qGKOBGyJCeeog==", + "dependencies": { + "@ethereumjs/common": "^2.5.0", + "ethereumjs-util": "^7.1.2" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/@types/node": { + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==" + }, + "node_modules/@truffle/interface-adapter/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/@truffle/interface-adapter/node_modules/cross-fetch": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", + "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/@truffle/interface-adapter/node_modules/eth-lib": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.8.tgz", + "integrity": "sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw==", + "dependencies": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "xhr-request-promise": "^0.1.2" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/eth-lib/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/@truffle/interface-adapter/node_modules/ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/ethers": { + "version": "4.0.49", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.49.tgz", + "integrity": "sha512-kPltTvWiyu+OktYy1IStSO16i2e7cS9D9OxZ81q2UUaiNPVrm/RTcbxamCXF9VUSKzJIdJV68EAIhTEVBalRWg==", + "dependencies": { + "aes-js": "3.0.0", + "bn.js": "^4.11.9", + "elliptic": "6.5.4", + "hash.js": "1.1.3", + "js-sha3": "0.5.7", + "scrypt-js": "2.0.4", + "setimmediate": "1.0.4", + "uuid": "2.0.1", + "xmlhttprequest": "1.8.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/ethers/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/@truffle/interface-adapter/node_modules/hash.js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", + "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==" + }, + "node_modules/@truffle/interface-adapter/node_modules/scrypt-js": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.4.tgz", + "integrity": "sha512-4KsaGcPnuhtCZQCxFxN3GVYIhKFPTdLd8PLC552XwbMndtD0cjRFAhDuuydXQ0h08ZfPgzqe6EKHozpuH74iDw==" + }, + "node_modules/@truffle/interface-adapter/node_modules/setimmediate": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.4.tgz", + "integrity": "sha512-/TjEmXQVEzdod/FFskf3o7oOAsGhHf2j1dZqRFbDzq4F3mvvxflIIi4Hd3bLQE9y/CpwqfSQam5JakI/mi3Pog==" + }, + "node_modules/@truffle/interface-adapter/node_modules/uuid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", + "integrity": "sha512-nWg9+Oa3qD2CQzHIP4qKUqwNfzKn8P0LtFhotaCTFchsV7ZfDhAybeip/HZVeMIpZi9JgY1E3nUlwaCmZT1sEg==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details." + }, + "node_modules/@truffle/interface-adapter/node_modules/web3": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3/-/web3-1.10.0.tgz", + "integrity": "sha512-YfKY9wSkGcM8seO+daR89oVTcbu18NsVfvOngzqMYGUU0pPSQmE57qQDvQzUeoIOHAnXEBNzrhjQJmm8ER0rng==", + "hasInstallScript": true, + "dependencies": { + "web3-bzz": "1.10.0", + "web3-core": "1.10.0", + "web3-eth": "1.10.0", + "web3-eth-personal": "1.10.0", + "web3-net": "1.10.0", + "web3-shh": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-bzz": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.10.0.tgz", + "integrity": "sha512-o9IR59io3pDUsXTsps5pO5hW1D5zBmg46iNc2t4j2DkaYHNdDLwk2IP9ukoM2wg47QILfPEJYzhTfkS/CcX0KA==", + "hasInstallScript": true, + "dependencies": { + "@types/node": "^12.12.6", + "got": "12.1.0", + "swarm-js": "^0.1.40" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.10.0.tgz", + "integrity": "sha512-fWySwqy2hn3TL89w5TM8wXF1Z2Q6frQTKHWmP0ppRQorEK8NcHJRfeMiv/mQlSKoTS1F6n/nv2uyZsixFycjYQ==", + "dependencies": { + "@types/bn.js": "^5.1.1", + "@types/node": "^12.12.6", + "bignumber.js": "^9.0.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-requestmanager": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-core-method": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.10.0.tgz", + "integrity": "sha512-4R700jTLAMKDMhQ+nsVfIXvH6IGJlJzGisIfMKWAIswH31h5AZz7uDUW2YctI+HrYd+5uOAlS4OJeeT9bIpvkA==", + "dependencies": { + "@ethersproject/transactions": "^5.6.2", + "web3-core-helpers": "1.10.0", + "web3-core-promievent": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-core-requestmanager": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.10.0.tgz", + "integrity": "sha512-3z/JKE++Os62APml4dvBM+GAuId4h3L9ckUrj7ebEtS2AR0ixyQPbrBodgL91Sv7j7cQ3Y+hllaluqjguxvSaQ==", + "dependencies": { + "util": "^0.12.5", + "web3-core-helpers": "1.10.0", + "web3-providers-http": "1.10.0", + "web3-providers-ipc": "1.10.0", + "web3-providers-ws": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-core-subscriptions": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.10.0.tgz", + "integrity": "sha512-HGm1PbDqsxejI075gxBc5OSkwymilRWZufIy9zEpnWKNmfbuv5FfHgW1/chtJP6aP3Uq2vHkvTDl3smQBb8l+g==", + "dependencies": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-eth": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.10.0.tgz", + "integrity": "sha512-Z5vT6slNMLPKuwRyKGbqeGYC87OAy8bOblaqRTgg94CXcn/mmqU7iPIlG4506YdcdK3x6cfEDG7B6w+jRxypKA==", + "dependencies": { + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-eth-abi": "1.10.0", + "web3-eth-accounts": "1.10.0", + "web3-eth-contract": "1.10.0", + "web3-eth-ens": "1.10.0", + "web3-eth-iban": "1.10.0", + "web3-eth-personal": "1.10.0", + "web3-net": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-eth-accounts": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.10.0.tgz", + "integrity": "sha512-wiq39Uc3mOI8rw24wE2n15hboLE0E9BsQLdlmsL4Zua9diDS6B5abXG0XhFcoNsXIGMWXVZz4TOq3u4EdpXF/Q==", + "dependencies": { + "@ethereumjs/common": "2.5.0", + "@ethereumjs/tx": "3.3.2", + "eth-lib": "0.2.8", + "ethereumjs-util": "^7.1.5", + "scrypt-js": "^3.0.1", + "uuid": "^9.0.0", + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-eth-accounts/node_modules/scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==" + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-eth-accounts/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-eth-contract": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.10.0.tgz", + "integrity": "sha512-MIC5FOzP/+2evDksQQ/dpcXhSqa/2hFNytdl/x61IeWxhh6vlFeSjq0YVTAyIzdjwnL7nEmZpjfI6y6/Ufhy7w==", + "dependencies": { + "@types/bn.js": "^5.1.1", + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-promievent": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-eth-abi": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-eth-ens": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.10.0.tgz", + "integrity": "sha512-3hpGgzX3qjgxNAmqdrC2YUQMTfnZbs4GeLEmy8aCWziVwogbuqQZ+Gzdfrym45eOZodk+lmXyLuAdqkNlvkc1g==", + "dependencies": { + "content-hash": "^2.5.2", + "eth-ens-namehash": "2.0.8", + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-promievent": "1.10.0", + "web3-eth-abi": "1.10.0", + "web3-eth-contract": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-eth-personal": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.10.0.tgz", + "integrity": "sha512-anseKn98w/d703eWq52uNuZi7GhQeVjTC5/svrBWEKob0WZ5kPdo+EZoFN0sp5a5ubbrk/E0xSl1/M5yORMtpg==", + "dependencies": { + "@types/node": "^12.12.6", + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-net": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-net": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.10.0.tgz", + "integrity": "sha512-NLH/N3IshYWASpxk4/18Ge6n60GEvWBVeM8inx2dmZJVmRI6SJIlUxbL8jySgiTn3MMZlhbdvrGo8fpUW7a1GA==", + "dependencies": { + "web3-core": "1.10.0", + "web3-core-method": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-providers-http": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.10.0.tgz", + "integrity": "sha512-eNr965YB8a9mLiNrkjAWNAPXgmQWfpBfkkn7tpEFlghfww0u3I0tktMZiaToJVcL2+Xq+81cxbkpeWJ5XQDwOA==", + "dependencies": { + "abortcontroller-polyfill": "^1.7.3", + "cross-fetch": "^3.1.4", + "es6-promise": "^4.2.8", + "web3-core-helpers": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-providers-ipc": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.10.0.tgz", + "integrity": "sha512-OfXG1aWN8L1OUqppshzq8YISkWrYHaATW9H8eh0p89TlWMc1KZOL9vttBuaBEi96D/n0eYDn2trzt22bqHWfXA==", + "dependencies": { + "oboe": "2.1.5", + "web3-core-helpers": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-providers-ws": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.10.0.tgz", + "integrity": "sha512-sK0fNcglW36yD5xjnjtSGBnEtf59cbw4vZzJ+CmOWIKGIR96mP5l684g0WD0Eo+f4NQc2anWWXG74lRc9OVMCQ==", + "dependencies": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.10.0", + "websocket": "^1.0.32" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-shh": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.10.0.tgz", + "integrity": "sha512-uNUUuNsO2AjX41GJARV9zJibs11eq6HtOe6Wr0FtRUcj8SN6nHeYIzwstAvJ4fXA53gRqFMTxdntHEt9aXVjpg==", + "hasInstallScript": true, + "dependencies": { + "web3-core": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-net": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-utils": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.0.tgz", + "integrity": "sha512-kSaCM0uMcZTNUSmn5vMEhlo02RObGNRRCkdX0V9UTAU0+lrvn0HSaudyCo6CQzuXUsnuY2ERJGCGPfeWmv19Rg==", + "dependencies": { + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereumjs-util": "^7.1.0", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@trufflesuite/bigint-buffer": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@trufflesuite/bigint-buffer/-/bigint-buffer-1.1.9.tgz", + "integrity": "sha512-bdM5cEGCOhDSwminryHJbRmXc1x7dPKg6Pqns3qyTwFlxsqUgxE29lsERS3PlIW1HTjoIGMUqsk1zQQwST1Yxw==", + "hasInstallScript": true, + "optional": true, + "peer": true, + "dependencies": { + "node-gyp-build": "4.3.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@trufflesuite/bigint-buffer/node_modules/node-gyp-build": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz", + "integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==", + "optional": true, + "peer": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/@trufflesuite/chromafi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@trufflesuite/chromafi/-/chromafi-3.0.0.tgz", + "integrity": "sha512-oqWcOqn8nT1bwlPPfidfzS55vqcIDdpfzo3HbU9EnUmcSTX+I8z0UyUFI3tZQjByVJulbzxHxUGS3ZJPwK/GPQ==", + "dependencies": { + "camelcase": "^4.1.0", + "chalk": "^2.3.2", + "cheerio": "^1.0.0-rc.2", + "detect-indent": "^5.0.0", + "highlight.js": "^10.4.1", + "lodash.merge": "^4.6.2", + "strip-ansi": "^4.0.0", + "strip-indent": "^2.0.0" + } + }, + "node_modules/@trufflesuite/chromafi/node_modules/ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@trufflesuite/chromafi/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@trufflesuite/chromafi/node_modules/camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha512-FxAv7HpHrXbh3aPo4o2qxHay2lkLY3x5Mw3KeE4KQE8ysVfziWeRZDwcjauvwBSGEC/nXUPzZy8zeh4HokqOnw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@trufflesuite/chromafi/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@trufflesuite/chromafi/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@trufflesuite/chromafi/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/@trufflesuite/chromafi/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@trufflesuite/chromafi/node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@trufflesuite/chromafi/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@typechain/ethers-v5": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/@typechain/ethers-v5/-/ethers-v5-10.2.1.tgz", + "integrity": "sha512-n3tQmCZjRE6IU4h6lqUGiQ1j866n5MTCBJreNEHHVWXa2u9GJTaeYyU1/k+1qLutkyw+sS6VAN+AbeiTqsxd/A==", + "peer": true, + "dependencies": { + "lodash": "^4.17.15", + "ts-essentials": "^7.0.1" + }, + "peerDependencies": { + "@ethersproject/abi": "^5.0.0", + "@ethersproject/providers": "^5.0.0", + "ethers": "^5.1.3", + "typechain": "^8.1.1", + "typescript": ">=4.3.0" + } + }, + "node_modules/@types/abstract-leveldown": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/@types/abstract-leveldown/-/abstract-leveldown-7.2.5.tgz", + "integrity": "sha512-/2B0nQF4UdupuxeKTJA2+Rj1D+uDemo6P4kMwKCpbfpnzeVaWSELTsAw4Lxn3VJD6APtRrZOCuYo+4nHUQfTfg==", + "peer": true + }, + "node_modules/@types/bn.js": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.5.tgz", + "integrity": "sha512-V46N0zwKRF5Q00AZ6hWtN0T8gGmDUaUzLWQvHFo5yThtVwK/VCenFY3wXVbOvNfajEpsTfQM4IN9k/d6gUVX3A==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", + "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", + "dependencies": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, + "node_modules/@types/chai": { + "version": "4.3.17", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.17.tgz", + "integrity": "sha512-zmZ21EWzR71B4Sscphjief5djsLre50M6lI622OSySTmn9DB3j+C3kWroHfBQWXbOBwbgg/M8CG/hUxDLIloow==", + "peer": true + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", + "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==" + }, + "node_modules/@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/level-errors": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/level-errors/-/level-errors-3.0.2.tgz", + "integrity": "sha512-gyZHbcQ2X5hNXf/9KS2qGEmgDe9EN2WDM3rJ5Ele467C0nA1sLhtmv1bZiPMDYfAYCfPWft0uQIaTvXbASSTRA==", + "peer": true + }, + "node_modules/@types/levelup": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@types/levelup/-/levelup-4.3.3.tgz", + "integrity": "sha512-K+OTIjJcZHVlZQN1HmU64VtrC0jC3dXWQozuEIR9zVvltIk90zaGPM2AgT+fIkChpzHhFE3YnvFLCbLtzAmexA==", + "peer": true, + "dependencies": { + "@types/abstract-leveldown": "*", + "@types/level-errors": "*", + "@types/node": "*" + } + }, + "node_modules/@types/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==", + "license": "MIT" + }, + "node_modules/@types/mkdirp": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@types/mkdirp/-/mkdirp-0.5.2.tgz", + "integrity": "sha512-U5icWpv7YnZYGsN4/cmh3WD2onMY0aJIiTE6+51TwJCttdHvtCYmkBNOobHlXwrJRL0nkH9jH4kD+1FAdMN4Tg==", + "peer": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "22.0.2", + "license": "MIT", + "dependencies": { + "undici-types": "~6.11.1" + } + }, + "node_modules/@types/node-fetch": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz", + "integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==", + "peer": true, + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.0" + } + }, + "node_modules/@types/pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/prettier": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz", + "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==", + "peer": true + }, + "node_modules/@types/responselike": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz", + "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/secp256k1": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.6.tgz", + "integrity": "sha512-hHxJU6PAEUn0TP4S/ZOzuTUvJWuZ6eIKeNKb5RBpODvSl6hp1Wrw4s7ATY50rklRCScUDpHzVA/DQdSjJ3UoYQ==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/sinon": { + "version": "17.0.3", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-17.0.3.tgz", + "integrity": "sha512-j3uovdn8ewky9kRBG19bOwaZbexJu/XjtkHyjvUgt4xfPFz18dcORIMqnYh66Fx3Powhcr85NT5+er3+oViapw==", + "peer": true, + "dependencies": { + "@types/sinonjs__fake-timers": "*" + } + }, + "node_modules/@types/sinon-chai": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/@types/sinon-chai/-/sinon-chai-3.2.12.tgz", + "integrity": "sha512-9y0Gflk3b0+NhQZ/oxGtaAJDvRywCa5sIyaVnounqLvmf93yBF4EgIRspePtkMs3Tr844nCclYMlcCNmLCvjuQ==", + "peer": true, + "dependencies": { + "@types/chai": "*", + "@types/sinon": "*" + } + }, + "node_modules/@types/sinonjs__fake-timers": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.5.tgz", + "integrity": "sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ==", + "peer": true + }, + "node_modules/@uniswap/lib": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@uniswap/lib/-/lib-1.1.1.tgz", + "integrity": "sha512-2yK7sLpKIT91TiS5sewHtOa7YuM8IuBXVl4GZv2jZFys4D2sY7K5vZh6MqD25TPA95Od+0YzCVq6cTF2IKrOmg==", + "license": "GPL-3.0-or-later", + "engines": { + "node": ">=10" + } + }, + "node_modules/@uniswap/v2-core": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@uniswap/v2-core/-/v2-core-1.0.0.tgz", + "integrity": "sha512-BJiXrBGnN8mti7saW49MXwxDBRFiWemGetE58q8zgfnPPzQKq55ADltEILqOt6VFZ22kVeVKbF8gVd8aY3l7pA==", + "license": "GPL-3.0-or-later", + "engines": { + "node": ">=10" + } + }, + "node_modules/@uniswap/v2-periphery": { + "version": "1.1.0-beta.0", + "resolved": "https://registry.npmjs.org/@uniswap/v2-periphery/-/v2-periphery-1.1.0-beta.0.tgz", + "integrity": "sha512-6dkwAMKza8nzqYiXEr2D86dgW3TTavUvCR0w2Tu33bAbM8Ah43LKAzH7oKKPRT5VJQaMi1jtkGs1E8JPor1n5g==", + "license": "GPL-3.0-or-later", + "dependencies": { + "@uniswap/lib": "1.1.1", + "@uniswap/v2-core": "1.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@uniswap/v3-core": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@uniswap/v3-core/-/v3-core-1.0.1.tgz", + "integrity": "sha512-7pVk4hEm00j9tc71Y9+ssYpO6ytkeI0y7WE9P6UcmNzhxPePwyAxImuhVsTqWK9YFvzgtvzJHi64pBl4jUzKMQ==", + "license": "BUSL-1.1", + "engines": { + "node": ">=10" + } + }, + "node_modules/@uniswap/v3-periphery": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/@uniswap/v3-periphery/-/v3-periphery-1.4.4.tgz", + "integrity": "sha512-S4+m+wh8HbWSO3DKk4LwUCPZJTpCugIsHrWR86m/OrUyvSqGDTXKFfc2sMuGXCZrD1ZqO3rhQsKgdWg3Hbb2Kw==", + "license": "GPL-2.0-or-later", + "dependencies": { + "@openzeppelin/contracts": "3.4.2-solc-0.7", + "@uniswap/lib": "^4.0.1-alpha", + "@uniswap/v2-core": "^1.0.1", + "@uniswap/v3-core": "^1.0.0", + "base64-sol": "1.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@uniswap/v3-periphery/node_modules/@openzeppelin/contracts": { + "version": "3.4.2-solc-0.7", + "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-3.4.2-solc-0.7.tgz", + "integrity": "sha512-W6QmqgkADuFcTLzHL8vVoNBtkwjvQRpYIAom7KiUNoLKghyx3FgH0GBjt8NRvigV1ZmMOBllvE1By1C+bi8WpA==", + "license": "MIT" + }, + "node_modules/@uniswap/v3-periphery/node_modules/@uniswap/lib": { + "version": "4.0.1-alpha", + "resolved": "https://registry.npmjs.org/@uniswap/lib/-/lib-4.0.1-alpha.tgz", + "integrity": "sha512-f6UIliwBbRsgVLxIaBANF6w09tYqc6Y/qXdsrbEmXHyFA7ILiKrIwRFXe1yOg8M3cksgVsO9N7yuL2DdCGQKBA==", + "license": "GPL-3.0-or-later", + "engines": { + "node": ">=10" + } + }, + "node_modules/@uniswap/v3-periphery/node_modules/@uniswap/v2-core": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@uniswap/v2-core/-/v2-core-1.0.1.tgz", + "integrity": "sha512-MtybtkUPSyysqLY2U210NBDeCHX+ltHt3oADGdjqoThZaFRDKwM6k1Nb3F0A3hk5hwuQvytFWhrWHOEq6nVJ8Q==", + "license": "GPL-3.0-or-later", + "engines": { + "node": ">=10" + } + }, + "node_modules/abortcontroller-polyfill": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz", + "integrity": "sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==" + }, + "node_modules/abstract-leveldown": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-6.3.0.tgz", + "integrity": "sha512-TU5nlYgta8YrBMNpc9FwQzRbiXsj49gsALsXadbGHt9CROPzX5fB0rWDR5mtdpOOKa5XqRFpbj1QroPAoPzVjQ==", + "peer": true, + "dependencies": { + "buffer": "^5.5.0", + "immediate": "^3.2.3", + "level-concat-iterator": "~2.0.0", + "level-supports": "~1.0.0", + "xtend": "~4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/adm-zip": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz", + "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==", + "license": "MIT", + "engines": { + "node": ">=0.3.0" + } + }, + "node_modules/aes-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", + "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==", + "license": "MIT" + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "license": "MIT", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "license": "ISC", + "dependencies": { + "string-width": "^4.1.0" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/array-back": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", + "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "engines": { + "node": "*" + } + }, + "node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "peer": true, + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/async-eventemitter": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/async-eventemitter/-/async-eventemitter-0.2.4.tgz", + "integrity": "sha512-pd20BwL7Yt1zwDFy+8MX8F1+WCT8aQeKj0kQnTrH9WaeRETlRamVhD0JtRPmrV4GfOJ2F9CvdQkZeZhnh2TuHw==", + "peer": true, + "dependencies": { + "async": "^2.4.0" + } + }, + "node_modules/async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.0.tgz", + "integrity": "sha512-3AungXC4I8kKsS9PuS4JH2nc+0bVY/mjgrephHTIi8fpEeGsTHBUJeosp0Wc1myYMElmD0B3Oc4XL/HVJ4PV2g==" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/base-x": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.10.tgz", + "integrity": "sha512-7d0s06rR9rYaIWHkpfLIFICM/tkSVdoPC9qYAQRpxn9DdKNWNsKC0uk++akckyLq16Tx2WIinnZ6WRriAt6njQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/base64-sol": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/base64-sol/-/base64-sol-1.0.1.tgz", + "integrity": "sha512-ld3cCNMeXt4uJXmLZBHFGMvVpK9KsLVEhPpFRXnvSVAqABKbuNZg/+dsq3NuM+wxFLb/UrVkz7m1ciWmkMfTbg==", + "license": "MIT" + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/bcrypt-pbkdf/node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==" + }, + "node_modules/bech32": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", + "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==", + "license": "MIT" + }, + "node_modules/big-integer": { + "version": "1.6.36", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.36.tgz", + "integrity": "sha512-t70bfa7HYEA1D9idDbmuv7YbsbVkQ+Hp+8KFSul4aE5e/i1bjCNIRYJZlA8Q8p0r9T8cF/RVvwUgRA//FydEyg==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/big.js": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-6.2.1.tgz", + "integrity": "sha512-bCtHMwL9LeDIozFn+oNhhFoq+yQ3BNdnsLSASUxLciOb1vgvpHsIO1dsENiGMgbb4SkP5TrzWzRiLddn8ahVOQ==", + "engines": { + "node": "*" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/bigjs" + } + }, + "node_modules/bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bip39": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.0.4.tgz", + "integrity": "sha512-YZKQlb752TrUWqHWj7XAwCSjYEgGAk+/Aas3V7NyjQeZYsztO8JnQUaCWhcnL4T+jL8nvB8typ2jRPzTlgugNw==", + "peer": true, + "dependencies": { + "@types/node": "11.11.6", + "create-hash": "^1.1.0", + "pbkdf2": "^3.0.9", + "randombytes": "^2.0.1" + } + }, + "node_modules/bip39/node_modules/@types/node": { + "version": "11.11.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-11.11.6.tgz", + "integrity": "sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ==", + "peer": true + }, + "node_modules/blakejs": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", + "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==", + "license": "MIT" + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, + "node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "license": "MIT" + }, + "node_modules/body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/body-parser/node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" + }, + "node_modules/boxen": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", + "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", + "license": "MIT", + "dependencies": { + "ansi-align": "^3.0.0", + "camelcase": "^6.2.0", + "chalk": "^4.1.0", + "cli-boxes": "^2.2.1", + "string-width": "^4.2.2", + "type-fest": "^0.20.2", + "widest-line": "^3.1.0", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "license": "MIT" + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "license": "ISC" + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "license": "MIT", + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "license": "MIT", + "dependencies": { + "base-x": "^3.0.2" + } + }, + "node_modules/bs58check": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", + "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", + "license": "MIT", + "dependencies": { + "bs58": "^4.0.0", + "create-hash": "^1.1.0", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/buffer-to-arraybuffer": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz", + "integrity": "sha512-3dthu5CYiVB1DEJp61FtApNnNndTckcqe4pFcLdvHtrpG+kcyekCJKg4MRiDcFW7A6AODnXB9U4dwQiCW5kzJQ==" + }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", + "license": "MIT" + }, + "node_modules/bufferutil": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.8.tgz", + "integrity": "sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==", + "hasInstallScript": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacheable-lookup": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-6.1.0.tgz", + "integrity": "sha512-KJ/Dmo1lDDhmW2XDPMo+9oiy/CeqosPguPCrgcVzKyZrL6pM1gU2GmPY/xo6OQPTUaA/c0kwHuywB4E6nmT9ww==", + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/cacheable-request": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", + "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-request/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cacheable-request/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/camel-case": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "integrity": "sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==", + "dependencies": { + "no-case": "^2.2.0", + "upper-case": "^1.1.1" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==" + }, + "node_modules/cbor": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/cbor/-/cbor-5.2.0.tgz", + "integrity": "sha512-5IMhi9e1QU76ppa5/ajP1BmMWZ2FHkhAhjeVKQ/EFCgYSEaeVaoGtL7cxJskf9oCCk+XjzaIdc3IuU/dbA/o2A==", + "dependencies": { + "bignumber.js": "^9.0.1", + "nofilter": "^1.0.4" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/chai": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", + "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==", + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/change-case": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-3.0.2.tgz", + "integrity": "sha512-Mww+SLF6MZ0U6kdg11algyKd5BARbyM4TbFBepwowYSR5ClfQGCGtxNXgykpN0uF/bstWeaGDT4JWaDh8zWAHA==", + "dependencies": { + "camel-case": "^3.0.0", + "constant-case": "^2.0.0", + "dot-case": "^2.1.0", + "header-case": "^1.0.0", + "is-lower-case": "^1.1.0", + "is-upper-case": "^1.1.0", + "lower-case": "^1.1.1", + "lower-case-first": "^1.0.0", + "no-case": "^2.3.2", + "param-case": "^2.1.0", + "pascal-case": "^2.0.0", + "path-case": "^2.1.0", + "sentence-case": "^2.1.0", + "snake-case": "^2.1.0", + "swap-case": "^1.1.0", + "title-case": "^2.1.0", + "upper-case": "^1.1.1", + "upper-case-first": "^1.1.0" + } + }, + "node_modules/check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dependencies": { + "get-func-name": "^2.0.2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/cheerio": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", + "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "dependencies": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0" + }, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "dependencies": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, + "node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "license": "MIT" + }, + "node_modules/cids": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/cids/-/cids-0.7.5.tgz", + "integrity": "sha512-zT7mPeghoWAu+ppn8+BS1tQ5qGmbMfB4AregnQjA/qHY3GC1m1ptI9GkWNlgeu38r7CuRdXB47uY2XgAYt6QVA==", + "deprecated": "This module has been superseded by the multiformats module", + "dependencies": { + "buffer": "^5.5.0", + "class-is": "^1.1.0", + "multibase": "~0.6.0", + "multicodec": "^1.0.0", + "multihashes": "~0.4.15" + }, + "engines": { + "node": ">=4.0.0", + "npm": ">=3.0.0" + } + }, + "node_modules/cids/node_modules/multicodec": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/multicodec/-/multicodec-1.0.4.tgz", + "integrity": "sha512-NDd7FeS3QamVtbgfvu5h7fd1IlbaC4EQ0/pgU4zqE2vdHCmBGsUa0TiM8/TdSeG6BMPC92OOCf8F1ocE/Wkrrg==", + "deprecated": "This module has been superseded by the multiformats module", + "dependencies": { + "buffer": "^5.6.0", + "varint": "^5.0.0" + } + }, + "node_modules/cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/class-is": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/class-is/-/class-is-1.1.0.tgz", + "integrity": "sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw==" + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "dependencies": { + "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/command-exists": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", + "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==", + "license": "MIT" + }, + "node_modules/command-line-args": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz", + "integrity": "sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==", + "peer": true, + "dependencies": { + "array-back": "^3.1.0", + "find-replace": "^3.0.0", + "lodash.camelcase": "^4.3.0", + "typical": "^4.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/command-line-usage": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.3.tgz", + "integrity": "sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw==", + "peer": true, + "dependencies": { + "array-back": "^4.0.2", + "chalk": "^2.4.2", + "table-layout": "^1.0.2", + "typical": "^5.2.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/command-line-usage/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "peer": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/command-line-usage/node_modules/array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/command-line-usage/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "peer": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/command-line-usage/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "peer": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/command-line-usage/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "peer": true + }, + "node_modules/command-line-usage/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/command-line-usage/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "peer": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/command-line-usage/node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" + }, + "node_modules/constant-case": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-2.0.0.tgz", + "integrity": "sha512-eS0N9WwmjTqrOmR3o83F5vW8Z+9R1HnVz3xmzT2PMFug9ly+Au/fxRWlEBSb6LcZwspSsEn9Xs1uw9YgzAg1EQ==", + "dependencies": { + "snake-case": "^2.1.0", + "upper-case": "^1.1.1" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-hash": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/content-hash/-/content-hash-2.5.2.tgz", + "integrity": "sha512-FvIQKy0S1JaWV10sMsA7TRx8bpU+pqPkhbsfvOJAdjRXvYxEckAwQWGwtRjiaJfh+E0DvcWUGqcdjwMGFjsSdw==", + "dependencies": { + "cids": "^0.7.1", + "multicodec": "^0.5.5", + "multihashes": "^0.4.15" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/core-js-pure": { + "version": "3.37.1", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.37.1.tgz", + "integrity": "sha512-J/r5JTHSmzTxbiYYrzXg9w1VpqrYt+gexenBE9pugeyhwPZTAEJddyiReJWsLO6uNQ8xJZFbod6XC7KKwatCiA==", + "hasInstallScript": true, + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "node_modules/crypto-addr-codec": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/crypto-addr-codec/-/crypto-addr-codec-0.1.8.tgz", + "integrity": "sha512-GqAK90iLLgP3FvhNmHbpT3wR6dEdaM8hZyZtLX29SPardh3OA13RFLHDR6sntGCgRWOfiHqW6sIyohpNqOtV/g==", + "dependencies": { + "base-x": "^3.0.8", + "big-integer": "1.6.36", + "blakejs": "^1.1.0", + "bs58": "^4.0.1", + "ripemd160-min": "0.0.6", + "safe-buffer": "^5.2.0", + "sha3": "^2.1.1" + } + }, + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/d": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", + "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", + "dependencies": { + "es5-ext": "^0.10.64", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/debug": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-eql": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", + "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "peer": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "engines": { + "node": ">=10" + } + }, + "node_modules/deferred-leveldown": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/deferred-leveldown/-/deferred-leveldown-5.3.0.tgz", + "integrity": "sha512-a59VOT+oDy7vtAbLRCZwWgxu2BaCfd5Hk7wxJd48ei7I+nsg8Orlb9CLG0PMZienk9BSUKgeAqkO2+Lw+1+Ukw==", + "peer": true, + "dependencies": { + "abstract-leveldown": "~6.2.1", + "inherits": "^2.0.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/deferred-leveldown/node_modules/abstract-leveldown": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-6.2.3.tgz", + "integrity": "sha512-BsLm5vFMRUrrLeCcRc+G0t2qOaTzpoJQLOubq2XM72eNpjF5UdU5o/5NvlNhx95XHcAvcl8OMXr4mlg/fRgUXQ==", + "peer": true, + "dependencies": { + "buffer": "^5.5.0", + "immediate": "^3.2.3", + "level-concat-iterator": "~2.0.0", + "level-supports": "~1.0.0", + "xtend": "~4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.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", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-indent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz", + "integrity": "sha512-rlpvsxUtM0PQvy9iZe640/IWwWYyBsTApREbA1pHOpmOUIl9MkP/U4z7vTtg4Oaojvqhxt7sdufnT0EzGaR31g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/diff": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/dom-walk": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", + "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==" + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-2.1.1.tgz", + "integrity": "sha512-HnM6ZlFqcajLsyudHq7LeeLDr2rFAVYtDv/hV5qchQEidSck8j9OPUsXY9KwJv/lHMtYlX4DjRQqwFYa+0r8Ug==", + "dependencies": { + "no-case": "^2.2.0" + } + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/elliptic": { + "version": "6.5.6", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.6.tgz", + "integrity": "sha512-mpzdtpeCLuS3BmE3pO3Cpp5bbjlOPY2Q0PgoF+Od1XZrHLYI28Xe3ossCmYCQt11FQKEYd9+PF8jymTvtWJSHQ==", + "license": "MIT", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/emittery": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.0.tgz", + "integrity": "sha512-AGvFfs+d0JKCJQ4o01ASQLGPmSCxgfU9RFXvzPvZdjKK8oscynksuJhWrSTSw7j7Ep/sZct5b5ZhYCi8S/t0HQ==", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/encoding-down": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/encoding-down/-/encoding-down-6.3.0.tgz", + "integrity": "sha512-QKrV0iKR6MZVJV08QY0wp1e7vF6QbhnbQhb07bwpEyuz4uZiZgPlEGdkCROuFkUwdxlFaiPIhjyarH1ee/3vhw==", + "peer": true, + "dependencies": { + "abstract-leveldown": "^6.2.1", + "inherits": "^2.0.3", + "level-codec": "^9.0.0", + "level-errors": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "peer": true, + "dependencies": { + "prr": "~1.0.1" + }, + "bin": { + "errno": "cli.js" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es5-ext": { + "version": "0.10.64", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", + "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", + "hasInstallScript": true, + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" + }, + "node_modules/es6-symbol": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", + "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", + "dependencies": { + "d": "^1.0.2", + "ext": "^1.7.0" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/esniff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", + "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eth-ens-namehash": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/eth-ens-namehash/-/eth-ens-namehash-2.0.8.tgz", + "integrity": "sha512-VWEI1+KJfz4Km//dadyvBBoBeSQ0MHTXPvr8UIXiLW6IanxvAV+DmlZAijZwAyggqGUfwQBeHf7tc9wzc1piSw==", + "dependencies": { + "idna-uts46-hx": "^2.3.1", + "js-sha3": "^0.5.7" + } + }, + "node_modules/eth-ens-namehash/node_modules/js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==" + }, + "node_modules/eth-lib": { + "version": "0.1.29", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.1.29.tgz", + "integrity": "sha512-bfttrr3/7gG4E02HoWTDUcDDslN003OlOoBxk9virpAZQ1ja/jDgwkWB8QfJF7ojuEowrqy+lzp9VcJG7/k5bQ==", + "dependencies": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "nano-json-stream-parser": "^0.1.2", + "servify": "^0.1.12", + "ws": "^3.0.0", + "xhr-request-promise": "^0.1.2" + } + }, + "node_modules/eth-lib/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/eth-lib/node_modules/ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "dependencies": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + }, + "node_modules/ethereum-bloom-filters": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ethereum-bloom-filters/-/ethereum-bloom-filters-1.2.0.tgz", + "integrity": "sha512-28hyiE7HVsWubqhpVLVmZXFd4ITeHi+BUu05o9isf0GUpMtzBUi+8/gFrGaGYzvGAJQmJ3JKj77Mk9G98T84rA==", + "dependencies": { + "@noble/hashes": "^1.4.0" + } + }, + "node_modules/ethereum-bloom-filters/node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "license": "MIT", + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/ethereum-waffle": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/ethereum-waffle/-/ethereum-waffle-4.0.10.tgz", + "integrity": "sha512-iw9z1otq7qNkGDNcMoeNeLIATF9yKl1M8AIeu42ElfNBplq0e+5PeasQmm8ybY/elkZ1XyRO0JBQxQdVRb8bqQ==", + "peer": true, + "dependencies": { + "@ethereum-waffle/chai": "4.0.10", + "@ethereum-waffle/compiler": "4.0.3", + "@ethereum-waffle/mock-contract": "4.0.4", + "@ethereum-waffle/provider": "4.0.5", + "solc": "0.8.15", + "typechain": "^8.0.0" + }, + "bin": { + "waffle": "bin/waffle" + }, + "engines": { + "node": ">=10.0" + }, + "peerDependencies": { + "ethers": "*" + } + }, + "node_modules/ethereum-waffle/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "peer": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/ethereum-waffle/node_modules/solc": { + "version": "0.8.15", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.8.15.tgz", + "integrity": "sha512-Riv0GNHNk/SddN/JyEuFKwbcWcEeho15iyupTSHw5Np6WuXA5D8kEHbyzDHi6sqmvLzu2l+8b1YmL8Ytple+8w==", + "peer": true, + "dependencies": { + "command-exists": "^1.2.8", + "commander": "^8.1.0", + "follow-redirects": "^1.12.1", + "js-sha3": "0.8.0", + "memorystream": "^0.3.1", + "semver": "^5.5.0", + "tmp": "0.0.33" + }, + "bin": { + "solcjs": "solc.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/ethereumjs-abi": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz", + "integrity": "sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA==", + "license": "MIT", + "dependencies": { + "bn.js": "^4.11.8", + "ethereumjs-util": "^6.0.0" + } + }, + "node_modules/ethereumjs-util": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", + "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", + "license": "MPL-2.0", + "dependencies": { + "@types/bn.js": "^4.11.3", + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "0.1.6", + "rlp": "^2.2.3" + } + }, + "node_modules/ethereumjs-util/node_modules/@types/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/ethers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz", + "integrity": "sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/abi": "5.7.0", + "@ethersproject/abstract-provider": "5.7.0", + "@ethersproject/abstract-signer": "5.7.0", + "@ethersproject/address": "5.7.0", + "@ethersproject/base64": "5.7.0", + "@ethersproject/basex": "5.7.0", + "@ethersproject/bignumber": "5.7.0", + "@ethersproject/bytes": "5.7.0", + "@ethersproject/constants": "5.7.0", + "@ethersproject/contracts": "5.7.0", + "@ethersproject/hash": "5.7.0", + "@ethersproject/hdnode": "5.7.0", + "@ethersproject/json-wallets": "5.7.0", + "@ethersproject/keccak256": "5.7.0", + "@ethersproject/logger": "5.7.0", + "@ethersproject/networks": "5.7.1", + "@ethersproject/pbkdf2": "5.7.0", + "@ethersproject/properties": "5.7.0", + "@ethersproject/providers": "5.7.2", + "@ethersproject/random": "5.7.0", + "@ethersproject/rlp": "5.7.0", + "@ethersproject/sha2": "5.7.0", + "@ethersproject/signing-key": "5.7.0", + "@ethersproject/solidity": "5.7.0", + "@ethersproject/strings": "5.7.0", + "@ethersproject/transactions": "5.7.0", + "@ethersproject/units": "5.7.0", + "@ethersproject/wallet": "5.7.0", + "@ethersproject/web": "5.7.1", + "@ethersproject/wordlists": "5.7.0" + } + }, + "node_modules/ethjs-abi": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/ethjs-abi/-/ethjs-abi-0.2.1.tgz", + "integrity": "sha512-g2AULSDYI6nEJyJaEVEXtTimRY2aPC2fi7ddSy0W+LXvEVL8Fe1y76o43ecbgdUKwZD+xsmEgX1yJr1Ia3r1IA==", + "dependencies": { + "bn.js": "4.11.6", + "js-sha3": "0.5.5", + "number-to-bn": "1.7.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/ethjs-abi/node_modules/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==" + }, + "node_modules/ethjs-abi/node_modules/js-sha3": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.5.tgz", + "integrity": "sha512-yLLwn44IVeunwjpDVTDZmQeVbB0h+dZpY2eO68B/Zik8hu6dH+rKeLxwua79GGIvW6xr8NBAcrtiUbYrTjEFTA==" + }, + "node_modules/ethjs-unit": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz", + "integrity": "sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw==", + "dependencies": { + "bn.js": "4.11.6", + "number-to-bn": "1.7.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/ethjs-unit/node_modules/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==" + }, + "node_modules/ethjs-util": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", + "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", + "license": "MIT", + "dependencies": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz", + "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==" + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "license": "MIT", + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/express": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/express/node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "dependencies": { + "type": "^2.7.2" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/fast-check": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.1.1.tgz", + "integrity": "sha512-3vtXinVyuUKCKFKYcwXhGE6NtGWkqF8Yh3rvMZNzmwz8EPrgoc/v4pDdLHyLnCyCI5MZpZZkDEwFyXyEONOxpA==", + "dependencies": { + "pure-rand": "^5.0.1" + }, + "engines": { + "node": ">=8.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/find-replace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", + "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", + "peer": true, + "dependencies": { + "array-back": "^3.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "license": "MIT", + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "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", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/form-data-encoder": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.1.tgz", + "integrity": "sha512-EFRDrsMm/kyqbTQocNvRXMLjc7Es2Vk+IQFx/YW7hkUH1eBl4J1fqiP34l74Yt0pFLCNpc06fkbVk00008mzjg==" + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fp-ts": { + "version": "1.19.3", + "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-1.19.3.tgz", + "integrity": "sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg==", + "license": "MIT" + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs-minipass": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "dependencies": { + "minipass": "^2.6.0" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "peer": true + }, + "node_modules/ganache": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/ganache/-/ganache-7.4.3.tgz", + "integrity": "sha512-RpEDUiCkqbouyE7+NMXG26ynZ+7sGiODU84Kz+FVoXUnQ4qQM4M8wif3Y4qUCt+D/eM1RVeGq0my62FPD6Y1KA==", + "bundleDependencies": [ + "@trufflesuite/bigint-buffer", + "emittery", + "keccak", + "leveldown", + "secp256k1", + "@types/bn.js", + "@types/lru-cache", + "@types/seedrandom" + ], + "hasShrinkwrap": true, + "peer": true, + "dependencies": { + "@trufflesuite/bigint-buffer": "1.1.10", + "@types/bn.js": "^5.1.0", + "@types/lru-cache": "5.1.1", + "@types/seedrandom": "3.0.1", + "emittery": "0.10.0", + "keccak": "3.0.2", + "leveldown": "6.1.0", + "secp256k1": "4.0.3" + }, + "bin": { + "ganache": "dist/node/cli.js", + "ganache-cli": "dist/node/cli.js" + }, + "optionalDependencies": { + "bufferutil": "4.0.5", + "utf-8-validate": "5.0.7" + } + }, + "node_modules/ganache/node_modules/@trufflesuite/bigint-buffer": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@trufflesuite/bigint-buffer/-/bigint-buffer-1.1.10.tgz", + "integrity": "sha512-pYIQC5EcMmID74t26GCC67946mgTJFiLXOT/BYozgrd4UEY2JHEGLhWi9cMiQCt5BSqFEvKkCHNnoj82SRjiEw==", + "hasInstallScript": true, + "inBundle": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "node-gyp-build": "4.4.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/ganache/node_modules/@trufflesuite/bigint-buffer/node_modules/node-gyp-build": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.4.0.tgz", + "integrity": "sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ==", + "inBundle": true, + "license": "MIT", + "peer": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/ganache/node_modules/@types/bn.js": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.0.tgz", + "integrity": "sha512-QSSVYj7pYFN49kW77o2s9xTCwZ8F2xLbjLLSEVh8D2F4JUhZtPAGOFLTD+ffqksBx/u4cE/KImFjyhqCjn/LIA==", + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/ganache/node_modules/@types/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==", + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/ganache/node_modules/@types/node": { + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.0.tgz", + "integrity": "sha512-eMhwJXc931Ihh4tkU+Y7GiLzT/y/DBNpNtr4yU9O2w3SYBsr9NaOPhQlLKRmoWtI54uNwuo0IOUFQjVOTZYRvw==", + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/ganache/node_modules/@types/seedrandom": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/seedrandom/-/seedrandom-3.0.1.tgz", + "integrity": "sha512-giB9gzDeiCeloIXDgzFBCgjj1k4WxcDrZtGl6h1IqmUPlxF+Nx8Ve+96QCyDZ/HseB/uvDsKbpib9hU5cU53pw==", + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/ganache/node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/ganache/node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/ganache/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/ganache/node_modules/bufferutil": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.5.tgz", + "integrity": "sha512-HTm14iMQKK2FjFLRTM5lAVcyaUzOnqbPtesFIvREgXpJHdQm8bWS+GkQgIkfaBYRHuCnea7w8UVNfwiAQhlr9A==", + "hasInstallScript": true, + "optional": true, + "peer": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + } + }, + "node_modules/ganache/node_modules/catering": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/catering/-/catering-2.1.0.tgz", + "integrity": "sha512-M5imwzQn6y+ODBfgi+cfgZv2hIUI6oYU/0f35Mdb1ujGeqeoI5tOnl9Q13DTH7LW+7er+NYq8stNOKZD/Z3U/A==", + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "queue-tick": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/ganache/node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/ganache/node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/ganache/node_modules/emittery": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.0.tgz", + "integrity": "sha512-AGvFfs+d0JKCJQ4o01ASQLGPmSCxgfU9RFXvzPvZdjKK8oscynksuJhWrSTSw7j7Ep/sZct5b5ZhYCi8S/t0HQ==", + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/ganache/node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/ganache/node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/ganache/node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "inBundle": true, + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/ganache/node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "inBundle": true, + "license": "ISC", + "peer": true + }, + "node_modules/ganache/node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/ganache/node_modules/keccak": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.2.tgz", + "integrity": "sha512-PyKKjkH53wDMLGrvmRGSNWgmSxZOUqbnXwKL9tmgbFYA1iAYqW21kfR7mZXV0MlESiefxQQE9X9fTa3X+2MPDQ==", + "hasInstallScript": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/ganache/node_modules/leveldown": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/leveldown/-/leveldown-6.1.0.tgz", + "integrity": "sha512-8C7oJDT44JXxh04aSSsfcMI8YiaGRhOFI9/pMEL7nWJLVsWajDPTRxsSHTM2WcTVY5nXM+SuRHzPPi0GbnDX+w==", + "hasInstallScript": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "abstract-leveldown": "^7.2.0", + "napi-macros": "~2.0.0", + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/ganache/node_modules/leveldown/node_modules/abstract-leveldown": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-7.2.0.tgz", + "integrity": "sha512-DnhQwcFEaYsvYDnACLZhMmCWd3rkOeEvglpa4q5i/5Jlm3UIsWaxVzuXvDLFCSCWRO3yy2/+V/G7FusFgejnfQ==", + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "buffer": "^6.0.3", + "catering": "^2.0.0", + "is-buffer": "^2.0.5", + "level-concat-iterator": "^3.0.0", + "level-supports": "^2.0.1", + "queue-microtask": "^1.2.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ganache/node_modules/leveldown/node_modules/level-concat-iterator": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/level-concat-iterator/-/level-concat-iterator-3.1.0.tgz", + "integrity": "sha512-BWRCMHBxbIqPxJ8vHOvKUsaO0v1sLYZtjN3K2iZJsRBYtp+ONsY6Jfi6hy9K3+zolgQRryhIn2NRZjZnWJ9NmQ==", + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "catering": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ganache/node_modules/leveldown/node_modules/level-supports": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-2.1.0.tgz", + "integrity": "sha512-E486g1NCjW5cF78KGPrMDRBYzPuueMZ6VBXHT6gC7A8UYWGiM14fGgp+s/L1oFfDWSPV/+SFkYCmZ0SiESkRKA==", + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ganache/node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "inBundle": true, + "license": "ISC", + "peer": true + }, + "node_modules/ganache/node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/ganache/node_modules/napi-macros": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.0.0.tgz", + "integrity": "sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg==", + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/ganache/node_modules/node-addon-api": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", + "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==", + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/ganache/node_modules/node-gyp-build": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz", + "integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==", + "inBundle": true, + "license": "MIT", + "peer": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/ganache/node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/ganache/node_modules/queue-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.0.tgz", + "integrity": "sha512-ULWhjjE8BmiICGn3G8+1L9wFpERNxkf8ysxkAer4+TFdRefDaXOCV5m92aMB9FtBVmn/8sETXLXY6BfW7hyaWQ==", + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/ganache/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/ganache/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/ganache/node_modules/secp256k1": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz", + "integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==", + "hasInstallScript": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "elliptic": "^6.5.4", + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/ganache/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/ganache/node_modules/utf-8-validate": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.7.tgz", + "integrity": "sha512-vLt1O5Pp+flcArHGIyKEQq883nBt8nN8tVBcoL0qUXj2XT1n7p70yGIq2VK98I5FdZ1YHc0wk/koOnHjnXWk1Q==", + "hasInstallScript": true, + "optional": true, + "peer": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + } + }, + "node_modules/ganache/node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "engines": { + "node": "*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/global": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", + "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", + "dependencies": { + "min-document": "^2.19.0", + "process": "^0.11.10" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/got": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/got/-/got-12.1.0.tgz", + "integrity": "sha512-hBv2ty9QN2RdbJJMK3hesmSkFTjVIHyIDDbssCKnSmq62edGgImJWD10Eb1k77TiV1bxloxqcFAVK8+9pkhOig==", + "dependencies": { + "@sindresorhus/is": "^4.6.0", + "@szmarczak/http-timer": "^5.0.1", + "@types/cacheable-request": "^6.0.2", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^6.0.4", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "form-data-encoder": "1.7.1", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/hardhat": { + "version": "2.22.7", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.22.7.tgz", + "integrity": "sha512-nrXQAl+qUr75TsCLDo8P41YXLc+5U7qQMMCIrbbmy1/uQaVPncdjDrD5BR0CENvHRj7EBqO+JkofpozXoIfJKg==", + "license": "MIT", + "dependencies": { + "@ethersproject/abi": "^5.1.2", + "@metamask/eth-sig-util": "^4.0.0", + "@nomicfoundation/edr": "^0.5.0", + "@nomicfoundation/ethereumjs-common": "4.0.4", + "@nomicfoundation/ethereumjs-tx": "5.0.4", + "@nomicfoundation/ethereumjs-util": "9.0.4", + "@nomicfoundation/solidity-analyzer": "^0.1.0", + "@sentry/node": "^5.18.1", + "@types/bn.js": "^5.1.0", + "@types/lru-cache": "^5.1.0", + "adm-zip": "^0.4.16", + "aggregate-error": "^3.0.0", + "ansi-escapes": "^4.3.0", + "boxen": "^5.1.2", + "chalk": "^2.4.2", + "chokidar": "^3.4.0", + "ci-info": "^2.0.0", + "debug": "^4.1.1", + "enquirer": "^2.3.0", + "env-paths": "^2.2.0", + "ethereum-cryptography": "^1.0.3", + "ethereumjs-abi": "^0.6.8", + "find-up": "^2.1.0", + "fp-ts": "1.19.3", + "fs-extra": "^7.0.1", + "glob": "7.2.0", + "immutable": "^4.0.0-rc.12", + "io-ts": "1.10.4", + "keccak": "^3.0.2", + "lodash": "^4.17.11", + "mnemonist": "^0.38.0", + "mocha": "^10.0.0", + "p-map": "^4.0.0", + "raw-body": "^2.4.1", + "resolve": "1.17.0", + "semver": "^6.3.0", + "solc": "0.8.26", + "source-map-support": "^0.5.13", + "stacktrace-parser": "^0.1.10", + "tsort": "0.0.1", + "undici": "^5.14.0", + "uuid": "^8.3.2", + "ws": "^7.4.6" + }, + "bin": { + "hardhat": "internal/cli/bootstrap.js" + }, + "peerDependencies": { + "ts-node": "*", + "typescript": "*" + }, + "peerDependenciesMeta": { + "ts-node": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/hardhat/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hardhat/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hardhat/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/hardhat/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" + }, + "node_modules/hardhat/node_modules/ethereum-cryptography": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz", + "integrity": "sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.2.0", + "@noble/secp256k1": "1.7.1", + "@scure/bip32": "1.1.5", + "@scure/bip39": "1.1.1" + } + }, + "node_modules/hardhat/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/hardhat/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/header-case": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/header-case/-/header-case-1.0.1.tgz", + "integrity": "sha512-i0q9mkOeSuhXw6bGgiQCCBgY/jlZuV/7dZXyZ9c6LcBrqwvT8eT719E9uxE5LiZftdl+z81Ugbg/VvXV4OJOeQ==", + "dependencies": { + "no-case": "^2.2.0", + "upper-case": "^1.1.3" + } + }, + "node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "engines": { + "node": "*" + } + }, + "node_modules/highlightjs-solidity": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/highlightjs-solidity/-/highlightjs-solidity-2.0.6.tgz", + "integrity": "sha512-DySXWfQghjm2l6a/flF+cteroJqD4gI8GSdL4PtvxZSsAHie8m3yVe2JFoRg03ROKT6hp2Lc/BxXkqerNmtQYg==" + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "license": "MIT", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==" + }, + "node_modules/htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-https": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/http-https/-/http-https-1.0.0.tgz", + "integrity": "sha512-o0PWwVCSp3O0wS6FvNr6xfBCHgt0m1tvPLFOCc2iFDKTRAXhB7m8klDf7ErowFH8POa6dVdGatKU5I1YYwzUyg==" + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/http2-wrapper": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", + "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/idna-uts46-hx": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/idna-uts46-hx/-/idna-uts46-hx-2.3.1.tgz", + "integrity": "sha512-PWoF9Keq6laYdIRwwCdhTPl60xRqAloYNMQLiyUnG42VjT53oW07BXIRM+NK7eQjzXjAk2gUvX9caRxlnF9TAA==", + "dependencies": { + "punycode": "2.1.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/immediate": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.3.0.tgz", + "integrity": "sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q==", + "peer": true + }, + "node_modules/immutable": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz", + "integrity": "sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==", + "license": "MIT" + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/io-ts": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/io-ts/-/io-ts-1.10.4.tgz", + "integrity": "sha512-b23PteSnYXSONJ6JQXRAlvJhuw8KOtkqa87W4wDtvMrud/DTJd5X+NpOOI+O/zZwVq6v0VLAaJ+1EDViKEuN9g==", + "license": "MIT", + "dependencies": { + "fp-ts": "^1.0.0" + } + }, + "node_modules/io-ts/node_modules/fp-ts": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-1.19.5.tgz", + "integrity": "sha512-wDNqTimnzs8QqpldiId9OavWK2NptormjXnRJTQecNjzwfyp6P/8s/zG8e4h3ja3oqkKaY72UlTjQYt/1yXf9A==", + "license": "MIT" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", + "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==" + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hex-prefixed": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz", + "integrity": "sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA==", + "license": "MIT", + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/is-lower-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-lower-case/-/is-lower-case-1.1.3.tgz", + "integrity": "sha512-+5A1e/WJpLLXZEDlgz4G//WYSHyQBD32qa4Jd3Lw06qQlv3fJHnp3YIHjTQSGzHMgzmVKz2ZP3rBxTHkPw/lxA==", + "dependencies": { + "lower-case": "^1.1.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "dependencies": { + "which-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-upper-case": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-upper-case/-/is-upper-case-1.1.2.tgz", + "integrity": "sha512-GQYSJMgfeAmVwh9ixyk888l7OIhNAGKtY6QA+IrWlu9MDTCaXmeozOZ2S9Knj7bQwBO/H6J2kb+pbyTUiMNbsw==", + "dependencies": { + "upper-case": "^1.1.0" + } + }, + "node_modules/is-url": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", + "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==", + "peer": true + }, + "node_modules/is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==" + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" + }, + "node_modules/js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==" + }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "peer": true, + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/keccak": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.4.tgz", + "integrity": "sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/klaw": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", + "integrity": "sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw==", + "optionalDependencies": { + "graceful-fs": "^4.1.9" + } + }, + "node_modules/lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha512-YiGkH6EnGrDGqLMITnGjXtGmNtjoXw9SVUzcaos8RBi7Ps0VBylkq+vOcY9QE5poLasPCR849ucFUkl0UzUyOw==", + "dependencies": { + "invert-kv": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/level-codec": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/level-codec/-/level-codec-9.0.2.tgz", + "integrity": "sha512-UyIwNb1lJBChJnGfjmO0OR+ezh2iVu1Kas3nvBS/BzGnx79dv6g7unpKIDNPMhfdTEGoc7mC8uAu51XEtX+FHQ==", + "peer": true, + "dependencies": { + "buffer": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/level-concat-iterator": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/level-concat-iterator/-/level-concat-iterator-2.0.1.tgz", + "integrity": "sha512-OTKKOqeav2QWcERMJR7IS9CUo1sHnke2C0gkSmcR7QuEtFNLLzHQAvnMw8ykvEcv0Qtkg0p7FOwP1v9e5Smdcw==", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/level-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/level-errors/-/level-errors-2.0.1.tgz", + "integrity": "sha512-UVprBJXite4gPS+3VznfgDSU8PTRuVX0NXwoWW50KLxd2yw4Y1t2JUR5In1itQnudZqRMT9DlAM3Q//9NCjCFw==", + "peer": true, + "dependencies": { + "errno": "~0.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/level-iterator-stream": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/level-iterator-stream/-/level-iterator-stream-4.0.2.tgz", + "integrity": "sha512-ZSthfEqzGSOMWoUGhTXdX9jv26d32XJuHz/5YnuHZzH6wldfWMOVwI9TBtKcya4BKTyTt3XVA0A3cF3q5CY30Q==", + "peer": true, + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^3.4.0", + "xtend": "^4.0.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/level-mem": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/level-mem/-/level-mem-5.0.1.tgz", + "integrity": "sha512-qd+qUJHXsGSFoHTziptAKXoLX87QjR7v2KMbqncDXPxQuCdsQlzmyX+gwrEHhlzn08vkf8TyipYyMmiC6Gobzg==", + "peer": true, + "dependencies": { + "level-packager": "^5.0.3", + "memdown": "^5.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/level-packager": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/level-packager/-/level-packager-5.1.1.tgz", + "integrity": "sha512-HMwMaQPlTC1IlcwT3+swhqf/NUO+ZhXVz6TY1zZIIZlIR0YSn8GtAAWmIvKjNY16ZkEg/JcpAuQskxsXqC0yOQ==", + "peer": true, + "dependencies": { + "encoding-down": "^6.3.0", + "levelup": "^4.3.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/level-supports": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-1.0.1.tgz", + "integrity": "sha512-rXM7GYnW8gsl1vedTJIbzOrRv85c/2uCMpiiCzO2fndd06U/kUXEEU9evYn4zFggBOg36IsBW8LzqIpETwwQzg==", + "peer": true, + "dependencies": { + "xtend": "^4.0.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/level-ws": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/level-ws/-/level-ws-2.0.0.tgz", + "integrity": "sha512-1iv7VXx0G9ec1isqQZ7y5LmoZo/ewAsyDHNA8EFDW5hqH2Kqovm33nSFkSdnLLAK+I5FlT+lo5Cw9itGe+CpQA==", + "peer": true, + "dependencies": { + "inherits": "^2.0.3", + "readable-stream": "^3.1.0", + "xtend": "^4.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/levelup": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/levelup/-/levelup-4.4.0.tgz", + "integrity": "sha512-94++VFO3qN95cM/d6eBXvd894oJE0w3cInq9USsyQzzoJxmiYzPAocNcuGCPGGjoXqDVJcr3C1jzt1TSjyaiLQ==", + "peer": true, + "dependencies": { + "deferred-leveldown": "~5.3.0", + "level-errors": "~2.0.0", + "level-iterator-stream": "~4.0.0", + "level-supports": "~1.0.0", + "xtend": "~4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==", + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "license": "MIT", + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/lodash.assign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "integrity": "sha512-hFuH8TY+Yji7Eja3mGiuAxBqLagejScbG8GbG0j6o9vzn0YL14My+ktnqtZgFTosKymC9/44wP6s7xyuLfnClw==" + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "peer": true + }, + "node_modules/lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "dependencies": { + "get-func-name": "^2.0.1" + } + }, + "node_modules/lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==" + }, + "node_modules/lower-case-first": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/lower-case-first/-/lower-case-first-1.0.2.tgz", + "integrity": "sha512-UuxaYakO7XeONbKrZf5FEgkantPf5DUqDayzP5VXZrtRPdH86s4kN47I8B3TW10S4QKiE3ziHNf3kRN//okHjA==", + "dependencies": { + "lower-case": "^1.1.2" + } + }, + "node_modules/lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru_map": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", + "integrity": "sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==", + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "peer": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/ltgt": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ltgt/-/ltgt-2.2.1.tgz", + "integrity": "sha512-AI2r85+4MquTw9ZYqabu4nMwy9Oftlfa/e/52t9IjtfG+mGBbTNdAoZ3RQKLHR6r0wQnwZnPIEh/Ya6XTWAKNA==", + "peer": true + }, + "node_modules/mcl-wasm": { + "version": "0.7.9", + "resolved": "https://registry.npmjs.org/mcl-wasm/-/mcl-wasm-0.7.9.tgz", + "integrity": "sha512-iJIUcQWA88IJB/5L15GnJVnSQJmf/YaxxV6zRavv83HILHaJQb6y0iFyDMdDO0gN8X37tdxmAOrH/P8B6RB8sQ==", + "peer": true, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "license": "MIT", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memdown": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/memdown/-/memdown-5.1.0.tgz", + "integrity": "sha512-B3J+UizMRAlEArDjWHTMmadet+UKwHd3UjMgGBkZcKAxAYVPS9o0Yeiha4qvz7iGiL2Sb3igUft6p7nbFWctpw==", + "peer": true, + "dependencies": { + "abstract-leveldown": "~6.2.1", + "functional-red-black-tree": "~1.0.1", + "immediate": "~3.2.3", + "inherits": "~2.0.1", + "ltgt": "~2.2.0", + "safe-buffer": "~5.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/memdown/node_modules/abstract-leveldown": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-6.2.3.tgz", + "integrity": "sha512-BsLm5vFMRUrrLeCcRc+G0t2qOaTzpoJQLOubq2XM72eNpjF5UdU5o/5NvlNhx95XHcAvcl8OMXr4mlg/fRgUXQ==", + "peer": true, + "dependencies": { + "buffer": "^5.5.0", + "immediate": "^3.2.3", + "level-concat-iterator": "~2.0.0", + "level-supports": "~1.0.0", + "xtend": "~4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/memdown/node_modules/immediate": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.2.3.tgz", + "integrity": "sha512-RrGCXRm/fRVqMIhqXrGEX9rRADavPiDFSoMb/k64i9XMk8uH4r/Omi5Ctierj6XzNecwDbO4WuFbDD1zmpl3Tg==", + "peer": true + }, + "node_modules/memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "node_modules/merkle-patricia-tree": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/merkle-patricia-tree/-/merkle-patricia-tree-4.2.4.tgz", + "integrity": "sha512-eHbf/BG6eGNsqqfbLED9rIqbsF4+sykEaBn6OLNs71tjclbMcMOk1tEPmJKcNcNCLkvbpY/lwyOlizWsqPNo8w==", + "peer": true, + "dependencies": { + "@types/levelup": "^4.3.0", + "ethereumjs-util": "^7.1.4", + "level-mem": "^5.0.1", + "level-ws": "^2.0.0", + "readable-stream": "^3.6.0", + "semaphore-async-await": "^1.5.1" + } + }, + "node_modules/merkle-patricia-tree/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==", + "peer": true + }, + "node_modules/merkle-patricia-tree/node_modules/ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "peer": true, + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micro-ftch": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/micro-ftch/-/micro-ftch-0.3.1.tgz", + "integrity": "sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg==" + }, + "node_modules/miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "peer": true, + "dependencies": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "bin": { + "miller-rabin": "bin/miller-rabin" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/min-document": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", + "integrity": "sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==", + "dependencies": { + "dom-walk": "^0.1.0" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "license": "ISC" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "license": "MIT" + }, + "node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "dependencies": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "node_modules/minizlib": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "dependencies": { + "minipass": "^2.9.0" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mkdirp-promise": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz", + "integrity": "sha512-Hepn5kb1lJPtVW84RFT40YG1OddBNTOVUZR2bzQUHc+Z03en8/3uX0+060JDhcEzyO08HmipsN9DcnFMxhIL9w==", + "deprecated": "This package is broken and no longer maintained. 'mkdirp' itself supports promises now, please switch to that.", + "dependencies": { + "mkdirp": "*" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mnemonist": { + "version": "0.38.5", + "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.38.5.tgz", + "integrity": "sha512-bZTFT5rrPKtPJxj8KSV0WkPyNxl72vQepqqVUAW2ARUpUSF2qXMB6jZj7hW5/k7C1rtpzqbD/IIbJwLXUjCHeg==", + "license": "MIT", + "dependencies": { + "obliterator": "^2.0.0" + } + }, + "node_modules/mocha": { + "version": "10.7.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.7.0.tgz", + "integrity": "sha512-v8/rBWr2VO5YkspYINnvu81inSz2y3ODJrhO175/Exzor1RcEZZkizgE2A+w/CAXXoESS8Kys5E62dOHGHzULA==", + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.3", + "browser-stdout": "^1.3.1", + "chokidar": "^3.5.3", + "debug": "^4.3.5", + "diff": "^5.2.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^8.1.0", + "he": "^1.2.0", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^5.1.6", + "ms": "^2.1.3", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^6.5.1", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.9", + "yargs-unparser": "^2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/mocha/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mocha/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/mocha/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/mock-fs": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-4.14.0.tgz", + "integrity": "sha512-qYvlv/exQ4+svI3UOvPUpLDF0OMX5euvUH0Ny4N5QyRyhNdgAgUrVH3iUINSzEPLvx0kbo/Bp28GJKIqvE7URw==" + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "license": "MIT" + }, + "node_modules/multibase": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-0.6.1.tgz", + "integrity": "sha512-pFfAwyTjbbQgNc3G7D48JkJxWtoJoBMaR4xQUOuB8RnCgRqaYmWNFeJTTvrJ2w51bjLq2zTby6Rqj9TQ9elSUw==", + "deprecated": "This module has been superseded by the multiformats module", + "dependencies": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + }, + "node_modules/multicodec": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/multicodec/-/multicodec-0.5.7.tgz", + "integrity": "sha512-PscoRxm3f+88fAtELwUnZxGDkduE2HD9Q6GHUOywQLjOGT/HAdhjLDYNZ1e7VR0s0TP0EwZ16LNUTFpoBGivOA==", + "deprecated": "This module has been superseded by the multiformats module", + "dependencies": { + "varint": "^5.0.0" + } + }, + "node_modules/multihashes": { + "version": "0.4.21", + "resolved": "https://registry.npmjs.org/multihashes/-/multihashes-0.4.21.tgz", + "integrity": "sha512-uVSvmeCWf36pU2nB4/1kzYZjsXD9vofZKpgudqkceYY5g2aZZXJ5r9lxuzoRLl1OAp28XljXsEJ/X/85ZsKmKw==", + "dependencies": { + "buffer": "^5.5.0", + "multibase": "^0.7.0", + "varint": "^5.0.0" + } + }, + "node_modules/multihashes/node_modules/multibase": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-0.7.0.tgz", + "integrity": "sha512-TW8q03O0f6PNFTQDvh3xxH03c8CjGaaYrjkl9UQPG6rz53TQzzxJVCIWVjzcbN/Q5Y53Zd0IBQBMVktVgNx4Fg==", + "deprecated": "This module has been superseded by the multiformats module", + "dependencies": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + }, + "node_modules/nano-base32": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/nano-base32/-/nano-base32-1.0.1.tgz", + "integrity": "sha512-sxEtoTqAPdjWVGv71Q17koMFGsOMSiHsIFEvzOM7cNp8BXB4AnEwmDabm5dorusJf/v1z7QxaZYxUorU9RKaAw==" + }, + "node_modules/nano-json-stream-parser": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz", + "integrity": "sha512-9MqxMH/BSJC7dnLsEMPyfN5Dvoo49IsPFYMcHw3Bcfc2kN0lpHRBSzlMSVx4HGyJ7s9B31CyBTVehWJoQ8Ctew==" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" + }, + "node_modules/no-case": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "dependencies": { + "lower-case": "^1.1.1" + } + }, + "node_modules/node-addon-api": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", + "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==", + "license": "MIT" + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-gyp-build": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.1.tgz", + "integrity": "sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==", + "license": "MIT", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/nofilter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-1.0.4.tgz", + "integrity": "sha512-N8lidFp+fCz+TD51+haYdbDGrcBWwuHX40F5+z0qkUjMJ5Tp+rdSuAkMJ9N9eoolDlEVTf6u5icM+cNKkKW2mA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/number-to-bn": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/number-to-bn/-/number-to-bn-1.7.0.tgz", + "integrity": "sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig==", + "dependencies": { + "bn.js": "4.11.6", + "strip-hex-prefix": "1.0.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/number-to-bn/node_modules/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==" + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "engines": { + "node": "*" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obliterator": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.4.tgz", + "integrity": "sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==", + "license": "MIT" + }, + "node_modules/oboe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/oboe/-/oboe-2.1.5.tgz", + "integrity": "sha512-zRFWiF+FoicxEs3jNI/WYUrVEgA7DeET/InK0XQuudGHRg8iIob3cNPrJTKaz4004uaA9Pbe+Dwa8iluhjLZWA==", + "dependencies": { + "http-https": "^1.0.0" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha512-PRT7ZORmwu2MEFt4/fv3Q+mEfN4zetKxufQrkShY2oGvUms9r8otu5HfdyIFHkYXjO7laNsoVGmM2MANfuTA8g==", + "dependencies": { + "lcid": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "engines": { + "node": ">=12.20" + } + }, + "node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "license": "MIT", + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "license": "MIT", + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/param-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "integrity": "sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==", + "dependencies": { + "no-case": "^2.2.0" + } + }, + "node_modules/parse-headers": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.5.tgz", + "integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==" + }, + "node_modules/parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", + "dependencies": { + "error-ex": "^1.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", + "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", + "dependencies": { + "domhandler": "^5.0.2", + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-2.0.1.tgz", + "integrity": "sha512-qjS4s8rBOJa2Xm0jmxXiyh1+OFf6ekCWOvUaRgAQSktzlTbMotS0nmG9gyYAybCWBcuP4fsBeRCKNwGBnMe2OQ==", + "dependencies": { + "camel-case": "^3.0.0", + "upper-case-first": "^1.1.0" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "peer": true + }, + "node_modules/path-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/path-case/-/path-case-2.1.1.tgz", + "integrity": "sha512-Ou0N05MioItesaLr9q8TtHVWmJ6fxWdqKB2RohFmNWVyJ+2zeKIeDNWAN6B/Pe7wpzWChhZX6nONYmOnMeJQ/Q==", + "dependencies": { + "no-case": "^2.2.0" + } + }, + "node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "node_modules/path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==", + "dependencies": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "engines": { + "node": "*" + } + }, + "node_modules/pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "license": "MIT", + "dependencies": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", + "dependencies": { + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "peer": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", + "peer": true + }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.0.tgz", + "integrity": "sha512-Yxz2kRwT90aPiWEMHVYnEf4+rhwF1tBmmZ4KepCP+Wkium9JxtWnUm1nqGwpiAHr/tnTSeHqr3wb++jgSkXjhA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/pure-rand": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-5.0.5.tgz", + "integrity": "sha512-BwQpbqxSCBJVpamI6ydzcKqyFmnd5msMWUGvzXLm1aXvusbbgkbOto/EUPM00hjveJEaJtdbhUjKSzWRhQVkaw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ] + }, + "node_modules/qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/query-string": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", + "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", + "dependencies": { + "decode-uri-component": "^0.2.0", + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", + "dependencies": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", + "dependencies": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-pkg-up/node_modules/find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", + "dependencies": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-pkg-up/node_modules/path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", + "dependencies": { + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/reduce-flatten": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", + "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/request/node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/request/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-1.2.1.tgz", + "integrity": "sha512-H7AkJWMobeskkttHyhTVtS0fxpFLjxhbfMa6Bk3wimP7sdPRGL3EyCg3sAQenFfAe+xQ+oAc85Nmtvq0ROM83Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==" + }, + "node_modules/resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "license": "MIT", + "dependencies": { + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==" + }, + "node_modules/responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", + "dependencies": { + "lowercase-keys": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/responselike/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "license": "MIT", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/ripemd160-min": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/ripemd160-min/-/ripemd160-min-0.0.6.tgz", + "integrity": "sha512-+GcJgQivhs6S9qvLogusiTcS9kQUfgR75whKuy5jIhuiOfQuJ8fjqxV6EGD5duH1Y/FawFUMtMhyeq3Fbnib8A==", + "engines": { + "node": ">=8" + } + }, + "node_modules/rlp": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.7.tgz", + "integrity": "sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==", + "license": "MPL-2.0", + "dependencies": { + "bn.js": "^5.2.0" + }, + "bin": { + "rlp": "bin/rlp" + } + }, + "node_modules/rlp/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==", + "license": "MIT" + }, + "node_modules/rustbn.js": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/rustbn.js/-/rustbn.js-0.2.0.tgz", + "integrity": "sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA==", + "peer": true + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", + "license": "MIT" + }, + "node_modules/secp256k1": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz", + "integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "elliptic": "^6.5.4", + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/seedrandom": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz", + "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==", + "peer": true + }, + "node_modules/semaphore-async-await": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/semaphore-async-await/-/semaphore-async-await-1.5.1.tgz", + "integrity": "sha512-b/ptP11hETwYWpeilHXXQiV5UJNJl7ZWWooKRE5eBIYWoom6dZ0SluCIdCtKycsMtZgKWE01/qAw6jblw1YVhg==", + "peer": true, + "engines": { + "node": ">=4.1" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/sentence-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-2.1.1.tgz", + "integrity": "sha512-ENl7cYHaK/Ktwk5OTD+aDbQ3uC8IByu/6Bkg+HDv8Mm+XnBnppVNalcfJTNsp1ibstKh030/JKQQWglDvtKwEQ==", + "dependencies": { + "no-case": "^2.2.0", + "upper-case-first": "^1.1.2" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/servify": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/servify/-/servify-0.1.12.tgz", + "integrity": "sha512-/xE6GvsKKqyo1BAY+KxOWXcLpPsUUyji7Qg3bVD7hh1eRze5bR1uYiuDA/k3Gof1s9BTzQZEJK8sNcNGFIzeWw==", + "dependencies": { + "body-parser": "^1.16.0", + "cors": "^2.8.1", + "express": "^4.14.0", + "request": "^2.79.0", + "xhr": "^2.3.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "license": "MIT" + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "license": "(MIT AND BSD-3-Clause)", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/sha3": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/sha3/-/sha3-2.1.4.tgz", + "integrity": "sha512-S8cNxbyb0UGUM2VhRD4Poe5N58gJnJsLJ5vC7FYWGUmGhcsj4++WaIOBFVDxlG0W3To6xBuiRh+i0Qp2oNCOtg==", + "dependencies": { + "buffer": "6.0.3" + } + }, + "node_modules/sha3/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/simple-get": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.2.tgz", + "integrity": "sha512-Ijd/rV5o+mSBBs4F/x9oDPtTx9Zb6X9brmnXvMW4J7IR15ngi9q5xxqWBKU744jTZiaXtxaPL7uHG6vtN8kUkw==", + "dependencies": { + "decompress-response": "^3.3.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/simple-get/node_modules/decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", + "dependencies": { + "mimic-response": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/snake-case": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-2.1.0.tgz", + "integrity": "sha512-FMR5YoPFwOLuh4rRz92dywJjyKYZNLpMn1R5ujVpIYkbA9p01fq8RMg0FkO4M+Yobt4MjHeLTJVm5xFFBHSV2Q==", + "dependencies": { + "no-case": "^2.2.0" + } + }, + "node_modules/solc": { + "version": "0.8.26", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.8.26.tgz", + "integrity": "sha512-yiPQNVf5rBFHwN6SIf3TUUvVAFKcQqmSUFeq+fb6pNRCo0ZCgpYOZDi3BVoezCPIAcKrVYd/qXlBLUP9wVrZ9g==", + "license": "MIT", + "dependencies": { + "command-exists": "^1.2.8", + "commander": "^8.1.0", + "follow-redirects": "^1.12.1", + "js-sha3": "0.8.0", + "memorystream": "^0.3.1", + "semver": "^5.5.0", + "tmp": "0.0.33" + }, + "bin": { + "solcjs": "solc.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/solc/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.18", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.18.tgz", + "integrity": "sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==" + }, + "node_modules/sshpk": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", + "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sshpk/node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==" + }, + "node_modules/stacktrace-parser": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz", + "integrity": "sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==", + "license": "MIT", + "dependencies": { + "type-fest": "^0.7.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/stacktrace-parser/node_modules/type-fest": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz", + "integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-format": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string-format/-/string-format-2.0.0.tgz", + "integrity": "sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA==", + "peer": true + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", + "dependencies": { + "is-utf8": "^0.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-hex-prefix": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz", + "integrity": "sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==", + "license": "MIT", + "dependencies": { + "is-hex-prefixed": "1.0.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/strip-indent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz", + "integrity": "sha512-RsSNPLpq6YUL7QYy44RnPVTn/lcVZtb48Uof3X5JLbF4zD/Gs7ZFDv2HWol+leoQN2mT86LAzSshGfkTlSOpsA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/swap-case": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/swap-case/-/swap-case-1.1.2.tgz", + "integrity": "sha512-BAmWG6/bx8syfc6qXPprof3Mn5vQgf5dwdUNJhsNqU9WdPt5P+ES/wQ5bxfijy8zwZgZZHslC3iAsxsuQMCzJQ==", + "dependencies": { + "lower-case": "^1.1.1", + "upper-case": "^1.1.1" + } + }, + "node_modules/swarm-js": { + "version": "0.1.42", + "resolved": "https://registry.npmjs.org/swarm-js/-/swarm-js-0.1.42.tgz", + "integrity": "sha512-BV7c/dVlA3R6ya1lMlSSNPLYrntt0LUq4YMgy3iwpCIc6rZnS5W2wUoctarZ5pXlpKtxDDf9hNziEkcfrxdhqQ==", + "dependencies": { + "bluebird": "^3.5.0", + "buffer": "^5.0.5", + "eth-lib": "^0.1.26", + "fs-extra": "^4.0.2", + "got": "^11.8.5", + "mime-types": "^2.1.16", + "mkdirp-promise": "^5.0.1", + "mock-fs": "^4.1.0", + "setimmediate": "^1.0.5", + "tar": "^4.0.2", + "xhr-request": "^1.0.1" + } + }, + "node_modules/swarm-js/node_modules/@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "dependencies": { + "defer-to-connect": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/swarm-js/node_modules/cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/swarm-js/node_modules/fs-extra": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "node_modules/swarm-js/node_modules/got": { + "version": "11.8.6", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", + "dependencies": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=10.19.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/swarm-js/node_modules/http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/swarm-js/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/swarm-js/node_modules/p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/table-layout": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.2.tgz", + "integrity": "sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==", + "peer": true, + "dependencies": { + "array-back": "^4.0.1", + "deep-extend": "~0.6.0", + "typical": "^5.2.0", + "wordwrapjs": "^4.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/table-layout/node_modules/array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/table-layout/node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar": { + "version": "4.4.19", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz", + "integrity": "sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==", + "dependencies": { + "chownr": "^1.1.4", + "fs-minipass": "^1.2.7", + "minipass": "^2.9.0", + "minizlib": "^1.3.3", + "mkdirp": "^0.5.5", + "safe-buffer": "^5.2.1", + "yallist": "^3.1.1" + }, + "engines": { + "node": ">=4.5" + } + }, + "node_modules/testrpc": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/testrpc/-/testrpc-0.0.1.tgz", + "integrity": "sha512-afH1hO+SQ/VPlmaLUFj2636QMeDvPCeQMc/9RBMW0IfjNe9gFD9Ra3ShqYkB7py0do1ZcCna/9acHyzTJ+GcNA==", + "deprecated": "testrpc has been renamed to ganache-cli, please use this package from now on." + }, + "node_modules/timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha512-G7r3AhovYtr5YKOWQkta8RKAPb+J9IsO4uVmzjl8AZwfhs8UcUwTiD6gcJYSgOtzyjvQKrKYn41syHbUWMkafA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/title-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/title-case/-/title-case-2.1.1.tgz", + "integrity": "sha512-EkJoZ2O3zdCz3zJsYCsxyq2OC5hrxR9mfdd5I+w8h/tmFfeOxJ+vvkxsKxdmN0WtS9zLdHEgfgVOiMVgv+Po4Q==", + "dependencies": { + "no-case": "^2.2.0", + "upper-case": "^1.0.3" + } + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "license": "MIT", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tough-cookie/node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/ts-command-line-args": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/ts-command-line-args/-/ts-command-line-args-2.5.1.tgz", + "integrity": "sha512-H69ZwTw3rFHb5WYpQya40YAX2/w7Ut75uUECbgBIsLmM+BNuYnxsltfyyLMxy6sEeKxgijLTnQtLd0nKd6+IYw==", + "peer": true, + "dependencies": { + "chalk": "^4.1.0", + "command-line-args": "^5.1.1", + "command-line-usage": "^6.1.0", + "string-format": "^2.0.0" + }, + "bin": { + "write-markdown": "dist/write-markdown.js" + } + }, + "node_modules/ts-essentials": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-7.0.3.tgz", + "integrity": "sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ==", + "peer": true, + "peerDependencies": { + "typescript": ">=3.7.0" + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, + "node_modules/tsort": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tsort/-/tsort-0.0.1.tgz", + "integrity": "sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==", + "license": "MIT" + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", + "license": "Unlicense" + }, + "node_modules/tweetnacl-util": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz", + "integrity": "sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==", + "license": "Unlicense" + }, + "node_modules/type": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz", + "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==" + }, + "node_modules/type-detect": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typechain": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/typechain/-/typechain-8.3.2.tgz", + "integrity": "sha512-x/sQYr5w9K7yv3es7jo4KTX05CLxOf7TRWwoHlrjRh8H82G64g+k7VuWPJlgMo6qrjfCulOdfBjiaDtmhFYD/Q==", + "peer": true, + "dependencies": { + "@types/prettier": "^2.1.1", + "debug": "^4.3.1", + "fs-extra": "^7.0.0", + "glob": "7.1.7", + "js-sha3": "^0.8.0", + "lodash": "^4.17.15", + "mkdirp": "^1.0.4", + "prettier": "^2.3.1", + "ts-command-line-args": "^2.2.0", + "ts-essentials": "^7.0.1" + }, + "bin": { + "typechain": "dist/cli/cli.js" + }, + "peerDependencies": { + "typescript": ">=4.3.0" + } + }, + "node_modules/typechain/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/typechain/node_modules/glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "peer": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/typechain/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/typechain/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "peer": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/typescript": { + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", + "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typical": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", + "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" + }, + "node_modules/undici": { + "version": "5.28.4", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz", + "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==", + "license": "MIT", + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/undici-types": { + "version": "6.11.1", + "license": "MIT" + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/upper-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==" + }, + "node_modules/upper-case-first": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-1.1.2.tgz", + "integrity": "sha512-wINKYvI3Db8dtjikdAqoBbZoP6Q+PZUyfMR7pmwHzjC2quzSkUq5DmPrTtPEqHaz8AGtmsB4TqwapMTM1QAQOQ==", + "dependencies": { + "upper-case": "^1.1.1" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.4.tgz", + "integrity": "sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==", + "peer": true, + "dependencies": { + "punycode": "^1.4.1", + "qs": "^6.12.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/url-set-query": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-set-query/-/url-set-query-1.0.0.tgz", + "integrity": "sha512-3AChu4NiXquPfeckE5R5cGdiHCMWJx1dwCWOmWIL4KHAziJNOFIYJlpGFeKDvwLPHovZRCxK3cYlwzqI9Vp+Gg==" + }, + "node_modules/url/node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "peer": true + }, + "node_modules/url/node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "peer": true, + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/utf-8-validate": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", + "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", + "hasInstallScript": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz", + "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==" + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/varint": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/varint/-/varint-5.0.2.tgz", + "integrity": "sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow==" + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/web3": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3/-/web3-1.10.4.tgz", + "integrity": "sha512-kgJvQZjkmjOEKimx/tJQsqWfRDPTTcBfYPa9XletxuHLpHcXdx67w8EFn5AW3eVxCutE9dTVHgGa9VYe8vgsEA==", + "hasInstallScript": true, + "dependencies": { + "web3-bzz": "1.10.4", + "web3-core": "1.10.4", + "web3-eth": "1.10.4", + "web3-eth-personal": "1.10.4", + "web3-net": "1.10.4", + "web3-shh": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-bzz": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.10.4.tgz", + "integrity": "sha512-ZZ/X4sJ0Uh2teU9lAGNS8EjveEppoHNQiKlOXAjedsrdWuaMErBPdLQjXfcrYvN6WM6Su9PMsAxf3FXXZ+HwQw==", + "hasInstallScript": true, + "dependencies": { + "@types/node": "^12.12.6", + "got": "12.1.0", + "swarm-js": "^0.1.40" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-bzz/node_modules/@types/node": { + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==" + }, + "node_modules/web3-core": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.10.4.tgz", + "integrity": "sha512-B6elffYm81MYZDTrat7aEhnhdtVE3lDBUZft16Z8awYMZYJDbnykEbJVS+l3mnA7AQTnSDr/1MjWofGDLBJPww==", + "dependencies": { + "@types/bn.js": "^5.1.1", + "@types/node": "^12.12.6", + "bignumber.js": "^9.0.0", + "web3-core-helpers": "1.10.4", + "web3-core-method": "1.10.4", + "web3-core-requestmanager": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-helpers": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.0.tgz", + "integrity": "sha512-pIxAzFDS5vnbXvfvLSpaA1tfRykAe9adw43YCKsEYQwH0gCLL0kMLkaCX3q+Q8EVmAh+e1jWL/nl9U0de1+++g==", + "dependencies": { + "web3-eth-iban": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-helpers/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/web3-core-helpers/node_modules/ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/web3-core-helpers/node_modules/web3-utils": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.0.tgz", + "integrity": "sha512-kSaCM0uMcZTNUSmn5vMEhlo02RObGNRRCkdX0V9UTAU0+lrvn0HSaudyCo6CQzuXUsnuY2ERJGCGPfeWmv19Rg==", + "dependencies": { + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereumjs-util": "^7.1.0", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-method": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.10.4.tgz", + "integrity": "sha512-uZTb7flr+Xl6LaDsyTeE2L1TylokCJwTDrIVfIfnrGmnwLc6bmTWCCrm71sSrQ0hqs6vp/MKbQYIYqUN0J8WyA==", + "dependencies": { + "@ethersproject/transactions": "^5.6.2", + "web3-core-helpers": "1.10.4", + "web3-core-promievent": "1.10.4", + "web3-core-subscriptions": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-method/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/web3-core-method/node_modules/web3-core-helpers": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz", + "integrity": "sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g==", + "dependencies": { + "web3-eth-iban": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-method/node_modules/web3-core-promievent": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.10.4.tgz", + "integrity": "sha512-2de5WnJQ72YcIhYwV/jHLc4/cWJnznuoGTJGD29ncFQHAfwW/MItHFSVKPPA5v8AhJe+r6y4Y12EKvZKjQVBvQ==", + "dependencies": { + "eventemitter3": "4.0.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-method/node_modules/web3-eth-iban": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz", + "integrity": "sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw==", + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-promievent": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.10.0.tgz", + "integrity": "sha512-68N7k5LWL5R38xRaKFrTFT2pm2jBNFaM4GioS00YjAKXRQ3KjmhijOMG3TICz6Aa5+6GDWYelDNx21YAeZ4YTg==", + "dependencies": { + "eventemitter3": "4.0.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-requestmanager": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.10.4.tgz", + "integrity": "sha512-vqP6pKH8RrhT/2MoaU+DY/OsYK9h7HmEBNCdoMj+4ZwujQtw/Mq2JifjwsJ7gits7Q+HWJwx8q6WmQoVZAWugg==", + "dependencies": { + "util": "^0.12.5", + "web3-core-helpers": "1.10.4", + "web3-providers-http": "1.10.4", + "web3-providers-ipc": "1.10.4", + "web3-providers-ws": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-requestmanager/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/web3-core-requestmanager/node_modules/web3-core-helpers": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz", + "integrity": "sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g==", + "dependencies": { + "web3-eth-iban": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-requestmanager/node_modules/web3-eth-iban": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz", + "integrity": "sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw==", + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-subscriptions": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.10.4.tgz", + "integrity": "sha512-o0lSQo/N/f7/L76C0HV63+S54loXiE9fUPfHFcTtpJRQNDBVsSDdWRdePbWwR206XlsBqD5VHApck1//jEafTw==", + "dependencies": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-subscriptions/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/web3-core-subscriptions/node_modules/web3-core-helpers": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz", + "integrity": "sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g==", + "dependencies": { + "web3-eth-iban": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-subscriptions/node_modules/web3-eth-iban": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz", + "integrity": "sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw==", + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core/node_modules/@types/node": { + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==" + }, + "node_modules/web3-core/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/web3-core/node_modules/web3-core-helpers": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz", + "integrity": "sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g==", + "dependencies": { + "web3-eth-iban": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core/node_modules/web3-eth-iban": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz", + "integrity": "sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw==", + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.10.4.tgz", + "integrity": "sha512-Sql2kYKmgt+T/cgvg7b9ce24uLS7xbFrxE4kuuor1zSCGrjhTJ5rRNG8gTJUkAJGKJc7KgnWmgW+cOfMBPUDSA==", + "dependencies": { + "web3-core": "1.10.4", + "web3-core-helpers": "1.10.4", + "web3-core-method": "1.10.4", + "web3-core-subscriptions": "1.10.4", + "web3-eth-abi": "1.10.4", + "web3-eth-accounts": "1.10.4", + "web3-eth-contract": "1.10.4", + "web3-eth-ens": "1.10.4", + "web3-eth-iban": "1.10.4", + "web3-eth-personal": "1.10.4", + "web3-net": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-abi": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.10.0.tgz", + "integrity": "sha512-cwS+qRBWpJ43aI9L3JS88QYPfFcSJJ3XapxOQ4j40v6mk7ATpA8CVK1vGTzpihNlOfMVRBkR95oAj7oL6aiDOg==", + "dependencies": { + "@ethersproject/abi": "^5.6.3", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-abi/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/web3-eth-abi/node_modules/ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/web3-eth-abi/node_modules/web3-utils": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.0.tgz", + "integrity": "sha512-kSaCM0uMcZTNUSmn5vMEhlo02RObGNRRCkdX0V9UTAU0+lrvn0HSaudyCo6CQzuXUsnuY2ERJGCGPfeWmv19Rg==", + "dependencies": { + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereumjs-util": "^7.1.0", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-accounts": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.10.4.tgz", + "integrity": "sha512-ysy5sVTg9snYS7tJjxVoQAH6DTOTkRGR8emEVCWNGLGiB9txj+qDvSeT0izjurS/g7D5xlMAgrEHLK1Vi6I3yg==", + "dependencies": { + "@ethereumjs/common": "2.6.5", + "@ethereumjs/tx": "3.5.2", + "@ethereumjs/util": "^8.1.0", + "eth-lib": "0.2.8", + "scrypt-js": "^3.0.1", + "uuid": "^9.0.0", + "web3-core": "1.10.4", + "web3-core-helpers": "1.10.4", + "web3-core-method": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-accounts/node_modules/@ethereumjs/common": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-2.6.5.tgz", + "integrity": "sha512-lRyVQOeCDaIVtgfbowla32pzeDv2Obr8oR8Put5RdUBNRGr1VGPGQNGP6elWIpgK3YdpzqTOh4GyUGOureVeeA==", + "dependencies": { + "crc-32": "^1.2.0", + "ethereumjs-util": "^7.1.5" + } + }, + "node_modules/web3-eth-accounts/node_modules/@ethereumjs/tx": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.5.2.tgz", + "integrity": "sha512-gQDNJWKrSDGu2w7w0PzVXVBNMzb7wwdDOmOqczmhNjqFxFuIbhVJDwiGEnxFNC2/b8ifcZzY7MLcluizohRzNw==", + "dependencies": { + "@ethereumjs/common": "^2.6.4", + "ethereumjs-util": "^7.1.5" + } + }, + "node_modules/web3-eth-accounts/node_modules/eth-lib": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.8.tgz", + "integrity": "sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw==", + "dependencies": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "xhr-request-promise": "^0.1.2" + } + }, + "node_modules/web3-eth-accounts/node_modules/ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/web3-eth-accounts/node_modules/ethereumjs-util/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/web3-eth-accounts/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/web3-eth-accounts/node_modules/web3-core-helpers": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz", + "integrity": "sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g==", + "dependencies": { + "web3-eth-iban": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-accounts/node_modules/web3-eth-iban": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz", + "integrity": "sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw==", + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-accounts/node_modules/web3-eth-iban/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/web3-eth-contract": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.10.4.tgz", + "integrity": "sha512-Q8PfolOJ4eV9TvnTj1TGdZ4RarpSLmHnUnzVxZ/6/NiTfe4maJz99R0ISgwZkntLhLRtw0C7LRJuklzGYCNN3A==", + "dependencies": { + "@types/bn.js": "^5.1.1", + "web3-core": "1.10.4", + "web3-core-helpers": "1.10.4", + "web3-core-method": "1.10.4", + "web3-core-promievent": "1.10.4", + "web3-core-subscriptions": "1.10.4", + "web3-eth-abi": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-contract/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/web3-eth-contract/node_modules/web3-core-helpers": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz", + "integrity": "sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g==", + "dependencies": { + "web3-eth-iban": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-contract/node_modules/web3-core-promievent": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.10.4.tgz", + "integrity": "sha512-2de5WnJQ72YcIhYwV/jHLc4/cWJnznuoGTJGD29ncFQHAfwW/MItHFSVKPPA5v8AhJe+r6y4Y12EKvZKjQVBvQ==", + "dependencies": { + "eventemitter3": "4.0.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-contract/node_modules/web3-eth-abi": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.10.4.tgz", + "integrity": "sha512-cZ0q65eJIkd/jyOlQPDjr8X4fU6CRL1eWgdLwbWEpo++MPU/2P4PFk5ZLAdye9T5Sdp+MomePPJ/gHjLMj2VfQ==", + "dependencies": { + "@ethersproject/abi": "^5.6.3", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-contract/node_modules/web3-eth-iban": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz", + "integrity": "sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw==", + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-ens": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.10.4.tgz", + "integrity": "sha512-LLrvxuFeVooRVZ9e5T6OWKVflHPFgrVjJ/jtisRWcmI7KN/b64+D/wJzXqgmp6CNsMQcE7rpmf4CQmJCrTdsgg==", + "dependencies": { + "content-hash": "^2.5.2", + "eth-ens-namehash": "2.0.8", + "web3-core": "1.10.4", + "web3-core-helpers": "1.10.4", + "web3-core-promievent": "1.10.4", + "web3-eth-abi": "1.10.4", + "web3-eth-contract": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-ens/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/web3-eth-ens/node_modules/web3-core-helpers": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz", + "integrity": "sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g==", + "dependencies": { + "web3-eth-iban": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-ens/node_modules/web3-core-promievent": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.10.4.tgz", + "integrity": "sha512-2de5WnJQ72YcIhYwV/jHLc4/cWJnznuoGTJGD29ncFQHAfwW/MItHFSVKPPA5v8AhJe+r6y4Y12EKvZKjQVBvQ==", + "dependencies": { + "eventemitter3": "4.0.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-ens/node_modules/web3-eth-abi": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.10.4.tgz", + "integrity": "sha512-cZ0q65eJIkd/jyOlQPDjr8X4fU6CRL1eWgdLwbWEpo++MPU/2P4PFk5ZLAdye9T5Sdp+MomePPJ/gHjLMj2VfQ==", + "dependencies": { + "@ethersproject/abi": "^5.6.3", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-ens/node_modules/web3-eth-iban": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz", + "integrity": "sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw==", + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-iban": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.0.tgz", + "integrity": "sha512-0l+SP3IGhInw7Q20LY3IVafYEuufo4Dn75jAHT7c2aDJsIolvf2Lc6ugHkBajlwUneGfbRQs/ccYPQ9JeMUbrg==", + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-iban/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/web3-eth-iban/node_modules/ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/web3-eth-iban/node_modules/web3-utils": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.0.tgz", + "integrity": "sha512-kSaCM0uMcZTNUSmn5vMEhlo02RObGNRRCkdX0V9UTAU0+lrvn0HSaudyCo6CQzuXUsnuY2ERJGCGPfeWmv19Rg==", + "dependencies": { + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereumjs-util": "^7.1.0", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-personal": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.10.4.tgz", + "integrity": "sha512-BRa/hs6jU1hKHz+AC/YkM71RP3f0Yci1dPk4paOic53R4ZZG4MgwKRkJhgt3/GPuPliwS46f/i5A7fEGBT4F9w==", + "dependencies": { + "@types/node": "^12.12.6", + "web3-core": "1.10.4", + "web3-core-helpers": "1.10.4", + "web3-core-method": "1.10.4", + "web3-net": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-personal/node_modules/@types/node": { + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==" + }, + "node_modules/web3-eth-personal/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/web3-eth-personal/node_modules/web3-core-helpers": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz", + "integrity": "sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g==", + "dependencies": { + "web3-eth-iban": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-personal/node_modules/web3-eth-iban": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz", + "integrity": "sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw==", + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth/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/web3-eth/node_modules/web3-core-helpers": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz", + "integrity": "sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g==", + "dependencies": { + "web3-eth-iban": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth/node_modules/web3-eth-abi": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.10.4.tgz", + "integrity": "sha512-cZ0q65eJIkd/jyOlQPDjr8X4fU6CRL1eWgdLwbWEpo++MPU/2P4PFk5ZLAdye9T5Sdp+MomePPJ/gHjLMj2VfQ==", + "dependencies": { + "@ethersproject/abi": "^5.6.3", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth/node_modules/web3-eth-iban": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz", + "integrity": "sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw==", + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-net": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.10.4.tgz", + "integrity": "sha512-mKINnhOOnZ4koA+yV2OT5s5ztVjIx7IY9a03w6s+yao/BUn+Luuty0/keNemZxTr1E8Ehvtn28vbOtW7Ids+Ow==", + "dependencies": { + "web3-core": "1.10.4", + "web3-core-method": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-http": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.10.4.tgz", + "integrity": "sha512-m2P5Idc8hdiO0l60O6DSCPw0kw64Zgi0pMjbEFRmxKIck2Py57RQMu4bxvkxJwkF06SlGaEQF8rFZBmuX7aagQ==", + "dependencies": { + "abortcontroller-polyfill": "^1.7.5", + "cross-fetch": "^4.0.0", + "es6-promise": "^4.2.8", + "web3-core-helpers": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-http/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/web3-providers-http/node_modules/web3-core-helpers": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz", + "integrity": "sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g==", + "dependencies": { + "web3-eth-iban": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-http/node_modules/web3-eth-iban": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz", + "integrity": "sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw==", + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-ipc": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.10.4.tgz", + "integrity": "sha512-YRF/bpQk9z3WwjT+A6FI/GmWRCASgd+gC0si7f9zbBWLXjwzYAKG73bQBaFRAHex1hl4CVcM5WUMaQXf3Opeuw==", + "dependencies": { + "oboe": "2.1.5", + "web3-core-helpers": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-ipc/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/web3-providers-ipc/node_modules/web3-core-helpers": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz", + "integrity": "sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g==", + "dependencies": { + "web3-eth-iban": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-ipc/node_modules/web3-eth-iban": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz", + "integrity": "sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw==", + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-ws": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.10.4.tgz", + "integrity": "sha512-j3FBMifyuFFmUIPVQR4pj+t5ILhAexAui0opgcpu9R5LxQrLRUZxHSnU+YO25UycSOa/NAX8A+qkqZNpcFAlxA==", + "dependencies": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.10.4", + "websocket": "^1.0.32" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-ws/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/web3-providers-ws/node_modules/web3-core-helpers": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz", + "integrity": "sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g==", + "dependencies": { + "web3-eth-iban": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-ws/node_modules/web3-eth-iban": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz", + "integrity": "sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw==", + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-shh": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.10.4.tgz", + "integrity": "sha512-cOH6iFFM71lCNwSQrC3niqDXagMqrdfFW85hC9PFUrAr3PUrIem8TNstTc3xna2bwZeWG6OBy99xSIhBvyIACw==", + "hasInstallScript": true, + "dependencies": { + "web3-core": "1.10.4", + "web3-core-method": "1.10.4", + "web3-core-subscriptions": "1.10.4", + "web3-net": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-utils": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.4.tgz", + "integrity": "sha512-tsu8FiKJLk2PzhDl9fXbGUWTkkVXYhtTA+SmEFkKft+9BgwLxfCRpU96sWv7ICC8zixBNd3JURVoiR3dUXgP8A==", + "dependencies": { + "@ethereumjs/util": "^8.1.0", + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereum-cryptography": "^2.1.2", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-utils/node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/web3-utils/node_modules/@scure/bip32": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", + "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", + "dependencies": { + "@noble/curves": "~1.4.0", + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/web3-utils/node_modules/@scure/bip39": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", + "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", + "dependencies": { + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/web3-utils/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/web3-utils/node_modules/ethereum-cryptography": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", + "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", + "dependencies": { + "@noble/curves": "1.4.2", + "@noble/hashes": "1.4.0", + "@scure/bip32": "1.4.0", + "@scure/bip39": "1.3.0" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/websocket": { + "version": "1.0.35", + "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.35.tgz", + "integrity": "sha512-/REy6amwPZl44DDzvRCkaI1q1bIiQB0mEFQLUrhz3z2EK91cp3n72rAjUlrTP0zV22HJIUOVHQGPxhFRjxjt+Q==", + "dependencies": { + "bufferutil": "^4.0.1", + "debug": "^2.2.0", + "es5-ext": "^0.10.63", + "typedarray-to-buffer": "^3.1.5", + "utf-8-validate": "^5.0.2", + "yaeti": "^0.0.6" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/websocket/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/websocket/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==" + }, + "node_modules/which-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "license": "MIT", + "dependencies": { + "string-width": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/window-size": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz", + "integrity": "sha512-UD7d8HFA2+PZsbKyaOCEy8gMh1oDtHgJh1LfgjQ4zVXmYjAT/kvz3PueITKuqDiIXQe7yzpPnxX3lNc+AhQMyw==", + "bin": { + "window-size": "cli.js" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/wordwrapjs": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.1.tgz", + "integrity": "sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==", + "peer": true, + "dependencies": { + "reduce-flatten": "^2.0.0", + "typical": "^5.2.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/wordwrapjs/node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/workerpool": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", + "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", + "license": "Apache-2.0" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xhr": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.6.0.tgz", + "integrity": "sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA==", + "dependencies": { + "global": "~4.4.0", + "is-function": "^1.0.1", + "parse-headers": "^2.0.0", + "xtend": "^4.0.0" + } + }, + "node_modules/xhr-request": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xhr-request/-/xhr-request-1.1.0.tgz", + "integrity": "sha512-Y7qzEaR3FDtL3fP30k9wO/e+FBnBByZeybKOhASsGP30NIkRAAkKD/sCnLvgEfAIEC1rcmK7YG8f4oEnIrrWzA==", + "dependencies": { + "buffer-to-arraybuffer": "^0.0.5", + "object-assign": "^4.1.1", + "query-string": "^5.0.1", + "simple-get": "^2.7.0", + "timed-out": "^4.0.1", + "url-set-query": "^1.0.0", + "xhr": "^2.0.4" + } + }, + "node_modules/xhr-request-promise": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/xhr-request-promise/-/xhr-request-promise-0.1.3.tgz", + "integrity": "sha512-YUBytBsuwgitWtdRzXDDkWAXzhdGB8bYm0sSzMPZT7Z2MBjMSTHFsyCT1yCRATY+XC69DUrQraRAEgcoCRaIPg==", + "dependencies": { + "xhr-request": "^1.1.0" + } + }, + "node_modules/xmlhttprequest": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz", + "integrity": "sha512-58Im/U0mlVBLM38NdZjHyhuMtCqa61469k2YP/AaPbvCoV9aQGUpbJBj1QRm2ytRiVQBD/fsw7L2bJGDVQswBA==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yaeti": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", + "integrity": "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==", + "engines": { + "node": ">=0.10.32" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "license": "MIT", + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/integration_test/dapp_tests/package.json b/integration_test/dapp_tests/package.json new file mode 100644 index 000000000..65b41c04d --- /dev/null +++ b/integration_test/dapp_tests/package.json @@ -0,0 +1,20 @@ +{ + "name": "dapp-tests", + "version": "1.0.0", + "description": "Project for dapp based integration tests", + "main": "index.js", + "author": "", + "license": "MIT", + "dependencies": { + "@nomiclabs/hardhat-ethers": "^2.2.3", + "@nomiclabs/hardhat-waffle": "^2.0.6", + "@openzeppelin/contracts": "^5.0.2", + "@openzeppelin/test-helpers": "^0.5.16", + "@uniswap/v2-periphery": "^1.1.0-beta.0", + "@uniswap/v3-core": "^1.0.1", + "@uniswap/v3-periphery": "^1.4.4", + "chai": "^4.2.0", + "ethers": "^5.7.2", + "hardhat": "^2.22.6" + } +} diff --git a/integration_test/dapp_tests/uniswap/uniswapTest.js b/integration_test/dapp_tests/uniswap/uniswapTest.js new file mode 100755 index 000000000..60b8be12b --- /dev/null +++ b/integration_test/dapp_tests/uniswap/uniswapTest.js @@ -0,0 +1,253 @@ +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, setupSigners, createTokenFactoryTokenAndMint, deployErc20PointerNative } = require("../../../contracts/test/lib.js"); + +const { expect } = require("chai"); + +describe("EVM Test", async function () { + let weth9; + let token; + let router; + let manager; + let deployer; + let user; + before(async function () { + [deployerObj] = await setupSigners(await hre.ethers.getSigners()); + deployer = deployerObj.signer + await fundAddress(deployer.address, amount="2000000000000000000000") + + // Fund user account + const userWallet = ethers.Wallet.createRandom(); + user = userWallet.connect(ethers.provider); + + await fundAddress(user.address) + // Deploy Required Tokens + + // Deploy TokenFactory token with ERC20 pointer + const time = Date.now().toString(); + const tokenName = `test${time}` + const denom = await createTokenFactoryTokenAndMint(tokenName, 10000000, deployerObj.seiAddress) + console.log("DENOM", denom) + const pointerAddr = await deployErc20PointerNative(hre.ethers.provider, denom) + console.log("Pointer Addr", pointerAddr); + + // Deploy WETH9 Token (ETH representation on Uniswap) + console.log("Deploying WETH9 with the account:", deployer.address); + const WETH9 = new hre.ethers.ContractFactory(WETH9_ABI, WETH9_BYTECODE, deployer); + weth9 = await WETH9.deploy(); + await weth9.deployed(); + console.log("WETH9 deployed to:", weth9.address); + + // Deploy MockToken + console.log("Deploying MockToken with the account:", deployer.address); + const MockERC20 = await hre.ethers.getContractFactory("MockERC20"); + token = await MockERC20.deploy("MockToken", "MKT", hre.ethers.utils.parseEther("1000000")); + await token.deployed(); + console.log("MockToken deployed to:", token.address); + + // Deploy NFT Descriptor. These NFTs are used by the NonFungiblePositionManager to represent liquidity positions. + console.log("Deploying NFT Descriptor with the account:", deployer.address); + const NFTDescriptor = new hre.ethers.ContractFactory(DESCRIPTOR_ABI, DESCRIPTOR_BYTECODE, deployer); + descriptor = await NFTDescriptor.deploy(); + await descriptor.deployed(); + console.log("NFTDescriptor deployed to:", descriptor.address); + + // Deploy Uniswap Contracts + // Create UniswapV3 Factory + console.log("Deploying Factory Contract with the account:", deployer.address); + const FactoryContract = new hre.ethers.ContractFactory(FACTORY_ABI, FACTORY_BYTECODE, deployer); + const factory = await FactoryContract.deploy(); + await factory.deployed(); + console.log("Uniswap V3 Factory deployed to:", factory.address); + + // Deploy NonFungiblePositionManager + const NonfungiblePositionManager = new hre.ethers.ContractFactory(MANAGER_ABI, MANAGER_BYTECODE, deployer); + manager = await NonfungiblePositionManager.deploy(factory.address, weth9.address, descriptor.address); + await manager.deployed(); + console.log("NonfungiblePositionManager deployed to:", manager.address); + + // Deploy SwapRouter + console.log("Deploying SwapRouter with the account:", deployer.address); + const SwapRouter = new hre.ethers.ContractFactory(SWAP_ROUTER_ABI, SWAP_ROUTER_BYTECODE, deployer); + router = await SwapRouter.deploy(factory.address, weth9.address); + await router.deployed(); + console.log("SwapRouter deployed to:", router.address); + + // Create WETH9 x MockToken liquidity pool + console.log("Deploying SwapRouter with the account:", deployer.address); + const fee = 3000; // Fee tier (0.3%) + const sqrtPriceX96 = BigInt(Math.sqrt(1)) * BigInt(2) ** BigInt(96); // Initial price (1:1) + + // token0 addr must be < token1 addr + let token0addr; + let token1addr; + if (parseInt(weth9.address, 16) < parseInt(token.address, 16)) { + token0addr = weth9.address; + token1addr = token.address; + } else { + token0addr = token.address; + token1addr = weth9.address; + } + const poolTx = await manager.createAndInitializePoolIfNecessary( + token0addr, + token1addr, + fee, + sqrtPriceX96 + ); + await poolTx.wait(); + console.log("Pool created and initialized"); + + // Add Liquidity to pool + // Define the amount of tokens to be approved and added as liquidity + console.log("Supplying liquidity to pool") + const amountETH = hre.ethers.utils.parseEther("100"); + const amountToken = hre.ethers.utils.parseEther("100"); + + let token0amt; + let token1amt; + if (token0addr === weth9.address) { + token0amt = amountETH; + token1amt = amountToken + } else { + token0amt = amountToken; + token1amt = amountETH; + } + + // Approve the NonfungiblePositionManager to spend the specified amount of the mock token + await token.approve(manager.address, amountToken); + + // Wrap ETH to WETH by depositing ETH into the WETH9 contract + const txWrap = await weth9.deposit({ value: amountETH }); + await txWrap.wait(); + console.log(`Deposited ${amountETH.toString()} ETH to WETH9`); + + // Approve the NonfungiblePositionManager to spend the specified amount of WETH + const approveWETHTx = await weth9.approve(manager.address, amountETH); + await approveWETHTx.wait(); + console.log(`Approved ${amountETH.toString()} WETH to the NonfungiblePositionManager`); + + + // Add liquidity to the pool + const liquidityTx = await manager.mint({ + token0: token0addr, + token1: token1addr, + fee: 3000, // Fee tier (0.3%) + tickLower: -887220, + tickUpper: 887220, + amount0Desired: token0amt, + amount1Desired: token1amt, + amount0Min: 0, + amount1Min: 0, + recipient: deployer.address, + deadline: Math.floor(Date.now() / 1000) + 60 * 10 // 10 minutes from now + }); + + await liquidityTx.wait(); + console.log("Liquidity added"); + }) + + describe("Swaps", async function () { + it("Associated account should swap successfully", async function () { + + let currSeiBal = await user.getBalance() + console.log(`Funded user account ${user.address} with ${hre.ethers.utils.formatEther(currSeiBal)} sei`); + + const fee = 3000; // Fee tier (0.3%) + + // Perform a Swap + const amountIn = hre.ethers.utils.parseEther("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(); + + const deposit = await weth9.connect(user).deposit({ value: amountIn, gasLimit, gasPrice }); + await deposit.wait(); + + const weth9balance = await weth9.connect(user).balanceOf(user.address); + expect(weth9balance).to.equal(amountIn.toString(), "weth9 balance should be equal to value passed in") + + const approval = await weth9.connect(user).approve(router.address, amountIn, {gasLimit, gasPrice}); + await approval.wait(); + + const allowance = await weth9.allowance(user.address, router.address); + // Change to expect + expect(allowance).to.equal(amountIn.toString(), "weth9 allowance for router should be equal to value passed in") + + const tx = await router.connect(user).exactInputSingle({ + tokenIn: weth9.address, + tokenOut: token.address, + fee, + recipient: user.address, + deadline: Math.floor(Date.now() / 1000) + 60 * 10, // 10 minutes from now + amountIn, + amountOutMinimum: amountOutMin, + sqrtPriceLimitX96: 0 + }, {gasLimit, gasPrice}); + + await tx.wait(); + + // Check User's MockToken Balance + const balance = BigInt(await token.balanceOf(user.address)); + // Check that it's more than 0 (no specified amount since there might be slippage) + expect(Number(balance)).to.greaterThan(0, "mocktoken should have been swapped successfully.") + }); + + it("Unassociated account should receive tokens successfully", async function () { + const unassocUserWallet = ethers.Wallet.createRandom(); + const unassocUser = unassocUserWallet.connect(ethers.provider); + + // Fund the user account + await fundAddress(unassocUser.address) + + const currSeiBal = await unassocUser.getBalance() + + const fee = 3000; // Fee tier (0.3%) + + // Perform a Swap + const amountIn = hre.ethers.utils.parseEther("1"); + const amountOutMin = hre.ethers.utils.parseEther("0"); // Minimum amount of MockToken expected + + const deposit = await weth9.deposit({ value: amountIn }); + await deposit.wait(); + + const weth9balance = await weth9.balanceOf(deployer.address); + + // Check that deployer has amountIn amount of weth9 + expect(weth9balance).to.equal(amountIn, "weth9 balance should be received by user") + + const approval = await weth9.approve(router.address, amountIn); + await approval.wait(); + + const allowance = await weth9.allowance(deployer.address, router.address); + + // Check that deployer has approved amountIn amount of weth9 to be used by router + expect(allowance).to.equal(amountIn, "weth9 allowance to router should be set correctly by user") + + const tx = await router.exactInputSingle({ + tokenIn: weth9.address, + tokenOut: token.address, + fee, + recipient: unassocUser.address, + deadline: Math.floor(Date.now() / 1000) + 60 * 10, // 10 minutes from now + amountIn, + amountOutMinimum: amountOutMin, + sqrtPriceLimitX96: 0 + }); + + await tx.wait(); + + // Check User's MockToken Balance + const balance = await token.balanceOf(unassocUser.address); + // 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 mocktoken") + }) + + }) +}) \ No newline at end of file From f7d899dab22d19c7c197a4b4d28e4697afd2e70b Mon Sep 17 00:00:00 2001 From: yzang2019 Date: Wed, 7 Aug 2024 23:28:43 -0700 Subject: [PATCH 03/38] Bump tendermint for high gas patch --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 451ce8ef8..97d405166 100644 --- a/go.mod +++ b/go.mod @@ -354,7 +354,7 @@ replace ( github.com/sei-protocol/sei-db => github.com/sei-protocol/sei-db v0.0.40 // Latest goleveldb is broken, we have to stick to this version github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 - github.com/tendermint/tendermint => github.com/sei-protocol/sei-tendermint v0.3.4 + github.com/tendermint/tendermint => github.com/sei-protocol/sei-tendermint v0.3.7 github.com/tendermint/tm-db => github.com/sei-protocol/tm-db v0.0.4 google.golang.org/grpc => google.golang.org/grpc v1.33.2 ) diff --git a/go.sum b/go.sum index a3cc0a21a..2a2ea8bd8 100644 --- a/go.sum +++ b/go.sum @@ -1355,8 +1355,8 @@ github.com/sei-protocol/sei-iavl v0.1.9 h1:y4mVYftxLNRs6533zl7N0/Ch+CzRQc04JDfHo github.com/sei-protocol/sei-iavl v0.1.9/go.mod h1:7PfkEVT5dcoQE+s/9KWdoXJ8VVVP1QpYYPLdxlkSXFk= github.com/sei-protocol/sei-ibc-go/v3 v3.3.1 h1:BPG9LWe27x3SATpY9nj8JPe+0igyKyrcpB0z2ZvdcXQ= github.com/sei-protocol/sei-ibc-go/v3 v3.3.1/go.mod h1:VwB/vWu4ysT5DN2aF78d17LYmx3omSAdq6gpKvM7XRA= -github.com/sei-protocol/sei-tendermint v0.3.4 h1:pAMXB2Cd0/rmmEkPgcEdIEjw7k64K7+cR2/2IuWBmM4= -github.com/sei-protocol/sei-tendermint v0.3.4/go.mod h1:4LSlJdhl3nf3OmohliwRNUFLOB1XWlrmSodrIP7fLh4= +github.com/sei-protocol/sei-tendermint v0.3.7 h1:cLY9hDvFm9R/z4817JJNSBE3dRQTawJQ89OekUqzDkE= +github.com/sei-protocol/sei-tendermint v0.3.7/go.mod h1:4LSlJdhl3nf3OmohliwRNUFLOB1XWlrmSodrIP7fLh4= github.com/sei-protocol/sei-tm-db v0.0.5 h1:3WONKdSXEqdZZeLuWYfK5hP37TJpfaUa13vAyAlvaQY= github.com/sei-protocol/sei-tm-db v0.0.5/go.mod h1:Cpa6rGyczgthq7/0pI31jys2Fw0Nfrc+/jKdP1prVqY= github.com/sei-protocol/sei-wasmd v0.1.9 h1:GrqrJgvLkzi+e/xhNFahYSo6ud8l4YjKSFm+FIDGW8k= From ea6f949b7bb147a7d93d32544da286a00096de15 Mon Sep 17 00:00:00 2001 From: Kartik Bhat Date: Thu, 8 Aug 2024 13:37:51 -0400 Subject: [PATCH 04/38] Evidence Max Bytes Update (#1812) --- app/app.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/app.go b/app/app.go index 544562f70..5643a5c74 100644 --- a/app/app.go +++ b/app/app.go @@ -1751,7 +1751,7 @@ func (app *App) getFinalizeBlockResponse(appHash []byte, events []abci.Event, tx Evidence: &tmproto.EvidenceParams{ MaxAgeNumBlocks: endBlockResp.ConsensusParamUpdates.Evidence.MaxAgeNumBlocks, MaxAgeDuration: endBlockResp.ConsensusParamUpdates.Evidence.MaxAgeDuration, - MaxBytes: endBlockResp.ConsensusParamUpdates.Block.MaxBytes, + MaxBytes: endBlockResp.ConsensusParamUpdates.Evidence.MaxBytes, }, Validator: &tmproto.ValidatorParams{ PubKeyTypes: endBlockResp.ConsensusParamUpdates.Validator.PubKeyTypes, From d1ee82faf6a342c49801f6e41ccade678cbf6f77 Mon Sep 17 00:00:00 2001 From: Matthieu Vachon Date: Fri, 9 Aug 2024 02:12:12 -0400 Subject: [PATCH 05/38] Fixed when transaction is processed on synchronous algorithm and has post deliver tx hook --- x/evm/tracers/firehose.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/x/evm/tracers/firehose.go b/x/evm/tracers/firehose.go index 9855429f7..163579583 100644 --- a/x/evm/tracers/firehose.go +++ b/x/evm/tracers/firehose.go @@ -780,9 +780,15 @@ func (f *Firehose) OnSeiPostTxCosmosEvents(event seitracing.SeiPostTxCosmosEvent firehoseInfo("post tx cosmos events on EVM transaction (tracer=%s, added_logs=%d, isolated=%t)", f.tracerID, len(event.AddedLogs), f.transactionIsolated) - transaction := f.transaction + var transaction *pbeth.TransactionTrace if f.transactionIsolated { transaction = f.transientTransaction + } else { + if len(f.block.TransactionTraces) == 0 { + f.panicInvalidState("block must have at least one transaction at this point", 1) + } + + transaction = f.block.TransactionTraces[len(f.block.TransactionTraces)-1] } if transaction == nil { From af0daedef28657446e7d27692a6f89629f12bfe2 Mon Sep 17 00:00:00 2001 From: Matthieu Vachon Date: Fri, 9 Aug 2024 02:17:28 -0400 Subject: [PATCH 06/38] Fixed previous fix by ensuring we do not tweak the state in serial execution --- x/evm/tracers/firehose.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/x/evm/tracers/firehose.go b/x/evm/tracers/firehose.go index 163579583..c87982f74 100644 --- a/x/evm/tracers/firehose.go +++ b/x/evm/tracers/firehose.go @@ -827,7 +827,9 @@ func (f *Firehose) OnSeiPostTxCosmosEvents(event seitracing.SeiPostTxCosmosEvent } transaction.Receipt.Logs = append(transaction.Receipt.Logs, firehoseLog) - f.transactionLogIndex += 1 + if f.transactionIsolated { + f.transactionLogIndex += 1 + } } transaction.Receipt.LogsBloom = event.NewReceipt.LogsBloom From a565f91662cc1681647aae1114e05048f5805b71 Mon Sep 17 00:00:00 2001 From: Matthieu Vachon Date: Fri, 9 Aug 2024 10:54:03 -0400 Subject: [PATCH 07/38] Fixed Firehose integration to catch the bug that happened when OCC (parallel tx) is not active --- integration_test/firehose_test/bootstrap.sh | 10 ++++++++ .../{run_test.sh => run_test_case.sh} | 24 +++++++++++++------ integration_test/firehose_test/run_tests.sh | 11 +++++++++ x/evm/tracers/firehose.go | 4 ---- 4 files changed, 38 insertions(+), 11 deletions(-) rename integration_test/firehose_test/{run_test.sh => run_test_case.sh} (83%) create mode 100755 integration_test/firehose_test/run_tests.sh diff --git a/integration_test/firehose_test/bootstrap.sh b/integration_test/firehose_test/bootstrap.sh index 476355e4a..9b4795b94 100644 --- a/integration_test/firehose_test/bootstrap.sh +++ b/integration_test/firehose_test/bootstrap.sh @@ -5,6 +5,12 @@ SCRIPTS="$ROOT/../../scripts" set -e main() { + parallel_tx_enabled=${PARALLEL_TX_ENABLED:-"true"} + + echo "Initializing local chain" + echo "- Parallel tx enabled: $parallel_tx_enabled" + echo "" + NO_RUN=1 $SCRIPTS/initialize_local_chain.sh if ! command -v "sd" &> /dev/null; then @@ -14,6 +20,10 @@ main() { fi sd '\[evm\]' "[evm]\nlive_evm_tracer = \"firehose\"" "$HOME/.sei/config/app.toml" + + if [[ "${PARALLEL_TX_ENABLED:-"true"}" != "true" ]]; then + sd 'occ-enabled *=.*' 'occ-enabled = false' "$HOME/.sei/config/app.toml" + fi } main "$@" diff --git a/integration_test/firehose_test/run_test.sh b/integration_test/firehose_test/run_test_case.sh similarity index 83% rename from integration_test/firehose_test/run_test.sh rename to integration_test/firehose_test/run_test_case.sh index 1733cf45e..ac498bbd9 100755 --- a/integration_test/firehose_test/run_test.sh +++ b/integration_test/firehose_test/run_test_case.sh @@ -8,11 +8,18 @@ set -e main() { trap "exit 1" TERM + if ! command -v "sd" &> /dev/null; then + echo "The 'sd' command is required for this script, please install it" + echo "by following instructions at https://github.com/chmln/sd?tab=readme-ov-file#installation" + exit 1 + fi + data_dir="$ROOT/.firehose-data" seid="${SEID:-seid}" seid_args="start --home \"$HOME/.sei\" --trace --chain-id sei-chain" fireeth_log="$ROOT/.fireeth.log" start_firehose="true" + parallel_tx_enabled=${PARALLEL_TX_ENABLED:-"true"} while getopts "s" opt; do case $opt in @@ -23,16 +30,16 @@ main() { fireeth="fireeth" if ! command -v "$fireeth" &> /dev/null; then - echo "The '$fireeth' could not be found, you can install it through one of those means." + echo "The '$fireeth' binary could not be found, you can install it through one of those means:" echo "" echo "- By running 'brew install streamingfast/tap/firehose-ethereum' on Mac or Linux system (with Homebrew installed)" - echo "- By downloading a pre-compiled binary from https://github.com/streamingfast/firehose-ethereum/releases" echo "- By building it from source cloning https://github.com/streamingfast/firehose-ethereum.git and then 'go install ./cmd/fireeth'" + echo "- By downloading a pre-compiled binary from https://github.com/streamingfast/firehose-ethereum/releases" exit 1 fi if [[ $start_firehose == "true" ]]; then - echo "Running Sei node with Firehose tracer activated via 'fireeth'" + echo "Running Sei node with Firehose tracer activated via 'fireeth' and parallel tx enabled: $parallel_tx_enabled" rm -rf "$data_dir" ("$fireeth" \ @@ -43,7 +50,7 @@ main() { --common-first-streamable-block=1 \ --reader-node-path="$seid" \ --reader-node-arguments="$seid_args" \ - --reader-node-bootstrap-data-url="bash://$ROOT/bootstrap.sh" \ + --reader-node-bootstrap-data-url="bash://$ROOT/bootstrap.sh?env_PARALLEL_TX_ENABLED=${parallel_tx_enabled}" \ --firehose-grpc-listen-addr="localhost:8089" &> "$fireeth_log") & fireeth_pid=$! trap "cleanup" EXIT @@ -117,9 +124,12 @@ show_logs_preview() { log_file="$1" >&2 echo "Here the first 25 lines followed by the last 25 lines of the log:" - >&2 head -n 25 "$log_file" - >&2 echo "\n...\n" - >&2 tail -n 25 "$log_file" + >&2 echo "" + + >&2 echo " ..." + head -n 25 "$log_file" | >&2 sd '^(.)' ' | $1' + >&2 echo " .\n ." + tail -n 25 "$log_file" | >&2 sd '^(.)' ' | $1' >&2 echo "" >&2 echo "See full logs with 'less `relpath $log_file`'" diff --git a/integration_test/firehose_test/run_tests.sh b/integration_test/firehose_test/run_tests.sh new file mode 100755 index 000000000..e613eb0dd --- /dev/null +++ b/integration_test/firehose_test/run_tests.sh @@ -0,0 +1,11 @@ + +ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +set -e + +main() { + PARALLEL_TX_ENABLED=false bash "$ROOT/run_test_case.sh" + PARALLEL_TX_ENABLED=true bash "$ROOT/run_test_case.sh" +} + +main "$@" diff --git a/x/evm/tracers/firehose.go b/x/evm/tracers/firehose.go index c87982f74..a90d7c778 100644 --- a/x/evm/tracers/firehose.go +++ b/x/evm/tracers/firehose.go @@ -826,10 +826,6 @@ func (f *Firehose) OnSeiPostTxCosmosEvents(event seitracing.SeiPostTxCosmosEvent rootCall.Logs = append(rootCall.Logs, firehoseLog) } transaction.Receipt.Logs = append(transaction.Receipt.Logs, firehoseLog) - - if f.transactionIsolated { - f.transactionLogIndex += 1 - } } transaction.Receipt.LogsBloom = event.NewReceipt.LogsBloom From e5260c252e53de0300739fe51ebe7dc472ac12b7 Mon Sep 17 00:00:00 2001 From: Uday Patil Date: Fri, 9 Aug 2024 11:43:26 -0500 Subject: [PATCH 08/38] V5.7.5 release (#1805) * Fix seidb default config value for KeepLastVersion * Fix unit test * remove serialize/deserialize for accesslist * disable accesslist * Revert "disable accesslist" This reverts commit 4fc5cc7c50d4cc38b88b3a76be840e84bde1ad79. * optimize * add cleanup * rebase * remove excess line * v5.7.5 release --------- Co-authored-by: yzang2019 Co-authored-by: codchen Co-authored-by: Yiming Zang <50607998+yzang2019@users.noreply.github.com> --- app/upgrades.go | 1 + x/evm/keeper/msg_server.go | 1 + x/evm/state/accesslist.go | 73 +++++++++++++++++++++----------------- x/evm/state/keys.go | 5 ++- x/evm/state/statedb.go | 9 +++++ 5 files changed, 53 insertions(+), 36 deletions(-) diff --git a/app/upgrades.go b/app/upgrades.go index cc764e717..14233f12f 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -108,6 +108,7 @@ var upgradesList = []string{ "v5.7.1", "v5.7.2", "v5.7.4", + "v5.7.5", } // if there is an override list, use that instead, for integration tests diff --git a/x/evm/keeper/msg_server.go b/x/evm/keeper/msg_server.go index 3b08a4640..293c62e14 100644 --- a/x/evm/keeper/msg_server.go +++ b/x/evm/keeper/msg_server.go @@ -61,6 +61,7 @@ func (server msgServer) EVMTransaction(goCtx context.Context, msg *types.MsgEVMT gp := server.GetGasPool() defer func() { + defer stateDB.Cleanup() if pe := recover(); pe != nil { if !strings.Contains(fmt.Sprintf("%s", pe), occtypes.ErrReadEstimate.Error()) { debug.PrintStack() diff --git a/x/evm/state/accesslist.go b/x/evm/state/accesslist.go index 21b98fd3a..f3c558e01 100644 --- a/x/evm/state/accesslist.go +++ b/x/evm/state/accesslist.go @@ -1,41 +1,61 @@ package state import ( - "encoding/json" - "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" ) +// all custom precompiles have an address greater than or equal to this address +var CustomPrecompileStartingAddr = common.HexToAddress("0x0000000000000000000000000000000000001001") + // Forked from go-ethereum, except journaling logic which is unnecessary with cacheKV type accessList struct { - Addresses map[common.Address]int `json:"addresses"` - Slots []map[common.Hash]struct{} `json:"slots"` + Addresses map[common.Address]int + Slots []map[common.Hash]struct{} } func (s *DBImpl) AddressInAccessList(addr common.Address) bool { s.k.PrepareReplayedAddr(s.ctx, addr) - _, ok := s.getAccessList().Addresses[addr] - return ok + _, ok := s.getCurrentAccessList().Addresses[addr] + if ok { + return true + } + for _, ts := range s.tempStatesHist { + if _, ok := ts.transientAccessLists.Addresses[addr]; ok { + return true + } + } + return false } func (s *DBImpl) SlotInAccessList(addr common.Address, slot common.Hash) (addressOk bool, slotOk bool) { s.k.PrepareReplayedAddr(s.ctx, addr) - al := s.getAccessList() - idx, ok := al.Addresses[addr] - if ok && idx != -1 { + al := s.getCurrentAccessList() + idx, addrOk := al.Addresses[addr] + if addrOk && idx != -1 { _, slotOk := al.Slots[idx][slot] - return ok, slotOk + if slotOk { + return true, true + } + } + for _, ts := range s.tempStatesHist { + idx, ok := ts.transientAccessLists.Addresses[addr] + addrOk = addrOk || ok + if ok && idx != -1 { + _, slotOk := ts.transientAccessLists.Slots[idx][slot] + if slotOk { + return true, true + } + } } - return ok, false + return addrOk, false } func (s *DBImpl) AddAddressToAccessList(addr common.Address) { s.k.PrepareReplayedAddr(s.ctx, addr) - al := s.getAccessList() - defer s.saveAccessList(al) + al := s.getCurrentAccessList() if _, present := al.Addresses[addr]; present { return } @@ -44,8 +64,7 @@ func (s *DBImpl) AddAddressToAccessList(addr common.Address) { func (s *DBImpl) AddSlotToAccessList(addr common.Address, slot common.Hash) { s.k.PrepareReplayedAddr(s.ctx, addr) - al := s.getAccessList() - defer s.saveAccessList(al) + al := s.getCurrentAccessList() idx, addrPresent := al.Addresses[addr] if !addrPresent || idx == -1 { // Address not present, or addr present but no slots there @@ -74,6 +93,10 @@ func (s *DBImpl) Prepare(_ params.Rules, sender, coinbase common.Address, dest * // If it's a create-tx, the destination will be added inside evm.create } for _, addr := range precompiles { + // skip any custom precompile + if addr.Cmp(CustomPrecompileStartingAddr) >= 0 { + continue + } s.AddAddressToAccessList(addr) } for _, el := range txAccesses { @@ -85,22 +108,6 @@ func (s *DBImpl) Prepare(_ params.Rules, sender, coinbase common.Address, dest * s.AddAddressToAccessList(coinbase) } -func (s *DBImpl) getAccessList() *accessList { - bz, found := s.getTransientModule(AccessListKey) - al := accessList{Addresses: make(map[common.Address]int)} - if !found || bz == nil { - return &al - } - if err := json.Unmarshal(bz, &al); err != nil { - panic(err) - } - return &al -} - -func (s *DBImpl) saveAccessList(al *accessList) { - albz, err := json.Marshal(al) - if err != nil { - panic(err) - } - s.tempStateCurrent.transientModuleStates[string(AccessListKey)] = albz +func (s *DBImpl) getCurrentAccessList() *accessList { + return s.tempStateCurrent.transientAccessLists } diff --git a/x/evm/state/keys.go b/x/evm/state/keys.go index f99ec0769..6404c1366 100644 --- a/x/evm/state/keys.go +++ b/x/evm/state/keys.go @@ -9,9 +9,8 @@ var ( // If evm module balance is higher than this value at the end of // the transaction, we need to burn from module balance in order // for this number to align. - GasRefundKey = []byte{0x01} - LogsKey = []byte{0x02} - AccessListKey = []byte{0x03} + GasRefundKey = []byte{0x01} + LogsKey = []byte{0x02} ) /* diff --git a/x/evm/state/statedb.go b/x/evm/state/statedb.go index 7cd888e82..101735618 100644 --- a/x/evm/state/statedb.go +++ b/x/evm/state/statedb.go @@ -81,6 +81,13 @@ func (s *DBImpl) SetEVM(evm *vm.EVM) {} // to the database. func (s *DBImpl) AddPreimage(_ common.Hash, _ []byte) {} +func (s *DBImpl) Cleanup() { + s.tempStateCurrent = nil + s.tempStatesHist = []*TemporaryState{} + s.logger = nil + s.snapshottedCtxs = nil +} + func (s *DBImpl) Finalize() (surplus sdk.Int, err error) { if s.simulation { panic("should never call finalize on a simulation DB") @@ -199,6 +206,7 @@ type TemporaryState struct { transientStates map[string]map[string]common.Hash transientAccounts map[string][]byte transientModuleStates map[string][]byte + transientAccessLists *accessList surplus sdk.Int // in wei } @@ -208,6 +216,7 @@ func NewTemporaryState() *TemporaryState { transientStates: make(map[string]map[string]common.Hash), transientAccounts: make(map[string][]byte), transientModuleStates: make(map[string][]byte), + transientAccessLists: &accessList{Addresses: make(map[common.Address]int), Slots: []map[common.Hash]struct{}{}}, surplus: utils.Sdk0, } } From c3aaf9981b4be75de132d0cba58af544b004ff2a Mon Sep 17 00:00:00 2001 From: Jeremy Wei Date: Fri, 9 Aug 2024 16:25:47 -0400 Subject: [PATCH 09/38] Tune Configs (#1813) tune configs --- app/receipt_test.go | 2 +- contracts/test/ERC20toNativePointerTest.js | 2 +- contracts/test/EVMCompatabilityTest.js | 4 ++-- x/evm/integration_test.go | 8 ++++---- x/evm/module_test.go | 2 +- x/evm/types/params.go | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/receipt_test.go b/app/receipt_test.go index 935031cef..ec791cef7 100644 --- a/app/receipt_test.go +++ b/app/receipt_test.go @@ -87,7 +87,7 @@ func TestEvmEventsForCw20(t *testing.T) { wasmAddr := common.HexToAddress(wasmd.WasmdAddress) txData := ethtypes.LegacyTx{ Nonce: 0, - GasPrice: big.NewInt(333000000000), + GasPrice: big.NewInt(100000000000), Gas: 1000000, To: &wasmAddr, Data: data, diff --git a/contracts/test/ERC20toNativePointerTest.js b/contracts/test/ERC20toNativePointerTest.js index f878e1eeb..0da89df78 100644 --- a/contracts/test/ERC20toNativePointerTest.js +++ b/contracts/test/ERC20toNativePointerTest.js @@ -95,7 +95,7 @@ describe("ERC20 to Native Pointer", function () { // unlinked wallet can send balance back to sender (becomes linked at this moment) await (await pointer.connect(recipientWallet).transfer(sender.evmAddress, amount, { - gasPrice: ethers.parseUnits('333', 'gwei') + gasPrice: ethers.parseUnits('100', 'gwei') })).wait() expect(await pointer.balanceOf(recipient)).to.equal(BigInt(0)); expect(await pointer.balanceOf(sender.evmAddress)).to.equal(startBal); diff --git a/contracts/test/EVMCompatabilityTest.js b/contracts/test/EVMCompatabilityTest.js index bbf1dbc7d..30703a6f2 100644 --- a/contracts/test/EVMCompatabilityTest.js +++ b/contracts/test/EVMCompatabilityTest.js @@ -498,7 +498,7 @@ describe("EVM Test", function () { describe("EIP-1559", async function() { const zero = ethers.parseUnits('0', 'ether') const highgp = ethers.parseUnits("400", "gwei"); - const gp = ethers.parseUnits("333", "gwei"); + const gp = ethers.parseUnits("100", "gwei"); const testCases = [ ["No truncation from max priority fee", gp, gp], @@ -507,7 +507,7 @@ describe("EVM Test", function () { ]; it("Should be able to send many EIP-1559 txs", async function () { - const gp = ethers.parseUnits("333", "gwei"); + const gp = ethers.parseUnits("100", "gwei"); const zero = ethers.parseUnits('0', 'ether') for (let i = 0; i < 10; i++) { const txResponse = await owner.sendTransaction({ diff --git a/x/evm/integration_test.go b/x/evm/integration_test.go index bb03ee0ae..fc1756559 100644 --- a/x/evm/integration_test.go +++ b/x/evm/integration_test.go @@ -75,7 +75,7 @@ func TestERC2981PointerToCW2981(t *testing.T) { require.Nil(t, err) txData := ethtypes.LegacyTx{ Nonce: 0, - GasPrice: big.NewInt(333000000000), + GasPrice: big.NewInt(100000000000), Gas: 5000000, To: &to, Data: data, @@ -108,7 +108,7 @@ func TestERC2981PointerToCW2981(t *testing.T) { require.Nil(t, err) txData = ethtypes.LegacyTx{ Nonce: 1, - GasPrice: big.NewInt(333000000000), + GasPrice: big.NewInt(100000000000), Gas: 1000000, To: &pointerAddr, Data: data, @@ -158,7 +158,7 @@ func TestCW2981PointerToERC2981(t *testing.T) { require.Nil(t, err) txData := ethtypes.LegacyTx{ Nonce: 0, - GasPrice: big.NewInt(333000000000), + GasPrice: big.NewInt(100000000000), Gas: 5000000, To: nil, Data: append(bz, data...), @@ -193,7 +193,7 @@ func TestCW2981PointerToERC2981(t *testing.T) { to := common.HexToAddress(receipt.ContractAddress) txData = ethtypes.LegacyTx{ Nonce: 1, - GasPrice: big.NewInt(333000000000), + GasPrice: big.NewInt(100000000000), Gas: 1000000, To: &to, Data: data, diff --git a/x/evm/module_test.go b/x/evm/module_test.go index 32e30c279..b5bda72dd 100644 --- a/x/evm/module_test.go +++ b/x/evm/module_test.go @@ -53,7 +53,7 @@ func TestModuleExportGenesis(t *testing.T) { module := evm.NewAppModule(nil, k) jsonMsg := module.ExportGenesis(ctx, types.ModuleCdc) jsonStr := string(jsonMsg) - assert.Equal(t, "{\"params\":{\"priority_normalizer\":\"1.000000000000000000\",\"base_fee_per_gas\":\"0.000000000000000000\",\"minimum_fee_per_gas\":\"333000000000.000000000000000000\",\"whitelisted_cw_code_hashes_for_delegate_call\":[]},\"address_associations\":[{\"sei_address\":\"sei17xpfvakm2amg962yls6f84z3kell8c5la4jkdu\",\"eth_address\":\"0x27F7B8B8B5A4e71E8E9aA671f4e4031E3773303F\"}],\"codes\":[],\"states\":[],\"nonces\":[],\"serialized\":[{\"prefix\":\"Fg==\",\"key\":\"AwAC\",\"value\":\"AAAAAAAAAAM=\"},{\"prefix\":\"Fg==\",\"key\":\"BAAG\",\"value\":\"AAAAAAAAAAQ=\"}]}", jsonStr) + assert.Equal(t, "{\"params\":{\"priority_normalizer\":\"1.000000000000000000\",\"base_fee_per_gas\":\"0.000000000000000000\",\"minimum_fee_per_gas\":\"100000000000.000000000000000000\",\"whitelisted_cw_code_hashes_for_delegate_call\":[]},\"address_associations\":[{\"sei_address\":\"sei17xpfvakm2amg962yls6f84z3kell8c5la4jkdu\",\"eth_address\":\"0x27F7B8B8B5A4e71E8E9aA671f4e4031E3773303F\"}],\"codes\":[],\"states\":[],\"nonces\":[],\"serialized\":[{\"prefix\":\"Fg==\",\"key\":\"AwAC\",\"value\":\"AAAAAAAAAAM=\"},{\"prefix\":\"Fg==\",\"key\":\"BAAG\",\"value\":\"AAAAAAAAAAQ=\"}]}", jsonStr) } func TestConsensusVersion(t *testing.T) { diff --git a/x/evm/types/params.go b/x/evm/types/params.go index 485782dc0..6e98e3ead 100644 --- a/x/evm/types/params.go +++ b/x/evm/types/params.go @@ -23,7 +23,7 @@ var DefaultPriorityNormalizer = sdk.NewDec(1) // burnt rather than go to validators (similar to base fee on // Ethereum). var DefaultBaseFeePerGas = sdk.NewDec(0) -var DefaultMinFeePerGas = sdk.NewDec(333000000000) +var DefaultMinFeePerGas = sdk.NewDec(100000000000) var DefaultWhitelistedCwCodeHashesForDelegateCall = generateDefaultWhitelistedCwCodeHashesForDelegateCall() From 1ca3dd426a0c10053a26c6308d1db62c7cd767ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Ma=C5=82ota-W=C3=B3jcik?= Date: Mon, 12 Aug 2024 09:51:48 +0200 Subject: [PATCH 10/38] Fix docker setup for local cluster (#1806) --- .github/workflows/integration-test.yml | 6 ----- Makefile | 18 ++++++++++----- docker/docker-compose.yml | 8 +++++++ docker/localnode/Dockerfile | 22 +++++++------------ docker/localnode/scripts/deploy.sh | 10 ++++----- .../scripts/step6_start_price_feeder.sh | 10 ++++----- docker/rpcnode/Dockerfile | 13 +++++------ 7 files changed, 45 insertions(+), 42 deletions(-) diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml index d0f5f8339..500863a3a 100644 --- a/.github/workflows/integration-test.yml +++ b/.github/workflows/integration-test.yml @@ -149,12 +149,6 @@ jobs: with: go-version: 1.21 - - name: Install Docker Compose - run: | - sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose - sudo chmod +x /usr/local/bin/docker-compose - docker-compose --version - - name: Start 4 node docker cluster run: make clean && INVARIANT_CHECK_INTERVAL=10 ${{matrix.test.env}} make docker-cluster-start & diff --git a/Makefile b/Makefile index 9fe570606..65b716257 100644 --- a/Makefile +++ b/Makefile @@ -138,8 +138,10 @@ run-local-node: kill-sei-node build-docker-node docker run --rm \ --name sei-node \ --network host \ + --user="$(shell id -u):$(shell id -g)" \ -v $(PROJECT_HOME):/sei-protocol/sei-chain:Z \ -v $(GO_PKG_PATH)/mod:/root/go/pkg/mod:Z \ + -v $(shell go env GOCACHE):/root/.cache/go-build:Z \ --platform linux/x86_64 \ sei-chain/localnode .PHONY: run-local-node @@ -149,11 +151,13 @@ run-rpc-node: build-rpc-node docker run --rm \ --name sei-rpc-node \ --network docker_localnet \ + --user="$(shell id -u):$(shell id -g)" \ -v $(PROJECT_HOME):/sei-protocol/sei-chain:Z \ -v $(PROJECT_HOME)/../sei-tendermint:/sei-protocol/sei-tendermint:Z \ -v $(PROJECT_HOME)/../sei-cosmos:/sei-protocol/sei-cosmos:Z \ -v $(PROJECT_HOME)/../sei-db:/sei-protocol/sei-db:Z \ -v $(GO_PKG_PATH)/mod:/root/go/pkg/mod:Z \ + -v $(shell go env GOCACHE):/root/.cache/go-build:Z \ -p 26668-26670:26656-26658 \ --platform linux/x86_64 \ sei-chain/rpcnode @@ -163,11 +167,13 @@ run-rpc-node-skipbuild: build-rpc-node docker run --rm \ --name sei-rpc-node \ --network docker_localnet \ + --user="$(shell id -u):$(shell id -g)" \ -v $(PROJECT_HOME):/sei-protocol/sei-chain:Z \ -v $(PROJECT_HOME)/../sei-tendermint:/sei-protocol/sei-tendermint:Z \ -v $(PROJECT_HOME)/../sei-cosmos:/sei-protocol/sei-cosmos:Z \ -v $(PROJECT_HOME)/../sei-db:/sei-protocol/sei-db:Z \ -v $(GO_PKG_PATH)/mod:/root/go/pkg/mod:Z \ + -v $(shell go env GOCACHE):/root/.cache/go-build:Z \ -p 26668-26670:26656-26658 \ --platform linux/x86_64 \ --env SKIP_BUILD=true \ @@ -175,27 +181,29 @@ run-rpc-node-skipbuild: build-rpc-node .PHONY: run-rpc-node kill-sei-node: - docker ps --filter name=sei-node --filter status=running -aq | xargs docker kill + docker ps --filter name=sei-node --filter status=running -aq | xargs docker kill 2> /dev/null || true kill-rpc-node: - docker ps --filter name=sei-rpc-node --filter status=running -aq | xargs docker kill + docker ps --filter name=sei-rpc-node --filter status=running -aq | xargs docker kill 2> /dev/null || true # Run a 4-node docker containers docker-cluster-start: docker-cluster-stop build-docker-node @rm -rf $(PROJECT_HOME)/build/generated - @cd docker && NUM_ACCOUNTS=10 INVARIANT_CHECK_INTERVAL=${INVARIANT_CHECK_INTERVAL} UPGRADE_VERSION_LIST=${UPGRADE_VERSION_LIST} docker-compose up + @mkdir -p $(shell go env GOPATH)/pkg/mod + @mkdir -p $(shell go env GOCACHE) + @cd docker && USERID=$(shell id -u) GROUPID=$(shell id -g) GOCACHE=$(shell go env GOCACHE) NUM_ACCOUNTS=10 INVARIANT_CHECK_INTERVAL=${INVARIANT_CHECK_INTERVAL} UPGRADE_VERSION_LIST=${UPGRADE_VERSION_LIST} docker compose up .PHONY: localnet-start # Use this to skip the seid build process docker-cluster-start-skipbuild: docker-cluster-stop build-docker-node @rm -rf $(PROJECT_HOME)/build/generated - @cd docker && NUM_ACCOUNTS=10 SKIP_BUILD=true docker-compose up + @cd docker && USERID=$(shell id -u) GROUPID=$(shell id -g) GOCACHE=$(shell go env GOCACHE) NUM_ACCOUNTS=10 SKIP_BUILD=true docker compose up .PHONY: localnet-start # Stop 4-node docker containers docker-cluster-stop: - @cd docker && docker-compose down + @cd docker && USERID=$(shell id -u) GROUPID=$(shell id -g) GOCACHE=$(shell go env GOCACHE) docker compose down .PHONY: localnet-stop diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 0a58689d0..bc3cc123e 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -5,6 +5,7 @@ services: platform: linux/amd64 container_name: sei-node-0 image: "sei-chain/localnode" + user: "${USERID}:${GROUPID}" ports: - "26656-26658:26656-26658" - "9090-9091:9090-9091" @@ -23,6 +24,7 @@ services: - "${PROJECT_HOME}/../sei-db:/sei-protocol/sei-db:Z" - "${PROJECT_HOME}/../go-ethereum:/sei-protocol/go-ethereum:Z" - "${GO_PKG_PATH}/mod:/root/go/pkg/mod:Z" + - "${GOCACHE}:/root/.cache/go-build:Z" networks: localnet: ipv4_address: 192.168.10.10 @@ -31,6 +33,7 @@ services: platform: linux/amd64 container_name: sei-node-1 image: "sei-chain/localnode" + user: "${USERID}:${GROUPID}" ports: - "26659-26661:26656-26658" - "9092-9093:9090-9091" @@ -48,6 +51,7 @@ services: - "${PROJECT_HOME}/../sei-db:/sei-protocol/sei-db:Z" - "${PROJECT_HOME}/../go-ethereum:/sei-protocol/go-ethereum:Z" - "${GO_PKG_PATH}/mod:/root/go/pkg/mod:Z" + - "${GOCACHE}:/root/.cache/go-build:Z" networks: localnet: ipv4_address: 192.168.10.11 @@ -56,6 +60,7 @@ services: platform: linux/amd64 container_name: sei-node-2 image: "sei-chain/localnode" + user: "${USERID}:${GROUPID}" environment: - ID=2 - CLUSTER_SIZE=4 @@ -73,6 +78,7 @@ services: - "${PROJECT_HOME}/../sei-db:/sei-protocol/sei-db:Z" - "${PROJECT_HOME}/../go-ethereum:/sei-protocol/go-ethereum:Z" - "${GO_PKG_PATH}/mod:/root/go/pkg/mod:Z" + - "${GOCACHE}:/root/.cache/go-build:Z" networks: localnet: ipv4_address: 192.168.10.12 @@ -81,6 +87,7 @@ services: platform: linux/amd64 container_name: sei-node-3 image: "sei-chain/localnode" + user: "${USERID}:${GROUPID}" environment: - ID=3 - CLUSTER_SIZE=4 @@ -98,6 +105,7 @@ services: - "${PROJECT_HOME}/../sei-db:/sei-protocol/sei-db:Z" - "${PROJECT_HOME}/../go-ethereum:/sei-protocol/go-ethereum:Z" - "${GO_PKG_PATH}/mod:/root/go/pkg/mod:Z" + - "${GOCACHE}:/root/.cache/go-build:Z" networks: localnet: ipv4_address: 192.168.10.13 diff --git a/docker/localnode/Dockerfile b/docker/localnode/Dockerfile index ca705b2b6..8b3c978e2 100644 --- a/docker/localnode/Dockerfile +++ b/docker/localnode/Dockerfile @@ -1,22 +1,16 @@ FROM ubuntu:latest +ENV HOME="/root" PATH="/root/go/bin:/sei-protocol/sei-chain/integration_test/upgrade_module/scripts/:$PATH" RUN apt-get update && \ - apt-get install -y make git wget build-essential jq python3 curl vim uuid-runtime -RUN rm -rf build/generated -RUN wget https://go.dev/dl/go1.22.4.linux-amd64.tar.gz -RUN tar -xvf go1.22.4.linux-amd64.tar.gz -RUN mv go /usr/local/ + apt-get install -y make git build-essential jq python3 curl vim uuid-runtime nodejs +RUN curl -L https://go.dev/dl/go1.22.4.linux-amd64.tar.gz | tar xvzf - -C /usr/local/ RUN curl -L https://foundry.paradigm.xyz | bash -RUN /root/.foundry/bin/foundryup RUN curl -sL https://deb.nodesource.com/setup_16.x | bash -RUN apt-get install -y nodejs -RUN mkdir -p /root/.config && \ - chmod -R 777 /root/.config +RUN /root/.foundry/bin/foundryup +RUN mkdir -p /root/go/pkg/mod && \ + mkdir -p /root/.cache && \ + chmod -R a+rwX /root SHELL ["/bin/bash", "-c"] - -VOLUME [ "/sei-protocol" ] -VOLUME [ "/root/go/pkg/mod" ] - WORKDIR /sei-protocol/sei-chain EXPOSE 26656 26657 26658 9090 9091 7171 @@ -33,4 +27,4 @@ COPY scripts/step3_add_validator_to_genesis.sh /usr/bin/add_validator_to_gensis. COPY scripts/step4_config_override.sh /usr/bin/config_override.sh COPY scripts/step5_start_sei.sh /usr/bin/start_sei.sh COPY scripts/step6_start_price_feeder.sh /usr/bin/start_price_feeder.sh -ENV PATH "$PATH:$HOME/go/bin:/sei-protocol/sei-chain/integration_test/upgrade_module/scripts/" + diff --git a/docker/localnode/scripts/deploy.sh b/docker/localnode/scripts/deploy.sh index 9591f2463..9a7502fd6 100755 --- a/docker/localnode/scripts/deploy.sh +++ b/docker/localnode/scripts/deploy.sh @@ -3,16 +3,16 @@ NODE_ID=${ID:-0} CLUSTER_SIZE=${CLUSTER_SIZE:-1} - # Clean up and env set up export GOPATH=$HOME/go export GOBIN=$GOPATH/bin export BUILD_PATH=/sei-protocol/sei-chain/build export PATH=$GOBIN:$PATH:/usr/local/go/bin:$BUILD_PATH -echo "export GOPATH=$HOME/go" >> /root/.bashrc -echo "GOBIN=$GOPATH/bin" >> /root/.bashrc -echo "export PATH=$GOBIN:$PATH:/usr/local/go/bin:$BUILD_PATH:/root/.foundry/bin" >> /root/.bashrc -/bin/bash -c "source /root/.bashrc" +echo "export GOPATH=$HOME/go" >> "$HOME/.bashrc" +echo "GOBIN=$GOPATH/bin" >> "$HOME/.bashrc" +echo "export PATH=$GOBIN:$PATH:/usr/local/go/bin:$BUILD_PATH:$HOME/.foundry/bin" >> "$HOME/.bashrc" +rm -rf build/generated +/bin/bash -c "source $HOME/.bashrc" mkdir -p $GOBIN # Step 0: Build on node 0 if [ "$NODE_ID" = 0 ] && [ -z "$SKIP_BUILD" ] diff --git a/docker/localnode/scripts/step6_start_price_feeder.sh b/docker/localnode/scripts/step6_start_price_feeder.sh index f4fdc5105..54deb7e6c 100755 --- a/docker/localnode/scripts/step6_start_price_feeder.sh +++ b/docker/localnode/scripts/step6_start_price_feeder.sh @@ -9,11 +9,11 @@ ORACLE_ACCOUNT="oracle" VALIDATOR_ACCOUNT="node_admin" # Create an oracle account -printf "12345678\n" | /root/go/bin/seid keys add $ORACLE_ACCOUNT --output json > /root/.sei/config/oracle_key.json -ORACLE_ACCOUNT_ADDRESS=$(printf "12345678\n" | /root/go/bin/seid keys show $ORACLE_ACCOUNT -a) -SEIVALOPER=$(printf "12345678\n" | /root/go/bin/seid keys show $VALIDATOR_ACCOUNT --bech=val -a) -printf "12345678\n" | /root/go/bin/seid tx oracle set-feeder "$ORACLE_ACCOUNT_ADDRESS" --from $VALIDATOR_ACCOUNT --fees 2000usei -b block -y --chain-id sei >/dev/null 2>&1 -printf "12345678\n" | /root/go/bin/seid tx bank send $VALIDATOR_ACCOUNT "$ORACLE_ACCOUNT_ADDRESS" --from $VALIDATOR_ACCOUNT 1000sei --fees 2000usei -b block -y >/dev/null 2>&1 +printf "12345678\n" | "$HOME/go/bin/seid" keys add $ORACLE_ACCOUNT --output json > "$HOME/.sei/config/oracle_key.json" +ORACLE_ACCOUNT_ADDRESS=$(printf "12345678\n" | "$HOME/go/bin/seid" keys show $ORACLE_ACCOUNT -a) +SEIVALOPER=$(printf "12345678\n" | "$HOME/go/bin/seid" keys show $VALIDATOR_ACCOUNT --bech=val -a) +printf "12345678\n" | "$HOME/go/bin/seid" tx oracle set-feeder "$ORACLE_ACCOUNT_ADDRESS" --from $VALIDATOR_ACCOUNT --fees 2000usei -b block -y --chain-id sei >/dev/null 2>&1 +printf "12345678\n" | "$HOME/go/bin/seid" tx bank send $VALIDATOR_ACCOUNT "$ORACLE_ACCOUNT_ADDRESS" --from $VALIDATOR_ACCOUNT 1000sei --fees 2000usei -b block -y >/dev/null 2>&1 sed -i.bak -e "s|^address *=.*|address = \"$ORACLE_ACCOUNT_ADDRESS\"|" $ORACLE_CONFIG_FILE diff --git a/docker/rpcnode/Dockerfile b/docker/rpcnode/Dockerfile index cf099206c..1b74d6a62 100644 --- a/docker/rpcnode/Dockerfile +++ b/docker/rpcnode/Dockerfile @@ -1,13 +1,13 @@ FROM ubuntu:latest +ENV HOME="/root" PATH="/root/go/bin:$PATH" RUN apt-get update && \ - apt-get install -y make git wget build-essential jq python3 curl vim uuid-runtime -RUN wget https://go.dev/dl/go1.21.4.linux-amd64.tar.gz -RUN tar -xvf go1.21.4.linux-amd64.tar.gz -RUN mv go /usr/local/ + apt-get install -y make git build-essential jq python3 curl vim uuid-runtime +RUN curl -L https://go.dev/dl/go1.21.4.linux-amd64.tar.gz | tar xvzf - -C /usr/local/ +RUN mkdir -p /root/go/pkg/mod && \ + mkdir -p /root/.cache && \ + chmod -R a+rwX /root SHELL ["/bin/bash", "-c"] -VOLUME [ "/sei-protocol" ] -VOLUME [ "/root/go/pkg/mod" ] WORKDIR /sei-protocol/sei-chain EXPOSE 26656 26657 26658 9090 9091 @@ -20,4 +20,3 @@ COPY scripts/deploy.sh /usr/bin/deploy.sh COPY scripts/step0_build.sh /usr/bin/build.sh COPY scripts/step1_configure_init.sh /usr/bin/configure_init.sh COPY scripts/step2_start_sei.sh /usr/bin/start_sei.sh -ENV PATH "$PATH:$HOME/go/bin" From c2d792580503935a37c7fe8b37145cd9e6320a40 Mon Sep 17 00:00:00 2001 From: codchen Date: Mon, 12 Aug 2024 22:14:58 +0800 Subject: [PATCH 11/38] Bump nonce even if tx fails (#1778) --- app/ante.go | 2 +- x/evm/ante/basic.go | 18 ++++++++++++++++-- x/evm/ante/basic_test.go | 4 ++-- x/evm/integration_test.go | 36 ++++++++++++++++++++++++++++++++++++ 4 files changed, 55 insertions(+), 5 deletions(-) diff --git a/app/ante.go b/app/ante.go index 3106816df..7b60e9191 100644 --- a/app/ante.go +++ b/app/ante.go @@ -118,7 +118,7 @@ func NewAnteHandlerAndDepGenerator(options HandlerOptions) (sdk.AnteHandler, sdk evmAnteDecorators := []sdk.AnteFullDecorator{ evmante.NewEVMPreprocessDecorator(options.EVMKeeper, options.EVMKeeper.AccountKeeper()), - sdk.DefaultWrappedAnteDecorator(evmante.NewBasicDecorator()), + sdk.DefaultWrappedAnteDecorator(evmante.NewBasicDecorator(options.EVMKeeper)), sdk.DefaultWrappedAnteDecorator(evmante.NewEVMFeeCheckDecorator(options.EVMKeeper)), sdk.DefaultWrappedAnteDecorator(evmante.NewEVMSigVerifyDecorator(options.EVMKeeper, options.LatestCtxGetter)), sdk.DefaultWrappedAnteDecorator(evmante.NewGasLimitDecorator(options.EVMKeeper)), diff --git a/x/evm/ante/basic.go b/x/evm/ante/basic.go index f3f7b45d0..7185a1566 100644 --- a/x/evm/ante/basic.go +++ b/x/evm/ante/basic.go @@ -9,14 +9,16 @@ import ( ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" + "github.com/sei-protocol/sei-chain/x/evm/keeper" evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" ) type BasicDecorator struct { + k *keeper.Keeper } -func NewBasicDecorator() *BasicDecorator { - return &BasicDecorator{} +func NewBasicDecorator(k *keeper.Keeper) *BasicDecorator { + return &BasicDecorator{k} } // cherrypicked from go-ethereum:txpool:ValidateTransaction @@ -24,6 +26,18 @@ func (gl BasicDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, n msg := evmtypes.MustGetEVMTransactionMessage(tx) etx, _ := msg.AsTransaction() + if msg.Derived != nil && !gl.k.EthReplayConfig.Enabled && !gl.k.EthBlockTestConfig.Enabled { + startingNonce := gl.k.GetNonce(ctx, msg.Derived.SenderEVMAddr) + if !ctx.IsCheckTx() && !ctx.IsReCheckTx() { + ctx = ctx.WithDeliverTxCallback(func(callCtx sdk.Context) { + // bump nonce if it is for some reason not incremented (e.g. ante failure) + if gl.k.GetNonce(callCtx, msg.Derived.SenderEVMAddr) == startingNonce { + gl.k.SetNonce(callCtx, msg.Derived.SenderEVMAddr, startingNonce+1) + } + }) + } + } + if etx.To() == nil && len(etx.Data()) > params.MaxInitCodeSize { return ctx, fmt.Errorf("%w: code size %v, limit %v", core.ErrMaxInitCodeSizeExceeded, len(etx.Data()), params.MaxInitCodeSize) } diff --git a/x/evm/ante/basic_test.go b/x/evm/ante/basic_test.go index c7d5255f0..d1976c87e 100644 --- a/x/evm/ante/basic_test.go +++ b/x/evm/ante/basic_test.go @@ -14,8 +14,8 @@ import ( ) func TestBasicDecorator(t *testing.T) { - _, ctx := testkeeper.MockEVMKeeper() - a := ante.NewBasicDecorator() + k, ctx := testkeeper.MockEVMKeeper() + a := ante.NewBasicDecorator(k) msg, _ := types.NewMsgEVMTransaction(ðtx.LegacyTx{}) ctx, err := a.AnteHandle(ctx, &mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { return ctx, nil diff --git a/x/evm/integration_test.go b/x/evm/integration_test.go index fc1756559..29eb74ab2 100644 --- a/x/evm/integration_test.go +++ b/x/evm/integration_test.go @@ -246,3 +246,39 @@ func TestCW2981PointerToERC2981(t *testing.T) { require.Nil(t, err) require.Equal(t, fmt.Sprintf("{\"address\":\"%s\",\"royalty_amount\":\"1000\"}", seiAddr.String()), string(ret)) } + +func TestNonceIncrementsForInsufficientFunds(t *testing.T) { + k := testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) + privKey := testkeeper.MockPrivateKey() + seiAddr, evmAddr := testkeeper.PrivateKeyToAddresses(privKey) + k.SetAddressMapping(ctx, seiAddr, evmAddr) + testPrivHex := hex.EncodeToString(privKey.Bytes()) + key, _ := crypto.HexToECDSA(testPrivHex) + txData := ethtypes.LegacyTx{ + Nonce: 0, + GasPrice: big.NewInt(100000000000), + Gas: 5000000, + To: nil, + Data: []byte{}, + } + chainID := k.ChainID(ctx) + chainCfg := types.DefaultChainConfig() + ethCfg := chainCfg.EthereumConfig(chainID) + blockNum := big.NewInt(ctx.BlockHeight()) + signer := ethtypes.MakeSigner(ethCfg, blockNum, uint64(ctx.BlockTime().Unix())) + tx, err := ethtypes.SignTx(ethtypes.NewTx(&txData), signer, key) + require.Nil(t, err) + typedTx, err := ethtx.NewLegacyTx(tx) + require.Nil(t, err) + msg, err := types.NewMsgEVMTransaction(typedTx) + require.Nil(t, err) + txBuilder := testkeeper.EVMTestApp.GetTxConfig().NewTxBuilder() + txBuilder.SetMsgs(msg) + cosmosTx := txBuilder.GetTx() + txbz, err := testkeeper.EVMTestApp.GetTxConfig().TxEncoder()(cosmosTx) + require.Nil(t, err) + res := testkeeper.EVMTestApp.DeliverTx(ctx, abci.RequestDeliverTx{Tx: txbz}, cosmosTx, sha256.Sum256(txbz)) + require.Equal(t, uint32(5), res.Code) // insufficient funds has error code 5 + require.Equal(t, uint64(1), k.GetNonce(ctx, evmAddr)) // make sure nonce is incremented regardless +} From fc36b39ec4f793d94173919c8704a7b470a2956f Mon Sep 17 00:00:00 2001 From: codchen Date: Tue, 13 Aug 2024 23:05:28 +0800 Subject: [PATCH 12/38] Allow CW->ERC pointers to be called through wasmd precompile (#1785) --- app/receipt_test.go | 3 +++ contracts/test/CW20toERC20PointerTest.js | 21 +++++++++++++++++ evmrpc/simulate.go | 18 ++++++++++---- precompiles/wasmd/wasmd.go | 16 ++++++++++--- precompiles/wasmd/wasmd_test.go | 1 + x/evm/keeper/evm.go | 21 +++++++++++++++-- x/evm/keeper/msg_server.go | 30 +++++++++++++++++++++++- x/evm/keeper/receipt.go | 5 ++++ 8 files changed, 105 insertions(+), 10 deletions(-) diff --git a/app/receipt_test.go b/app/receipt_test.go index ec791cef7..625818286 100644 --- a/app/receipt_test.go +++ b/app/receipt_test.go @@ -110,10 +110,12 @@ func TestEvmEventsForCw20(t *testing.T) { tx = txBuilder.GetTx() txbz, err = testkeeper.EVMTestApp.GetTxConfig().TxEncoder()(tx) require.Nil(t, err) + sum = sha256.Sum256(txbz) res = testkeeper.EVMTestApp.DeliverTx(ctx.WithEventManager(sdk.NewEventManager()).WithTxIndex(1), abci.RequestDeliverTx{Tx: txbz}, tx, sum) require.Equal(t, uint32(0), res.Code) receipt, err = testkeeper.EVMTestApp.EvmKeeper.GetTransientReceipt(ctx, signedTx.Hash()) require.Nil(t, err) + fmt.Println(receipt.Logs) require.Equal(t, 1, len(receipt.Logs)) require.NotEmpty(t, receipt.LogsBloom) require.Equal(t, mockPointerAddr.Hex(), receipt.Logs[0].Address) @@ -225,6 +227,7 @@ func TestEvmEventsForCw721(t *testing.T) { tx = txBuilder.GetTx() txbz, err = testkeeper.EVMTestApp.GetTxConfig().TxEncoder()(tx) require.Nil(t, err) + sum = sha256.Sum256(txbz) res = testkeeper.EVMTestApp.DeliverTx(ctx.WithEventManager(sdk.NewEventManager()).WithTxIndex(1), abci.RequestDeliverTx{Tx: txbz}, tx, sum) require.Equal(t, uint32(0), res.Code) receipt, err = testkeeper.EVMTestApp.EvmKeeper.GetTransientReceipt(ctx, signedTx.Hash()) diff --git a/contracts/test/CW20toERC20PointerTest.js b/contracts/test/CW20toERC20PointerTest.js index 8c695260e..0638aa38f 100644 --- a/contracts/test/CW20toERC20PointerTest.js +++ b/contracts/test/CW20toERC20PointerTest.js @@ -164,6 +164,27 @@ describe("CW20 to ERC20 Pointer", function () { const balanceAfter = respAfter.data.balance; expect(balanceAfter).to.equal((parseInt(balanceBefore) - 100).toString()); }); + + it("should transfer if called through wasmd precompile", async function() { + const WasmPrecompileContract = '0x0000000000000000000000000000000000001002'; + const contractABIPath = '../../precompiles/wasmd/abi.json'; + const contractABI = require(contractABIPath); + wasmd = new ethers.Contract(WasmPrecompileContract, contractABI, accounts[0].signer); + + const encoder = new TextEncoder(); + + const transferMsg = { transfer: { recipient: accounts[1].seiAddress, amount: "100" } }; + const transferStr = JSON.stringify(transferMsg); + const transferBz = encoder.encode(transferStr); + + const coins = []; + const coinsStr = JSON.stringify(coins); + const coinsBz = encoder.encode(coinsStr); + + const response = await wasmd.execute(pointer, transferBz, coinsBz); + const receipt = await response.wait(); + expect(receipt.status).to.equal(1); + }); }); }); } diff --git a/evmrpc/simulate.go b/evmrpc/simulate.go index 428ebc0ac..e78c500f3 100644 --- a/evmrpc/simulate.go +++ b/evmrpc/simulate.go @@ -8,6 +8,7 @@ import ( "strings" "time" + "github.com/sei-protocol/sei-chain/precompiles/wasmd" "github.com/sei-protocol/sei-chain/utils/helpers" sdk "github.com/cosmos/cosmos-sdk/types" @@ -34,6 +35,10 @@ import ( "github.com/tendermint/tendermint/rpc/coretypes" ) +type CtxIsWasmdPrecompileCallKeyType string + +const CtxIsWasmdPrecompileCallKey CtxIsWasmdPrecompileCallKeyType = "CtxIsWasmdPrecompileCallKey" + type SimulationAPI struct { backend *Backend connectionType ConnectionType @@ -66,6 +71,7 @@ func (s *SimulationAPI) CreateAccessList(ctx context.Context, args ethapi.Transa if blockNrOrHash != nil { bNrOrHash = *blockNrOrHash } + ctx = context.WithValue(ctx, CtxIsWasmdPrecompileCallKey, wasmd.IsWasmdCall(args.To)) acl, gasUsed, vmerr, err := ethapi.AccessList(ctx, s.backend, bNrOrHash, args) if err != nil { return nil, err @@ -84,6 +90,7 @@ func (s *SimulationAPI) EstimateGas(ctx context.Context, args ethapi.Transaction if blockNrOrHash != nil { bNrOrHash = *blockNrOrHash } + ctx = context.WithValue(ctx, CtxIsWasmdPrecompileCallKey, wasmd.IsWasmdCall(args.To)) estimate, err := ethapi.DoEstimateGas(ctx, s.backend, args, bNrOrHash, overrides, s.backend.RPCGasCap()) return estimate, err } @@ -104,6 +111,7 @@ func (s *SimulationAPI) Call(ctx context.Context, args ethapi.TransactionArgs, b latest := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber) blockNrOrHash = &latest } + ctx = context.WithValue(ctx, CtxIsWasmdPrecompileCallKey, wasmd.IsWasmdCall(args.To)) callResult, err := ethapi.DoCall(ctx, s.backend, args, *blockNrOrHash, overrides, blockOverrides, s.backend.RPCEVMTimeout(), s.backend.RPCGasCap()) if err != nil { return nil, err @@ -176,11 +184,12 @@ func (b *Backend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHas if err != nil { return nil, nil, err } - sdkCtx := b.ctxProvider(height) + isWasmdCall, ok := ctx.Value(CtxIsWasmdPrecompileCallKey).(bool) + sdkCtx := b.ctxProvider(height).WithIsEVM(true).WithEVMEntryViaWasmdPrecompile(ok && isWasmdCall) if err := CheckVersion(sdkCtx, b.keeper); err != nil { return nil, nil, err } - return state.NewDBImpl(b.ctxProvider(height), b.keeper, true), b.getHeader(big.NewInt(height)), nil + return state.NewDBImpl(sdkCtx, b.keeper, true), b.getHeader(big.NewInt(height)), nil } func (b *Backend) GetTransaction(ctx context.Context, txHash common.Hash) (tx *ethtypes.Transaction, blockHash common.Hash, blockNumber uint64, index uint64, err error) { @@ -291,7 +300,7 @@ func (b *Backend) StateAtTransaction(ctx context.Context, block *ethtypes.Block, // get the parent block using block.parentHash prevBlockHeight := block.Number().Int64() - 1 // Get statedb of parent block from the store - statedb := state.NewDBImpl(b.ctxProvider(prevBlockHeight), b.keeper, true) + statedb := state.NewDBImpl(b.ctxProvider(prevBlockHeight).WithIsEVM(true), b.keeper, true) if txIndex == 0 && len(block.Transactions()) == 0 { return nil, vm.BlockContext{}, statedb, emptyRelease, nil } @@ -329,6 +338,7 @@ func (b *Backend) StateAtTransaction(ctx context.Context, block *ethtypes.Block, if idx == txIndex { return tx, *blockContext, statedb, emptyRelease, nil } + statedb.WithCtx(statedb.Ctx().WithEVMEntryViaWasmdPrecompile(wasmd.IsWasmdCall(tx.To()))) // Not yet the searched for transaction, execute on top of the current state vmenv := vm.NewEVM(*blockContext, txContext, statedb, b.ChainConfig(), vm.Config{}) statedb.SetTxContext(tx.Hash(), idx) @@ -371,7 +381,7 @@ func (b *Backend) StateAtBlock(ctx context.Context, block *ethtypes.Block, reexe func (b *Backend) GetEVM(_ context.Context, msg *core.Message, stateDB vm.StateDB, _ *ethtypes.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) *vm.EVM { txContext := core.NewEVMTxContext(msg) if blockCtx == nil { - blockCtx, _ = b.keeper.GetVMBlockContext(b.ctxProvider(LatestCtxHeight), core.GasPool(b.RPCGasCap())) + blockCtx, _ = b.keeper.GetVMBlockContext(b.ctxProvider(LatestCtxHeight).WithIsEVM(true).WithEVMEntryViaWasmdPrecompile(wasmd.IsWasmdCall(msg.To)), core.GasPool(b.RPCGasCap())) } return vm.NewEVM(*blockCtx, txContext, stateDB, b.ChainConfig(), *vmConfig) } diff --git a/precompiles/wasmd/wasmd.go b/precompiles/wasmd/wasmd.go index 279132e8d..d28f00684 100644 --- a/precompiles/wasmd/wasmd.go +++ b/precompiles/wasmd/wasmd.go @@ -27,6 +27,8 @@ const ( const WasmdAddress = "0x0000000000000000000000000000000000001002" +var Address = common.HexToAddress(WasmdAddress) + // Embed abi json file to the executable binary. Needed when importing as dependency. // //go:embed abi.json @@ -51,15 +53,19 @@ type ExecuteMsg struct { Coins []byte `json:"coins"` } +func GetABI() abi.ABI { + return pcommon.MustGetABI(f, "abi.json") +} + func NewPrecompile(evmKeeper pcommon.EVMKeeper, wasmdKeeper pcommon.WasmdKeeper, wasmdViewKeeper pcommon.WasmdViewKeeper, bankKeeper pcommon.BankKeeper) (*pcommon.DynamicGasPrecompile, error) { - newAbi := pcommon.MustGetABI(f, "abi.json") + newAbi := GetABI() executor := &PrecompileExecutor{ wasmdKeeper: wasmdKeeper, wasmdViewKeeper: wasmdViewKeeper, evmKeeper: evmKeeper, bankKeeper: bankKeeper, - address: common.HexToAddress(WasmdAddress), + address: Address, } for name, m := range newAbi.Methods { @@ -74,7 +80,7 @@ func NewPrecompile(evmKeeper pcommon.EVMKeeper, wasmdKeeper pcommon.WasmdKeeper, executor.QueryID = m.ID } } - return pcommon.NewDynamicGasPrecompile(newAbi, executor, common.HexToAddress(WasmdAddress), "wasmd"), nil + return pcommon.NewDynamicGasPrecompile(newAbi, executor, Address, "wasmd"), nil } func (p PrecompileExecutor) Execute(ctx sdk.Context, method *abi.Method, caller common.Address, callingContract common.Address, args []interface{}, value *big.Int, readOnly bool, evm *vm.EVM, suppliedGas uint64) (ret []byte, remainingGas uint64, err error) { @@ -452,3 +458,7 @@ func (p PrecompileExecutor) query(ctx sdk.Context, method *abi.Method, args []in remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) return } + +func IsWasmdCall(to *common.Address) bool { + return to != nil && (to.Cmp(Address) == 0) +} diff --git a/precompiles/wasmd/wasmd_test.go b/precompiles/wasmd/wasmd_test.go index b653ed14d..1e6670c51 100644 --- a/precompiles/wasmd/wasmd_test.go +++ b/precompiles/wasmd/wasmd_test.go @@ -154,6 +154,7 @@ func TestExecute(t *testing.T) { testApp.BankKeeper.SendCoins(ctx, mockAddr, testApp.EvmKeeper.GetSeiAddressOrDefault(ctx, common.HexToAddress(wasmd.WasmdAddress)), amts) // circular interop statedb.WithCtx(statedb.Ctx().WithIsEVM(false)) + testApp.EvmKeeper.SetCode(statedb.Ctx(), mockEVMAddr, []byte{1, 2, 3}) res, _, err := p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.GetExecutor().(*wasmd.PrecompileExecutor).ExecuteID, args...), suppliedGas, big.NewInt(1000_000_000_000_000), nil, false) require.Equal(t, "sei does not support CW->EVM->CW call pattern", string(res)) require.Equal(t, vm.ErrExecutionReverted, err) diff --git a/x/evm/keeper/evm.go b/x/evm/keeper/evm.go index 97695dc14..147912140 100644 --- a/x/evm/keeper/evm.go +++ b/x/evm/keeper/evm.go @@ -73,7 +73,7 @@ func (k *Keeper) HandleInternalEVMDelegateCall(ctx sdk.Context, req *types.MsgIn } func (k *Keeper) CallEVM(ctx sdk.Context, from common.Address, to *common.Address, val *sdk.Int, data []byte) (retdata []byte, reterr error) { - if ctx.IsEVM() { + if ctx.IsEVM() && !ctx.EVMEntryViaWasmdPrecompile() { return nil, errors.New("sei does not support EVM->CW->EVM call pattern") } if to == nil && len(data) > params.MaxInitCodeSize { @@ -87,7 +87,7 @@ func (k *Keeper) CallEVM(ctx sdk.Context, from common.Address, to *common.Addres value = val.BigInt() } // This call was not part of an existing StateTransition, so it should trigger one - executionCtx := ctx.WithGasMeter(sdk.NewInfiniteGasMeterWithMultiplier(ctx)) + executionCtx := ctx.WithGasMeter(sdk.NewInfiniteGasMeterWithMultiplier(ctx)).WithEVMEntryViaWasmdPrecompile(false) stateDB := state.NewDBImpl(executionCtx, k, false) gp := k.GetGasPool() evmMsg := &core.Message{ @@ -118,6 +118,23 @@ func (k *Keeper) CallEVM(ctx sdk.Context, from common.Address, to *common.Addres if res.Err != nil { vmErr = res.Err.Error() } + existingReceipt, err := k.GetTransientReceipt(ctx, ctx.TxSum()) + if err == nil { + for _, l := range existingReceipt.Logs { + stateDB.AddLog(ðtypes.Log{ + Address: common.HexToAddress(l.Address), + Topics: utils.Map(l.Topics, common.HexToHash), + Data: l.Data, + }) + } + if existingReceipt.VmError != "" { + vmErr = fmt.Sprintf("%s\n%s\n", existingReceipt.VmError, vmErr) + } + } + existingDeferredInfo, found := k.GetEVMTxDeferredInfo(ctx) + if found { + surplus = surplus.Add(existingDeferredInfo.Surplus) + } receipt, err := k.WriteReceipt(ctx, stateDB, evmMsg, ethtypes.LegacyTxType, ctx.TxSum(), res.UsedGas, vmErr) if err != nil { return nil, err diff --git a/x/evm/keeper/msg_server.go b/x/evm/keeper/msg_server.go index 293c62e14..358a9f001 100644 --- a/x/evm/keeper/msg_server.go +++ b/x/evm/keeper/msg_server.go @@ -21,6 +21,8 @@ import ( "github.com/ethereum/go-ethereum/core" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" + "github.com/sei-protocol/sei-chain/precompiles/wasmd" + "github.com/sei-protocol/sei-chain/utils" "github.com/sei-protocol/sei-chain/x/evm/artifacts/erc20" "github.com/sei-protocol/sei-chain/x/evm/artifacts/erc721" "github.com/sei-protocol/sei-chain/x/evm/state" @@ -45,6 +47,11 @@ func (server msgServer) EVMTransaction(goCtx context.Context, msg *types.MsgEVMT return &types.MsgEVMTransactionResponse{}, nil } ctx := sdk.UnwrapSDKContext(goCtx) + tx, _ := msg.AsTransaction() + isWasmdPrecompileCall := wasmd.IsWasmdCall(tx.To()) + if isWasmdPrecompileCall { + ctx = ctx.WithEVMEntryViaWasmdPrecompile(true) + } // EVM has a special case here, mainly because for an EVM transaction the gas limit is set on EVM payload level, not on top-level GasWanted field // as normal transactions (because existing eth client can't). As a result EVM has its own dedicated ante handler chain. The full sequence is: @@ -56,7 +63,6 @@ func (server msgServer) EVMTransaction(goCtx context.Context, msg *types.MsgEVMT ctx = ctx.WithGasMeter(sdk.NewInfiniteGasMeterWithMultiplier(ctx)) stateDB := state.NewDBImpl(ctx, &server, false) - tx, _ := msg.AsTransaction() emsg := server.GetEVMMessage(ctx, tx, msg.Derived.SenderEVMAddr) gp := server.GetGasPool() @@ -82,6 +88,27 @@ func (server msgServer) EVMTransaction(goCtx context.Context, msg *types.MsgEVMT ) return } + extraSurplus := sdk.ZeroInt() + if isWasmdPrecompileCall { + syntheticReceipt, err := server.GetTransientReceipt(ctx, ctx.TxSum()) + if err == nil { + for _, l := range syntheticReceipt.Logs { + stateDB.AddLog(ðtypes.Log{ + Address: common.HexToAddress(l.Address), + Topics: utils.Map(l.Topics, common.HexToHash), + Data: l.Data, + }) + } + if syntheticReceipt.VmError != "" { + serverRes.VmError = fmt.Sprintf("%s\n%s\n", serverRes.VmError, syntheticReceipt.VmError) + } + server.DeleteTransientReceipt(ctx, ctx.TxSum()) + } + syntheticDeferredInfo, found := server.GetEVMTxDeferredInfo(ctx) + if found { + extraSurplus = extraSurplus.Add(syntheticDeferredInfo.Surplus) + } + } receipt, rerr := server.WriteReceipt(ctx, stateDB, emsg, uint32(tx.Type()), tx.Hash(), serverRes.GasUsed, serverRes.VmError) if rerr != nil { err = rerr @@ -118,6 +145,7 @@ func (server msgServer) EVMTransaction(goCtx context.Context, msg *types.MsgEVMT ) return } + surplus = surplus.Add(extraSurplus) bloom := ethtypes.Bloom{} bloom.SetBytes(receipt.LogsBloom) server.AppendToEvmTxDeferredInfo(ctx, bloom, tx.Hash(), surplus) diff --git a/x/evm/keeper/receipt.go b/x/evm/keeper/receipt.go index fa2c79e2b..1f0134209 100644 --- a/x/evm/keeper/receipt.go +++ b/x/evm/keeper/receipt.go @@ -41,6 +41,11 @@ func (k *Keeper) GetTransientReceipt(ctx sdk.Context, txHash common.Hash) (*type return r, nil } +func (k *Keeper) DeleteTransientReceipt(ctx sdk.Context, txHash common.Hash) { + store := ctx.TransientStore(k.transientStoreKey) + store.Delete(types.ReceiptKey(txHash)) +} + // GetReceipt returns a data structure that stores EVM specific transaction metadata. // Many EVM applications (e.g. MetaMask) relies on being on able to query receipt // by EVM transaction hash (not Sei transaction hash) to function properly. From a901610225fbc7d05a124edb9fa05d2926e1b607 Mon Sep 17 00:00:00 2001 From: bt <99624770+besated@users.noreply.github.com> Date: Tue, 13 Aug 2024 10:35:01 -0700 Subject: [PATCH 13/38] Add basic LST integration tests (#1814) * Add test setup * Add tests for bonding and unbonding * Add steak tests to test script * Fix wasm path * Combine bonding and unbonding tests * Fix json strings --- integration_test/dapp_tests/dapp_tests.sh | 1 + integration_test/dapp_tests/package-lock.json | 28 ++- integration_test/dapp_tests/package.json | 3 +- .../dapp_tests/steak/SteakTests.js | 165 ++++++++++++++++++ .../dapp_tests/steak/contracts/steak_hub.wasm | Bin 0 -> 421959 bytes .../steak/contracts/steak_token.wasm | Bin 0 -> 331107 bytes integration_test/dapp_tests/steak/utils.js | 154 ++++++++++++++++ 7 files changed, 341 insertions(+), 10 deletions(-) create mode 100644 integration_test/dapp_tests/steak/SteakTests.js create mode 100644 integration_test/dapp_tests/steak/contracts/steak_hub.wasm create mode 100644 integration_test/dapp_tests/steak/contracts/steak_token.wasm create mode 100644 integration_test/dapp_tests/steak/utils.js diff --git a/integration_test/dapp_tests/dapp_tests.sh b/integration_test/dapp_tests/dapp_tests.sh index a824b88dd..6fcd2d24e 100755 --- a/integration_test/dapp_tests/dapp_tests.sh +++ b/integration_test/dapp_tests/dapp_tests.sh @@ -12,3 +12,4 @@ npm ci npx hardhat compile npx hardhat test --network seilocal uniswap/uniswapTest.js +npx hardhat test --network seilocal steak/SteakTests.js \ No newline at end of file diff --git a/integration_test/dapp_tests/package-lock.json b/integration_test/dapp_tests/package-lock.json index 584964141..014b92e2d 100644 --- a/integration_test/dapp_tests/package-lock.json +++ b/integration_test/dapp_tests/package-lock.json @@ -1,11 +1,11 @@ { - "name": "uniswapv3-deployment", + "name": "dapp-tests", "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "uniswapv3-deployment", + "name": "dapp-tests", "version": "1.0.0", "license": "MIT", "dependencies": { @@ -18,7 +18,8 @@ "@uniswap/v3-periphery": "^1.4.4", "chai": "^4.2.0", "ethers": "^5.7.2", - "hardhat": "^2.22.6" + "hardhat": "^2.22.6", + "uuid": "^10.0.0" } }, "node_modules/@babel/runtime": { @@ -6322,7 +6323,6 @@ "version": "4.0.5", "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.5.tgz", "integrity": "sha512-HTm14iMQKK2FjFLRTM5lAVcyaUzOnqbPtesFIvREgXpJHdQm8bWS+GkQgIkfaBYRHuCnea7w8UVNfwiAQhlr9A==", - "hasInstallScript": true, "optional": true, "peer": true, "dependencies": { @@ -6685,7 +6685,6 @@ "version": "5.0.7", "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.7.tgz", "integrity": "sha512-vLt1O5Pp+flcArHGIyKEQq883nBt8nN8tVBcoL0qUXj2XT1n7p70yGIq2VK98I5FdZ1YHc0wk/koOnHjnXWk1Q==", - "hasInstallScript": true, "optional": true, "peer": true, "dependencies": { @@ -7021,6 +7020,14 @@ "node": ">=4" } }, + "node_modules/hardhat/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -10375,10 +10382,13 @@ } }, "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "license": "MIT", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], "bin": { "uuid": "dist/bin/uuid" } diff --git a/integration_test/dapp_tests/package.json b/integration_test/dapp_tests/package.json index 65b41c04d..9aaf4a0f7 100644 --- a/integration_test/dapp_tests/package.json +++ b/integration_test/dapp_tests/package.json @@ -15,6 +15,7 @@ "@uniswap/v3-periphery": "^1.4.4", "chai": "^4.2.0", "ethers": "^5.7.2", - "hardhat": "^2.22.6" + "hardhat": "^2.22.6", + "uuid": "^10.0.0" } } diff --git a/integration_test/dapp_tests/steak/SteakTests.js b/integration_test/dapp_tests/steak/SteakTests.js new file mode 100644 index 000000000..6186501c2 --- /dev/null +++ b/integration_test/dapp_tests/steak/SteakTests.js @@ -0,0 +1,165 @@ +const { + storeWasm, + deployErc20PointerForCw20, + ABI, + getEvmAddress, + fundSeiAddress, + associateKey, +} = require("../../../contracts/test/lib.js"); +const { + getValidators, + instantiateHubContract, + bond, + addAccount, + queryTokenBalance, + unbond, + transferTokens, +} = require("./utils.js"); + +const { expect } = require("chai"); +const { v4: uuidv4 } = require("uuid"); + +const STEAK_HUB_WASM = + "../integration_test/dapp_tests/steak/contracts/steak_hub.wasm"; +const STEAK_TOKEN_WASM = + "../integration_test/dapp_tests/steak/contracts/steak_token.wasm"; + +describe("Steak", async function () { + let owner; + let hubAddress; + let tokenAddress; + let tokenPointer; + + async function setupAccount(baseName, associate = true) { + const uniqueName = `${baseName}-${uuidv4()}`; + const account = await addAccount(uniqueName); + await fundSeiAddress(account.address); + if (associate) { + await associateKey(account.address); + } + return account; + } + + async function deployContracts(ownerAddress) { + // Store CW20 token wasm + const tokenCodeId = await storeWasm(STEAK_TOKEN_WASM); + + // Store Hub contract + const hubCodeId = await storeWasm(STEAK_HUB_WASM); + + // 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 + ); + 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 () { + // Set up the owner account + owner = await setupAccount("steak-owner"); + + // 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); + }); + + it("Unassociated account should be able to bond", async function () { + const unassociatedAccount = await setupAccount("unassociated", false); + // 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); + 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); + }); + }); +}); diff --git a/integration_test/dapp_tests/steak/contracts/steak_hub.wasm b/integration_test/dapp_tests/steak/contracts/steak_hub.wasm new file mode 100644 index 0000000000000000000000000000000000000000..26680f9439f9ef35e2136cb1bb78295f80500ef3 GIT binary patch literal 421959 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%0A0Cg!s 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 z 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�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 D2mow@ literal 0 HcmV?d00001 diff --git a/integration_test/dapp_tests/steak/contracts/steak_token.wasm b/integration_test/dapp_tests/steak/contracts/steak_token.wasm new file mode 100644 index 0000000000000000000000000000000000000000..d8f096ffb7a03ce45bde4b950a0659de09f84845 GIT binary patch literal 331107 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 { + return Buffer.from(JSON.stringify(obj)).toString("base64"); +}; + +const getValidators = async () => { + const command = `seid q staking validators --output json`; + const output = await execute(command); + const response = JSON.parse(output); + return response.validators.map((v) => v.operator_address); +}; + +const getCodeIdFromContractAddress = async (contractAddress) => { + const command = `seid q wasm contract ${contractAddress} --output json`; + const output = await execute(command); + const response = JSON.parse(output); + return response.contract_info.code_id; +}; + +// Note: Not using the `deployWasm` function because we need to retrieve the +// hub and token contract addresses from the event logs +const instantiateHubContract = async ( + codeId, + adminAddress, + instantiateMsg, + label +) => { + const jsonString = JSON.stringify(instantiateMsg).replace(/"/g, '\\"'); + const command = `seid tx wasm instantiate ${codeId} "${jsonString}" --label ${label} --admin ${adminAddress} --from admin --gas=5000000 --fees=1000000usei -y --broadcast-mode block -o json`; + const output = await execute(command); + const response = JSON.parse(output); + // Get all attributes with _contractAddress + if (!response.logs || response.logs.length === 0) { + throw new Error("logs not returned"); + } + const addresses = []; + for (let event of response.logs[0].events) { + if (event.type === "instantiate") { + for (let attribute of event.attributes) { + if (attribute.key === "_contract_address") { + addresses.push(attribute.value); + } + } + } + } + + // Return hub and token contracts + const contracts = {}; + for (let address of addresses) { + const contractCodeId = await getCodeIdFromContractAddress(address); + if (contractCodeId === `${codeId}`) { + contracts.hubContract = address; + } else { + contracts.tokenContract = address; + } + } + return contracts; +}; + +const bond = async (contractAddress, address, amount) => { + const msg = { + 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 output = await execute(command); + const response = JSON.parse(output); + if (response.code !== 0) { + throw new Error(response.raw_log); + } + return response; +}; + +const unbond = async (hubAddress, tokenAddress, address, amount) => { + const msg = { + send: { + contract: hubAddress, + amount: `${amount}`, + msg: encodeBase64({ + queue_unbond: {}, + }), + }, + }; + const jsonString = JSON.stringify(msg).replace(/"/g, '\\"'); + const command = `seid tx wasm execute ${tokenAddress} "${jsonString}" --from=${address} --gas=500000 --gas-prices=0.1usei --broadcast-mode=block -y --output=json`; + const output = await execute(command); + const response = JSON.parse(output); + if (response.code !== 0) { + throw new Error(response.raw_log); + } + return response; +}; + +const harvest = async (contractAddress, address) => { + const msg = { + harvest: {}, + }; + const jsonString = JSON.stringify(msg).replace(/"/g, '\\"'); + const command = `seid tx wasm execute ${contractAddress} "${jsonString}" --from=${address} --gas=500000 --gas-prices=0.1usei --broadcast-mode=block -y --output=json`; + const output = await execute(command); + const response = JSON.parse(output); + if (response.code !== 0) { + throw new Error(response.raw_log); + } + return response; +}; + +const queryTokenBalance = async (contractAddress, address) => { + const msg = { + balance: { + address, + }, + }; + const jsonString = JSON.stringify(msg).replace(/"/g, '\\"'); + const command = `seid q wasm contract-state smart ${contractAddress} "${jsonString}" --output=json`; + const output = await execute(command); + const response = JSON.parse(output); + return response.data.balance; +}; + +const addAccount = async (accountName) => { + const command = `seid keys add ${accountName}-${Date.now()} --output=json`; + const output = await execute(command); + return JSON.parse(output); +}; + +const transferTokens = async (tokenAddress, sender, destination, amount) => { + const msg = { + transfer: { + recipient: destination, + amount: `${amount}`, + }, + }; + const jsonString = JSON.stringify(msg).replace(/"/g, '\\"'); + const command = `seid tx wasm execute ${tokenAddress} "${jsonString}" --from=${sender} --gas=200000 --gas-prices=0.1usei --broadcast-mode=block -y --output=json`; + const output = await execute(command); + const response = JSON.parse(output); + if (response.code !== 0) { + throw new Error(response.raw_log); + } + return response; +}; + +module.exports = { + getValidators, + instantiateHubContract, + bond, + unbond, + harvest, + queryTokenBalance, + addAccount, + transferTokens, +}; From 556baab448c0b7395e0c556a1e9e32c1cde9d94f Mon Sep 17 00:00:00 2001 From: mj Date: Tue, 13 Aug 2024 15:30:04 -0400 Subject: [PATCH 14/38] Add more DEX dapp tests (#1809) * draft * draft * working protoype * poc fix * import * imports issue * use fund address * amount * expect * working tests * put package.json in dapp_tests * dont commit artifacts * no build * run ci * update package json * more tests * working tests * wasm access * wasmloc * fix * works with other chains * add workflow * path --- .github/workflows/dapp_tests.yml | 33 ++ .github/workflows/integration-test.yml | 2 +- contracts/test/lib.js | 9 +- integration_test/dapp_tests/dapp_tests.sh | 12 +- integration_test/dapp_tests/hardhat.config.js | 5 + integration_test/dapp_tests/package-lock.json | 23 +- integration_test/dapp_tests/package.json | 5 +- .../dapp_tests/uniswap/constants.js | 24 ++ .../dapp_tests/uniswap/cw20_base.wasm | Bin 0 -> 376689 bytes .../dapp_tests/uniswap/uniswapHelpers.js | 196 +++++++++ .../dapp_tests/uniswap/uniswapTest.js | 401 +++++++++++------- 11 files changed, 536 insertions(+), 174 deletions(-) create mode 100644 .github/workflows/dapp_tests.yml create mode 100644 integration_test/dapp_tests/uniswap/constants.js create mode 100755 integration_test/dapp_tests/uniswap/cw20_base.wasm create mode 100644 integration_test/dapp_tests/uniswap/uniswapHelpers.js diff --git a/.github/workflows/dapp_tests.yml b/.github/workflows/dapp_tests.yml new file mode 100644 index 000000000..baf5531fc --- /dev/null +++ b/.github/workflows/dapp_tests.yml @@ -0,0 +1,33 @@ +name: Run Dapp Tests + +# Only runs when manually triggered +on: + workflow_dispatch: + +jobs: + run-tests-devnet: + name: Run Tests on Devnet + runs-on: ubuntu-latest + environment: + name: devnet + needs: run-tests-testnet + steps: + - uses: actions/checkout@v3 + + - name: Run Dapp Tests Script on Devnet + run: | + chmod +x ./integration_test/dapp_tests/dapp_tests.sh + ./integration_test/dapp_tests/dapp_tests.sh devnet + + run-tests-testnet: + name: Run Tests on Testnet + runs-on: ubuntu-latest + environment: + name: testnet + steps: + - uses: actions/checkout@v3 + + - name: Run Dapp Tests Script on Testnet + run: | + chmod +x ./integration_test/dapp_tests/dapp_tests.sh + ./integration_test/dapp_tests/dapp_tests.sh testnet diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml index 500863a3a..597d619e7 100644 --- a/.github/workflows/integration-test.yml +++ b/.github/workflows/integration-test.yml @@ -124,7 +124,7 @@ jobs: { name: "dApp Tests", scripts: [ - "./integration_test/dapp_tests/dapp_tests.sh" + "./integration_test/dapp_tests/dapp_tests.sh seilocal" ] }, ] diff --git a/contracts/test/lib.js b/contracts/test/lib.js index 2292a91a3..fa1b92dc5 100644 --- a/contracts/test/lib.js +++ b/contracts/test/lib.js @@ -174,15 +174,15 @@ async function incrementPointerVersion(provider, pointerType, offset) { } } -async function createTokenFactoryTokenAndMint(name, amount, recipient) { - const command = `seid tx tokenfactory create-denom ${name} --from ${adminKeyName} --gas=5000000 --fees=1000000usei -y --broadcast-mode block -o json` +async function createTokenFactoryTokenAndMint(name, amount, recipient, from=adminKeyName) { + const command = `seid tx tokenfactory create-denom ${name} --from ${from} --gas=5000000 --fees=1000000usei -y --broadcast-mode block -o json` const output = await execute(command); const response = JSON.parse(output) const token_denom = getEventAttribute(response, "create_denom", "new_token_denom") - const mint_command = `seid tx tokenfactory mint ${amount}${token_denom} --from ${adminKeyName} --gas=5000000 --fees=1000000usei -y --broadcast-mode block -o json` + const mint_command = `seid tx tokenfactory mint ${amount}${token_denom} --from ${from} --gas=5000000 --fees=1000000usei -y --broadcast-mode block -o json` await execute(mint_command); - const send_command = `seid tx bank send ${adminKeyName} ${recipient} ${amount}${token_denom} --from ${adminKeyName} --gas=5000000 --fees=1000000usei -y --broadcast-mode block -o json` + const send_command = `seid tx bank send ${adminKeyName} ${recipient} ${amount}${token_denom} --from ${from} --gas=5000000 --fees=1000000usei -y --broadcast-mode block -o json` await execute(send_command); return token_denom } @@ -469,6 +469,7 @@ module.exports = { deployErc721PointerForCw721, registerPointerForERC20, registerPointerForERC721, + getPointerForNative, proposeCW20toERC20Upgrade, importKey, getNativeAccount, diff --git a/integration_test/dapp_tests/dapp_tests.sh b/integration_test/dapp_tests/dapp_tests.sh index 6fcd2d24e..96edb5430 100755 --- a/integration_test/dapp_tests/dapp_tests.sh +++ b/integration_test/dapp_tests/dapp_tests.sh @@ -1,5 +1,11 @@ #!/bin/bash +# Check if a configuration argument is passed +if [ -z "$1" ]; then + echo "Please provide a chain (seilocal, devnet, or testnet)." + exit 1 +fi + set -e # Build contacts repo first since we rely on that for lib.js @@ -11,5 +17,7 @@ npm ci npx hardhat compile -npx hardhat test --network seilocal uniswap/uniswapTest.js -npx hardhat test --network seilocal steak/SteakTests.js \ No newline at end of file +# Set the CONFIG environment variable +export DAPP_TEST_ENV=$1 +npx hardhat test --network $1 uniswap/uniswapTest.js +npx hardhat test --network $1 steak/SteakTests.js diff --git a/integration_test/dapp_tests/hardhat.config.js b/integration_test/dapp_tests/hardhat.config.js index 55f4f7935..ac5fb70fe 100644 --- a/integration_test/dapp_tests/hardhat.config.js +++ b/integration_test/dapp_tests/hardhat.config.js @@ -21,5 +21,10 @@ module.exports = { address: ["0xF87A299e6bC7bEba58dbBe5a5Aa21d49bCD16D52", "0x70997970C51812dc3A010C7d01b50e0d17dc79C8"], accounts: ["0x57acb95d82739866a5c29e40b0aa2590742ae50425b7dd5b5d279a986370189e", "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d"], }, + testnet: { + url: "https://evm-rpc-testnet.sei-apis.com", + address: ["0xF87A299e6bC7bEba58dbBe5a5Aa21d49bCD16D52", "0x70997970C51812dc3A010C7d01b50e0d17dc79C8"], + accounts: ["0x57acb95d82739866a5c29e40b0aa2590742ae50425b7dd5b5d279a986370189e", "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d"], + }, }, }; diff --git a/integration_test/dapp_tests/package-lock.json b/integration_test/dapp_tests/package-lock.json index 014b92e2d..c1617b5c5 100644 --- a/integration_test/dapp_tests/package-lock.json +++ b/integration_test/dapp_tests/package-lock.json @@ -17,8 +17,11 @@ "@uniswap/v3-core": "^1.0.1", "@uniswap/v3-periphery": "^1.4.4", "chai": "^4.2.0", - "ethers": "^5.7.2", + "ethers": "^5.7.2" + }, + "devDependencies": { "hardhat": "^2.22.6", + "it-each": "^0.5.0", "uuid": "^10.0.0" } }, @@ -5300,6 +5303,12 @@ "no-case": "^2.2.0" } }, + "node_modules/dot-notes": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/dot-notes/-/dot-notes-3.2.2.tgz", + "integrity": "sha512-X+shiSI51ai9axY9C6LD0L0UmpD7XyDWHMy+iIpwcn8EOEmcCSiIHUE7QvzQihaAbuQae9yAnRhN0rYAqafp3w==", + "dev": true + }, "node_modules/ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -6323,6 +6332,7 @@ "version": "4.0.5", "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.5.tgz", "integrity": "sha512-HTm14iMQKK2FjFLRTM5lAVcyaUzOnqbPtesFIvREgXpJHdQm8bWS+GkQgIkfaBYRHuCnea7w8UVNfwiAQhlr9A==", + "hasInstallScript": true, "optional": true, "peer": true, "dependencies": { @@ -6685,6 +6695,7 @@ "version": "5.0.7", "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.7.tgz", "integrity": "sha512-vLt1O5Pp+flcArHGIyKEQq883nBt8nN8tVBcoL0qUXj2XT1n7p70yGIq2VK98I5FdZ1YHc0wk/koOnHjnXWk1Q==", + "hasInstallScript": true, "optional": true, "peer": true, "dependencies": { @@ -7542,6 +7553,15 @@ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" }, + "node_modules/it-each": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/it-each/-/it-each-0.5.0.tgz", + "integrity": "sha512-wBaPbvhzI0Wecs4aO0iAbp6IPXac0N9/vUCS/HmUzO8znqFLGIbUcaJ/4Ew/UlyrcIGgMWIBEXUtEQxLSnSllA==", + "dev": true, + "dependencies": { + "dot-notes": "^3.2.2" + } + }, "node_modules/js-sha3": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", @@ -10385,6 +10405,7 @@ "version": "10.0.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", + "dev": true, "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" diff --git a/integration_test/dapp_tests/package.json b/integration_test/dapp_tests/package.json index 9aaf4a0f7..bd6d8ef52 100644 --- a/integration_test/dapp_tests/package.json +++ b/integration_test/dapp_tests/package.json @@ -14,7 +14,10 @@ "@uniswap/v3-core": "^1.0.1", "@uniswap/v3-periphery": "^1.4.4", "chai": "^4.2.0", - "ethers": "^5.7.2", + "ethers": "^5.7.2" + }, + "devDependencies": { + "it-each": "^0.5.0", "hardhat": "^2.22.6", "uuid": "^10.0.0" } diff --git a/integration_test/dapp_tests/uniswap/constants.js b/integration_test/dapp_tests/uniswap/constants.js new file mode 100644 index 000000000..b819fb3df --- /dev/null +++ b/integration_test/dapp_tests/uniswap/constants.js @@ -0,0 +1,24 @@ +const tokenFactoryDenoms = { + "testnet": "factory/sei10xlj95ef20tczjrq5w5ah0vz8t5pxzeza4gaad/dapptest" +} + +const cw20Addresses = { + "testnet": {"evm": "0xcD10A4FdeE9CefB7732161f4B20b018bA3F4e7fF", "sei": "sei1d5cs4y0cfdm8dvak4fnmcudqd9htgsnw0djryuvpwhhmyvywypmsxv7vnq"} +} + +const rpcUrls = { + "testnet": "https://rpc-testnet.sei-apis.com", + "devnet": "https://rpc-arctic-1.sei-apis.com" +} + +const chainIds = { + "testnet": "atlantic-2", + "devnet": "arctic-1" +} + +module.exports = { + tokenFactoryDenoms, + cw20Addresses, + rpcUrls, + chainIds +} \ No newline at end of file diff --git a/integration_test/dapp_tests/uniswap/cw20_base.wasm b/integration_test/dapp_tests/uniswap/cw20_base.wasm new file mode 100755 index 0000000000000000000000000000000000000000..b750812a2b2616d5e16cd339b734212969173f97 GIT binary patch literal 376689 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

<{*}5hB%{UJT(+l$qLi6Fz*t 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

O>GK@0a^_@Tn=e7A4IPu3=B90$ojS0 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 literal 0 HcmV?d00001 diff --git a/integration_test/dapp_tests/uniswap/uniswapHelpers.js b/integration_test/dapp_tests/uniswap/uniswapHelpers.js new file mode 100644 index 000000000..9133aa085 --- /dev/null +++ b/integration_test/dapp_tests/uniswap/uniswapHelpers.js @@ -0,0 +1,196 @@ +const hre = require("hardhat"); +const {BigNumber} = require("ethers"); // Require Hardhat Runtime Environment +const { ABI, deployErc20PointerForCw20, deployWasm, execute } = require("../../../contracts/test/lib.js"); + +async function deployTokenPool(managerContract, firstTokenAddr, secondTokenAddr, swapRatio=1, fee=3000) { + const sqrtPriceX96 = BigInt(Math.sqrt(swapRatio) * (2 ** 96)); // Initial price (1:1) + + const gasPrice = await hre.ethers.provider.getGasPrice(); + const [token0, token1] = tokenOrder(firstTokenAddr, secondTokenAddr); + + let gasLimit = await managerContract.estimateGas.createAndInitializePoolIfNecessary( + token0.address, + token1.address, + fee, + sqrtPriceX96, + ); + + gasLimit = gasLimit.mul(12).div(10) + console.log("EST GAS", gasLimit) + // token0 addr must be < token1 addr + const poolTx = await managerContract.createAndInitializePoolIfNecessary( + token0.address, + token1.address, + fee, + sqrtPriceX96, + {gasLimit, gasPrice} + ); + await poolTx.wait(); + console.log("Pool created and initialized"); +} + +// Supplies liquidity to then given pools. The signer connected to the contracts must have the prerequisite tokens or this will fail. +async function supplyLiquidity(managerContract, recipientAddr, firstTokenContract, secondTokenContract, firstTokenAmt=100, secondTokenAmt=100) { + // Define the amount of tokens to be approved and added as liquidity + console.log("Supplying liquidity to pool") + const [token0, token1] = tokenOrder(firstTokenContract.address, secondTokenContract.address, firstTokenAmt, secondTokenAmt); + const gasPrice = await hre.ethers.provider.getGasPrice(); + + let gasLimit = await firstTokenContract.estimateGas.approve(managerContract.address, firstTokenAmt); + gasLimit = gasLimit.mul(12).div(10) + + // Approve the NonfungiblePositionManager to spend the specified amount of firstToken + const approveFirstTokenTx = await firstTokenContract.approve(managerContract.address, firstTokenAmt, {gasLimit, gasPrice}); + await approveFirstTokenTx.wait(); + let allowance = await firstTokenContract.allowance(recipientAddr, managerContract.address); + console.log('allowance1', allowance); + let balance = await firstTokenContract.balanceOf(recipientAddr); + console.log("bal1", balance) + + gasLimit = await secondTokenContract.estimateGas.approve(managerContract.address, secondTokenAmt); + gasLimit = gasLimit.mul(12).div(10) + + // Approve the NonfungiblePositionManager to spend the specified amount of secondToken + const approveSecondTokenTx = await secondTokenContract.approve(managerContract.address, secondTokenAmt, {gasLimit, gasPrice}); + await approveSecondTokenTx.wait(); + + allowance = await secondTokenContract.allowance(recipientAddr, managerContract.address); + console.log('allowance2', allowance); + balance = await secondTokenContract.balanceOf(recipientAddr); + console.log("bal2", balance) + + gasLimit = await managerContract.estimateGas.mint({ + token0: token0.address, + token1: token1.address, + fee: 3000, // Fee tier (0.3%) + tickLower: -887220, + tickUpper: 887220, + amount0Desired: token0.amount, + amount1Desired: token1.amount, + amount0Min: 0, + amount1Min: 0, + recipient: recipientAddr, + deadline: Math.floor(Date.now() / 1000) + 60 * 10, // 10 minutes from now + }) + + gasLimit = gasLimit.mul(12).div(10) + console.log("Liquidity Gas Limit", gasLimit); + + // Add liquidity to the pool + const liquidityTx = await managerContract.mint({ + token0: token0.address, + token1: token1.address, + fee: 3000, // Fee tier (0.3%) + tickLower: -887220, + tickUpper: 887220, + amount0Desired: token0.amount, + amount1Desired: token1.amount, + amount0Min: 0, + amount1Min: 0, + recipient: recipientAddr, + deadline: Math.floor(Date.now() / 1000) + 60 * 10, // 10 minutes from now + }, {gasLimit, gasPrice}); + + await liquidityTx.wait(); + console.log("Liquidity added"); +} + +// Orders the 2 addresses sequentially, since this is required by uniswap. +function tokenOrder(firstTokenAddr, secondTokenAddr, firstTokenAmount=0, secondTokenAmount=0) { + let token0; + let token1; + if (parseInt(firstTokenAddr, 16) < parseInt(secondTokenAddr, 16)) { + token0= {address: firstTokenAddr, amount: firstTokenAmount}; + token1 = {address: secondTokenAddr, amount: secondTokenAmount}; + } else { + token0 = {address: secondTokenAddr, amount: secondTokenAmount}; + token1 = {address: firstTokenAddr, amount: firstTokenAmount}; + } + return [token0, token1] +} + +async function deployCw20WithPointer(deployerSeiAddr, signer, time) { + const cw20Address = await deployWasm('../integration_test/dapp_tests/uniswap/cw20_base.wasm', deployerSeiAddr, "cw20", { + name: `testCw20${time}`, + symbol: "TEST", + decimals: 6, + initial_balances: [ + { address: deployerSeiAddr, amount: "1000000000" } + ], + mint: { + "minter": deployerSeiAddr, "cap": "99900000000" + } + }); + + const pointerAddr = await deployErc20PointerForCw20(hre.ethers.provider, cw20Address); + const pointerContract = new hre.ethers.Contract(pointerAddr, ABI.ERC20, signer); + return {"pointerContract": pointerContract, "cw20Address": cw20Address} +} + +async function deployEthersContract(name, abi, bytecode, deployer, deployParams=[]) { + const contract = new hre.ethers.ContractFactory(abi, bytecode, deployer); + const deployed = await contract.deploy(...deployParams); + await deployed.deployed(); + console.log(`${name} deployed to:`, deployed.address); + return deployed; +} + +async function addDeployerKey(keyName, mnemonic, path) { + try { + const output = await execute(`seid keys show ${keyName} --output json`); + const parsed = JSON.parse(output); + console.log("OUTOPUT", parsed); + return parsed.address; + } catch (e) { + console.log(e) + } + + try { + await execute(`printf "${mnemonic}" | seid keys add ${keyName} --recover --hd-path "${path}" --keyring-backend test`) + } + catch (e) { + console.log(e); + } + + const output = await execute(`seid keys show ${keyName} --output json`); + const parsed = JSON.parse(output); + + return parsed.address; +} + +async function doesTokenFactoryDenomExist(denom) { + const output = await execute(`seid q tokenfactory denom-authority-metadata ${denom} --output json`); + const parsed = JSON.parse(output); + + return parsed.authority_metadata.admin !== ""; +} + +async function sendFunds(amountSei, recipient, signer) { + const bal = await signer.getBalance(); + const gasLimit = await signer.estimateGas({ + to: recipient, + value: hre.ethers.utils.parseEther(amountSei) + }) + + // Get current gas price from the network + const gasPrice = await signer.getGasPrice(); + + const fundUser = await signer.sendTransaction({ + to: recipient, + value: hre.ethers.utils.parseEther(amountSei), + gasLimit: gasLimit.mul(12).div(10), + gasPrice: gasPrice, + }) + + await fundUser.wait(); +} + +module.exports = { + deployTokenPool, + supplyLiquidity, + deployCw20WithPointer, + deployEthersContract, + addDeployerKey, + doesTokenFactoryDenomExist, + sendFunds +} \ No newline at end of file diff --git a/integration_test/dapp_tests/uniswap/uniswapTest.js b/integration_test/dapp_tests/uniswap/uniswapTest.js index 60b8be12b..17e2d4a49 100755 --- a/integration_test/dapp_tests/uniswap/uniswapTest.js +++ b/integration_test/dapp_tests/uniswap/uniswapTest.js @@ -6,43 +6,79 @@ const { abi: DESCRIPTOR_ABI, bytecode: DESCRIPTOR_BYTECODE } = require("@uniswap 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, setupSigners, createTokenFactoryTokenAndMint, deployErc20PointerNative } = require("../../../contracts/test/lib.js"); - +const { fundAddress, createTokenFactoryTokenAndMint, getPointerForNative, deployErc20PointerNative, execute, getSeiAddress, queryWasm, getSeiBalance, ABI } = require("../../../contracts/test/lib.js"); +const { deployTokenPool, supplyLiquidity, deployCw20WithPointer, deployEthersContract, sendFunds } = require("./uniswapHelpers.js") +const {cw20Addresses, tokenFactoryDenoms, rpcUrls, chainIds} = require("./constants") const { expect } = require("chai"); -describe("EVM Test", async function () { +const testChain = process.env.DAPP_TEST_ENV; + +describe("EVM Test", function () { let weth9; let token; + let erc20TokenFactory; + let tokenFactoryDenom; + let erc20cw20; + let cw20Address; let router; let manager; let deployer; let user; before(async function () { - [deployerObj] = await setupSigners(await hre.ethers.getSigners()); - deployer = deployerObj.signer - await fundAddress(deployer.address, amount="2000000000000000000000") + [deployer] = await hre.ethers.getSigners(); + + // const account = hre.config.networks.hardhat.accounts; + // const deployerKeyName = "deployer" + // const deployerAddr = await addDeployerKey(deployerKeyName, account.mnemonic, account.path); + // console.log(deployerAddr); + 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]}`) + } // Fund user account - const userWallet = ethers.Wallet.createRandom(); - user = userWallet.connect(ethers.provider); + const userWallet = hre.ethers.Wallet.createRandom(); + user = userWallet.connect(hre.ethers.provider); - await fundAddress(user.address) - // Deploy Required Tokens + await sendFunds("20", user.address, deployer) + + const deployerSeiAddr = await getSeiAddress(deployer.address); - // Deploy TokenFactory token with ERC20 pointer + // Deploy Required Tokens + // If local chain, deployer should have received all the tokens on first mint. + // Otherwise, deployer needs to own all the tokens before this test is run. const time = Date.now().toString(); - const tokenName = `test${time}` - const denom = await createTokenFactoryTokenAndMint(tokenName, 10000000, deployerObj.seiAddress) - console.log("DENOM", denom) - const pointerAddr = await deployErc20PointerNative(hre.ethers.provider, denom) - console.log("Pointer Addr", pointerAddr); + + if (testChain === 'seilocal') { + // Deploy TokenFactory token with ERC20 pointer + const tokenName = `dappTests${time}` + tokenFactoryDenom = await createTokenFactoryTokenAndMint(tokenName, 10000000000, deployerSeiAddr) + console.log("DENOM", tokenFactoryDenom) + const pointerAddr = await deployErc20PointerNative(hre.ethers.provider, tokenFactoryDenom) + console.log("Pointer Addr", pointerAddr); + erc20TokenFactory = new hre.ethers.Contract(pointerAddr, ABI.ERC20, deployer); + } else { + tokenFactoryDenom = tokenFactoryDenoms[testChain] + const pointer= await getPointerForNative(tokenFactoryDenom); + erc20TokenFactory = new hre.ethers.Contract(pointer.pointer, ABI.ERC20, deployer); + } + + if (testChain === 'seilocal') { + // Deploy CW20 token with ERC20 pointer + const cw20Details = await deployCw20WithPointer(deployerSeiAddr, deployer, time) + erc20cw20 = cw20Details.pointerContract; + cw20Address = cw20Details.cw20Address; + } else { + const cw20addrs = cw20Addresses[testChain] + cw20Address = cw20addrs.sei + erc20cw20 = new hre.ethers.Contract(cw20addrs.evm, ABI.ERC20, deployer); + } // Deploy WETH9 Token (ETH representation on Uniswap) - console.log("Deploying WETH9 with the account:", deployer.address); - const WETH9 = new hre.ethers.ContractFactory(WETH9_ABI, WETH9_BYTECODE, deployer); - weth9 = await WETH9.deploy(); - await weth9.deployed(); - console.log("WETH9 deployed to:", weth9.address); + weth9 = await deployEthersContract("WETH9", WETH9_ABI, WETH9_BYTECODE, deployer); // Deploy MockToken console.log("Deploying MockToken with the account:", deployer.address); @@ -52,112 +88,39 @@ describe("EVM Test", async function () { console.log("MockToken deployed to:", token.address); // Deploy NFT Descriptor. These NFTs are used by the NonFungiblePositionManager to represent liquidity positions. - console.log("Deploying NFT Descriptor with the account:", deployer.address); - const NFTDescriptor = new hre.ethers.ContractFactory(DESCRIPTOR_ABI, DESCRIPTOR_BYTECODE, deployer); - descriptor = await NFTDescriptor.deploy(); - await descriptor.deployed(); - console.log("NFTDescriptor deployed to:", descriptor.address); + const descriptor = await deployEthersContract("NFT Descriptor", DESCRIPTOR_ABI, DESCRIPTOR_BYTECODE, deployer); // Deploy Uniswap Contracts // Create UniswapV3 Factory - console.log("Deploying Factory Contract with the account:", deployer.address); - const FactoryContract = new hre.ethers.ContractFactory(FACTORY_ABI, FACTORY_BYTECODE, deployer); - const factory = await FactoryContract.deploy(); - await factory.deployed(); - console.log("Uniswap V3 Factory deployed to:", factory.address); + const factory = await deployEthersContract("Uniswap V3 Factory", FACTORY_ABI, FACTORY_BYTECODE, deployer); // Deploy NonFungiblePositionManager - const NonfungiblePositionManager = new hre.ethers.ContractFactory(MANAGER_ABI, MANAGER_BYTECODE, deployer); - manager = await NonfungiblePositionManager.deploy(factory.address, weth9.address, descriptor.address); - await manager.deployed(); - console.log("NonfungiblePositionManager deployed to:", manager.address); + manager = await deployEthersContract("NonfungiblePositionManager", MANAGER_ABI, MANAGER_BYTECODE, deployer, deployParams=[factory.address, weth9.address, descriptor.address]); // Deploy SwapRouter - console.log("Deploying SwapRouter with the account:", deployer.address); - const SwapRouter = new hre.ethers.ContractFactory(SWAP_ROUTER_ABI, SWAP_ROUTER_BYTECODE, deployer); - router = await SwapRouter.deploy(factory.address, weth9.address); - await router.deployed(); - console.log("SwapRouter deployed to:", router.address); - - // Create WETH9 x MockToken liquidity pool - console.log("Deploying SwapRouter with the account:", deployer.address); - const fee = 3000; // Fee tier (0.3%) - const sqrtPriceX96 = BigInt(Math.sqrt(1)) * BigInt(2) ** BigInt(96); // Initial price (1:1) - - // token0 addr must be < token1 addr - let token0addr; - let token1addr; - if (parseInt(weth9.address, 16) < parseInt(token.address, 16)) { - token0addr = weth9.address; - token1addr = token.address; - } else { - token0addr = token.address; - token1addr = weth9.address; - } - const poolTx = await manager.createAndInitializePoolIfNecessary( - token0addr, - token1addr, - fee, - sqrtPriceX96 - ); - await poolTx.wait(); - console.log("Pool created and initialized"); - - // Add Liquidity to pool - // Define the amount of tokens to be approved and added as liquidity - console.log("Supplying liquidity to pool") - const amountETH = hre.ethers.utils.parseEther("100"); - const amountToken = hre.ethers.utils.parseEther("100"); - - let token0amt; - let token1amt; - if (token0addr === weth9.address) { - token0amt = amountETH; - token1amt = amountToken - } else { - token0amt = amountToken; - token1amt = amountETH; - } + router = await deployEthersContract("SwapRouter", SWAP_ROUTER_ABI, SWAP_ROUTER_BYTECODE, deployer, deployParams=[factory.address, weth9.address]); - // Approve the NonfungiblePositionManager to spend the specified amount of the mock token - await token.approve(manager.address, amountToken); + const amountETH = hre.ethers.utils.parseEther("30") - // Wrap ETH to WETH by depositing ETH into the WETH9 contract + // Gets the amount of WETH9 required to instantiate pools by depositing Sei to the contract const txWrap = await weth9.deposit({ value: amountETH }); await txWrap.wait(); - console.log(`Deposited ${amountETH.toString()} ETH to WETH9`); - - // Approve the NonfungiblePositionManager to spend the specified amount of WETH - const approveWETHTx = await weth9.approve(manager.address, amountETH); - await approveWETHTx.wait(); - console.log(`Approved ${amountETH.toString()} WETH to the NonfungiblePositionManager`); - - - // Add liquidity to the pool - const liquidityTx = await manager.mint({ - token0: token0addr, - token1: token1addr, - fee: 3000, // Fee tier (0.3%) - tickLower: -887220, - tickUpper: 887220, - amount0Desired: token0amt, - amount1Desired: token1amt, - amount0Min: 0, - amount1Min: 0, - recipient: deployer.address, - deadline: Math.floor(Date.now() / 1000) + 60 * 10 // 10 minutes from now - }); + console.log(`Deposited ${amountETH.toString()} to WETH9`); - await liquidityTx.wait(); - console.log("Liquidity added"); - }) - - describe("Swaps", async function () { - it("Associated account should swap successfully", async function () { + // Create liquidity pools + await deployTokenPool(manager, weth9.address, token.address) + await deployTokenPool(manager, weth9.address, erc20TokenFactory.address, swapRatio=10**-13) + await deployTokenPool(manager, weth9.address, erc20cw20.address, swapRatio=10**-13) - let currSeiBal = await user.getBalance() - console.log(`Funded user account ${user.address} with ${hre.ethers.utils.formatEther(currSeiBal)} sei`); + // Add Liquidity to pools + await supplyLiquidity(manager, deployer.address, weth9, token, hre.ethers.utils.parseEther("10"), hre.ethers.utils.parseEther("10")) + await supplyLiquidity(manager, deployer.address, weth9, erc20TokenFactory, hre.ethers.utils.parseEther("10"), 100000000) + await supplyLiquidity(manager, deployer.address, weth9, erc20cw20, hre.ethers.utils.parseEther("10"), 100000000) + }) + describe("Swaps", function () { + // Swaps token1 for token2. + async function basicSwapTestAssociated(token1, token2, expectSwapFail=false) { const fee = 3000; // Fee tier (0.3%) // Perform a Swap @@ -167,46 +130,57 @@ describe("EVM Test", async function () { const gasLimit = hre.ethers.utils.hexlify(1000000); // Example gas limit const gasPrice = await hre.ethers.provider.getGasPrice(); - const deposit = await weth9.connect(user).deposit({ value: amountIn, gasLimit, gasPrice }); + const deposit = await token1.connect(user).deposit({ value: amountIn, gasLimit, gasPrice }); await deposit.wait(); - const weth9balance = await weth9.connect(user).balanceOf(user.address); - expect(weth9balance).to.equal(amountIn.toString(), "weth9 balance should be equal to value passed in") + const token1balance = await token1.connect(user).balanceOf(user.address); + expect(token1balance).to.equal(amountIn.toString(), "token1 balance should be equal to value passed in") - const approval = await weth9.connect(user).approve(router.address, amountIn, {gasLimit, gasPrice}); + const approval = await token1.connect(user).approve(router.address, amountIn, {gasLimit, gasPrice}); await approval.wait(); - const allowance = await weth9.allowance(user.address, router.address); + const allowance = await token1.allowance(user.address, router.address); // Change to expect - expect(allowance).to.equal(amountIn.toString(), "weth9 allowance for router should be equal to value passed in") - - const tx = await router.connect(user).exactInputSingle({ - tokenIn: weth9.address, - tokenOut: token.address, - fee, - recipient: user.address, - deadline: Math.floor(Date.now() / 1000) + 60 * 10, // 10 minutes from now - amountIn, - amountOutMinimum: amountOutMin, - sqrtPriceLimitX96: 0 - }, {gasLimit, gasPrice}); - - await tx.wait(); - - // Check User's MockToken Balance - const balance = BigInt(await token.balanceOf(user.address)); - // Check that it's more than 0 (no specified amount since there might be slippage) - expect(Number(balance)).to.greaterThan(0, "mocktoken should have been swapped successfully.") - }); + expect(allowance).to.equal(amountIn.toString(), "token1 allowance for router should be equal to value passed in") + + if (expectSwapFail) { + expect(router.connect(user).exactInputSingle({ + tokenIn: token1.address, + tokenOut: token2.address, + fee, + recipient: user.address, + deadline: Math.floor(Date.now() / 1000) + 60 * 10, // 10 minutes from now + amountIn, + amountOutMinimum: amountOutMin, + sqrtPriceLimitX96: 0 + }, {gasLimit, gasPrice})).to.be.reverted; + } else { + const tx = await router.connect(user).exactInputSingle({ + tokenIn: token1.address, + tokenOut: token2.address, + fee, + recipient: user.address, + deadline: Math.floor(Date.now() / 1000) + 60 * 10, // 10 minutes from now + amountIn, + amountOutMinimum: amountOutMin, + sqrtPriceLimitX96: 0 + }, {gasLimit, gasPrice}); + + await tx.wait(); + + // Check User's MockToken Balance + const balance = BigInt(await token2.balanceOf(user.address)); + // Check that it's more than 0 (no specified amount since there might be slippage) + expect(Number(balance)).to.greaterThan(0, "Token2 should have been swapped successfully.") + } + } - it("Unassociated account should receive tokens successfully", async function () { + async function basicSwapTestUnassociated(token1, token2, expectSwapFail=false) { const unassocUserWallet = ethers.Wallet.createRandom(); const unassocUser = unassocUserWallet.connect(ethers.provider); // Fund the user account - await fundAddress(unassocUser.address) - - const currSeiBal = await unassocUser.getBalance() + await sendFunds("2", unassocUser.address, deployer) const fee = 3000; // Fee tier (0.3%) @@ -214,40 +188,137 @@ describe("EVM Test", async function () { const amountIn = hre.ethers.utils.parseEther("1"); const amountOutMin = hre.ethers.utils.parseEther("0"); // Minimum amount of MockToken expected - const deposit = await weth9.deposit({ value: amountIn }); + const deposit = await token1.deposit({ value: amountIn }); await deposit.wait(); - const weth9balance = await weth9.balanceOf(deployer.address); + const token1balance = await token1.balanceOf(deployer.address); - // Check that deployer has amountIn amount of weth9 - expect(weth9balance).to.equal(amountIn, "weth9 balance should be received by user") + // Check that deployer has amountIn amount of token1 + expect(Number(token1balance)).to.greaterThanOrEqual(Number(amountIn), "token1 balance should be received by user") - const approval = await weth9.approve(router.address, amountIn); + const approval = await token1.approve(router.address, amountIn); await approval.wait(); - const allowance = await weth9.allowance(deployer.address, router.address); + const allowance = await token1.allowance(deployer.address, router.address); + + // Check that deployer has approved amountIn amount of token1 to be used by router + expect(allowance).to.equal(amountIn, "token1 allowance to router should be set correctly by user") + + if (expectSwapFail) { + expect(router.exactInputSingle({ + tokenIn: token1.address, + tokenOut: token2.address, + fee, + recipient: unassocUser.address, + deadline: Math.floor(Date.now() / 1000) + 60 * 10, // 10 minutes from now + amountIn, + amountOutMinimum: amountOutMin, + sqrtPriceLimitX96: 0 + })).to.be.reverted; + } else { + // Perform the swap, with recipient being the unassociated account. + const tx = await router.exactInputSingle({ + tokenIn: token1.address, + tokenOut: token2.address, + fee, + recipient: unassocUser.address, + deadline: Math.floor(Date.now() / 1000) + 60 * 10, // 10 minutes from now + amountIn, + amountOutMinimum: amountOutMin, + sqrtPriceLimitX96: 0 + }); + + await tx.wait(); + + // Check User's MockToken Balance + const balance = await token2.balanceOf(unassocUser.address); + // 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") + } + + // Return the user in case we want to run any more tests. + return unassocUser; + } - // Check that deployer has approved amountIn amount of weth9 to be used by router - expect(allowance).to.equal(amountIn, "weth9 allowance to router should be set correctly by user") + it("Associated account should swap erc20 successfully", async function () { + await basicSwapTestAssociated(weth9, token); + }); - const tx = await router.exactInputSingle({ - tokenIn: weth9.address, - tokenOut: token.address, - fee, - recipient: unassocUser.address, - deadline: Math.floor(Date.now() / 1000) + 60 * 10, // 10 minutes from now - amountIn, - amountOutMinimum: amountOutMin, - sqrtPriceLimitX96: 0 - }); + it("Associated account should swap erc20-tokenfactory successfully", async function () { + await basicSwapTestAssociated(weth9, erc20TokenFactory); + const userSeiAddr = await getSeiAddress(user.address); - await tx.wait(); + const userBal = await getSeiBalance(userSeiAddr, tokenFactoryDenom) + expect(Number(userBal)).to.be.greaterThan(0); + }); + + it("Associated account should swap erc20-cw20 successfully", async function () { + await basicSwapTestAssociated(weth9, erc20cw20); + + // Also check on the cw20 side that the token balance has been updated. + const userSeiAddr = await getSeiAddress(user.address); + const result = await queryWasm(cw20Address, "balance", {address: userSeiAddr}); + expect(Number(result.data.balance)).to.be.greaterThan(0); + }); + + it("Unassociated account should receive erc20 tokens successfully", async function () { + await basicSwapTestUnassociated(weth9, token) + }); + + it("Unassociated account should receive erc20-tokenfactory tokens successfully", async function () { + const unassocUser = await basicSwapTestUnassociated(weth9, erc20TokenFactory) + + // Send funds to associate accounts. + await sendFunds("0.001", deployer.address, unassocUser) + const userSeiAddr = await getSeiAddress(unassocUser.address); + + const userBal = await getSeiBalance(userSeiAddr, tokenFactoryDenom) + expect(Number(userBal)).to.be.greaterThan(0); + }) - // Check User's MockToken Balance - const balance = await token.balanceOf(unassocUser.address); - // 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 mocktoken") + it("Unassociated account should not be able to receive erc20cw20 tokens successfully", async function () { + 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); + + // Fund the user account. Creating pools is a expensive operation so we supply more funds here for gas. + await sendFunds("5", unassocUser.address, deployer) + + await deployTokenPool(manager.connect(unassocUser), erc20TokenFactory.address, token.address) }) + it("Unssosciated account should be able to supply liquidity pools successfully", async function () { + const unassocUserWallet = hre.ethers.Wallet.createRandom(); + const unassocUser = unassocUserWallet.connect(hre.ethers.provider); + + // Fund the user account + await sendFunds("2", unassocUser.address, deployer) + + const erc20TokenFactoryAmount = "100000" + const tx = await erc20TokenFactory.transfer(unassocUser.address, erc20TokenFactoryAmount); + await tx.wait(); + const mockTokenAmount = "100000" + const tx2 = await token.transfer(unassocUser.address, mockTokenAmount); + await tx2.wait(); + 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) + }) + }) + + after(async function () { + // Set the chain back to regular state + console.log("Resetting") + if (testChain !== 'seilocal') { + await execute(`seid config chain-id sei-chain`) + await execute(`seid config node tcp://localhost:26657`) + } }) }) \ No newline at end of file From 95c47672accf156aed87d7db669af835563fcdee Mon Sep 17 00:00:00 2001 From: mj Date: Fri, 16 Aug 2024 15:04:24 -0400 Subject: [PATCH 15/38] Update dapp tests to be compatible with test chains (#1820) * test * test * add more setup * add to path * githubpath * seid path * dapp tests * try artifacts * ditch setup step * deps * test workflow * set keyring * without * keys add * add to sh * nobackend * no script * test * keyring * no sh * test * fix flakiness * cleanup * move seid config command * only if docker * test without * if isdocker * printf mnemonic * try escape path * try single quotes * try modifying execute * no path * backend * try without keyring * move keyring * path * basedir * try pwd * config reset * seid config * redeclare * print * docker path * dynamic path * config for all * full * lint issue * backend * cleanup --- .github/workflows/dapp_tests.yml | 25 +- .github/workflows/integration-test.yml | 1 + contracts/test/lib.js | 35 +- integration_test/dapp_tests/constants.js | 20 + integration_test/dapp_tests/dapp_tests.sh | 1 + integration_test/dapp_tests/hardhat.config.js | 25 +- .../dapp_tests/steak/SteakTests.js | 67 +++- integration_test/dapp_tests/steak/utils.js | 154 -------- .../dapp_tests/uniswap/constants.js | 24 -- .../dapp_tests/uniswap/uniswapHelpers.js | 196 ---------- .../dapp_tests/uniswap/uniswapTest.js | 148 ++++--- integration_test/dapp_tests/utils.js | 368 ++++++++++++++++++ loadtest/loadtest_client.go | 2 +- 13 files changed, 581 insertions(+), 485 deletions(-) create mode 100644 integration_test/dapp_tests/constants.js delete mode 100644 integration_test/dapp_tests/steak/utils.js delete mode 100644 integration_test/dapp_tests/uniswap/constants.js delete mode 100644 integration_test/dapp_tests/uniswap/uniswapHelpers.js create mode 100644 integration_test/dapp_tests/utils.js diff --git a/.github/workflows/dapp_tests.yml b/.github/workflows/dapp_tests.yml index baf5531fc..a88c333f6 100644 --- a/.github/workflows/dapp_tests.yml +++ b/.github/workflows/dapp_tests.yml @@ -10,13 +10,22 @@ jobs: runs-on: ubuntu-latest environment: name: devnet - needs: run-tests-testnet + env: + DAPP_TESTS_MNEMONIC: ${{ secrets.DAPP_TESTS_MNEMONIC }} steps: - uses: actions/checkout@v3 + - name: Install seid + run: | + # Install seid using go install + make install + + # Add the Go bin directory to the PATH + echo "$(go env GOPATH)/bin" >> $GITHUB_PATH + echo "$HOME/go/bin" >> $GITHUB_PATH + - name: Run Dapp Tests Script on Devnet run: | - chmod +x ./integration_test/dapp_tests/dapp_tests.sh ./integration_test/dapp_tests/dapp_tests.sh devnet run-tests-testnet: @@ -24,10 +33,20 @@ jobs: runs-on: ubuntu-latest environment: name: testnet + env: + DAPP_TESTS_MNEMONIC: ${{ secrets.DAPP_TESTS_MNEMONIC }} steps: - uses: actions/checkout@v3 + - name: Install seid + run: | + # Install seid using go install + make install + + # Add the Go bin directory to the PATH + echo "$(go env GOPATH)/bin" >> $GITHUB_PATH + echo "$HOME/go/bin" >> $GITHUB_PATH + - name: Run Dapp Tests Script on Testnet run: | - chmod +x ./integration_test/dapp_tests/dapp_tests.sh ./integration_test/dapp_tests/dapp_tests.sh testnet diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml index 597d619e7..1898be0ed 100644 --- a/.github/workflows/integration-test.yml +++ b/.github/workflows/integration-test.yml @@ -26,6 +26,7 @@ jobs: env: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + DAPP_TESTS_MNEMONIC: ${{ secrets.DAPP_TESTS_MNEMONIC }} strategy: # other jobs should run even if one integration test fails fail-fast: false diff --git a/contracts/test/lib.js b/contracts/test/lib.js index fa1b92dc5..3c5fbf633 100644 --- a/contracts/test/lib.js +++ b/contracts/test/lib.js @@ -77,8 +77,8 @@ async function bankSend(toAddr, fromKey, amount="100000000000", denom="usei") { return result } -async function fundSeiAddress(seiAddr, amount="100000000000", denom="usei") { - return await execute(`seid tx bank send ${adminKeyName} ${seiAddr} ${amount}${denom} -b block --fees 20000usei -y`); +async function fundSeiAddress(seiAddr, amount="100000000000", denom="usei", funder=adminKeyName) { + return await execute(`seid tx bank send ${funder} ${seiAddr} ${amount}${denom} -b block --fees 20000usei -y`); } async function getSeiBalance(seiAddr, denom="usei") { @@ -182,7 +182,7 @@ async function createTokenFactoryTokenAndMint(name, amount, recipient, from=admi const mint_command = `seid tx tokenfactory mint ${amount}${token_denom} --from ${from} --gas=5000000 --fees=1000000usei -y --broadcast-mode block -o json` await execute(mint_command); - const send_command = `seid tx bank send ${adminKeyName} ${recipient} ${amount}${token_denom} --from ${from} --gas=5000000 --fees=1000000usei -y --broadcast-mode block -o json` + const send_command = `seid tx bank send ${from} ${recipient} ${amount}${token_denom} --from ${from} --gas=5000000 --fees=1000000usei -y --broadcast-mode block -o json` await execute(send_command); return token_denom } @@ -193,12 +193,13 @@ async function getPointerForNative(name) { return JSON.parse(output); } -async function storeWasm(path) { - const command = `seid tx wasm store ${path} --from ${adminKeyName} --gas=5000000 --fees=1000000usei -y --broadcast-mode block -o json` +async function storeWasm(path, from=adminKeyName) { + const command = `seid tx wasm store ${path} --from ${from} --gas=5000000 --fees=1000000usei -y --broadcast-mode block -o json` const output = await execute(command); const response = JSON.parse(output) return getEventAttribute(response, "store_code", "code_id") } + async function getPointerForCw20(cw20Address) { const command = `seid query evm pointer CW20 ${cw20Address} -o json` const output = await execute(command); @@ -211,8 +212,11 @@ async function getPointerForCw721(cw721Address) { return JSON.parse(output); } -async function deployErc20PointerForCw20(provider, cw20Address, attempts=10) { - const command = `seid tx evm register-evm-pointer CW20 ${cw20Address} --from=admin -b block` +async function deployErc20PointerForCw20(provider, cw20Address, attempts=10, from=adminKeyName, evmRpc="") { + let command = `seid tx evm register-evm-pointer CW20 ${cw20Address} --from=${from} -b block` + if (evmRpc) { + command = command + ` --evm-rpc=${evmRpc}` + } const output = await execute(command); const txHash = output.replace(/.*0x/, "0x").trim() let attempt = 0; @@ -229,8 +233,11 @@ async function deployErc20PointerForCw20(provider, cw20Address, attempts=10) { throw new Error("contract deployment failed") } -async function deployErc20PointerNative(provider, name) { - const command = `seid tx evm call-precompile pointer addNativePointer ${name} --from=admin -b block` +async function deployErc20PointerNative(provider, name, from=adminKeyName, evmRpc="") { + let command = `seid tx evm call-precompile pointer addNativePointer ${name} --from=${from} -b block` + if (evmRpc) { + command = command + ` --evm-rpc=${evmRpc}` + } const output = await execute(command); const txHash = output.replace(/.*0x/, "0x").trim() let attempt = 0; @@ -263,14 +270,14 @@ async function deployErc721PointerForCw721(provider, cw721Address) { throw new Error("contract deployment failed") } -async function deployWasm(path, adminAddr, label, args = {}) { - const codeId = await storeWasm(path) - return await instantiateWasm(codeId, adminAddr, label, args) +async function deployWasm(path, adminAddr, label, args = {}, from=adminKeyName) { + const codeId = await storeWasm(path, from) + return await instantiateWasm(codeId, adminAddr, label, args, from) } -async function instantiateWasm(codeId, adminAddr, label, args = {}) { +async function instantiateWasm(codeId, adminAddr, label, args = {}, from=adminKeyName) { const jsonString = JSON.stringify(args).replace(/"/g, '\\"'); - const command = `seid tx wasm instantiate ${codeId} "${jsonString}" --label ${label} --admin ${adminAddr} --from ${adminKeyName} --gas=5000000 --fees=1000000usei -y --broadcast-mode block -o json`; + const command = `seid tx wasm instantiate ${codeId} "${jsonString}" --label ${label} --admin ${adminAddr} --from ${from} --gas=5000000 --fees=1000000usei -y --broadcast-mode block -o json`; const output = await execute(command); const response = JSON.parse(output); return getEventAttribute(response, "instantiate", "_contract_address"); diff --git a/integration_test/dapp_tests/constants.js b/integration_test/dapp_tests/constants.js new file mode 100644 index 000000000..aafad4d58 --- /dev/null +++ b/integration_test/dapp_tests/constants.js @@ -0,0 +1,20 @@ +const rpcUrls = { + "testnet": "https://rpc-testnet.sei-apis.com", + "devnet": "https://rpc-arctic-1.sei-apis.com" +} + +const evmRpcUrls = { + "testnet": "https://evm-rpc-testnet.sei-apis.com", + "devnet": "https://evm-rpc-arctic-1.sei-apis.com" +} + +const chainIds = { + "testnet": "atlantic-2", + "devnet": "arctic-1" +} + +module.exports = { + rpcUrls, + evmRpcUrls, + chainIds +} \ No newline at end of file diff --git a/integration_test/dapp_tests/dapp_tests.sh b/integration_test/dapp_tests/dapp_tests.sh index 96edb5430..a889b3d2b 100755 --- a/integration_test/dapp_tests/dapp_tests.sh +++ b/integration_test/dapp_tests/dapp_tests.sh @@ -19,5 +19,6 @@ npx hardhat compile # Set the CONFIG environment variable export DAPP_TEST_ENV=$1 + npx hardhat test --network $1 uniswap/uniswapTest.js npx hardhat test --network $1 steak/SteakTests.js diff --git a/integration_test/dapp_tests/hardhat.config.js b/integration_test/dapp_tests/hardhat.config.js index ac5fb70fe..c2e5a8496 100644 --- a/integration_test/dapp_tests/hardhat.config.js +++ b/integration_test/dapp_tests/hardhat.config.js @@ -18,13 +18,30 @@ module.exports = { networks: { seilocal: { url: "http://127.0.0.1:8545", - address: ["0xF87A299e6bC7bEba58dbBe5a5Aa21d49bCD16D52", "0x70997970C51812dc3A010C7d01b50e0d17dc79C8"], - accounts: ["0x57acb95d82739866a5c29e40b0aa2590742ae50425b7dd5b5d279a986370189e", "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d"], + accounts: { + mnemonic: process.env.DAPP_TESTS_MNEMONIC, + path: "m/44'/118'/0'/0/0", + initialIndex: 0, + count: 1 + }, }, testnet: { url: "https://evm-rpc-testnet.sei-apis.com", - address: ["0xF87A299e6bC7bEba58dbBe5a5Aa21d49bCD16D52", "0x70997970C51812dc3A010C7d01b50e0d17dc79C8"], - accounts: ["0x57acb95d82739866a5c29e40b0aa2590742ae50425b7dd5b5d279a986370189e", "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d"], + accounts: { + mnemonic: process.env.DAPP_TESTS_MNEMONIC, + path: "m/44'/118'/0'/0/0", + initialIndex: 0, + count: 1 + }, + }, + devnet: { + url: "https://evm-rpc-arctic-1.sei-apis.com", + accounts: { + mnemonic: process.env.DAPP_TESTS_MNEMONIC, + path: "m/44'/118'/0'/0/0", + initialIndex: 0, + count: 1 + }, }, }, }; diff --git a/integration_test/dapp_tests/steak/SteakTests.js b/integration_test/dapp_tests/steak/SteakTests.js index 6186501c2..6f7786da6 100644 --- a/integration_test/dapp_tests/steak/SteakTests.js +++ b/integration_test/dapp_tests/steak/SteakTests.js @@ -5,6 +5,8 @@ const { getEvmAddress, fundSeiAddress, associateKey, + execute, + isDocker, } = require("../../../contracts/test/lib.js"); const { getValidators, @@ -14,38 +16,45 @@ const { queryTokenBalance, unbond, transferTokens, -} = require("./utils.js"); + setupAccountWithMnemonic, + sendFunds +} = require("../utils.js"); const { expect } = require("chai"); const { v4: uuidv4 } = require("uuid"); +const hre = require("hardhat"); +const {chainIds, rpcUrls, evmRpcUrls} = require("../constants"); +const path = require("path"); -const STEAK_HUB_WASM = - "../integration_test/dapp_tests/steak/contracts/steak_hub.wasm"; -const STEAK_TOKEN_WASM = - "../integration_test/dapp_tests/steak/contracts/steak_token.wasm"; +const testChain = process.env.DAPP_TEST_ENV; describe("Steak", async function () { let owner; let hubAddress; let tokenAddress; let tokenPointer; + let originalSeidConfig; - async function setupAccount(baseName, associate = true) { + 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); + await fundSeiAddress(account.address, amount, denom, funder); if (associate) { await associateKey(account.address); } + return account; } async function deployContracts(ownerAddress) { // Store CW20 token wasm - const tokenCodeId = await storeWasm(STEAK_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 hubCodeId = await storeWasm(STEAK_HUB_WASM); + 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(); @@ -69,8 +78,12 @@ describe("Steak", async function () { // Deploy pointer for token contract const pointerAddr = await deployErc20PointerForCw20( hre.ethers.provider, - contractAddresses.tokenContract + contractAddresses.tokenContract, + 10, + ownerAddress, + evmRpcUrls[testChain] ); + const tokenPointer = new hre.ethers.Contract( pointerAddr, ABI.ERC20, @@ -104,8 +117,28 @@ describe("Steak", async function () { } before(async function () { + + const seidConfig = await execute('seid config'); + originalSeidConfig = JSON.parse(seidConfig); + // Set up the owner account - owner = await setupAccount("steak-owner"); + 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) + } + + await execute(`seid config keyring-backend test`); // Store and deploy contracts ({ hubAddress, tokenAddress, tokenPointer } = await deployContracts( @@ -130,7 +163,7 @@ describe("Steak", async function () { }); it("Unassociated account should be able to bond", async function () { - const unassociatedAccount = await setupAccount("unassociated", false); + const unassociatedAccount = await setupAccount("unassociated", false, '2000000', 'usei', owner.address); // Verify that account is not associated yet const initialEvmAddress = await getEvmAddress( unassociatedAccount.address @@ -144,7 +177,7 @@ describe("Steak", async function () { expect(evmAddress).to.not.be.empty; // Send tokens to a new unassociated account - const newUnassociatedAccount = await setupAccount("unassociated", false); + const newUnassociatedAccount = await setupAccount("unassociated", false, '2000000', 'usei', owner.address); const transferAmount = 500000; await transferTokens( tokenAddress, @@ -162,4 +195,12 @@ describe("Steak", async function () { 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"]}`) + }) }); diff --git a/integration_test/dapp_tests/steak/utils.js b/integration_test/dapp_tests/steak/utils.js deleted file mode 100644 index 78188be73..000000000 --- a/integration_test/dapp_tests/steak/utils.js +++ /dev/null @@ -1,154 +0,0 @@ -const { execute } = require("../../../contracts/test/lib"); - -const encodeBase64 = (obj) => { - return Buffer.from(JSON.stringify(obj)).toString("base64"); -}; - -const getValidators = async () => { - const command = `seid q staking validators --output json`; - const output = await execute(command); - const response = JSON.parse(output); - return response.validators.map((v) => v.operator_address); -}; - -const getCodeIdFromContractAddress = async (contractAddress) => { - const command = `seid q wasm contract ${contractAddress} --output json`; - const output = await execute(command); - const response = JSON.parse(output); - return response.contract_info.code_id; -}; - -// Note: Not using the `deployWasm` function because we need to retrieve the -// hub and token contract addresses from the event logs -const instantiateHubContract = async ( - codeId, - adminAddress, - instantiateMsg, - label -) => { - const jsonString = JSON.stringify(instantiateMsg).replace(/"/g, '\\"'); - const command = `seid tx wasm instantiate ${codeId} "${jsonString}" --label ${label} --admin ${adminAddress} --from admin --gas=5000000 --fees=1000000usei -y --broadcast-mode block -o json`; - const output = await execute(command); - const response = JSON.parse(output); - // Get all attributes with _contractAddress - if (!response.logs || response.logs.length === 0) { - throw new Error("logs not returned"); - } - const addresses = []; - for (let event of response.logs[0].events) { - if (event.type === "instantiate") { - for (let attribute of event.attributes) { - if (attribute.key === "_contract_address") { - addresses.push(attribute.value); - } - } - } - } - - // Return hub and token contracts - const contracts = {}; - for (let address of addresses) { - const contractCodeId = await getCodeIdFromContractAddress(address); - if (contractCodeId === `${codeId}`) { - contracts.hubContract = address; - } else { - contracts.tokenContract = address; - } - } - return contracts; -}; - -const bond = async (contractAddress, address, amount) => { - const msg = { - 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 output = await execute(command); - const response = JSON.parse(output); - if (response.code !== 0) { - throw new Error(response.raw_log); - } - return response; -}; - -const unbond = async (hubAddress, tokenAddress, address, amount) => { - const msg = { - send: { - contract: hubAddress, - amount: `${amount}`, - msg: encodeBase64({ - queue_unbond: {}, - }), - }, - }; - const jsonString = JSON.stringify(msg).replace(/"/g, '\\"'); - const command = `seid tx wasm execute ${tokenAddress} "${jsonString}" --from=${address} --gas=500000 --gas-prices=0.1usei --broadcast-mode=block -y --output=json`; - const output = await execute(command); - const response = JSON.parse(output); - if (response.code !== 0) { - throw new Error(response.raw_log); - } - return response; -}; - -const harvest = async (contractAddress, address) => { - const msg = { - harvest: {}, - }; - const jsonString = JSON.stringify(msg).replace(/"/g, '\\"'); - const command = `seid tx wasm execute ${contractAddress} "${jsonString}" --from=${address} --gas=500000 --gas-prices=0.1usei --broadcast-mode=block -y --output=json`; - const output = await execute(command); - const response = JSON.parse(output); - if (response.code !== 0) { - throw new Error(response.raw_log); - } - return response; -}; - -const queryTokenBalance = async (contractAddress, address) => { - const msg = { - balance: { - address, - }, - }; - const jsonString = JSON.stringify(msg).replace(/"/g, '\\"'); - const command = `seid q wasm contract-state smart ${contractAddress} "${jsonString}" --output=json`; - const output = await execute(command); - const response = JSON.parse(output); - return response.data.balance; -}; - -const addAccount = async (accountName) => { - const command = `seid keys add ${accountName}-${Date.now()} --output=json`; - const output = await execute(command); - return JSON.parse(output); -}; - -const transferTokens = async (tokenAddress, sender, destination, amount) => { - const msg = { - transfer: { - recipient: destination, - amount: `${amount}`, - }, - }; - const jsonString = JSON.stringify(msg).replace(/"/g, '\\"'); - const command = `seid tx wasm execute ${tokenAddress} "${jsonString}" --from=${sender} --gas=200000 --gas-prices=0.1usei --broadcast-mode=block -y --output=json`; - const output = await execute(command); - const response = JSON.parse(output); - if (response.code !== 0) { - throw new Error(response.raw_log); - } - return response; -}; - -module.exports = { - getValidators, - instantiateHubContract, - bond, - unbond, - harvest, - queryTokenBalance, - addAccount, - transferTokens, -}; diff --git a/integration_test/dapp_tests/uniswap/constants.js b/integration_test/dapp_tests/uniswap/constants.js deleted file mode 100644 index b819fb3df..000000000 --- a/integration_test/dapp_tests/uniswap/constants.js +++ /dev/null @@ -1,24 +0,0 @@ -const tokenFactoryDenoms = { - "testnet": "factory/sei10xlj95ef20tczjrq5w5ah0vz8t5pxzeza4gaad/dapptest" -} - -const cw20Addresses = { - "testnet": {"evm": "0xcD10A4FdeE9CefB7732161f4B20b018bA3F4e7fF", "sei": "sei1d5cs4y0cfdm8dvak4fnmcudqd9htgsnw0djryuvpwhhmyvywypmsxv7vnq"} -} - -const rpcUrls = { - "testnet": "https://rpc-testnet.sei-apis.com", - "devnet": "https://rpc-arctic-1.sei-apis.com" -} - -const chainIds = { - "testnet": "atlantic-2", - "devnet": "arctic-1" -} - -module.exports = { - tokenFactoryDenoms, - cw20Addresses, - rpcUrls, - chainIds -} \ No newline at end of file diff --git a/integration_test/dapp_tests/uniswap/uniswapHelpers.js b/integration_test/dapp_tests/uniswap/uniswapHelpers.js deleted file mode 100644 index 9133aa085..000000000 --- a/integration_test/dapp_tests/uniswap/uniswapHelpers.js +++ /dev/null @@ -1,196 +0,0 @@ -const hre = require("hardhat"); -const {BigNumber} = require("ethers"); // Require Hardhat Runtime Environment -const { ABI, deployErc20PointerForCw20, deployWasm, execute } = require("../../../contracts/test/lib.js"); - -async function deployTokenPool(managerContract, firstTokenAddr, secondTokenAddr, swapRatio=1, fee=3000) { - const sqrtPriceX96 = BigInt(Math.sqrt(swapRatio) * (2 ** 96)); // Initial price (1:1) - - const gasPrice = await hre.ethers.provider.getGasPrice(); - const [token0, token1] = tokenOrder(firstTokenAddr, secondTokenAddr); - - let gasLimit = await managerContract.estimateGas.createAndInitializePoolIfNecessary( - token0.address, - token1.address, - fee, - sqrtPriceX96, - ); - - gasLimit = gasLimit.mul(12).div(10) - console.log("EST GAS", gasLimit) - // token0 addr must be < token1 addr - const poolTx = await managerContract.createAndInitializePoolIfNecessary( - token0.address, - token1.address, - fee, - sqrtPriceX96, - {gasLimit, gasPrice} - ); - await poolTx.wait(); - console.log("Pool created and initialized"); -} - -// Supplies liquidity to then given pools. The signer connected to the contracts must have the prerequisite tokens or this will fail. -async function supplyLiquidity(managerContract, recipientAddr, firstTokenContract, secondTokenContract, firstTokenAmt=100, secondTokenAmt=100) { - // Define the amount of tokens to be approved and added as liquidity - console.log("Supplying liquidity to pool") - const [token0, token1] = tokenOrder(firstTokenContract.address, secondTokenContract.address, firstTokenAmt, secondTokenAmt); - const gasPrice = await hre.ethers.provider.getGasPrice(); - - let gasLimit = await firstTokenContract.estimateGas.approve(managerContract.address, firstTokenAmt); - gasLimit = gasLimit.mul(12).div(10) - - // Approve the NonfungiblePositionManager to spend the specified amount of firstToken - const approveFirstTokenTx = await firstTokenContract.approve(managerContract.address, firstTokenAmt, {gasLimit, gasPrice}); - await approveFirstTokenTx.wait(); - let allowance = await firstTokenContract.allowance(recipientAddr, managerContract.address); - console.log('allowance1', allowance); - let balance = await firstTokenContract.balanceOf(recipientAddr); - console.log("bal1", balance) - - gasLimit = await secondTokenContract.estimateGas.approve(managerContract.address, secondTokenAmt); - gasLimit = gasLimit.mul(12).div(10) - - // Approve the NonfungiblePositionManager to spend the specified amount of secondToken - const approveSecondTokenTx = await secondTokenContract.approve(managerContract.address, secondTokenAmt, {gasLimit, gasPrice}); - await approveSecondTokenTx.wait(); - - allowance = await secondTokenContract.allowance(recipientAddr, managerContract.address); - console.log('allowance2', allowance); - balance = await secondTokenContract.balanceOf(recipientAddr); - console.log("bal2", balance) - - gasLimit = await managerContract.estimateGas.mint({ - token0: token0.address, - token1: token1.address, - fee: 3000, // Fee tier (0.3%) - tickLower: -887220, - tickUpper: 887220, - amount0Desired: token0.amount, - amount1Desired: token1.amount, - amount0Min: 0, - amount1Min: 0, - recipient: recipientAddr, - deadline: Math.floor(Date.now() / 1000) + 60 * 10, // 10 minutes from now - }) - - gasLimit = gasLimit.mul(12).div(10) - console.log("Liquidity Gas Limit", gasLimit); - - // Add liquidity to the pool - const liquidityTx = await managerContract.mint({ - token0: token0.address, - token1: token1.address, - fee: 3000, // Fee tier (0.3%) - tickLower: -887220, - tickUpper: 887220, - amount0Desired: token0.amount, - amount1Desired: token1.amount, - amount0Min: 0, - amount1Min: 0, - recipient: recipientAddr, - deadline: Math.floor(Date.now() / 1000) + 60 * 10, // 10 minutes from now - }, {gasLimit, gasPrice}); - - await liquidityTx.wait(); - console.log("Liquidity added"); -} - -// Orders the 2 addresses sequentially, since this is required by uniswap. -function tokenOrder(firstTokenAddr, secondTokenAddr, firstTokenAmount=0, secondTokenAmount=0) { - let token0; - let token1; - if (parseInt(firstTokenAddr, 16) < parseInt(secondTokenAddr, 16)) { - token0= {address: firstTokenAddr, amount: firstTokenAmount}; - token1 = {address: secondTokenAddr, amount: secondTokenAmount}; - } else { - token0 = {address: secondTokenAddr, amount: secondTokenAmount}; - token1 = {address: firstTokenAddr, amount: firstTokenAmount}; - } - return [token0, token1] -} - -async function deployCw20WithPointer(deployerSeiAddr, signer, time) { - const cw20Address = await deployWasm('../integration_test/dapp_tests/uniswap/cw20_base.wasm', deployerSeiAddr, "cw20", { - name: `testCw20${time}`, - symbol: "TEST", - decimals: 6, - initial_balances: [ - { address: deployerSeiAddr, amount: "1000000000" } - ], - mint: { - "minter": deployerSeiAddr, "cap": "99900000000" - } - }); - - const pointerAddr = await deployErc20PointerForCw20(hre.ethers.provider, cw20Address); - const pointerContract = new hre.ethers.Contract(pointerAddr, ABI.ERC20, signer); - return {"pointerContract": pointerContract, "cw20Address": cw20Address} -} - -async function deployEthersContract(name, abi, bytecode, deployer, deployParams=[]) { - const contract = new hre.ethers.ContractFactory(abi, bytecode, deployer); - const deployed = await contract.deploy(...deployParams); - await deployed.deployed(); - console.log(`${name} deployed to:`, deployed.address); - return deployed; -} - -async function addDeployerKey(keyName, mnemonic, path) { - try { - const output = await execute(`seid keys show ${keyName} --output json`); - const parsed = JSON.parse(output); - console.log("OUTOPUT", parsed); - return parsed.address; - } catch (e) { - console.log(e) - } - - try { - await execute(`printf "${mnemonic}" | seid keys add ${keyName} --recover --hd-path "${path}" --keyring-backend test`) - } - catch (e) { - console.log(e); - } - - const output = await execute(`seid keys show ${keyName} --output json`); - const parsed = JSON.parse(output); - - return parsed.address; -} - -async function doesTokenFactoryDenomExist(denom) { - const output = await execute(`seid q tokenfactory denom-authority-metadata ${denom} --output json`); - const parsed = JSON.parse(output); - - return parsed.authority_metadata.admin !== ""; -} - -async function sendFunds(amountSei, recipient, signer) { - const bal = await signer.getBalance(); - const gasLimit = await signer.estimateGas({ - to: recipient, - value: hre.ethers.utils.parseEther(amountSei) - }) - - // Get current gas price from the network - const gasPrice = await signer.getGasPrice(); - - const fundUser = await signer.sendTransaction({ - to: recipient, - value: hre.ethers.utils.parseEther(amountSei), - gasLimit: gasLimit.mul(12).div(10), - gasPrice: gasPrice, - }) - - await fundUser.wait(); -} - -module.exports = { - deployTokenPool, - supplyLiquidity, - deployCw20WithPointer, - deployEthersContract, - addDeployerKey, - doesTokenFactoryDenomExist, - sendFunds -} \ No newline at end of file diff --git a/integration_test/dapp_tests/uniswap/uniswapTest.js b/integration_test/dapp_tests/uniswap/uniswapTest.js index 17e2d4a49..9347abe07 100755 --- a/integration_test/dapp_tests/uniswap/uniswapTest.js +++ b/integration_test/dapp_tests/uniswap/uniswapTest.js @@ -6,31 +6,34 @@ const { abi: DESCRIPTOR_ABI, bytecode: DESCRIPTOR_BYTECODE } = require("@uniswap 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, getPointerForNative, deployErc20PointerNative, execute, getSeiAddress, queryWasm, getSeiBalance, ABI } = require("../../../contracts/test/lib.js"); -const { deployTokenPool, supplyLiquidity, deployCw20WithPointer, deployEthersContract, sendFunds } = require("./uniswapHelpers.js") -const {cw20Addresses, tokenFactoryDenoms, rpcUrls, chainIds} = require("./constants") +const { fundAddress, createTokenFactoryTokenAndMint, deployErc20PointerNative, execute, getSeiAddress, queryWasm, getSeiBalance, isDocker, ABI } = require("../../../contracts/test/lib.js"); +const { deployTokenPool, supplyLiquidity, deployCw20WithPointer, deployEthersContract, sendFunds, pollBalance, setupAccountWithMnemonic } = require("../utils.js") +const { rpcUrls, chainIds, evmRpcUrls} = require("../constants") const { expect } = require("chai"); const testChain = process.env.DAPP_TEST_ENV; -describe("EVM Test", function () { +describe("Uniswap Test", function () { let weth9; let token; let erc20TokenFactory; let tokenFactoryDenom; let erc20cw20; let cw20Address; + let factory; let router; let manager; let deployer; let user; + let originalSeidConfig; before(async function () { - [deployer] = await hre.ethers.getSigners(); + 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); - // const account = hre.config.networks.hardhat.accounts; - // const deployerKeyName = "deployer" - // const deployerAddr = await addDeployerKey(deployerKeyName, account.mnemonic, account.path); - // console.log(deployerAddr); if (testChain === 'seilocal') { await fundAddress(deployer.address, amount="2000000000000000000000"); } else { @@ -39,60 +42,51 @@ describe("EVM Test", function () { 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); + + // Fund user account const userWallet = hre.ethers.Wallet.createRandom(); user = userWallet.connect(hre.ethers.provider); - await sendFunds("20", user.address, deployer) + await sendFunds("5", user.address, deployer) const deployerSeiAddr = await getSeiAddress(deployer.address); // Deploy Required Tokens - // If local chain, deployer should have received all the tokens on first mint. - // Otherwise, deployer needs to own all the tokens before this test is run. const time = Date.now().toString(); - if (testChain === 'seilocal') { - // Deploy TokenFactory token with ERC20 pointer - const tokenName = `dappTests${time}` - tokenFactoryDenom = await createTokenFactoryTokenAndMint(tokenName, 10000000000, deployerSeiAddr) - console.log("DENOM", tokenFactoryDenom) - const pointerAddr = await deployErc20PointerNative(hre.ethers.provider, tokenFactoryDenom) - console.log("Pointer Addr", pointerAddr); - erc20TokenFactory = new hre.ethers.Contract(pointerAddr, ABI.ERC20, deployer); - } else { - tokenFactoryDenom = tokenFactoryDenoms[testChain] - const pointer= await getPointerForNative(tokenFactoryDenom); - erc20TokenFactory = new hre.ethers.Contract(pointer.pointer, ABI.ERC20, deployer); - } + // 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); - if (testChain === 'seilocal') { - // Deploy CW20 token with ERC20 pointer - const cw20Details = await deployCw20WithPointer(deployerSeiAddr, deployer, time) - erc20cw20 = cw20Details.pointerContract; - cw20Address = cw20Details.cw20Address; - } else { - const cw20addrs = cw20Addresses[testChain] - cw20Address = cw20addrs.sei - erc20cw20 = new hre.ethers.Contract(cw20addrs.evm, 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 MockERC20 = await hre.ethers.getContractFactory("MockERC20"); - token = await MockERC20.deploy("MockToken", "MKT", hre.ethers.utils.parseEther("1000000")); - await token.deployed(); - console.log("MockToken deployed to:", token.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 - const factory = await deployEthersContract("Uniswap V3 Factory", FACTORY_ABI, FACTORY_BYTECODE, deployer); + 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]); @@ -103,19 +97,21 @@ describe("EVM Test", function () { const amountETH = hre.ethers.utils.parseEther("30") // Gets the amount of WETH9 required to instantiate pools by depositing Sei to the contract - const txWrap = await weth9.deposit({ value: amountETH }); + 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, swapRatio=10**-13) - await deployTokenPool(manager, weth9.address, erc20cw20.address, swapRatio=10**-13) + 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("10"), hre.ethers.utils.parseEther("10")) - await supplyLiquidity(manager, deployer.address, weth9, erc20TokenFactory, hre.ethers.utils.parseEther("10"), 100000000) - await supplyLiquidity(manager, deployer.address, weth9, erc20cw20, hre.ethers.utils.parseEther("10"), 100000000) + await supplyLiquidity(manager, deployer.address, weth9, erc20TokenFactory, hre.ethers.utils.parseEther("10"), hre.ethers.utils.parseEther("10")) + await supplyLiquidity(manager, deployer.address, weth9, erc20cw20, hre.ethers.utils.parseEther("10"), hre.ethers.utils.parseEther("10")) }) describe("Swaps", function () { @@ -180,7 +176,7 @@ describe("EVM Test", function () { const unassocUser = unassocUserWallet.connect(ethers.provider); // Fund the user account - await sendFunds("2", unassocUser.address, deployer) + await sendFunds("0.1", unassocUser.address, deployer) const fee = 3000; // Fee tier (0.3%) @@ -188,7 +184,9 @@ describe("EVM Test", function () { const amountIn = hre.ethers.utils.parseEther("1"); const amountOutMin = hre.ethers.utils.parseEther("0"); // Minimum amount of MockToken expected - const deposit = await token1.deposit({ value: amountIn }); + let gasPrice = await deployer.getGasPrice(); + let gasLimit = token1.estimateGas.deposit({ value: amountIn }); + const deposit = await token1.deposit({ value: amountIn, gasPrice, gasLimit }); await deposit.wait(); const token1balance = await token1.balanceOf(deployer.address); @@ -196,42 +194,37 @@ describe("EVM Test", function () { // Check that deployer has amountIn amount of token1 expect(Number(token1balance)).to.greaterThanOrEqual(Number(amountIn), "token1 balance should be received by user") - const approval = await token1.approve(router.address, amountIn); + gasLimit = token1.estimateGas.approve(router.address, amountIn); + const approval = await token1.approve(router.address, amountIn, {gasPrice, gasLimit}); await approval.wait(); - const allowance = await token1.allowance(deployer.address, router.address); // Check that deployer has approved amountIn amount of token1 to be used by router expect(allowance).to.equal(amountIn, "token1 allowance to router should be set correctly by user") + const txParams = { + tokenIn: token1.address, + tokenOut: token2.address, + fee, + recipient: unassocUser.address, + deadline: Math.floor(Date.now() / 1000) + 60 * 10, // 10 minutes from now + amountIn, + amountOutMinimum: amountOutMin, + sqrtPriceLimitX96: 0 + } + gasLimit = router.estimateGas.exactInputSingle(txParams); + if (expectSwapFail) { - expect(router.exactInputSingle({ - tokenIn: token1.address, - tokenOut: token2.address, - fee, - recipient: unassocUser.address, - deadline: Math.floor(Date.now() / 1000) + 60 * 10, // 10 minutes from now - amountIn, - amountOutMinimum: amountOutMin, - sqrtPriceLimitX96: 0 - })).to.be.reverted; + expect(router.exactInputSingle(txParams, {gasPrice, gasLimit})).to.be.reverted; } else { // Perform the swap, with recipient being the unassociated account. - const tx = await router.exactInputSingle({ - tokenIn: token1.address, - tokenOut: token2.address, - fee, - recipient: unassocUser.address, - deadline: Math.floor(Date.now() / 1000) + 60 * 10, // 10 minutes from now - amountIn, - amountOutMinimum: amountOutMin, - sqrtPriceLimitX96: 0 - }); + const tx = await router.exactInputSingle(txParams, {gasPrice, gasLimit}); await tx.wait(); // Check User's MockToken Balance - const balance = await token2.balanceOf(unassocUser.address); + 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") } @@ -301,10 +294,14 @@ describe("EVM Test", function () { await sendFunds("2", unassocUser.address, deployer) const erc20TokenFactoryAmount = "100000" - const tx = await erc20TokenFactory.transfer(unassocUser.address, erc20TokenFactoryAmount); + let gasPrice = deployer.getGasPrice(); + let gasLimit = erc20TokenFactory.estimateGas.transfer(unassocUser.address, erc20TokenFactoryAmount); + const tx = await erc20TokenFactory.transfer(unassocUser.address, erc20TokenFactoryAmount, {gasPrice, gasLimit}); await tx.wait(); const mockTokenAmount = "100000" - const tx2 = await token.transfer(unassocUser.address, mockTokenAmount); + + gasLimit = token.estimateGas.transfer(unassocUser.address, mockTokenAmount); + const tx2 = await token.transfer(unassocUser.address, mockTokenAmount, {gasPrice, gasLimit}); await tx2.wait(); const managerConnected = manager.connect(unassocUser); const erc20TokenFactoryConnected = erc20TokenFactory.connect(unassocUser); @@ -316,9 +313,8 @@ describe("EVM Test", function () { after(async function () { // Set the chain back to regular state console.log("Resetting") - if (testChain !== 'seilocal') { - await execute(`seid config chain-id sei-chain`) - await execute(`seid config node tcp://localhost:26657`) - } + 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"]}`) }) }) \ No newline at end of file diff --git a/integration_test/dapp_tests/utils.js b/integration_test/dapp_tests/utils.js new file mode 100644 index 000000000..31a22a7f9 --- /dev/null +++ b/integration_test/dapp_tests/utils.js @@ -0,0 +1,368 @@ +const {v4: uuidv4} = require("uuid"); +const hre = require("hardhat"); +const { ABI, deployErc20PointerForCw20, getSeiAddress, deployWasm, execute, delay, isDocker } = require("../../contracts/test/lib.js"); +const path = require('path') + +async function deployTokenPool(managerContract, firstTokenAddr, secondTokenAddr, swapRatio=1, fee=3000) { + const sqrtPriceX96 = BigInt(Math.sqrt(swapRatio) * (2 ** 96)); // Initial price (1:1) + + const gasPrice = await hre.ethers.provider.getGasPrice(); + const [token0, token1] = tokenOrder(firstTokenAddr, secondTokenAddr); + + let gasLimit = await managerContract.estimateGas.createAndInitializePoolIfNecessary( + token0.address, + token1.address, + fee, + sqrtPriceX96, + ); + + gasLimit = gasLimit.mul(12).div(10) + // token0 addr must be < token1 addr + const poolTx = await managerContract.createAndInitializePoolIfNecessary( + token0.address, + token1.address, + fee, + sqrtPriceX96, + {gasLimit, gasPrice} + ); + await poolTx.wait(); + console.log("Pool created and initialized"); +} + +// Supplies liquidity to then given pools. The signer connected to the contracts must have the prerequisite tokens or this will fail. +async function supplyLiquidity(managerContract, recipientAddr, firstTokenContract, secondTokenContract, firstTokenAmt=100, secondTokenAmt=100) { + // Define the amount of tokens to be approved and added as liquidity + console.log("Supplying liquidity to pool") + const [token0, token1] = tokenOrder(firstTokenContract.address, secondTokenContract.address, firstTokenAmt, secondTokenAmt); + const gasPrice = await hre.ethers.provider.getGasPrice(); + + let gasLimit = await firstTokenContract.estimateGas.approve(managerContract.address, firstTokenAmt); + gasLimit = gasLimit.mul(12).div(10) + + // Approve the NonfungiblePositionManager to spend the specified amount of firstToken + const approveFirstTokenTx = await firstTokenContract.approve(managerContract.address, firstTokenAmt, {gasLimit, gasPrice}); + await approveFirstTokenTx.wait(); + let allowance = await firstTokenContract.allowance(recipientAddr, managerContract.address); + let balance = await firstTokenContract.balanceOf(recipientAddr); + + gasLimit = await secondTokenContract.estimateGas.approve(managerContract.address, secondTokenAmt); + gasLimit = gasLimit.mul(12).div(10) + + // Approve the NonfungiblePositionManager to spend the specified amount of secondToken + const approveSecondTokenTx = await secondTokenContract.approve(managerContract.address, secondTokenAmt, {gasLimit, gasPrice}); + await approveSecondTokenTx.wait(); + + allowance = await secondTokenContract.allowance(recipientAddr, managerContract.address); + balance = await secondTokenContract.balanceOf(recipientAddr); + + gasLimit = await managerContract.estimateGas.mint({ + token0: token0.address, + token1: token1.address, + fee: 3000, // Fee tier (0.3%) + tickLower: -887220, + tickUpper: 887220, + amount0Desired: token0.amount, + amount1Desired: token1.amount, + amount0Min: 0, + amount1Min: 0, + recipient: recipientAddr, + deadline: Math.floor(Date.now() / 1000) + 60 * 10, // 10 minutes from now + }) + + gasLimit = gasLimit.mul(12).div(10) + + // Add liquidity to the pool + const liquidityTx = await managerContract.mint({ + token0: token0.address, + token1: token1.address, + fee: 3000, // Fee tier (0.3%) + tickLower: -887220, + tickUpper: 887220, + amount0Desired: token0.amount, + amount1Desired: token1.amount, + amount0Min: 0, + amount1Min: 0, + recipient: recipientAddr, + deadline: Math.floor(Date.now() / 1000) + 60 * 10, // 10 minutes from now + }, {gasLimit, gasPrice}); + + await liquidityTx.wait(); + console.log("Liquidity added"); +} + +// Orders the 2 addresses sequentially, since this is required by uniswap. +function tokenOrder(firstTokenAddr, secondTokenAddr, firstTokenAmount=0, secondTokenAmount=0) { + let token0; + let token1; + if (parseInt(firstTokenAddr, 16) < parseInt(secondTokenAddr, 16)) { + token0= {address: firstTokenAddr, amount: firstTokenAmount}; + token1 = {address: secondTokenAddr, amount: secondTokenAmount}; + } else { + token0 = {address: secondTokenAddr, amount: secondTokenAmount}; + token1 = {address: firstTokenAddr, amount: firstTokenAmount}; + } + return [token0, token1] +} + +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", { + name: `testCw20${time}`, + symbol: "TEST", + decimals: 6, + initial_balances: [ + { address: deployerSeiAddr, amount: hre.ethers.utils.parseEther("1000000").toString() } + ], + mint: { + "minter": deployerSeiAddr, "cap": hre.ethers.utils.parseEther("10000000").toString() + } + }, deployerSeiAddr); + const pointerAddr = await deployErc20PointerForCw20(hre.ethers.provider, cw20Address, 10, deployerSeiAddr, evmRpc); + const pointerContract = new hre.ethers.Contract(pointerAddr, ABI.ERC20, signer); + return {"pointerContract": pointerContract, "cw20Address": cw20Address} +} + +async function deployEthersContract(name, abi, bytecode, deployer, deployParams=[]) { + const contract = new hre.ethers.ContractFactory(abi, bytecode, deployer); + const deployTx = contract.getDeployTransaction(...deployParams); + const gasEstimate = await deployer.estimateGas(deployTx); + const gasPrice = await deployer.getGasPrice(); + const deployed = await contract.deploy(...deployParams, {gasPrice, gasLimit: gasEstimate}); + await deployed.deployed(); + console.log(`${name} deployed to:`, deployed.address); + return deployed; +} + +async function doesTokenFactoryDenomExist(denom) { + const output = await execute(`seid q tokenfactory denom-authority-metadata ${denom} --output json`); + const parsed = JSON.parse(output); + + return parsed.authority_metadata.admin !== ""; +} + +async function sendFunds(amountSei, recipient, signer) { + const gasLimit = await signer.estimateGas({ + to: recipient, + value: hre.ethers.utils.parseEther(amountSei) + }) + + // Get current gas price from the network + const gasPrice = await signer.getGasPrice(); + + const fundUser = await signer.sendTransaction({ + to: recipient, + value: hre.ethers.utils.parseEther(amountSei), + gasLimit: gasLimit.mul(12).div(10), + gasPrice: gasPrice, + }) + + await fundUser.wait(); +} + +async function pollBalance(erc20Contract, address, criteria, maxAttempts=3) { + let bal = 0; + let attempt = 1; + while (attempt === 1 || attempt <= maxAttempts) { + bal = await erc20Contract.balanceOf(address); + attempt++; + if (criteria(bal)) { + return bal; + } + await delay(); + } + + return bal; +} + +const encodeBase64 = (obj) => { + return Buffer.from(JSON.stringify(obj)).toString("base64"); +}; + +const getValidators = async () => { + const command = `seid q staking validators --output json`; + const output = await execute(command); + const response = JSON.parse(output); + return response.validators.map((v) => v.operator_address); +}; + +const getCodeIdFromContractAddress = async (contractAddress) => { + const command = `seid q wasm contract ${contractAddress} --output json`; + const output = await execute(command); + const response = JSON.parse(output); + return response.contract_info.code_id; +}; + +// Note: Not using the `deployWasm` function because we need to retrieve the +// hub and token contract addresses from the event logs +const instantiateHubContract = async ( + codeId, + adminAddress, + instantiateMsg, + label +) => { + const jsonString = JSON.stringify(instantiateMsg).replace(/"/g, '\\"'); + const command = `seid tx wasm instantiate ${codeId} "${jsonString}" --label ${label} --admin ${adminAddress} --from ${adminAddress} --gas=5000000 --fees=1000000usei -y --broadcast-mode block -o json`; + const output = await execute(command); + const response = JSON.parse(output); + // Get all attributes with _contractAddress + if (!response.logs || response.logs.length === 0) { + throw new Error("logs not returned"); + } + const addresses = []; + for (let event of response.logs[0].events) { + if (event.type === "instantiate") { + for (let attribute of event.attributes) { + if (attribute.key === "_contract_address") { + addresses.push(attribute.value); + } + } + } + } + + // Return hub and token contracts + const contracts = {}; + for (let address of addresses) { + const contractCodeId = await getCodeIdFromContractAddress(address); + if (contractCodeId === `${codeId}`) { + contracts.hubContract = address; + } else { + contracts.tokenContract = address; + } + } + return contracts; +}; + +const bond = async (contractAddress, address, amount) => { + const msg = { + 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 output = await execute(command); + const response = JSON.parse(output); + if (response.code !== 0) { + throw new Error(response.raw_log); + } + return response; +}; + +const unbond = async (hubAddress, tokenAddress, address, amount) => { + const msg = { + send: { + contract: hubAddress, + amount: `${amount}`, + msg: encodeBase64({ + queue_unbond: {}, + }), + }, + }; + const jsonString = JSON.stringify(msg).replace(/"/g, '\\"'); + const command = `seid tx wasm execute ${tokenAddress} "${jsonString}" --from=${address} --gas=500000 --gas-prices=0.1usei --broadcast-mode=block -y --output=json`; + const output = await execute(command); + const response = JSON.parse(output); + if (response.code !== 0) { + throw new Error(response.raw_log); + } + return response; +}; + +const harvest = async (contractAddress, address) => { + const msg = { + harvest: {}, + }; + const jsonString = JSON.stringify(msg).replace(/"/g, '\\"'); + const command = `seid tx wasm execute ${contractAddress} "${jsonString}" --from=${address} --gas=500000 --gas-prices=0.1usei --broadcast-mode=block -y --output=json`; + const output = await execute(command); + const response = JSON.parse(output); + if (response.code !== 0) { + throw new Error(response.raw_log); + } + return response; +}; + +const queryTokenBalance = async (contractAddress, address) => { + const msg = { + balance: { + address, + }, + }; + const jsonString = JSON.stringify(msg).replace(/"/g, '\\"'); + const command = `seid q wasm contract-state smart ${contractAddress} "${jsonString}" --output=json`; + const output = await execute(command); + const response = JSON.parse(output); + return response.data.balance; +}; + +const addAccount = async (accountName) => { + const command = `seid keys add ${accountName}-${Date.now()} --output=json --keyring-backend test`; + const output = await execute(command); + return JSON.parse(output); +}; + +const transferTokens = async (tokenAddress, sender, destination, amount) => { + const msg = { + transfer: { + recipient: destination, + amount: `${amount}`, + }, + }; + const jsonString = JSON.stringify(msg).replace(/"/g, '\\"'); + const command = `seid tx wasm execute ${tokenAddress} "${jsonString}" --from=${sender} --gas=200000 --gas-prices=0.1usei --broadcast-mode=block -y --output=json`; + const output = await execute(command); + const response = JSON.parse(output); + if (response.code !== 0) { + throw new Error(response.raw_log); + } + return response; +}; + +async function setupAccountWithMnemonic(baseName, mnemonic, deployer) { + const uniqueName = `${baseName}-${uuidv4()}`; + const address = await getSeiAddress(deployer.address) + + return await addDeployerAccount(uniqueName, address, mnemonic) +} + +async function addDeployerAccount(keyName, address, mnemonic) { + // First try to retrieve by address + try { + const output = await execute(`seid keys show ${address} --output json --keyring-backend test`); + return JSON.parse(output); + } catch (e) {} + + // Since the address doesn't exist, create the key with random name + try { + let output; + if (await isDocker()) { + // NOTE: The path here is assumed to be "m/44'/118'/0'/0/0" + output = await execute(`seid keys add ${keyName} --recover --keyring-backend test`,`printf "${mnemonic}"`) + } else { + output = await execute(`printf "${mnemonic}" | seid keys add ${keyName} --recover --keyring-backend test`) + } + } + catch (e) {} + + // If both of the calls above fail, this one will fail. + const output = await execute(`seid keys show ${keyName} --output json --keyring-backend test`); + return JSON.parse(output); +} + +module.exports = { + getValidators, + instantiateHubContract, + bond, + unbond, + harvest, + queryTokenBalance, + addAccount, + addDeployerAccount, + setupAccountWithMnemonic, + transferTokens, + deployTokenPool, + supplyLiquidity, + deployCw20WithPointer, + deployEthersContract, + doesTokenFactoryDenomExist, + pollBalance, + sendFunds +}; \ No newline at end of file diff --git a/loadtest/loadtest_client.go b/loadtest/loadtest_client.go index 945de4bc9..a990c11a3 100644 --- a/loadtest/loadtest_client.go +++ b/loadtest/loadtest_client.go @@ -265,7 +265,7 @@ func (c *LoadTestClient) SendTxs( fmt.Printf("Failed to acquire semaphore: %v", err) break } - if tx.TxBytes != nil && len(tx.TxBytes) > 0 { + if len(tx.TxBytes) > 0 { // Send Cosmos Transactions if SendTx(ctx, tx.TxBytes, typestx.BroadcastMode_BROADCAST_MODE_BLOCK, *c) { atomic.AddInt64(producedCountPerMsgType[tx.MsgType], 1) From 97ec7f466c9e0cbde9abe56725582d35e86f08de Mon Sep 17 00:00:00 2001 From: codchen Date: Mon, 19 Aug 2024 22:59:50 +0800 Subject: [PATCH 16/38] bump tendermint (#1819) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 16142d8af..4bc4abfed 100644 --- a/go.mod +++ b/go.mod @@ -354,7 +354,7 @@ replace ( github.com/sei-protocol/sei-db => github.com/sei-protocol/sei-db v0.0.40 // Latest goleveldb is broken, we have to stick to this version github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 - github.com/tendermint/tendermint => github.com/sei-protocol/sei-tendermint v0.3.6 + github.com/tendermint/tendermint => github.com/sei-protocol/sei-tendermint v0.3.8 github.com/tendermint/tm-db => github.com/sei-protocol/tm-db v0.0.4 google.golang.org/grpc => google.golang.org/grpc v1.33.2 ) diff --git a/go.sum b/go.sum index d35f21e68..849123f0b 100644 --- a/go.sum +++ b/go.sum @@ -1355,8 +1355,8 @@ github.com/sei-protocol/sei-iavl v0.1.9 h1:y4mVYftxLNRs6533zl7N0/Ch+CzRQc04JDfHo github.com/sei-protocol/sei-iavl v0.1.9/go.mod h1:7PfkEVT5dcoQE+s/9KWdoXJ8VVVP1QpYYPLdxlkSXFk= github.com/sei-protocol/sei-ibc-go/v3 v3.3.2 h1:BaMZ6gjwqe3R/5dLmcJ1TkSZ3omcWy2TjaAZAeOJH44= github.com/sei-protocol/sei-ibc-go/v3 v3.3.2/go.mod h1:VwB/vWu4ysT5DN2aF78d17LYmx3omSAdq6gpKvM7XRA= -github.com/sei-protocol/sei-tendermint v0.3.6 h1:bvvyWHyJcdCo6+b5Da8p9STyC+7tSNKAI9XPQsYgBuU= -github.com/sei-protocol/sei-tendermint v0.3.6/go.mod h1:4LSlJdhl3nf3OmohliwRNUFLOB1XWlrmSodrIP7fLh4= +github.com/sei-protocol/sei-tendermint v0.3.8 h1:9o+A3tL6q1ki++dLng/J8MHHiT6y3l7D4Ir2UIQSkAQ= +github.com/sei-protocol/sei-tendermint v0.3.8/go.mod h1:4LSlJdhl3nf3OmohliwRNUFLOB1XWlrmSodrIP7fLh4= github.com/sei-protocol/sei-tm-db v0.0.5 h1:3WONKdSXEqdZZeLuWYfK5hP37TJpfaUa13vAyAlvaQY= github.com/sei-protocol/sei-tm-db v0.0.5/go.mod h1:Cpa6rGyczgthq7/0pI31jys2Fw0Nfrc+/jKdP1prVqY= github.com/sei-protocol/sei-wasmd v0.2.3 h1:txB7LIx4Luh7+fxVN4/PiHEAjYnkutKyrpsuIFW8lmA= From c1c8bdcecd5dbafbeabb64ed894dc0eda9551d9e Mon Sep 17 00:00:00 2001 From: Yiming Zang <50607998+yzang2019@users.noreply.github.com> Date: Mon, 19 Aug 2024 10:21:58 -0700 Subject: [PATCH 17/38] Bump seidb to fix receipt missing on restart issue (#1817) * Bump seidb to fix receipt missing on restart issue * Fix go mod --- app/test_state_store.go | 4 ++++ go.mod | 2 +- go.sum | 4 ++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/app/test_state_store.go b/app/test_state_store.go index a942221a2..7595fd954 100644 --- a/app/test_state_store.go +++ b/app/test_state_store.go @@ -235,6 +235,10 @@ func (s *InMemoryStateStore) Prune(version int64) error { return nil } +func (db *InMemoryStateStore) RawImport(ch <-chan types.RawSnapshotNode) error { + panic("implement me") +} + func (s *InMemoryStateStore) Close() error { s.mu.Lock() defer s.mu.Unlock() diff --git a/go.mod b/go.mod index 4bc4abfed..4ced8fd34 100644 --- a/go.mod +++ b/go.mod @@ -351,7 +351,7 @@ replace ( github.com/cosmos/ibc-go/v3 => github.com/sei-protocol/sei-ibc-go/v3 v3.3.2 github.com/ethereum/go-ethereum => github.com/sei-protocol/go-ethereum v1.13.5-sei-22 github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 - github.com/sei-protocol/sei-db => github.com/sei-protocol/sei-db v0.0.40 + github.com/sei-protocol/sei-db => github.com/sei-protocol/sei-db v0.0.43 // Latest goleveldb is broken, we have to stick to this version github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 github.com/tendermint/tendermint => github.com/sei-protocol/sei-tendermint v0.3.8 diff --git a/go.sum b/go.sum index 849123f0b..dddd1476d 100644 --- a/go.sum +++ b/go.sum @@ -1349,8 +1349,8 @@ github.com/sei-protocol/goutils v0.0.2 h1:Bfa7Sv+4CVLNM20QcpvGb81B8C5HkQC/kW1CQp github.com/sei-protocol/goutils v0.0.2/go.mod h1:iYE2DuJfEnM+APPehr2gOUXfuLuPsVxorcDO+Tzq9q8= github.com/sei-protocol/sei-cosmos v0.3.31 h1:8qnubgQd83F2/Pxx5DmNH2vnl1XtTOAFbW44cEHbeCo= github.com/sei-protocol/sei-cosmos v0.3.31/go.mod h1:og/KbejR/zSQ8otapODEDU9zYNhFSUDbq9+tgeYePyU= -github.com/sei-protocol/sei-db v0.0.40 h1:s6B3u9u0r2Ypd67P8Lrz2IR/QU/FXwtS2X/fnYEix2g= -github.com/sei-protocol/sei-db v0.0.40/go.mod h1:F/ZKZA8HJPcUzSZPA8yt6pfwlGriJ4RDR4eHKSGLStI= +github.com/sei-protocol/sei-db v0.0.43 h1:m9kIWqSBCvKRLPGbAttlqCytIlPxVZbKchAEbVKSHHk= +github.com/sei-protocol/sei-db v0.0.43/go.mod h1:F/ZKZA8HJPcUzSZPA8yt6pfwlGriJ4RDR4eHKSGLStI= github.com/sei-protocol/sei-iavl v0.1.9 h1:y4mVYftxLNRs6533zl7N0/Ch+CzRQc04JDfHolIxgBE= github.com/sei-protocol/sei-iavl v0.1.9/go.mod h1:7PfkEVT5dcoQE+s/9KWdoXJ8VVVP1QpYYPLdxlkSXFk= github.com/sei-protocol/sei-ibc-go/v3 v3.3.2 h1:BaMZ6gjwqe3R/5dLmcJ1TkSZ3omcWy2TjaAZAeOJH44= From 68597936bc3decc1c3f0495f05fbc8203bbe2cfa Mon Sep 17 00:00:00 2001 From: Yiming Zang <50607998+yzang2019@users.noreply.github.com> Date: Mon, 19 Aug 2024 10:21:58 -0700 Subject: [PATCH 18/38] Bump seidb to fix receipt missing on restart issue (#1817) * Bump seidb to fix receipt missing on restart issue * Fix go mod --- app/test_state_store.go | 4 ++++ go.mod | 2 +- go.sum | 4 ++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/app/test_state_store.go b/app/test_state_store.go index a942221a2..7595fd954 100644 --- a/app/test_state_store.go +++ b/app/test_state_store.go @@ -235,6 +235,10 @@ func (s *InMemoryStateStore) Prune(version int64) error { return nil } +func (db *InMemoryStateStore) RawImport(ch <-chan types.RawSnapshotNode) error { + panic("implement me") +} + func (s *InMemoryStateStore) Close() error { s.mu.Lock() defer s.mu.Unlock() diff --git a/go.mod b/go.mod index 16142d8af..1fc634458 100644 --- a/go.mod +++ b/go.mod @@ -351,7 +351,7 @@ replace ( github.com/cosmos/ibc-go/v3 => github.com/sei-protocol/sei-ibc-go/v3 v3.3.2 github.com/ethereum/go-ethereum => github.com/sei-protocol/go-ethereum v1.13.5-sei-22 github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 - github.com/sei-protocol/sei-db => github.com/sei-protocol/sei-db v0.0.40 + github.com/sei-protocol/sei-db => github.com/sei-protocol/sei-db v0.0.43 // Latest goleveldb is broken, we have to stick to this version github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 github.com/tendermint/tendermint => github.com/sei-protocol/sei-tendermint v0.3.6 diff --git a/go.sum b/go.sum index d35f21e68..98498d577 100644 --- a/go.sum +++ b/go.sum @@ -1349,8 +1349,8 @@ github.com/sei-protocol/goutils v0.0.2 h1:Bfa7Sv+4CVLNM20QcpvGb81B8C5HkQC/kW1CQp github.com/sei-protocol/goutils v0.0.2/go.mod h1:iYE2DuJfEnM+APPehr2gOUXfuLuPsVxorcDO+Tzq9q8= github.com/sei-protocol/sei-cosmos v0.3.31 h1:8qnubgQd83F2/Pxx5DmNH2vnl1XtTOAFbW44cEHbeCo= github.com/sei-protocol/sei-cosmos v0.3.31/go.mod h1:og/KbejR/zSQ8otapODEDU9zYNhFSUDbq9+tgeYePyU= -github.com/sei-protocol/sei-db v0.0.40 h1:s6B3u9u0r2Ypd67P8Lrz2IR/QU/FXwtS2X/fnYEix2g= -github.com/sei-protocol/sei-db v0.0.40/go.mod h1:F/ZKZA8HJPcUzSZPA8yt6pfwlGriJ4RDR4eHKSGLStI= +github.com/sei-protocol/sei-db v0.0.43 h1:m9kIWqSBCvKRLPGbAttlqCytIlPxVZbKchAEbVKSHHk= +github.com/sei-protocol/sei-db v0.0.43/go.mod h1:F/ZKZA8HJPcUzSZPA8yt6pfwlGriJ4RDR4eHKSGLStI= github.com/sei-protocol/sei-iavl v0.1.9 h1:y4mVYftxLNRs6533zl7N0/Ch+CzRQc04JDfHolIxgBE= github.com/sei-protocol/sei-iavl v0.1.9/go.mod h1:7PfkEVT5dcoQE+s/9KWdoXJ8VVVP1QpYYPLdxlkSXFk= github.com/sei-protocol/sei-ibc-go/v3 v3.3.2 h1:BaMZ6gjwqe3R/5dLmcJ1TkSZ3omcWy2TjaAZAeOJH44= From da9d59c8d2d4b2849333be01ad8e49e9c91ad606 Mon Sep 17 00:00:00 2001 From: Uday Patil Date: Tue, 20 Aug 2024 15:21:10 -0500 Subject: [PATCH 19/38] Remove dex actually (#1816) * Revert "Revert dex removal (#1801)" This reverts commit d5023963657e11861cd923b9f79f11679a1928d2. * register v5.8.0 upgrade and bump sei-cosmos * update go mod * update sei-cosmos tag --- .github/workflows/fuzz.yml | 40 - aclmapping/bank/mappings.go | 1 - aclmapping/dependency_generator.go | 2 - aclmapping/dex/mappings.go | 229 - aclmapping/dex/mappings_test.go | 292 - aclmapping/utils/resource_type.go | 70 - app/ante.go | 10 - app/ante_test.go | 2 - app/antedecorators/gasless.go | 38 - app/antedecorators/gasless_test.go | 33 +- app/antedecorators/priority_test.go | 3 +- app/app.go | 81 +- app/app_test.go | 70 +- app/apptesting/test_suite.go | 2 - app/test_helpers.go | 2 - app/upgrades.go | 1 + cmd/seid/cmd/debug.go | 2 +- cmd/seid/cmd/iavl_parser.go | 61 - go.mod | 4 +- go.sum | 4 +- .../dex_module/cancel_order_test.yaml | 25 - .../dex_module/place_order_test.yaml | 46 - .../staking_module/staking_test.yaml | 2 +- loadtest/main.go | 166 - occ_tests/utils/utils.go | 5 - proto/dex/asset_list.proto | 23 - proto/dex/contract.proto | 47 - proto/dex/deposit.proto | 21 - proto/dex/enums.proto | 42 - proto/dex/genesis.proto | 37 - proto/dex/gov.proto | 22 - proto/dex/long_book.proto | 19 - proto/dex/match_result.proto | 15 - proto/dex/order.proto | 108 - proto/dex/order_entry.proto | 46 - proto/dex/pair.proto | 30 - proto/dex/params.proto | 70 - proto/dex/price.proto | 52 - proto/dex/query.proto | 401 - proto/dex/settlement.proto | 40 - proto/dex/short_book.proto | 19 - proto/dex/tick_size.proto | 22 - proto/dex/twap.proto | 24 - proto/dex/tx.proto | 147 - proto/mint/v1beta1/gov.proto | 2 - scripts/dump_app_state_for_height.sh | 2 +- scripts/upload_clearing_house_contract.sh | 18 - testutil/fuzzing/dex.go | 228 - testutil/keeper/dex.go | 196 - testutil/keeper/epoch.go | 5 + testutil/processblock/msgs/dex.go | 101 - testutil/processblock/presets.go | 36 - testutil/processblock/verify/bank.go | 7 - testutil/processblock/verify/dex.go | 269 - wasmbinding/bindings/msg.go | 13 - wasmbinding/encoder.go | 7 - wasmbinding/queries.go | 73 +- wasmbinding/query_plugin.go | 3 - wasmbinding/test/encoder_test.go | 68 - wasmbinding/test/query_test.go | 131 +- wasmbinding/wasm.go | 6 +- x/dex/README.md | 57 - x/dex/ante.go | 178 - x/dex/ante_test.go | 283 - x/dex/cache/cache.go | 318 - x/dex/cache/cache_test.go | 225 - x/dex/cache/cancel.go | 65 - x/dex/cache/cancel_test.go | 76 - x/dex/cache/context.go | 44 - x/dex/cache/deposit.go | 51 - x/dex/cache/deposit_test.go | 48 - x/dex/cache/order.go | 142 - x/dex/cache/order_test.go | 257 - x/dex/client/cli/query/query.go | 48 - x/dex/client/cli/query/query_asset_list.go | 80 - .../cli/query/query_get_latest_price.go | 53 - .../client/cli/query/query_get_order_count.go | 52 - x/dex/client/cli/query/query_get_price.go | 58 - x/dex/client/cli/query/query_get_prices.go | 53 - x/dex/client/cli/query/query_get_twaps.go | 53 - x/dex/client/cli/query/query_long_book.go | 90 - .../client/cli/query/query_long_book_test.go | 176 - x/dex/client/cli/query/query_match_result.go | 49 - x/dex/client/cli/query/query_orders.go | 96 - x/dex/client/cli/query/query_params.go | 34 - .../cli/query/query_registered_contract.go | 48 - .../cli/query/query_registered_pairs.go | 48 - x/dex/client/cli/query/query_short_book.go | 92 - .../client/cli/query/query_short_book_test.go | 181 - x/dex/client/cli/tx/gov_tx.go | 60 - x/dex/client/cli/tx/tx.go | 40 - x/dex/client/cli/tx/tx_cancel_orders.go | 75 - .../client/cli/tx/tx_contract_deposit_rent.go | 52 - x/dex/client/cli/tx/tx_place_orders.go | 98 - x/dex/client/cli/tx/tx_register_contract.go | 68 - x/dex/client/cli/tx/tx_register_pairs.go | 54 - x/dex/client/cli/tx/tx_unregister_contract.go | 46 - x/dex/client/cli/tx/tx_unsuspend_contract.go | 46 - .../cli/tx/tx_update_price_tick_size.go | 54 - .../cli/tx/tx_update_quantity_tick_size.go | 54 - x/dex/client/utils/utils.go | 203 - x/dex/client/wasm/bindings/queries.go | 12 - x/dex/client/wasm/encoder.go | 36 - x/dex/client/wasm/query.go | 48 - x/dex/contract/abci.go | 323 - x/dex/contract/abci_test.go | 43 - x/dex/contract/dag.go | 78 - x/dex/contract/dag_test.go | 110 - x/dex/contract/execution.go | 219 - x/dex/contract/execution_test.go | 373 - x/dex/contract/market_order.go | 68 - x/dex/contract/runner.go | 178 - x/dex/contract/runner_test.go | 141 - x/dex/contract/settlement.go | 39 - x/dex/contract/whitelist.go | 91 - x/dex/contract/whitelist_test.go | 28 - .../example/add-asset-metadata-proposal.json | 55 - x/dex/example/register-pair-tx.json | 15 - x/dex/example/update-tick-size-tx.json | 12 - x/dex/exchange/cancel_order.go | 53 - x/dex/exchange/cancel_order_test.go | 105 - x/dex/exchange/helpers.go | 24 - x/dex/exchange/helpers_test.go | 64 - x/dex/exchange/limit_order.go | 103 - x/dex/exchange/limit_order_fuzz_test.go | 55 - x/dex/exchange/limit_order_test.go | 1165 -- x/dex/exchange/market_order.go | 273 - x/dex/exchange/market_order_fuzz_test.go | 92 - x/dex/exchange/market_order_test.go | 1175 -- x/dex/exchange/settlement.go | 129 - x/dex/exchange/settlement_fuzz_test.go | 118 - x/dex/genesis.go | 85 - x/dex/genesis_test.go | 105 - x/dex/gov.go | 14 - x/dex/handler.go | 67 - x/dex/keeper/abci/end_block_cancel_orders.go | 45 - x/dex/keeper/abci/end_block_deposit.go | 58 - x/dex/keeper/abci/end_block_place_orders.go | 83 - .../abci/end_block_place_orders_test.go | 67 - x/dex/keeper/abci/keeper_wrapper.go | 9 - x/dex/keeper/asset_list.go | 43 - x/dex/keeper/asset_list_test.go | 35 - x/dex/keeper/common.go | 22 - x/dex/keeper/contract.go | 244 - x/dex/keeper/contract_test.go | 368 - x/dex/keeper/epoch.go | 26 - x/dex/keeper/keeper.go | 78 - x/dex/keeper/long_book.go | 184 - x/dex/keeper/long_book_test.go | 92 - x/dex/keeper/match_result.go | 45 - x/dex/keeper/msgserver/msg_server.go | 18 - .../msgserver/msg_server_cancel_orders.go | 12 - .../msg_server_cancel_orders_test.go | 36 - .../msg_server_contract_deposit_rent.go | 12 - .../msg_server_contract_deposit_rent_test.go | 34 - .../msgserver/msg_server_place_orders.go | 12 - .../msg_server_place_orders_fuzz_test.go | 65 - .../msgserver/msg_server_place_orders_test.go | 49 - .../msgserver/msg_server_register_contract.go | 12 - .../msg_server_register_contract_test.go | 34 - .../msgserver/msg_server_register_pairs.go | 12 - .../msg_server_register_pairs_test.go | 38 - .../msg_server_unregister_contract.go | 12 - .../msg_server_unregister_contract_test.go | 34 - .../msg_server_unsuspend_contract.go | 12 - .../msg_server_unsuspend_contract_test.go | 23 - .../msg_server_update_price_tick_size.go | 12 - .../msg_server_update_price_tick_size_test.go | 40 - .../msg_server_update_quantity_tick_size.go | 12 - ...g_server_update_quantity_tick_size_test.go | 41 - x/dex/keeper/msgserver/testdata/hackatom.wasm | Bin 208805 -> 0 bytes x/dex/keeper/msgserver/validations.go | 40 - x/dex/keeper/order_count.go | 56 - x/dex/keeper/order_count_test.go | 35 - x/dex/keeper/order_placement.go | 33 - x/dex/keeper/pair.go | 56 - x/dex/keeper/pair_test.go | 41 - x/dex/keeper/params.go | 42 - x/dex/keeper/params_test.go | 24 - x/dex/keeper/price.go | 98 - x/dex/keeper/price_test.go | 20 - x/dex/keeper/query/grpc_query.go | 7 - x/dex/keeper/query/grpc_query_asset_list.go | 36 - .../query/grpc_query_asset_list_test.go | 50 - .../query/grpc_query_get_historical_prices.go | 119 - .../grpc_query_get_historical_prices_test.go | 185 - .../query/grpc_query_get_latest_price.go | 37 - .../query/grpc_query_get_latest_price_test.go | 30 - .../query/grpc_query_get_market_summary.go | 49 - .../grpc_query_get_market_summary_test.go | 33 - .../query/grpc_query_get_order_count.go | 19 - .../query/grpc_query_get_order_count_test.go | 29 - x/dex/keeper/query/grpc_query_get_price.go | 25 - .../keeper/query/grpc_query_get_price_test.go | 32 - x/dex/keeper/query/grpc_query_get_prices.go | 24 - x/dex/keeper/query/grpc_query_get_twaps.go | 57 - .../keeper/query/grpc_query_get_twaps_test.go | 143 - x/dex/keeper/query/grpc_query_long_book.go | 50 - .../keeper/query/grpc_query_long_book_test.go | 123 - x/dex/keeper/query/grpc_query_match_result.go | 24 - x/dex/keeper/query/grpc_query_order.go | 112 - .../query/grpc_query_order_simulation.go | 120 - .../query/grpc_query_order_simulation_test.go | 101 - x/dex/keeper/query/grpc_query_order_test.go | 75 - x/dex/keeper/query/grpc_query_params.go | 19 - x/dex/keeper/query/grpc_query_params_test.go | 23 - .../query/grpc_query_registered_contract.go | 24 - .../grpc_query_registered_contract_test.go | 42 - .../query/grpc_query_registered_pairs.go | 21 - .../query/grpc_query_registered_pairs_test.go | 39 - x/dex/keeper/query/grpc_query_short_book.go | 46 - .../query/grpc_query_short_book_test.go | 123 - x/dex/keeper/query/keeper_wrapper.go | 9 - x/dex/keeper/short_book.go | 165 - x/dex/keeper/short_book_test.go | 92 - x/dex/keeper/tick.go | 60 - x/dex/keeper/tick_test.go | 42 - x/dex/keeper/utils/order_book.go | 89 - x/dex/keeper/utils/price.go | 28 - x/dex/keeper/utils/wasm.go | 116 - x/dex/migrations/v10_to_v11.go | 45 - x/dex/migrations/v10_to_v11_test.go | 60 - x/dex/migrations/v11_to_v12.go | 13 - x/dex/migrations/v11_to_v12_test.go | 31 - x/dex/migrations/v12_to_v13.go | 15 - x/dex/migrations/v12_to_v13_test.go | 32 - x/dex/migrations/v13_to_v14.go | 69 - x/dex/migrations/v13_to_v14_test.go | 79 - x/dex/migrations/v14_to_v15.go | 15 - x/dex/migrations/v14_to_v15_test.go | 26 - x/dex/migrations/v15_to_v16.go | 15 - x/dex/migrations/v15_to_v16_test.go | 24 - x/dex/migrations/v16_to_v17.go | 110 - x/dex/migrations/v16_to_v17_test.go | 89 - x/dex/migrations/v17_to_v18.go | 33 - x/dex/migrations/v17_to_v18_test.go | 62 - x/dex/migrations/v2_to_v3.go | 35 - x/dex/migrations/v3_to_v4.go | 21 - x/dex/migrations/v3_to_v4_test.go | 48 - x/dex/migrations/v4_to_v5.go | 28 - x/dex/migrations/v4_to_v5_test.go | 59 - x/dex/migrations/v5_to_v6.go | 57 - x/dex/migrations/v5_to_v6_test.go | 79 - x/dex/migrations/v6_to_v7.go | 84 - x/dex/migrations/v6_to_v7_test.go | 89 - x/dex/migrations/v7_to_v8.go | 101 - x/dex/migrations/v7_to_v8_test.go | 98 - x/dex/migrations/v8_to_v9.go | 38 - x/dex/migrations/v8_to_v9_test.go | 42 - x/dex/migrations/v9_to_v10.go | 91 - x/dex/migrations/v9_to_v10_test.go | 94 - x/dex/module.go | 383 - x/dex/module_simulation.go | 91 - x/dex/module_test.go | 835 -- x/dex/simulation/simap.go | 15 - x/dex/spec/README.md | 56 - x/dex/testdata/clearing_house.wasm | Bin 833624 -> 0 bytes x/dex/testdata/mars.wasm | Bin 191011 -> 0 bytes x/dex/types/alias.go | 24 - x/dex/types/alias_test.go | 20 - x/dex/types/asset_list.pb.go | 768 -- x/dex/types/codec.go | 71 - x/dex/types/contract.pb.go | 1902 --- x/dex/types/deposit.go | 19 - x/dex/types/deposit.pb.go | 422 - x/dex/types/enums.go | 29 - x/dex/types/enums.pb.go | 235 - x/dex/types/enums_test.go | 53 - x/dex/types/errors.go | 28 - x/dex/types/events.go | 21 - x/dex/types/expected_keepers.go | 18 - x/dex/types/genesis.go | 75 - x/dex/types/genesis.pb.go | 1188 -- x/dex/types/genesis_test.go | 228 - x/dex/types/gov.go | 57 - x/dex/types/gov.pb.go | 418 - x/dex/types/keys.go | 190 - x/dex/types/keys_test.go | 29 - x/dex/types/long_book.pb.go | 380 - x/dex/types/match_result.go | 28 - x/dex/types/match_result.pb.go | 548 - x/dex/types/match_result_test.go | 54 - x/dex/types/message_cancel_orders.go | 72 - x/dex/types/message_cancel_orders_test.go | 42 - x/dex/types/message_contract_deposit_rent.go | 56 - x/dex/types/message_place_orders.go | 85 - x/dex/types/message_place_orders_test.go | 102 - x/dex/types/message_register_contract.go | 75 - x/dex/types/message_register_pairs.go | 83 - x/dex/types/message_unregister_contract.go | 55 - x/dex/types/message_unsuspend_contract.go | 55 - x/dex/types/message_update_price_tick_size.go | 69 - .../message_update_quantity_tick_size.go | 69 - x/dex/types/order.pb.go | 1680 --- x/dex/types/order_cancellation.go | 9 - x/dex/types/order_entry.pb.go | 790 -- x/dex/types/order_placement.go | 31 - x/dex/types/orders.go | 244 - x/dex/types/orders_test.go | 166 - x/dex/types/pair.pb.go | 718 -- x/dex/types/params.go | 143 - x/dex/types/params.pb.go | 870 -- x/dex/types/params_test.go | 17 - x/dex/types/price.pb.go | 881 -- x/dex/types/query.pb.go | 10031 ---------------- x/dex/types/query.pb.gw.go | 2389 ---- x/dex/types/settlement.go | 36 - x/dex/types/settlement.pb.go | 1044 -- x/dex/types/settlement_test.go | 31 - x/dex/types/short_book.pb.go | 380 - x/dex/types/tick_size.pb.go | 433 - x/dex/types/twap.pb.go | 416 - x/dex/types/tx.pb.go | 3884 ------ x/dex/types/types.go | 6 - x/dex/types/utils.go | 14 - x/dex/utils/context.go | 18 - x/dex/utils/dec.go | 71 - x/dex/utils/dec_test.go | 54 - x/dex/utils/errors.go | 11 - x/evm/keeper/msg_server_test.go | 6 - x/mint/keeper/hooks_test.go | 10 - x/mint/types/gov.pb.go | 2 - 322 files changed, 40 insertions(+), 52599 deletions(-) delete mode 100644 .github/workflows/fuzz.yml delete mode 100644 aclmapping/dex/mappings.go delete mode 100644 aclmapping/dex/mappings_test.go delete mode 100644 integration_test/dex_module/cancel_order_test.yaml delete mode 100644 integration_test/dex_module/place_order_test.yaml delete mode 100644 proto/dex/asset_list.proto delete mode 100644 proto/dex/contract.proto delete mode 100644 proto/dex/deposit.proto delete mode 100644 proto/dex/enums.proto delete mode 100644 proto/dex/genesis.proto delete mode 100644 proto/dex/gov.proto delete mode 100644 proto/dex/long_book.proto delete mode 100644 proto/dex/match_result.proto delete mode 100644 proto/dex/order.proto delete mode 100644 proto/dex/order_entry.proto delete mode 100644 proto/dex/pair.proto delete mode 100644 proto/dex/params.proto delete mode 100644 proto/dex/price.proto delete mode 100644 proto/dex/query.proto delete mode 100644 proto/dex/settlement.proto delete mode 100644 proto/dex/short_book.proto delete mode 100644 proto/dex/tick_size.proto delete mode 100644 proto/dex/twap.proto delete mode 100644 proto/dex/tx.proto delete mode 100755 scripts/upload_clearing_house_contract.sh delete mode 100644 testutil/fuzzing/dex.go delete mode 100644 testutil/keeper/dex.go delete mode 100644 testutil/processblock/msgs/dex.go delete mode 100644 testutil/processblock/verify/dex.go delete mode 100644 x/dex/README.md delete mode 100644 x/dex/ante.go delete mode 100644 x/dex/ante_test.go delete mode 100644 x/dex/cache/cache.go delete mode 100644 x/dex/cache/cache_test.go delete mode 100644 x/dex/cache/cancel.go delete mode 100644 x/dex/cache/cancel_test.go delete mode 100644 x/dex/cache/context.go delete mode 100644 x/dex/cache/deposit.go delete mode 100644 x/dex/cache/deposit_test.go delete mode 100644 x/dex/cache/order.go delete mode 100644 x/dex/cache/order_test.go delete mode 100644 x/dex/client/cli/query/query.go delete mode 100644 x/dex/client/cli/query/query_asset_list.go delete mode 100644 x/dex/client/cli/query/query_get_latest_price.go delete mode 100644 x/dex/client/cli/query/query_get_order_count.go delete mode 100644 x/dex/client/cli/query/query_get_price.go delete mode 100644 x/dex/client/cli/query/query_get_prices.go delete mode 100644 x/dex/client/cli/query/query_get_twaps.go delete mode 100644 x/dex/client/cli/query/query_long_book.go delete mode 100644 x/dex/client/cli/query/query_long_book_test.go delete mode 100644 x/dex/client/cli/query/query_match_result.go delete mode 100644 x/dex/client/cli/query/query_orders.go delete mode 100644 x/dex/client/cli/query/query_params.go delete mode 100644 x/dex/client/cli/query/query_registered_contract.go delete mode 100644 x/dex/client/cli/query/query_registered_pairs.go delete mode 100644 x/dex/client/cli/query/query_short_book.go delete mode 100644 x/dex/client/cli/query/query_short_book_test.go delete mode 100644 x/dex/client/cli/tx/gov_tx.go delete mode 100644 x/dex/client/cli/tx/tx.go delete mode 100644 x/dex/client/cli/tx/tx_cancel_orders.go delete mode 100644 x/dex/client/cli/tx/tx_contract_deposit_rent.go delete mode 100644 x/dex/client/cli/tx/tx_place_orders.go delete mode 100644 x/dex/client/cli/tx/tx_register_contract.go delete mode 100644 x/dex/client/cli/tx/tx_register_pairs.go delete mode 100644 x/dex/client/cli/tx/tx_unregister_contract.go delete mode 100644 x/dex/client/cli/tx/tx_unsuspend_contract.go delete mode 100644 x/dex/client/cli/tx/tx_update_price_tick_size.go delete mode 100644 x/dex/client/cli/tx/tx_update_quantity_tick_size.go delete mode 100644 x/dex/client/utils/utils.go delete mode 100644 x/dex/client/wasm/bindings/queries.go delete mode 100644 x/dex/client/wasm/encoder.go delete mode 100644 x/dex/client/wasm/query.go delete mode 100644 x/dex/contract/abci.go delete mode 100644 x/dex/contract/abci_test.go delete mode 100644 x/dex/contract/dag.go delete mode 100644 x/dex/contract/dag_test.go delete mode 100644 x/dex/contract/execution.go delete mode 100644 x/dex/contract/execution_test.go delete mode 100644 x/dex/contract/market_order.go delete mode 100644 x/dex/contract/runner.go delete mode 100644 x/dex/contract/runner_test.go delete mode 100644 x/dex/contract/settlement.go delete mode 100644 x/dex/contract/whitelist.go delete mode 100644 x/dex/contract/whitelist_test.go delete mode 100644 x/dex/example/add-asset-metadata-proposal.json delete mode 100644 x/dex/example/register-pair-tx.json delete mode 100644 x/dex/example/update-tick-size-tx.json delete mode 100644 x/dex/exchange/cancel_order.go delete mode 100644 x/dex/exchange/cancel_order_test.go delete mode 100644 x/dex/exchange/helpers.go delete mode 100644 x/dex/exchange/helpers_test.go delete mode 100644 x/dex/exchange/limit_order.go delete mode 100644 x/dex/exchange/limit_order_fuzz_test.go delete mode 100644 x/dex/exchange/limit_order_test.go delete mode 100644 x/dex/exchange/market_order.go delete mode 100644 x/dex/exchange/market_order_fuzz_test.go delete mode 100644 x/dex/exchange/market_order_test.go delete mode 100644 x/dex/exchange/settlement.go delete mode 100644 x/dex/exchange/settlement_fuzz_test.go delete mode 100644 x/dex/genesis.go delete mode 100644 x/dex/genesis_test.go delete mode 100644 x/dex/gov.go delete mode 100644 x/dex/handler.go delete mode 100644 x/dex/keeper/abci/end_block_cancel_orders.go delete mode 100644 x/dex/keeper/abci/end_block_deposit.go delete mode 100644 x/dex/keeper/abci/end_block_place_orders.go delete mode 100644 x/dex/keeper/abci/end_block_place_orders_test.go delete mode 100644 x/dex/keeper/abci/keeper_wrapper.go delete mode 100644 x/dex/keeper/asset_list.go delete mode 100644 x/dex/keeper/asset_list_test.go delete mode 100644 x/dex/keeper/common.go delete mode 100644 x/dex/keeper/contract.go delete mode 100644 x/dex/keeper/contract_test.go delete mode 100644 x/dex/keeper/epoch.go delete mode 100644 x/dex/keeper/keeper.go delete mode 100644 x/dex/keeper/long_book.go delete mode 100644 x/dex/keeper/long_book_test.go delete mode 100644 x/dex/keeper/match_result.go delete mode 100644 x/dex/keeper/msgserver/msg_server.go delete mode 100644 x/dex/keeper/msgserver/msg_server_cancel_orders.go delete mode 100644 x/dex/keeper/msgserver/msg_server_cancel_orders_test.go delete mode 100644 x/dex/keeper/msgserver/msg_server_contract_deposit_rent.go delete mode 100644 x/dex/keeper/msgserver/msg_server_contract_deposit_rent_test.go delete mode 100644 x/dex/keeper/msgserver/msg_server_place_orders.go delete mode 100644 x/dex/keeper/msgserver/msg_server_place_orders_fuzz_test.go delete mode 100644 x/dex/keeper/msgserver/msg_server_place_orders_test.go delete mode 100644 x/dex/keeper/msgserver/msg_server_register_contract.go delete mode 100644 x/dex/keeper/msgserver/msg_server_register_contract_test.go delete mode 100644 x/dex/keeper/msgserver/msg_server_register_pairs.go delete mode 100644 x/dex/keeper/msgserver/msg_server_register_pairs_test.go delete mode 100644 x/dex/keeper/msgserver/msg_server_unregister_contract.go delete mode 100644 x/dex/keeper/msgserver/msg_server_unregister_contract_test.go delete mode 100644 x/dex/keeper/msgserver/msg_server_unsuspend_contract.go delete mode 100644 x/dex/keeper/msgserver/msg_server_unsuspend_contract_test.go delete mode 100644 x/dex/keeper/msgserver/msg_server_update_price_tick_size.go delete mode 100644 x/dex/keeper/msgserver/msg_server_update_price_tick_size_test.go delete mode 100644 x/dex/keeper/msgserver/msg_server_update_quantity_tick_size.go delete mode 100644 x/dex/keeper/msgserver/msg_server_update_quantity_tick_size_test.go delete mode 100644 x/dex/keeper/msgserver/testdata/hackatom.wasm delete mode 100644 x/dex/keeper/msgserver/validations.go delete mode 100644 x/dex/keeper/order_count.go delete mode 100644 x/dex/keeper/order_count_test.go delete mode 100644 x/dex/keeper/order_placement.go delete mode 100644 x/dex/keeper/pair.go delete mode 100644 x/dex/keeper/pair_test.go delete mode 100644 x/dex/keeper/params.go delete mode 100644 x/dex/keeper/params_test.go delete mode 100644 x/dex/keeper/price.go delete mode 100644 x/dex/keeper/price_test.go delete mode 100644 x/dex/keeper/query/grpc_query.go delete mode 100644 x/dex/keeper/query/grpc_query_asset_list.go delete mode 100644 x/dex/keeper/query/grpc_query_asset_list_test.go delete mode 100644 x/dex/keeper/query/grpc_query_get_historical_prices.go delete mode 100644 x/dex/keeper/query/grpc_query_get_historical_prices_test.go delete mode 100644 x/dex/keeper/query/grpc_query_get_latest_price.go delete mode 100644 x/dex/keeper/query/grpc_query_get_latest_price_test.go delete mode 100644 x/dex/keeper/query/grpc_query_get_market_summary.go delete mode 100644 x/dex/keeper/query/grpc_query_get_market_summary_test.go delete mode 100644 x/dex/keeper/query/grpc_query_get_order_count.go delete mode 100644 x/dex/keeper/query/grpc_query_get_order_count_test.go delete mode 100644 x/dex/keeper/query/grpc_query_get_price.go delete mode 100644 x/dex/keeper/query/grpc_query_get_price_test.go delete mode 100644 x/dex/keeper/query/grpc_query_get_prices.go delete mode 100644 x/dex/keeper/query/grpc_query_get_twaps.go delete mode 100644 x/dex/keeper/query/grpc_query_get_twaps_test.go delete mode 100644 x/dex/keeper/query/grpc_query_long_book.go delete mode 100644 x/dex/keeper/query/grpc_query_long_book_test.go delete mode 100644 x/dex/keeper/query/grpc_query_match_result.go delete mode 100644 x/dex/keeper/query/grpc_query_order.go delete mode 100644 x/dex/keeper/query/grpc_query_order_simulation.go delete mode 100644 x/dex/keeper/query/grpc_query_order_simulation_test.go delete mode 100644 x/dex/keeper/query/grpc_query_order_test.go delete mode 100644 x/dex/keeper/query/grpc_query_params.go delete mode 100644 x/dex/keeper/query/grpc_query_params_test.go delete mode 100644 x/dex/keeper/query/grpc_query_registered_contract.go delete mode 100644 x/dex/keeper/query/grpc_query_registered_contract_test.go delete mode 100644 x/dex/keeper/query/grpc_query_registered_pairs.go delete mode 100644 x/dex/keeper/query/grpc_query_registered_pairs_test.go delete mode 100644 x/dex/keeper/query/grpc_query_short_book.go delete mode 100644 x/dex/keeper/query/grpc_query_short_book_test.go delete mode 100644 x/dex/keeper/query/keeper_wrapper.go delete mode 100644 x/dex/keeper/short_book.go delete mode 100644 x/dex/keeper/short_book_test.go delete mode 100644 x/dex/keeper/tick.go delete mode 100644 x/dex/keeper/tick_test.go delete mode 100644 x/dex/keeper/utils/order_book.go delete mode 100644 x/dex/keeper/utils/price.go delete mode 100644 x/dex/keeper/utils/wasm.go delete mode 100644 x/dex/migrations/v10_to_v11.go delete mode 100644 x/dex/migrations/v10_to_v11_test.go delete mode 100644 x/dex/migrations/v11_to_v12.go delete mode 100644 x/dex/migrations/v11_to_v12_test.go delete mode 100644 x/dex/migrations/v12_to_v13.go delete mode 100644 x/dex/migrations/v12_to_v13_test.go delete mode 100644 x/dex/migrations/v13_to_v14.go delete mode 100644 x/dex/migrations/v13_to_v14_test.go delete mode 100644 x/dex/migrations/v14_to_v15.go delete mode 100644 x/dex/migrations/v14_to_v15_test.go delete mode 100644 x/dex/migrations/v15_to_v16.go delete mode 100644 x/dex/migrations/v15_to_v16_test.go delete mode 100644 x/dex/migrations/v16_to_v17.go delete mode 100644 x/dex/migrations/v16_to_v17_test.go delete mode 100644 x/dex/migrations/v17_to_v18.go delete mode 100644 x/dex/migrations/v17_to_v18_test.go delete mode 100644 x/dex/migrations/v2_to_v3.go delete mode 100644 x/dex/migrations/v3_to_v4.go delete mode 100644 x/dex/migrations/v3_to_v4_test.go delete mode 100644 x/dex/migrations/v4_to_v5.go delete mode 100644 x/dex/migrations/v4_to_v5_test.go delete mode 100644 x/dex/migrations/v5_to_v6.go delete mode 100644 x/dex/migrations/v5_to_v6_test.go delete mode 100644 x/dex/migrations/v6_to_v7.go delete mode 100644 x/dex/migrations/v6_to_v7_test.go delete mode 100644 x/dex/migrations/v7_to_v8.go delete mode 100644 x/dex/migrations/v7_to_v8_test.go delete mode 100644 x/dex/migrations/v8_to_v9.go delete mode 100644 x/dex/migrations/v8_to_v9_test.go delete mode 100644 x/dex/migrations/v9_to_v10.go delete mode 100644 x/dex/migrations/v9_to_v10_test.go delete mode 100644 x/dex/module.go delete mode 100644 x/dex/module_simulation.go delete mode 100644 x/dex/module_test.go delete mode 100644 x/dex/simulation/simap.go delete mode 100644 x/dex/spec/README.md delete mode 100644 x/dex/testdata/clearing_house.wasm delete mode 100644 x/dex/testdata/mars.wasm delete mode 100644 x/dex/types/alias.go delete mode 100644 x/dex/types/alias_test.go delete mode 100644 x/dex/types/asset_list.pb.go delete mode 100644 x/dex/types/codec.go delete mode 100644 x/dex/types/contract.pb.go delete mode 100644 x/dex/types/deposit.go delete mode 100644 x/dex/types/deposit.pb.go delete mode 100644 x/dex/types/enums.go delete mode 100644 x/dex/types/enums.pb.go delete mode 100644 x/dex/types/enums_test.go delete mode 100644 x/dex/types/errors.go delete mode 100644 x/dex/types/events.go delete mode 100644 x/dex/types/expected_keepers.go delete mode 100644 x/dex/types/genesis.go delete mode 100644 x/dex/types/genesis.pb.go delete mode 100644 x/dex/types/genesis_test.go delete mode 100644 x/dex/types/gov.go delete mode 100644 x/dex/types/gov.pb.go delete mode 100644 x/dex/types/keys.go delete mode 100644 x/dex/types/keys_test.go delete mode 100644 x/dex/types/long_book.pb.go delete mode 100644 x/dex/types/match_result.go delete mode 100644 x/dex/types/match_result.pb.go delete mode 100644 x/dex/types/match_result_test.go delete mode 100644 x/dex/types/message_cancel_orders.go delete mode 100644 x/dex/types/message_cancel_orders_test.go delete mode 100644 x/dex/types/message_contract_deposit_rent.go delete mode 100644 x/dex/types/message_place_orders.go delete mode 100644 x/dex/types/message_place_orders_test.go delete mode 100644 x/dex/types/message_register_contract.go delete mode 100644 x/dex/types/message_register_pairs.go delete mode 100644 x/dex/types/message_unregister_contract.go delete mode 100644 x/dex/types/message_unsuspend_contract.go delete mode 100644 x/dex/types/message_update_price_tick_size.go delete mode 100644 x/dex/types/message_update_quantity_tick_size.go delete mode 100644 x/dex/types/order.pb.go delete mode 100644 x/dex/types/order_cancellation.go delete mode 100644 x/dex/types/order_entry.pb.go delete mode 100644 x/dex/types/order_placement.go delete mode 100644 x/dex/types/orders.go delete mode 100644 x/dex/types/orders_test.go delete mode 100644 x/dex/types/pair.pb.go delete mode 100644 x/dex/types/params.go delete mode 100644 x/dex/types/params.pb.go delete mode 100644 x/dex/types/params_test.go delete mode 100644 x/dex/types/price.pb.go delete mode 100644 x/dex/types/query.pb.go delete mode 100644 x/dex/types/query.pb.gw.go delete mode 100644 x/dex/types/settlement.go delete mode 100644 x/dex/types/settlement.pb.go delete mode 100644 x/dex/types/settlement_test.go delete mode 100644 x/dex/types/short_book.pb.go delete mode 100644 x/dex/types/tick_size.pb.go delete mode 100644 x/dex/types/twap.pb.go delete mode 100644 x/dex/types/tx.pb.go delete mode 100644 x/dex/types/types.go delete mode 100644 x/dex/types/utils.go delete mode 100644 x/dex/utils/context.go delete mode 100644 x/dex/utils/dec.go delete mode 100644 x/dex/utils/dec_test.go delete mode 100644 x/dex/utils/errors.go diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml deleted file mode 100644 index 01f3ef71a..000000000 --- a/.github/workflows/fuzz.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: Fuzzing - - -on: - push: - branches: - - main - pull_request: - branches: - - main - -defaults: - run: - shell: bash - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - - name: Set up Go - uses: actions/setup-go@v2 - with: - go-version: 1.21 - - - name: Fuzz Place Order Msg - run: go test github.com/sei-protocol/sei-chain/x/dex/keeper/msgserver -fuzz FuzzPlaceOrders -fuzztime 30s - - - name: Fuzz Limit Order Matching - run: go test github.com/sei-protocol/sei-chain/x/dex/exchange -fuzz FuzzMatchLimitOrders -fuzztime 30s - - - name: Fuzz Market Order Matching - run: go test github.com/sei-protocol/sei-chain/x/dex/exchange -fuzz FuzzMatchMarketOrders -fuzztime 30s - - - name: Fuzz Limit Order Settlement - run: go test github.com/sei-protocol/sei-chain/x/dex/exchange -fuzz FuzzSettleLimitOrder -fuzztime 30s - - - name: Fuzz Market Order Settlement - run: go test github.com/sei-protocol/sei-chain/x/dex/exchange -fuzz FuzzSettleMarketOrder -fuzztime 30s diff --git a/aclmapping/bank/mappings.go b/aclmapping/bank/mappings.go index 047c9092a..140e9d463 100644 --- a/aclmapping/bank/mappings.go +++ b/aclmapping/bank/mappings.go @@ -18,7 +18,6 @@ var ErrorInvalidMsgType = fmt.Errorf("invalid message received for bank module") func GetBankDepedencyGenerator() aclkeeper.DependencyGeneratorMap { dependencyGeneratorMap := make(aclkeeper.DependencyGeneratorMap) - // dex place orders placeOrdersKey := acltypes.GenerateMessageKey(&banktypes.MsgSend{}) dependencyGeneratorMap[placeOrdersKey] = MsgSendDependencyGenerator diff --git a/aclmapping/dependency_generator.go b/aclmapping/dependency_generator.go index 8a8cabe81..2e83c1ca7 100644 --- a/aclmapping/dependency_generator.go +++ b/aclmapping/dependency_generator.go @@ -3,7 +3,6 @@ package aclmapping import ( aclkeeper "github.com/cosmos/cosmos-sdk/x/accesscontrol/keeper" aclbankmapping "github.com/sei-protocol/sei-chain/aclmapping/bank" - acldexmapping "github.com/sei-protocol/sei-chain/aclmapping/dex" aclevmmapping "github.com/sei-protocol/sei-chain/aclmapping/evm" acloraclemapping "github.com/sei-protocol/sei-chain/aclmapping/oracle" acltokenfactorymapping "github.com/sei-protocol/sei-chain/aclmapping/tokenfactory" @@ -21,7 +20,6 @@ func (customDepGen CustomDependencyGenerator) GetCustomDependencyGenerators(evmK dependencyGeneratorMap := make(aclkeeper.DependencyGeneratorMap) wasmDependencyGenerators := aclwasmmapping.NewWasmDependencyGenerator() - dependencyGeneratorMap = dependencyGeneratorMap.Merge(acldexmapping.GetDexDependencyGenerators()) dependencyGeneratorMap = dependencyGeneratorMap.Merge(aclbankmapping.GetBankDepedencyGenerator()) dependencyGeneratorMap = dependencyGeneratorMap.Merge(acltokenfactorymapping.GetTokenFactoryDependencyGenerators()) dependencyGeneratorMap = dependencyGeneratorMap.Merge(wasmDependencyGenerators.GetWasmDependencyGenerators()) diff --git a/aclmapping/dex/mappings.go b/aclmapping/dex/mappings.go deleted file mode 100644 index df5350c12..000000000 --- a/aclmapping/dex/mappings.go +++ /dev/null @@ -1,229 +0,0 @@ -package acldexmapping - -import ( - "encoding/hex" - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" - sdkacltypes "github.com/cosmos/cosmos-sdk/types/accesscontrol" - aclkeeper "github.com/cosmos/cosmos-sdk/x/accesscontrol/keeper" - acltypes "github.com/cosmos/cosmos-sdk/x/accesscontrol/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - dexkeeper "github.com/sei-protocol/sei-chain/x/dex/keeper" - dextypes "github.com/sei-protocol/sei-chain/x/dex/types" -) - -var ErrPlaceOrdersGenerator = fmt.Errorf("invalid message received for dex module") - -func GetDexDependencyGenerators() aclkeeper.DependencyGeneratorMap { - dependencyGeneratorMap := make(aclkeeper.DependencyGeneratorMap) - - // dex place orders - placeOrdersKey := acltypes.GenerateMessageKey(&dextypes.MsgPlaceOrders{}) - cancelOrdersKey := acltypes.GenerateMessageKey(&dextypes.MsgCancelOrders{}) - dependencyGeneratorMap[placeOrdersKey] = DexPlaceOrdersDependencyGenerator - dependencyGeneratorMap[cancelOrdersKey] = DexCancelOrdersDependencyGenerator - - return dependencyGeneratorMap -} - -func GetLongShortOrderBookOps(contractAddr string, priceDenom string, assetDenom string) []sdkacltypes.AccessOperation { - return []sdkacltypes.AccessOperation{ - { - AccessType: sdkacltypes.AccessType_READ, - ResourceType: sdkacltypes.ResourceType_KV_DEX_CONTRACT_LONGBOOK, - IdentifierTemplate: hex.EncodeToString(dextypes.OrderBookPrefix(true, contractAddr, priceDenom, assetDenom)), - }, - - { - AccessType: sdkacltypes.AccessType_READ, - ResourceType: sdkacltypes.ResourceType_KV_DEX_CONTRACT_SHORTBOOK, - IdentifierTemplate: hex.EncodeToString(dextypes.OrderBookPrefix(false, contractAddr, priceDenom, assetDenom)), - }, - } -} - -func DexPlaceOrdersDependencyGenerator(keeper aclkeeper.Keeper, _ sdk.Context, msg sdk.Msg) ([]sdkacltypes.AccessOperation, error) { - // TODO: read + write downstream, write contracts to process - placeOrdersMsg, ok := msg.(*dextypes.MsgPlaceOrders) - if !ok { - return []sdkacltypes.AccessOperation{}, ErrPlaceOrdersGenerator - } - - moduleAdr := keeper.AccountKeeper.GetModuleAddress(dextypes.ModuleName) - - senderBankAddrIdentifier := hex.EncodeToString(banktypes.CreateAccountBalancesPrefixFromBech32(placeOrdersMsg.Creator)) - contractAddr := placeOrdersMsg.ContractAddr - - aclOps := []sdkacltypes.AccessOperation{ - { - AccessType: sdkacltypes.AccessType_READ, - ResourceType: sdkacltypes.ResourceType_KV_DEX_NEXT_ORDER_ID, - IdentifierTemplate: hex.EncodeToString(dextypes.NextOrderIDPrefix(contractAddr)), - }, - { - AccessType: sdkacltypes.AccessType_WRITE, - ResourceType: sdkacltypes.ResourceType_KV_DEX_NEXT_ORDER_ID, - IdentifierTemplate: hex.EncodeToString(dextypes.NextOrderIDPrefix(contractAddr)), - }, - { - AccessType: sdkacltypes.AccessType_READ, - ResourceType: sdkacltypes.ResourceType_KV_DEX_REGISTERED_PAIR, - IdentifierTemplate: hex.EncodeToString(dextypes.RegisteredPairPrefix(contractAddr)), - }, - { - AccessType: sdkacltypes.AccessType_READ, - ResourceType: sdkacltypes.ResourceType_KV_DEX_MEM_DEPOSIT, - IdentifierTemplate: hex.EncodeToString(append( - dextypes.MemDepositPrefix(contractAddr), - []byte(placeOrdersMsg.Creator)..., - )), - }, - { - AccessType: sdkacltypes.AccessType_WRITE, - ResourceType: sdkacltypes.ResourceType_KV_DEX_MEM_DEPOSIT, - IdentifierTemplate: hex.EncodeToString(append( - dextypes.MemDepositPrefix(contractAddr), - []byte(placeOrdersMsg.Creator)..., - )), - }, - - { - AccessType: sdkacltypes.AccessType_READ, - ResourceType: sdkacltypes.ResourceType_KV_DEX_MEM_ORDER, - IdentifierTemplate: hex.EncodeToString(dextypes.MemOrderPrefix(contractAddr)), - }, - { - AccessType: sdkacltypes.AccessType_WRITE, - ResourceType: sdkacltypes.ResourceType_KV_DEX_MEM_ORDER, - IdentifierTemplate: hex.EncodeToString(dextypes.MemOrderPrefix(contractAddr)), - }, - - { - AccessType: sdkacltypes.AccessType_READ, - ResourceType: sdkacltypes.ResourceType_KV_DEX_MEM_DOWNSTREAM_CONTRACTS, - IdentifierTemplate: hex.EncodeToString(dextypes.MemDownstreamContractsKey(contractAddr)), - }, - { - AccessType: sdkacltypes.AccessType_WRITE, - ResourceType: sdkacltypes.ResourceType_KV_DEX_MEM_DOWNSTREAM_CONTRACTS, - IdentifierTemplate: hex.EncodeToString(dextypes.MemDownstreamContractsKey(contractAddr)), - }, - { - AccessType: sdkacltypes.AccessType_WRITE, - ResourceType: sdkacltypes.ResourceType_KV_DEX_MEM_CONTRACTS_TO_PROCESS, - IdentifierTemplate: hex.EncodeToString(dextypes.MemContractsToProcessKey(contractAddr)), - }, - - // Checks balance of sender - { - AccessType: sdkacltypes.AccessType_READ, - ResourceType: sdkacltypes.ResourceType_KV_BANK_BALANCES, - IdentifierTemplate: senderBankAddrIdentifier, - }, - // Reduce the amount from the sender's balance - { - AccessType: sdkacltypes.AccessType_WRITE, - ResourceType: sdkacltypes.ResourceType_KV_BANK_BALANCES, - IdentifierTemplate: senderBankAddrIdentifier, - }, - - // update the amounts for dex module balance - { - AccessType: sdkacltypes.AccessType_READ, - ResourceType: sdkacltypes.ResourceType_KV_AUTH_ADDRESS_STORE, - IdentifierTemplate: hex.EncodeToString(authtypes.AddressStoreKey(moduleAdr)), - }, - { - AccessType: sdkacltypes.AccessType_READ, - ResourceType: sdkacltypes.ResourceType_KV_BANK_BALANCES, - IdentifierTemplate: hex.EncodeToString(banktypes.CreateAccountBalancesPrefix(moduleAdr)), - }, - { - AccessType: sdkacltypes.AccessType_WRITE, - ResourceType: sdkacltypes.ResourceType_KV_BANK_BALANCES, - IdentifierTemplate: hex.EncodeToString(banktypes.CreateAccountBalancesPrefix(moduleAdr)), - }, - - // Gets Account Info for the sender - { - AccessType: sdkacltypes.AccessType_READ, - ResourceType: sdkacltypes.ResourceType_KV_AUTH_ADDRESS_STORE, - IdentifierTemplate: hex.EncodeToString(authtypes.CreateAddressStoreKeyFromBech32(placeOrdersMsg.Creator)), - }, - - { - AccessType: sdkacltypes.AccessType_READ, - ResourceType: sdkacltypes.ResourceType_KV_DEX_CONTRACT, - IdentifierTemplate: hex.EncodeToString([]byte(dexkeeper.ContractPrefixKey)), - }, - - { - AccessType: sdkacltypes.AccessType_READ, - ResourceType: sdkacltypes.ResourceType_KV_DEX_LONG_ORDER_COUNT, - IdentifierTemplate: hex.EncodeToString([]byte(dextypes.LongOrderCountKey)), - }, - - { - AccessType: sdkacltypes.AccessType_READ, - ResourceType: sdkacltypes.ResourceType_KV_DEX_SHORT_ORDER_COUNT, - IdentifierTemplate: hex.EncodeToString([]byte(dextypes.ShortOrderCountKey)), - }, - } - - // Last Operation should always be a commit - aclOps = append(aclOps, *acltypes.CommitAccessOp()) - return aclOps, nil -} - -func DexCancelOrdersDependencyGenerator(_ aclkeeper.Keeper, _ sdk.Context, msg sdk.Msg) ([]sdkacltypes.AccessOperation, error) { - cancelOrdersMsg, ok := msg.(*dextypes.MsgCancelOrders) - if !ok { - return []sdkacltypes.AccessOperation{}, ErrPlaceOrdersGenerator - } - contractAddr := cancelOrdersMsg.ContractAddr - - aclOps := []sdkacltypes.AccessOperation{ - { - AccessType: sdkacltypes.AccessType_READ, - ResourceType: sdkacltypes.ResourceType_KV_DEX_MEM_CANCEL, - IdentifierTemplate: hex.EncodeToString(dextypes.MemCancelPrefix(contractAddr)), - }, - { - AccessType: sdkacltypes.AccessType_WRITE, - ResourceType: sdkacltypes.ResourceType_KV_DEX_MEM_CANCEL, - IdentifierTemplate: hex.EncodeToString(dextypes.MemCancelPrefix(contractAddr)), - }, - { - AccessType: sdkacltypes.AccessType_READ, - ResourceType: sdkacltypes.ResourceType_KV_DEX_CONTRACT, - IdentifierTemplate: hex.EncodeToString([]byte(dexkeeper.ContractPrefixKey)), - }, - { - AccessType: sdkacltypes.AccessType_READ, - ResourceType: sdkacltypes.ResourceType_KV_DEX_MEM_DOWNSTREAM_CONTRACTS, - IdentifierTemplate: hex.EncodeToString(dextypes.MemDownstreamContractsKey(contractAddr)), - }, - { - AccessType: sdkacltypes.AccessType_WRITE, - ResourceType: sdkacltypes.ResourceType_KV_DEX_MEM_DOWNSTREAM_CONTRACTS, - IdentifierTemplate: hex.EncodeToString(dextypes.MemDownstreamContractsKey(contractAddr)), - }, - { - AccessType: sdkacltypes.AccessType_WRITE, - ResourceType: sdkacltypes.ResourceType_KV_DEX_MEM_CONTRACTS_TO_PROCESS, - IdentifierTemplate: hex.EncodeToString(dextypes.MemContractsToProcessKey(contractAddr)), - }, - } - - for _, order := range cancelOrdersMsg.GetCancellations() { - priceDenom := order.GetPriceDenom() - assetDenom := order.GetAssetDenom() - aclOps = append(aclOps, GetLongShortOrderBookOps(contractAddr, priceDenom, assetDenom)...) - } - - // Last Operation should always be a commit - aclOps = append(aclOps, *acltypes.CommitAccessOp()) - return aclOps, nil -} diff --git a/aclmapping/dex/mappings_test.go b/aclmapping/dex/mappings_test.go deleted file mode 100644 index 5e189ac8d..000000000 --- a/aclmapping/dex/mappings_test.go +++ /dev/null @@ -1,292 +0,0 @@ -package acldexmapping_test - -import ( - "context" - "fmt" - "testing" - "time" - - "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkacltypes "github.com/cosmos/cosmos-sdk/types/accesscontrol" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - acltypes "github.com/cosmos/cosmos-sdk/x/accesscontrol/types" - "github.com/k0kubun/pp/v3" - dexacl "github.com/sei-protocol/sei-chain/aclmapping/dex" - aclutils "github.com/sei-protocol/sei-chain/aclmapping/utils" - "github.com/sei-protocol/sei-chain/app" - "github.com/sei-protocol/sei-chain/app/apptesting" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - dexcache "github.com/sei-protocol/sei-chain/x/dex/cache" - dexmsgserver "github.com/sei-protocol/sei-chain/x/dex/keeper/msgserver" - "github.com/sei-protocol/sei-chain/x/dex/types" - dextypes "github.com/sei-protocol/sei-chain/x/dex/types" - dexutils "github.com/sei-protocol/sei-chain/x/dex/utils" - oracletypes "github.com/sei-protocol/sei-chain/x/oracle/types" - "github.com/stretchr/testify/require" - "github.com/stretchr/testify/suite" -) - -type KeeperTestSuite struct { - apptesting.KeeperTestHelper - - queryClient dextypes.QueryClient - msgServer dextypes.MsgServer - defaultDenom string - defaultExchangeRate string - initialBalance sdk.Coins - creator string - contract string - - msgPlaceOrders *dextypes.MsgPlaceOrders - msgCancelOrders *dextypes.MsgCancelOrders -} - -func TestKeeperTestSuite(t *testing.T) { - suite.Run(t, new(KeeperTestSuite)) -} - -// Runs before each test case -func (suite *KeeperTestSuite) SetupTest() { - suite.Setup() -} - -// Explicitly only run once during setup -func (suite *KeeperTestSuite) PrepareTest() { - suite.defaultDenom = "usei" - suite.defaultExchangeRate = fmt.Sprintf("%dusei", sdk.NewDec(1700)) - - suite.initialBalance = sdk.Coins{sdk.NewInt64Coin(suite.defaultDenom, 100000000000)} - suite.initialBalance = sdk.Coins{sdk.NewInt64Coin("usei", 100000000000)} - suite.FundAcc(suite.TestAccs[0], suite.initialBalance) - - suite.queryClient = dextypes.NewQueryClient(suite.QueryHelper) - suite.msgServer = dexmsgserver.NewMsgServerImpl(suite.App.DexKeeper) - - msgValidator := sdkacltypes.NewMsgValidator(aclutils.StoreKeyToResourceTypePrefixMap) - suite.Ctx = suite.Ctx.WithMsgValidator(msgValidator) - - suite.Ctx = suite.Ctx.WithBlockHeight(10) - suite.Ctx = suite.Ctx.WithBlockTime(time.Unix(333, 0)) - - suite.creator = suite.TestAccs[0].String() - suite.contract = "sei14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sh9m79m" - - suite.App.DexKeeper.AddRegisteredPair(suite.Ctx, suite.contract, keepertest.TestPair) - suite.App.DexKeeper.SetPriceTickSizeForPair(suite.Ctx, suite.contract, keepertest.TestPair, *keepertest.TestPair.PriceTicksize) - suite.App.DexKeeper.SetQuantityTickSizeForPair(suite.Ctx, suite.contract, keepertest.TestPair, *keepertest.TestPair.PriceTicksize) - - suite.msgPlaceOrders = &types.MsgPlaceOrders{ - Creator: suite.creator, - ContractAddr: suite.contract, - Orders: []*types.Order{ - { - Price: sdk.MustNewDecFromStr("10"), - Quantity: sdk.MustNewDecFromStr("10"), - Data: "", - PositionDirection: types.PositionDirection_LONG, - OrderType: types.OrderType_LIMIT, - PriceDenom: keepertest.TestPriceDenom, - AssetDenom: keepertest.TestAssetDenom, - }, - { - Price: sdk.MustNewDecFromStr("20"), - Quantity: sdk.MustNewDecFromStr("5"), - Data: "", - PositionDirection: types.PositionDirection_SHORT, - OrderType: types.OrderType_MARKET, - PriceDenom: keepertest.TestPriceDenom, - AssetDenom: keepertest.TestAssetDenom, - }, - }, - } - - suite.msgCancelOrders = &types.MsgCancelOrders{ - Creator: suite.creator, - ContractAddr: suite.contract, - Cancellations: []*types.Cancellation{ - { - Id: 1, - Price: sdk.MustNewDecFromStr("10"), - Creator: suite.creator, - PositionDirection: types.PositionDirection_LONG, - PriceDenom: keepertest.TestPriceDenom, - AssetDenom: keepertest.TestAssetDenom, - }, - { - Id: 2, - Creator: suite.creator, - Price: sdk.MustNewDecFromStr("20"), - PositionDirection: types.PositionDirection_SHORT, - PriceDenom: keepertest.TestPriceDenom, - AssetDenom: keepertest.TestAssetDenom, - }, - }, - } -} - -func (suite *KeeperTestSuite) TestMsgPlaceOrder() { - suite.PrepareTest() - tests := []struct { - name string - expectedError error - msg *dextypes.MsgPlaceOrders - dynamicDep bool - }{ - { - name: "default place order", - msg: suite.msgPlaceOrders, - expectedError: sdkerrors.Wrapf(sdkerrors.ErrNotSupported, "deprecated"), - dynamicDep: true, - }, - { - name: "dont check synchronous", - msg: suite.msgPlaceOrders, - expectedError: sdkerrors.Wrapf(sdkerrors.ErrNotSupported, "deprecated"), - dynamicDep: false, - }, - } - for _, tc := range tests { - suite.Run(fmt.Sprintf("Test Case: %s", tc.name), func() { - goCtx := context.WithValue(suite.Ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(suite.App.GetMemKey(dextypes.MemStoreKey))) - suite.Ctx = suite.Ctx.WithContext(goCtx) - - handlerCtx, cms := aclutils.CacheTxContext(suite.Ctx) - _, err := suite.msgServer.PlaceOrders( - sdk.WrapSDKContext(handlerCtx), - tc.msg, - ) - - depdenencies, _ := dexacl.DexPlaceOrdersDependencyGenerator( - suite.App.AccessControlKeeper, - handlerCtx, - tc.msg, - ) - - if !tc.dynamicDep { - depdenencies = sdkacltypes.SynchronousAccessOps() - } - - if tc.expectedError != nil { - suite.Require().EqualError(err, tc.expectedError.Error()) - } else { - suite.Require().NoError(err) - } - - missing := handlerCtx.MsgValidator().ValidateAccessOperations(depdenencies, cms.GetEvents()) - pp.Default.SetColoringEnabled(false) - - suite.Require().Empty(missing) - }) - } -} - -func (suite *KeeperTestSuite) TestMsgCancelOrder() { - suite.PrepareTest() - tests := []struct { - name string - expectedError error - msg *dextypes.MsgCancelOrders - dynamicDep bool - }{ - { - name: "default cancel order", - msg: suite.msgCancelOrders, - expectedError: sdkerrors.Wrapf(sdkerrors.ErrNotSupported, "deprecated"), - dynamicDep: true, - }, - { - name: "dont check synchronous", - msg: suite.msgCancelOrders, - expectedError: sdkerrors.Wrapf(sdkerrors.ErrNotSupported, "deprecated"), - dynamicDep: false, - }, - } - for _, tc := range tests { - suite.Run(fmt.Sprintf("Test Case: %s", tc.name), func() { - goCtx := context.WithValue(suite.Ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(suite.App.GetMemKey(dextypes.MemStoreKey))) - suite.Ctx = suite.Ctx.WithContext(goCtx) - - _, err := suite.msgServer.PlaceOrders( - sdk.WrapSDKContext(suite.Ctx), - suite.msgPlaceOrders, - ) - - handlerCtx, cms := aclutils.CacheTxContext(suite.Ctx) - _, err = suite.msgServer.CancelOrders( - sdk.WrapSDKContext(handlerCtx), - tc.msg, - ) - - depdenencies, _ := dexacl.DexCancelOrdersDependencyGenerator( - suite.App.AccessControlKeeper, - handlerCtx, - tc.msg, - ) - - if !tc.dynamicDep { - depdenencies = sdkacltypes.SynchronousAccessOps() - } - - if tc.expectedError != nil { - suite.Require().EqualError(err, tc.expectedError.Error()) - } else { - suite.Require().NoError(err) - } - - missing := handlerCtx.MsgValidator().ValidateAccessOperations(depdenencies, cms.GetEvents()) - suite.Require().Empty(missing) - }) - } -} - -func TestGeneratorInvalidMessageTypes(t *testing.T) { - tm := time.Now().UTC() - valPub := secp256k1.GenPrivKey().PubKey() - testWrapper := app.NewTestWrapper(t, tm, valPub, false) - - oracleVote := oracletypes.MsgAggregateExchangeRateVote{ - ExchangeRates: "1usei", - Feeder: "test", - Validator: "validator", - } - - _, err := dexacl.DexPlaceOrdersDependencyGenerator( - testWrapper.App.AccessControlKeeper, - testWrapper.Ctx, - &oracleVote, - ) - require.Error(t, err) - - _, err = dexacl.DexCancelOrdersDependencyGenerator( - testWrapper.App.AccessControlKeeper, - testWrapper.Ctx, - &oracleVote, - ) - require.Error(t, err) -} - -func (suite *KeeperTestSuite) TestMsgPlaceOrderGenerator() { - suite.PrepareTest() - - accessOps, err := dexacl.DexPlaceOrdersDependencyGenerator( - suite.App.AccessControlKeeper, - suite.Ctx, - suite.msgPlaceOrders, - ) - require.NoError(suite.T(), err) - err = acltypes.ValidateAccessOps(accessOps) - require.NoError(suite.T(), err) -} - -func (suite *KeeperTestSuite) TestMsgCancelOrderGenerator() { - suite.PrepareTest() - accessOps, err := dexacl.DexCancelOrdersDependencyGenerator( - suite.App.AccessControlKeeper, - suite.Ctx, - suite.msgCancelOrders, - ) - require.NoError(suite.T(), err) - err = acltypes.ValidateAccessOps(accessOps) - require.NoError(suite.T(), err) -} diff --git a/aclmapping/utils/resource_type.go b/aclmapping/utils/resource_type.go index 34fd3cbd6..747cc086c 100644 --- a/aclmapping/utils/resource_type.go +++ b/aclmapping/utils/resource_type.go @@ -11,8 +11,6 @@ import ( feegranttypes "github.com/cosmos/cosmos-sdk/x/feegrant" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - dexkeeper "github.com/sei-protocol/sei-chain/x/dex/keeper" - dextypes "github.com/sei-protocol/sei-chain/x/dex/types" epochtypes "github.com/sei-protocol/sei-chain/x/epoch/types" evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" oracletypes "github.com/sei-protocol/sei-chain/x/oracle/types" @@ -29,40 +27,6 @@ var StoreKeyToResourceTypePrefixMap = aclsdktypes.StoreKeyToResourceTypePrefixMa aclsdktypes.ResourceType_KV: aclsdktypes.EmptyPrefix, aclsdktypes.ResourceType_Mem: aclsdktypes.EmptyPrefix, }, - dextypes.StoreKey: { - aclsdktypes.ResourceType_KV_DEX: aclsdktypes.EmptyPrefix, - aclsdktypes.ResourceType_DexMem: aclsdktypes.EmptyPrefix, - aclsdktypes.ResourceType_KV_DEX_CONTRACT_LONGBOOK: dextypes.KeyPrefix(dextypes.LongBookKey), - aclsdktypes.ResourceType_KV_DEX_CONTRACT_SHORTBOOK: dextypes.KeyPrefix(dextypes.ShortBookKey), - // pricedenom and assetdenoms are the prefixes - aclsdktypes.ResourceType_KV_DEX_PAIR_PREFIX: aclsdktypes.EmptyPrefix, - aclsdktypes.ResourceType_KV_DEX_TWAP: dextypes.KeyPrefix(dextypes.TwapKey), - aclsdktypes.ResourceType_KV_DEX_PRICE: dextypes.KeyPrefix(dextypes.PriceKey), - aclsdktypes.ResourceType_KV_DEX_SETTLEMENT_ENTRY: dextypes.KeyPrefix(dextypes.SettlementEntryKey), - aclsdktypes.ResourceType_KV_DEX_REGISTERED_PAIR: dextypes.KeyPrefix(dextypes.RegisteredPairKey), - aclsdktypes.ResourceType_KV_DEX_ORDER: dextypes.KeyPrefix(dextypes.OrderKey), - aclsdktypes.ResourceType_KV_DEX_CANCEL: dextypes.KeyPrefix(dextypes.CancelKey), - aclsdktypes.ResourceType_KV_DEX_ACCOUNT_ACTIVE_ORDERS: dextypes.KeyPrefix(dextypes.AccountActiveOrdersKey), - aclsdktypes.ResourceType_KV_DEX_ASSET_LIST: dextypes.KeyPrefix(dextypes.AssetListKey), - aclsdktypes.ResourceType_KV_DEX_NEXT_ORDER_ID: dextypes.KeyPrefix(dextypes.NextOrderIDKey), - aclsdktypes.ResourceType_KV_DEX_NEXT_SETTLEMENT_ID: dextypes.KeyPrefix(dextypes.NextSettlementIDKey), - aclsdktypes.ResourceType_KV_DEX_MATCH_RESULT: dextypes.KeyPrefix(dextypes.MatchResultKey), - aclsdktypes.ResourceType_KV_DEX_CONTRACT: dextypes.KeyPrefix(dexkeeper.ContractPrefixKey), - aclsdktypes.ResourceType_KV_DEX_ORDER_BOOK: dextypes.KeyPrefix(dextypes.NextOrderIDKey), - aclsdktypes.ResourceType_KV_DEX_LONG_ORDER_COUNT: dextypes.KeyPrefix(dextypes.LongOrderCountKey), - aclsdktypes.ResourceType_KV_DEX_SHORT_ORDER_COUNT: dextypes.KeyPrefix(dextypes.ShortOrderCountKey), - // SETTLEMENT keys are prefixed with account and order id - aclsdktypes.ResourceType_KV_DEX_SETTLEMENT_ORDER_ID: aclsdktypes.EmptyPrefix, - aclsdktypes.ResourceType_KV_DEX_SETTLEMENT: aclsdktypes.EmptyPrefix, - }, - dextypes.MemStoreKey: { - // mem - aclsdktypes.ResourceType_KV_DEX_MEM_ORDER: dextypes.KeyPrefix(dextypes.MemOrderKey), - aclsdktypes.ResourceType_KV_DEX_MEM_CANCEL: dextypes.KeyPrefix(dextypes.MemCancelKey), - aclsdktypes.ResourceType_KV_DEX_MEM_DEPOSIT: dextypes.KeyPrefix(dextypes.MemDepositKey), - aclsdktypes.ResourceType_KV_DEX_MEM_CONTRACTS_TO_PROCESS: dextypes.KeyPrefix(dextypes.MemContractsToProcess), - aclsdktypes.ResourceType_KV_DEX_MEM_DOWNSTREAM_CONTRACTS: dextypes.KeyPrefix(dextypes.MemDownstreamContracts), - }, banktypes.StoreKey: { aclsdktypes.ResourceType_KV_BANK: aclsdktypes.EmptyPrefix, aclsdktypes.ResourceType_KV_BANK_BALANCES: banktypes.BalancesPrefix, @@ -173,40 +137,6 @@ var StoreKeyToResourceTypePrefixMap = aclsdktypes.StoreKeyToResourceTypePrefixMa // ResourceTypeToStoreKeyMap this maps between resource types and their respective storekey var ResourceTypeToStoreKeyMap = aclsdktypes.ResourceTypeToStoreKeyMap{ // ANY, KV, and MEM are intentionally excluded because they don't map to a specific store key - - // ~~~~ DEX Resource Types ~~~~ - aclsdktypes.ResourceType_KV_DEX: dextypes.StoreKey, - aclsdktypes.ResourceType_DexMem: dextypes.StoreKey, - aclsdktypes.ResourceType_KV_DEX_CONTRACT_LONGBOOK: dextypes.StoreKey, - aclsdktypes.ResourceType_KV_DEX_CONTRACT_SHORTBOOK: dextypes.StoreKey, - // pricedenom and assetdenoms are the prefixes - aclsdktypes.ResourceType_KV_DEX_PAIR_PREFIX: dextypes.StoreKey, - aclsdktypes.ResourceType_KV_DEX_TWAP: dextypes.StoreKey, - aclsdktypes.ResourceType_KV_DEX_PRICE: dextypes.StoreKey, - aclsdktypes.ResourceType_KV_DEX_SETTLEMENT_ENTRY: dextypes.StoreKey, - aclsdktypes.ResourceType_KV_DEX_REGISTERED_PAIR: dextypes.StoreKey, - aclsdktypes.ResourceType_KV_DEX_ORDER: dextypes.StoreKey, - aclsdktypes.ResourceType_KV_DEX_CANCEL: dextypes.StoreKey, - aclsdktypes.ResourceType_KV_DEX_ACCOUNT_ACTIVE_ORDERS: dextypes.StoreKey, - aclsdktypes.ResourceType_KV_DEX_ASSET_LIST: dextypes.StoreKey, - aclsdktypes.ResourceType_KV_DEX_NEXT_ORDER_ID: dextypes.StoreKey, - aclsdktypes.ResourceType_KV_DEX_NEXT_SETTLEMENT_ID: dextypes.StoreKey, - aclsdktypes.ResourceType_KV_DEX_MATCH_RESULT: dextypes.StoreKey, - aclsdktypes.ResourceType_KV_DEX_CONTRACT: dextypes.StoreKey, - aclsdktypes.ResourceType_KV_DEX_ORDER_BOOK: dextypes.StoreKey, - aclsdktypes.ResourceType_KV_DEX_LONG_ORDER_COUNT: dextypes.StoreKey, - aclsdktypes.ResourceType_KV_DEX_SHORT_ORDER_COUNT: dextypes.StoreKey, - // SETTLEMENT keys are prefixed with account and order id - aclsdktypes.ResourceType_KV_DEX_SETTLEMENT_ORDER_ID: dextypes.StoreKey, - aclsdktypes.ResourceType_KV_DEX_SETTLEMENT: dextypes.StoreKey, - - // ~~~~ DEX MEM Resource Types ~~~~ - aclsdktypes.ResourceType_KV_DEX_MEM_ORDER: dextypes.MemStoreKey, - aclsdktypes.ResourceType_KV_DEX_MEM_CANCEL: dextypes.MemStoreKey, - aclsdktypes.ResourceType_KV_DEX_MEM_DEPOSIT: dextypes.MemStoreKey, - aclsdktypes.ResourceType_KV_DEX_MEM_CONTRACTS_TO_PROCESS: dextypes.MemStoreKey, - aclsdktypes.ResourceType_KV_DEX_MEM_DOWNSTREAM_CONTRACTS: dextypes.MemStoreKey, - // ~~~~ BANK Resource Types ~~~~ aclsdktypes.ResourceType_KV_BANK: banktypes.StoreKey, aclsdktypes.ResourceType_KV_BANK_BALANCES: banktypes.StoreKey, diff --git a/app/ante.go b/app/ante.go index 7b60e9191..768408616 100644 --- a/app/ante.go +++ b/app/ante.go @@ -14,9 +14,6 @@ import ( ibckeeper "github.com/cosmos/ibc-go/v3/modules/core/keeper" "github.com/sei-protocol/sei-chain/app/antedecorators" "github.com/sei-protocol/sei-chain/app/antedecorators/depdecorators" - "github.com/sei-protocol/sei-chain/x/dex" - dexcache "github.com/sei-protocol/sei-chain/x/dex/cache" - dexkeeper "github.com/sei-protocol/sei-chain/x/dex/keeper" evmante "github.com/sei-protocol/sei-chain/x/evm/ante" evmkeeper "github.com/sei-protocol/sei-chain/x/evm/keeper" "github.com/sei-protocol/sei-chain/x/oracle" @@ -32,11 +29,9 @@ type HandlerOptions struct { WasmConfig *wasmtypes.WasmConfig WasmKeeper *wasm.Keeper OracleKeeper *oraclekeeper.Keeper - DexKeeper *dexkeeper.Keeper AccessControlKeeper *aclkeeper.Keeper EVMKeeper *evmkeeper.Keeper TXCounterStoreKey sdk.StoreKey - CheckTxMemState *dexcache.MemState LatestCtxGetter func() sdk.Context TracingInfo *tracing.Info @@ -70,9 +65,6 @@ func NewAnteHandlerAndDepGenerator(options HandlerOptions) (sdk.AnteHandler, sdk if options.TracingInfo == nil { return nil, nil, sdkerrors.Wrap(sdkerrors.ErrLogic, "tracing info is required for ante builder") } - if options.CheckTxMemState == nil { - return nil, nil, sdkerrors.Wrap(sdkerrors.ErrLogic, "checktx memstate is required for ante builder") - } if options.EVMKeeper == nil { return nil, nil, sdkerrors.Wrap(sdkerrors.ErrLogic, "evm keeper is required for ante builder") } @@ -109,8 +101,6 @@ func NewAnteHandlerAndDepGenerator(options HandlerOptions) (sdk.AnteHandler, sdk sdk.DefaultWrappedAnteDecorator(evmante.NewEVMAddressDecorator(options.EVMKeeper, options.EVMKeeper.AccountKeeper())), sdk.DefaultWrappedAnteDecorator(antedecorators.NewAuthzNestedMessageDecorator()), sdk.DefaultWrappedAnteDecorator(ibcante.NewAnteDecorator(options.IBCKeeper)), - sdk.DefaultWrappedAnteDecorator(dex.NewTickSizeMultipleDecorator(*options.DexKeeper)), - dex.NewCheckDexGasDecorator(*options.DexKeeper, options.CheckTxMemState), antedecorators.NewACLWasmDependencyDecorator(*options.AccessControlKeeper, *options.WasmKeeper), } diff --git a/app/ante_test.go b/app/ante_test.go index a433e5d83..dfbf7a533 100644 --- a/app/ante_test.go +++ b/app/ante_test.go @@ -99,10 +99,8 @@ func (suite *AnteTestSuite) SetupTest(isCheckTx bool) { WasmConfig: &wasmConfig, WasmKeeper: &suite.App.WasmKeeper, OracleKeeper: &suite.App.OracleKeeper, - DexKeeper: &suite.App.DexKeeper, AccessControlKeeper: &suite.App.AccessControlKeeper, TracingInfo: tracingInfo, - CheckTxMemState: suite.App.CheckTxMemState, EVMKeeper: &suite.App.EvmKeeper, LatestCtxGetter: func() sdk.Context { return suite.Ctx }, }, diff --git a/app/antedecorators/gasless.go b/app/antedecorators/gasless.go index f71798b1d..2835b93ba 100644 --- a/app/antedecorators/gasless.go +++ b/app/antedecorators/gasless.go @@ -1,7 +1,6 @@ package antedecorators import ( - "bytes" "encoding/hex" storetypes "github.com/cosmos/cosmos-sdk/store/types" @@ -9,7 +8,6 @@ import ( sdkacltypes "github.com/cosmos/cosmos-sdk/types/accesscontrol" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - dextypes "github.com/sei-protocol/sei-chain/x/dex/types" evmkeeper "github.com/sei-protocol/sei-chain/x/evm/keeper" evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" oraclekeeper "github.com/sei-protocol/sei-chain/x/oracle/keeper" @@ -118,15 +116,6 @@ func IsTxGasless(tx sdk.Tx, ctx sdk.Context, oracleKeeper oraclekeeper.Keeper, e } for _, msg := range tx.GetMsgs() { switch m := msg.(type) { - case *dextypes.MsgPlaceOrders: - if !dexPlaceOrdersIsGasless(m) { - return false, nil - } - - case *dextypes.MsgCancelOrders: - if !dexCancelOrdersIsGasless(m) { - return false, nil - } case *oracletypes.MsgAggregateExchangeRateVote: isGasless, err := oracleVoteIsGasless(m, ctx, oracleKeeper) if err != nil || !isGasless { @@ -143,33 +132,6 @@ func IsTxGasless(tx sdk.Tx, ctx sdk.Context, oracleKeeper oraclekeeper.Keeper, e return true, nil } -func dexPlaceOrdersIsGasless(_ *dextypes.MsgPlaceOrders) bool { - return false -} - -// WhitelistedGaslessCancellationAddrs TODO: migrate this into params state -var WhitelistedGaslessCancellationAddrs = []sdk.AccAddress{} - -func dexCancelOrdersIsGasless(msg *dextypes.MsgCancelOrders) bool { - return allSignersWhitelisted(msg) -} - -func allSignersWhitelisted(msg *dextypes.MsgCancelOrders) bool { - for _, signer := range msg.GetSigners() { - isWhitelisted := false - for _, whitelisted := range WhitelistedGaslessCancellationAddrs { - if bytes.Compare(signer, whitelisted) == 0 { //nolint:gosimple - isWhitelisted = true - break - } - } - if !isWhitelisted { - return false - } - } - return true -} - func oracleVoteIsGasless(msg *oracletypes.MsgAggregateExchangeRateVote, ctx sdk.Context, keeper oraclekeeper.Keeper) (bool, error) { feederAddr, err := sdk.AccAddressFromBech32(msg.Feeder) if err != nil { diff --git a/app/antedecorators/gasless_test.go b/app/antedecorators/gasless_test.go index 58143c1ce..8152dceab 100644 --- a/app/antedecorators/gasless_test.go +++ b/app/antedecorators/gasless_test.go @@ -8,12 +8,10 @@ import ( "github.com/cosmos/cosmos-sdk/types/accesscontrol" "github.com/cosmos/cosmos-sdk/x/staking" "github.com/sei-protocol/sei-chain/app/antedecorators" - "github.com/sei-protocol/sei-chain/x/dex/types" evmkeeper "github.com/sei-protocol/sei-chain/x/evm/keeper" oraclekeeper "github.com/sei-protocol/sei-chain/x/oracle/keeper" oracletypes "github.com/sei-protocol/sei-chain/x/oracle/types" "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/crypto/secp256k1" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" ) @@ -151,40 +149,11 @@ func TestOracleVoteGasless(t *testing.T) { require.True(t, gasless) } -func TestDexCancelOrderGasless(t *testing.T) { - addr1 := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) - addr2 := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) - - antedecorators.WhitelistedGaslessCancellationAddrs = []sdk.AccAddress{ - addr2, - } - - cancelMsg1 := types.MsgCancelOrders{ - Creator: addr1.String(), - } - cancelMsg2 := types.MsgCancelOrders{ - Creator: addr2.String(), - } - // not whitelisted - // reset gasless - gasless = true - err := CallGaslessDecoratorWithMsg(sdk.NewContext(nil, tmproto.Header{}, false, nil).WithIsCheckTx(true), &cancelMsg1, oraclekeeper.Keeper{}, nil) - require.NoError(t, err) - require.False(t, gasless) - - // whitelisted - // reset gasless - gasless = true - err = CallGaslessDecoratorWithMsg(sdk.NewContext(nil, tmproto.Header{}, false, nil).WithIsCheckTx(true), &cancelMsg2, oraclekeeper.Keeper{}, nil) - require.NoError(t, err) - require.True(t, gasless) -} - func TestNonGaslessMsg(t *testing.T) { // this needs to be updated if its changed from constant true // reset gasless gasless = true - err := CallGaslessDecoratorWithMsg(sdk.NewContext(nil, tmproto.Header{}, false, nil).WithIsCheckTx(true), &types.MsgRegisterContract{}, oraclekeeper.Keeper{}, nil) + err := CallGaslessDecoratorWithMsg(sdk.NewContext(nil, tmproto.Header{}, false, nil).WithIsCheckTx(true), &oracletypes.MsgDelegateFeedConsent{}, oraclekeeper.Keeper{}, nil) require.NoError(t, err) require.False(t, gasless) } diff --git a/app/antedecorators/priority_test.go b/app/antedecorators/priority_test.go index bc5ceff19..4083fac1e 100644 --- a/app/antedecorators/priority_test.go +++ b/app/antedecorators/priority_test.go @@ -7,7 +7,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/sei-protocol/sei-chain/app/antedecorators" - "github.com/sei-protocol/sei-chain/x/dex/types" oracletypes "github.com/sei-protocol/sei-chain/x/oracle/types" "github.com/stretchr/testify/require" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" @@ -42,7 +41,7 @@ func TestPriorityAnteDecoratorTooHighPriority(t *testing.T) { ctx.WithPriority(math.MaxInt64-50), FakeTx{ FakeMsgs: []sdk.Msg{ - &types.MsgPlaceOrders{}, + &oracletypes.MsgDelegateFeedConsent{}, }, }, false, diff --git a/app/app.go b/app/app.go index 5643a5c74..be0a2801d 100644 --- a/app/app.go +++ b/app/app.go @@ -143,12 +143,6 @@ import ( "github.com/sei-protocol/sei-chain/utils/metrics" - dexmodule "github.com/sei-protocol/sei-chain/x/dex" - dexcache "github.com/sei-protocol/sei-chain/x/dex/cache" - dexmodulekeeper "github.com/sei-protocol/sei-chain/x/dex/keeper" - dexmoduletypes "github.com/sei-protocol/sei-chain/x/dex/types" - dexutils "github.com/sei-protocol/sei-chain/x/dex/utils" - oraclemodule "github.com/sei-protocol/sei-chain/x/oracle" oraclekeeper "github.com/sei-protocol/sei-chain/x/oracle/keeper" oracletypes "github.com/sei-protocol/sei-chain/x/oracle/types" @@ -220,7 +214,6 @@ var ( oraclemodule.AppModuleBasic{}, evm.AppModuleBasic{}, wasm.AppModuleBasic{}, - dexmodule.AppModuleBasic{}, epochmodule.AppModuleBasic{}, tokenfactorymodule.AppModuleBasic{}, // this line is used by starport scaffolding # stargate/app/moduleBasic @@ -239,7 +232,6 @@ var ( oracletypes.ModuleName: nil, wasm.ModuleName: {authtypes.Burner}, evmtypes.ModuleName: {authtypes.Minter, authtypes.Burner}, - dexmoduletypes.ModuleName: {authtypes.Burner}, tokenfactorytypes.ModuleName: {authtypes.Minter, authtypes.Burner}, // this line is used by starport scaffolding # stargate/app/maccPerms } @@ -353,8 +345,6 @@ type App struct { ScopedTransferKeeper capabilitykeeper.ScopedKeeper ScopedWasmKeeper capabilitykeeper.ScopedKeeper - DexKeeper dexmodulekeeper.Keeper - EpochKeeper epochmodulekeeper.Keeper TokenFactoryKeeper tokenfactorykeeper.Keeper @@ -379,10 +369,6 @@ type App struct { mounter func() - CheckTxMemState *dexcache.MemState - ProcessProposalMemState *dexcache.MemState - MemState *dexcache.MemState - HardForkManager *upgrades.HardForkManager encodingConfig appparams.EncodingConfig @@ -432,13 +418,12 @@ func New( govtypes.StoreKey, paramstypes.StoreKey, ibchost.StoreKey, upgradetypes.StoreKey, feegrant.StoreKey, evidencetypes.StoreKey, ibctransfertypes.StoreKey, capabilitytypes.StoreKey, oracletypes.StoreKey, evmtypes.StoreKey, wasm.StoreKey, - dexmoduletypes.StoreKey, epochmoduletypes.StoreKey, tokenfactorytypes.StoreKey, // this line is used by starport scaffolding # stargate/app/storeKey ) tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey, evmtypes.TransientStoreKey) - memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey, dexmoduletypes.MemStoreKey, banktypes.DeferredCacheStoreKey, oracletypes.MemStoreKey) + memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey, banktypes.DeferredCacheStoreKey, oracletypes.MemStoreKey) app := &App{ BaseApp: bApp, @@ -555,15 +540,7 @@ func New( app.GetSubspace(epochmoduletypes.ModuleName), ).SetHooks(epochmoduletypes.NewMultiEpochHooks( app.MintKeeper.Hooks())) - app.DexKeeper = *dexmodulekeeper.NewKeeper( - appCodec, - keys[dexmoduletypes.StoreKey], - memKeys[dexmoduletypes.MemStoreKey], - app.GetSubspace(dexmoduletypes.ModuleName), - app.EpochKeeper, - app.BankKeeper, - app.AccountKeeper, - ) + app.TokenFactoryKeeper = tokenfactorykeeper.NewKeeper( appCodec, app.keys[tokenfactorytypes.StoreKey], @@ -579,7 +556,6 @@ func New( wasmOpts = append( wasmbinding.RegisterCustomPlugins( &app.OracleKeeper, - &app.DexKeeper, &app.EpochKeeper, &app.TokenFactoryKeeper, &app.AccountKeeper, @@ -686,8 +662,6 @@ func New( aclOpts..., ) - app.DexKeeper.SetWasmKeeper(&app.WasmKeeper) - dexModule := dexmodule.NewAppModule(appCodec, app.DexKeeper, app.AccountKeeper, app.BankKeeper, app.WasmKeeper, app.GetBaseApp().TracingInfo) epochModule := epochmodule.NewAppModule(appCodec, app.EpochKeeper, app.AccountKeeper, app.BankKeeper) // register the proposal types @@ -697,7 +671,6 @@ func New( AddRoute(distrtypes.RouterKey, distr.NewCommunityPoolSpendProposalHandler(app.DistrKeeper)). AddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(app.UpgradeKeeper)). AddRoute(ibcclienttypes.RouterKey, ibcclient.NewClientProposalHandler(app.IBCKeeper.ClientKeeper)). - AddRoute(dexmoduletypes.RouterKey, dexmodule.NewProposalHandler(app.DexKeeper)). AddRoute(minttypes.RouterKey, mint.NewProposalHandler(app.MintKeeper)). AddRoute(tokenfactorytypes.RouterKey, tokenfactorymodule.NewProposalHandler(app.TokenFactoryKeeper)). AddRoute(acltypes.ModuleName, aclmodule.NewProposalHandler(app.AccessControlKeeper)). @@ -776,7 +749,6 @@ func New( wasm.NewAppModule(appCodec, &app.WasmKeeper, app.StakingKeeper, app.AccountKeeper, app.BankKeeper), evm.NewAppModule(appCodec, &app.EvmKeeper), transferModule, - dexModule, epochModule, tokenfactorymodule.NewAppModule(app.TokenFactoryKeeper, app.AccountKeeper, app.BankKeeper), authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry), @@ -808,7 +780,6 @@ func New( ibchost.ModuleName, ibctransfertypes.ModuleName, oracletypes.ModuleName, - dexmoduletypes.ModuleName, evmtypes.ModuleName, wasm.ModuleName, tokenfactorytypes.ModuleName, @@ -840,7 +811,6 @@ func New( ibctransfertypes.ModuleName, oracletypes.ModuleName, epochmoduletypes.ModuleName, - dexmoduletypes.ModuleName, evmtypes.ModuleName, wasm.ModuleName, tokenfactorytypes.ModuleName, @@ -866,7 +836,6 @@ func New( vestingtypes.ModuleName, crisistypes.ModuleName, ibchost.ModuleName, - dexmoduletypes.ModuleName, genutiltypes.ModuleName, evidencetypes.ModuleName, ibctransfertypes.ModuleName, @@ -903,7 +872,6 @@ func New( wasm.NewAppModule(appCodec, &app.WasmKeeper, app.StakingKeeper, app.AccountKeeper, app.BankKeeper), ibc.NewAppModule(app.IBCKeeper), transferModule, - dexModule, epochModule, tokenfactorymodule.NewAppModule(app.TokenFactoryKeeper, app.AccountKeeper, app.BankKeeper), // this line is used by starport scaffolding # stargate/app/appModule @@ -921,10 +889,6 @@ func New( } app.mounter() - app.CheckTxMemState = dexcache.NewMemState(app.GetMemKey(dexmoduletypes.MemStoreKey)) - app.ProcessProposalMemState = dexcache.NewMemState(app.GetMemKey(dexmoduletypes.MemStoreKey)) - app.MemState = dexcache.NewMemState(app.GetMemKey(dexmoduletypes.MemStoreKey)) - // initialize BaseApp app.SetInitChainer(app.InitChainer) app.SetBeginBlocker(app.BeginBlocker) @@ -948,11 +912,9 @@ func New( WasmConfig: &wasmConfig, WasmKeeper: &app.WasmKeeper, OracleKeeper: &app.OracleKeeper, - DexKeeper: &app.DexKeeper, EVMKeeper: &app.EvmKeeper, TracingInfo: app.GetBaseApp().TracingInfo, AccessControlKeeper: &app.AccessControlKeeper, - CheckTxMemState: app.CheckTxMemState, LatestCtxGetter: func() sdk.Context { return app.GetCheckCtx() }, @@ -1084,6 +1046,16 @@ func (app *App) SetStoreUpgradeHandlers() { Added: []string{evmtypes.StoreKey}, } + // configure store loader that checks if version == upgradeHeight and applies store upgrades + app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades)) + } + // TODO: change this upgrade name if the planned upgrade version number ends up changing more + if (upgradeInfo.Name == "v5.8.0") && !app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) { + dexStoreKeyName := "dex" + storeUpgrades := storetypes.StoreUpgrades{ + Deleted: []string{dexStoreKeyName}, + } + // configure store loader that checks if version == upgradeHeight and applies store upgrades app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades)) } @@ -1123,7 +1095,6 @@ func (app *App) InitChainer(ctx sdk.Context, req abci.RequestInitChain) abci.Res panic(err) } } - ctx = ctx.WithContext(app.decorateContextWithDexMemState(ctx.Context())) app.UpgradeKeeper.SetModuleVersionMap(ctx, app.mm.GetVersionMap()) return app.mm.InitGenesis(ctx, app.appCodec, genesisState, app.genesisImportConfig) } @@ -1170,7 +1141,6 @@ func (app *App) ProcessProposalHandler(ctx sdk.Context, req *abci.RequestProcess app.optimisticProcessingInfo.Completion <- struct{}{} } else { go func() { - ctx = ctx.WithContext(app.decorateProcessProposalContextWithDexMemState(ctx.Context())) events, txResults, endBlockResp, _ := app.ProcessBlock(ctx, req.Txs, req, req.ProposedLastCommit) optimisticProcessingInfo.Events = events optimisticProcessingInfo.TxRes = txResults @@ -1210,8 +1180,6 @@ func (app *App) FinalizeBlocker(ctx sdk.Context, req *abci.RequestFinalizeBlock) } metrics.IncrementOptimisticProcessingCounter(false) ctx.Logger().Info("optimistic processing ineligible") - ctx = ctx.WithContext(app.decorateContextWithDexMemState(ctx.Context())) - events, txResults, endBlockResp, _ := app.ProcessBlock(ctx, req.Txs, req, req.DecidedLastCommit) app.SetDeliverStateToCommit() @@ -1420,7 +1388,6 @@ func (app *App) ProcessTxs( dependencyDag.TxMsgAccessOpMapping, absoluteTxIndices, ) - oldDexMemState := dexutils.GetMemState(ctx.Context()).DeepCopy() if ok { // Write the results back to the concurrent contexts - if concurrent execution fails, // this should not be called and the state is rolled back and retried with synchronous execution @@ -1431,13 +1398,6 @@ func (app *App) ProcessTxs( ctx = app.addBadWasmDependenciesToContext(ctx, concurrentResults) ctx.Logger().Error("Concurrent Execution failed, retrying with Synchronous") - oldDexMemStateCtx := context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, oldDexMemState) - ctx = ctx.WithContext(oldDexMemStateCtx) - - dexMemState := dexutils.GetMemState(ctx.Context()) - dexMemState.Clear(ctx) - dexMemState.ClearContractToDependencies(ctx) - txResults := app.ProcessBlockSynchronous(ctx, txs, typedTxs, absoluteTxIndices) processBlockCache.Write() return txResults, ctx @@ -1463,12 +1423,6 @@ func (app *App) PartitionPrioritizedTxs(_ sdk.Context, txs [][]byte, typedTxs [] switch msg.(type) { case *oracletypes.MsgAggregateExchangeRateVote: prioritized = true - case *dexmoduletypes.MsgRegisterContract: - prioritized = true - case *dexmoduletypes.MsgUnregisterContract: - prioritized = true - case *dexmoduletypes.MsgUnsuspendContract: - prioritized = true default: prioritized = false break msgLoop @@ -1590,8 +1544,6 @@ func (app *App) BuildDependenciesAndRunTxs(ctx sdk.Context, txs [][]byte, typedT func (app *App) ProcessBlock(ctx sdk.Context, txs [][]byte, req BlockProcessRequest, lastCommit abci.CommitInfo) ([]abci.Event, []*abci.ExecTxResult, abci.ResponseEndBlock, error) { ctx = ctx.WithIsOCCEnabled(app.OccEnabled()) - goCtx := app.decorateContextWithDexMemState(ctx.Context()) - ctx = ctx.WithContext(goCtx) events := []abci.Event{} beginBlockReq := abci.RequestBeginBlock{ @@ -1971,7 +1923,6 @@ func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino paramsKeeper.Subspace(oracletypes.ModuleName) paramsKeeper.Subspace(wasm.ModuleName) paramsKeeper.Subspace(evmtypes.ModuleName) - paramsKeeper.Subspace(dexmoduletypes.ModuleName) paramsKeeper.Subspace(epochmoduletypes.ModuleName) paramsKeeper.Subspace(tokenfactorytypes.ModuleName) // this line is used by starport scaffolding # stargate/app/paramSubspace @@ -1998,14 +1949,6 @@ func (app *App) SetTxDecoder(txDecoder sdk.TxDecoder) { app.txDecoder = txDecoder } -func (app *App) decorateProcessProposalContextWithDexMemState(base context.Context) context.Context { - return context.WithValue(base, dexutils.DexMemStateContextKey, app.ProcessProposalMemState) -} - -func (app *App) decorateContextWithDexMemState(base context.Context) context.Context { - return context.WithValue(base, dexutils.DexMemStateContextKey, app.MemState) -} - func init() { // override max wasm size to 2MB wasmtypes.MaxWasmSize = 2 * 1024 * 1024 diff --git a/app/app_test.go b/app/app_test.go index b28160188..09da0963d 100644 --- a/app/app_test.go +++ b/app/app_test.go @@ -28,7 +28,6 @@ import ( "github.com/k0kubun/pp/v3" "github.com/sei-protocol/sei-chain/app" testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" - dextypes "github.com/sei-protocol/sei-chain/x/dex/types" "github.com/sei-protocol/sei-chain/x/evm/config" evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" @@ -137,25 +136,6 @@ func TestPartitionPrioritizedTxs(t *testing.T) { Validator: validator, } - contractRegisterMsg := &dextypes.MsgRegisterContract{ - Creator: account, - Contract: &dextypes.ContractInfoV2{ - CodeId: 1, - ContractAddr: "sei1dc34p57spmhguak2ns88u3vxmt73gnu3c0j6phqv5ukfytklkqjsgepv26", - NeedOrderMatching: true, - }, - } - - contractUnregisterMsg := &dextypes.MsgUnregisterContract{ - Creator: account, - ContractAddr: "sei1dc34p57spmhguak2ns88u3vxmt73gnu3c0j6phqv5ukfytklkqjsgepv26", - } - - contractUnsuspendMsg := &dextypes.MsgUnsuspendContract{ - Creator: account, - ContractAddr: "sei1dc34p57spmhguak2ns88u3vxmt73gnu3c0j6phqv5ukfytklkqjsgepv26", - } - otherMsg := &stakingtypes.MsgDelegate{ DelegatorAddress: account, ValidatorAddress: validator, @@ -164,9 +144,6 @@ func TestPartitionPrioritizedTxs(t *testing.T) { txEncoder := app.MakeEncodingConfig().TxConfig.TxEncoder() oracleTxBuilder := app.MakeEncodingConfig().TxConfig.NewTxBuilder() - contractRegisterBuilder := app.MakeEncodingConfig().TxConfig.NewTxBuilder() - contractUnregisterBuilder := app.MakeEncodingConfig().TxConfig.NewTxBuilder() - contractUnsuspendBuilder := app.MakeEncodingConfig().TxConfig.NewTxBuilder() otherTxBuilder := app.MakeEncodingConfig().TxConfig.NewTxBuilder() mixedTxBuilder := app.MakeEncodingConfig().TxConfig.NewTxBuilder() @@ -175,21 +152,6 @@ func TestPartitionPrioritizedTxs(t *testing.T) { oracleTx, err := txEncoder(oracleTxBuilder.GetTx()) require.NoError(t, err) - err = contractRegisterBuilder.SetMsgs(contractRegisterMsg) - require.NoError(t, err) - contractRegisterTx, err := txEncoder(contractRegisterBuilder.GetTx()) - require.NoError(t, err) - - err = contractUnregisterBuilder.SetMsgs(contractUnregisterMsg) - require.NoError(t, err) - contractUnregisterTx, err := txEncoder(contractUnregisterBuilder.GetTx()) - require.NoError(t, err) - - err = contractUnsuspendBuilder.SetMsgs(contractUnsuspendMsg) - require.NoError(t, err) - contractSuspendTx, err := txEncoder(contractUnsuspendBuilder.GetTx()) - require.NoError(t, err) - err = otherTxBuilder.SetMsgs(otherMsg) require.NoError(t, err) otherTx, err := txEncoder(otherTxBuilder.GetTx()) @@ -203,52 +165,40 @@ func TestPartitionPrioritizedTxs(t *testing.T) { txs := [][]byte{ oracleTx, - contractRegisterTx, - contractUnregisterTx, - contractSuspendTx, otherTx, mixedTx, } typedTxs := []sdk.Tx{ oracleTxBuilder.GetTx(), - contractRegisterBuilder.GetTx(), - contractUnregisterBuilder.GetTx(), - contractUnsuspendBuilder.GetTx(), otherTxBuilder.GetTx(), mixedTxBuilder.GetTx(), } prioritizedTxs, otherTxs, prioritizedTypedTxs, otherTypedTxs, prioIdxs, otherIdxs := testWrapper.App.PartitionPrioritizedTxs(testWrapper.Ctx, txs, typedTxs) - require.Equal(t, [][]byte{oracleTx, contractRegisterTx, contractUnregisterTx, contractSuspendTx}, prioritizedTxs) + require.Equal(t, [][]byte{oracleTx}, prioritizedTxs) require.Equal(t, [][]byte{otherTx, mixedTx}, otherTxs) - require.Equal(t, []int{0, 1, 2, 3}, prioIdxs) - require.Equal(t, []int{4, 5}, otherIdxs) - require.Equal(t, 4, len(prioritizedTypedTxs)) + require.Equal(t, []int{0}, prioIdxs) + require.Equal(t, []int{1, 2}, otherIdxs) + require.Equal(t, 1, len(prioritizedTypedTxs)) require.Equal(t, 2, len(otherTypedTxs)) diffOrderTxs := [][]byte{ - oracleTx, otherTx, - contractRegisterTx, - contractUnregisterTx, + oracleTx, mixedTx, - contractSuspendTx, } differOrderTypedTxs := []sdk.Tx{ - oracleTxBuilder.GetTx(), otherTxBuilder.GetTx(), - contractRegisterBuilder.GetTx(), - contractUnregisterBuilder.GetTx(), + oracleTxBuilder.GetTx(), mixedTxBuilder.GetTx(), - contractUnsuspendBuilder.GetTx(), } prioritizedTxs, otherTxs, prioritizedTypedTxs, otherTypedTxs, prioIdxs, otherIdxs = testWrapper.App.PartitionPrioritizedTxs(testWrapper.Ctx, diffOrderTxs, differOrderTypedTxs) - require.Equal(t, [][]byte{oracleTx, contractRegisterTx, contractUnregisterTx, contractSuspendTx}, prioritizedTxs) + require.Equal(t, [][]byte{oracleTx}, prioritizedTxs) require.Equal(t, [][]byte{otherTx, mixedTx}, otherTxs) - require.Equal(t, []int{0, 2, 3, 5}, prioIdxs) - require.Equal(t, []int{1, 4}, otherIdxs) - require.Equal(t, 4, len(prioritizedTypedTxs)) + require.Equal(t, []int{1}, prioIdxs) + require.Equal(t, []int{0, 2}, otherIdxs) + require.Equal(t, 1, len(prioritizedTypedTxs)) require.Equal(t, 2, len(otherTypedTxs)) } diff --git a/app/apptesting/test_suite.go b/app/apptesting/test_suite.go index 9d72cc9f6..26ec97dd3 100644 --- a/app/apptesting/test_suite.go +++ b/app/apptesting/test_suite.go @@ -16,7 +16,6 @@ import ( slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" "github.com/cosmos/cosmos-sdk/x/staking/teststaking" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - dexutils "github.com/sei-protocol/sei-chain/x/dex/utils" "github.com/stretchr/testify/suite" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto/ed25519" @@ -40,7 +39,6 @@ type KeeperTestHelper struct { func (s *KeeperTestHelper) Setup() { s.App = app.Setup(false, false) s.Ctx = s.App.BaseApp.NewContext(false, tmtypes.Header{Height: 1, ChainID: "sei-test", Time: time.Now().UTC()}) - s.Ctx = s.Ctx.WithContext(context.WithValue(s.Ctx.Context(), dexutils.DexMemStateContextKey, s.App.MemState)) s.QueryHelper = &baseapp.QueryServiceTestHelper{ GRPCQueryRouter: s.App.GRPCQueryRouter(), Ctx: s.Ctx, diff --git a/app/test_helpers.go b/app/test_helpers.go index e80e7f357..16c1c80c1 100644 --- a/app/test_helpers.go +++ b/app/test_helpers.go @@ -22,7 +22,6 @@ import ( tmproto "github.com/tendermint/tendermint/proto/tendermint/types" dbm "github.com/tendermint/tm-db" - dexutils "github.com/sei-protocol/sei-chain/x/dex/utils" minttypes "github.com/sei-protocol/sei-chain/x/mint/types" ) @@ -82,7 +81,6 @@ func newTestWrapper(t *testing.T, tm time.Time, valPub crptotypes.PubKey, enable appPtr = Setup(false, enableEVMCustomPrecompiles, baseAppOptions...) } ctx := appPtr.BaseApp.NewContext(false, tmproto.Header{Height: 1, ChainID: "sei-test", Time: tm}) - ctx = ctx.WithContext(context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, appPtr.MemState)) wrapper := &TestWrapper{ App: appPtr, Ctx: ctx, diff --git a/app/upgrades.go b/app/upgrades.go index 14233f12f..ffd33662a 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -109,6 +109,7 @@ var upgradesList = []string{ "v5.7.2", "v5.7.4", "v5.7.5", + "v5.8.0", } // if there is an override list, use that instead, for integration tests diff --git a/cmd/seid/cmd/debug.go b/cmd/seid/cmd/debug.go index d0a7e3240..ed95da572 100644 --- a/cmd/seid/cmd/debug.go +++ b/cmd/seid/cmd/debug.go @@ -26,7 +26,7 @@ const ( ) var modules = []string{ - "dex", "wasm", "aclaccesscontrol", "oracle", "epoch", "mint", "acc", "bank", "crisis", "feegrant", "staking", "distribution", "slashing", "gov", "params", "ibc", "upgrade", "evidence", "transfer", "tokenfactory", + "wasm", "aclaccesscontrol", "oracle", "epoch", "mint", "acc", "bank", "crisis", "feegrant", "staking", "distribution", "slashing", "gov", "params", "ibc", "upgrade", "evidence", "transfer", "tokenfactory", } func DumpIavlCmd() *cobra.Command { diff --git a/cmd/seid/cmd/iavl_parser.go b/cmd/seid/cmd/iavl_parser.go index fcb54a182..345332f53 100644 --- a/cmd/seid/cmd/iavl_parser.go +++ b/cmd/seid/cmd/iavl_parser.go @@ -9,8 +9,6 @@ import ( banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/sei-protocol/sei-chain/app/params" - dexkeeper "github.com/sei-protocol/sei-chain/x/dex/keeper" - dextypes "github.com/sei-protocol/sei-chain/x/dex/types" minttypes "github.com/sei-protocol/sei-chain/x/mint/types" ) @@ -21,7 +19,6 @@ const UNRECOGNIZED = "Unrecognized Prefix" var ModuleParserMap = map[string]ModuleParser{ "bank": BankParser, "mint": MintParser, - "dex": DexParser, "staking": StakingParser, "acc": AccountParser, } @@ -84,64 +81,6 @@ func BankParser(key []byte) ([]string, error) { return keyItems, nil } -func DexParser(key []byte) ([]string, error) { - keyItems := []string{} - if matched, items, _, err := MatchAndExtractDexAddressPrefixKeys(key); matched { - if err != nil { - return keyItems, err - } - keyItems = append(keyItems, items...) - return keyItems, nil - } - switch { - case bytes.HasPrefix(key, []byte(dexkeeper.EpochKey)): - // do nothing since the key is a string and no other data to be parsed - default: - keyItems = append(keyItems, UNRECOGNIZED) - } - return keyItems, nil -} - -func MatchAndExtractDexAddressPrefixKeys(key []byte) (bool, []string, []byte, error) { - keyItems := []string{} - keysToMatch := []string{ - // Source of truth: github.com/sei-protocol/sei-chain/x/dex/types/keys.go - contains key constants represented here - dextypes.LongBookKey, - dextypes.ShortBookKey, - dextypes.PriceKey, - dextypes.TwapKey, - dextypes.SettlementEntryKey, - dextypes.RegisteredPairKey, - dextypes.OrderKey, - dextypes.CancelKey, - dextypes.AccountActiveOrdersKey, - dextypes.NextOrderIDKey, - dextypes.NextSettlementIDKey, - dextypes.MatchResultKey, - dextypes.MemOrderKey, - dextypes.MemCancelKey, - dextypes.MemDepositKey, - dexkeeper.ContractPrefixKey, - } - - for _, prefix := range keysToMatch { - if bytes.HasPrefix(key, dextypes.KeyPrefix(prefix)) { - keyItems = append(keyItems, prefix) - remaining := bytes.TrimPrefix(key, dextypes.KeyPrefix(prefix)) - items, remaining, err := parseLengthPrefixedAddress(remaining) - if err != nil { - return true, keyItems, remaining, err - } - keyItems = append(keyItems, items...) - if len(remaining) > 0 { - keyItems = append(keyItems, fmt.Sprintf("RemainingString: %s", string(remaining))) - } - return true, keyItems, remaining, nil - } - } - return false, keyItems, key, nil -} - func parseLengthPrefixedAddress(remainingKey []byte) ([]string, []byte, error) { keyItems := []string{} lengthPrefix, remaining := int(remainingKey[0]), remainingKey[1:] diff --git a/go.mod b/go.mod index 4ced8fd34..2705d6310 100644 --- a/go.mod +++ b/go.mod @@ -42,7 +42,6 @@ require ( go.opentelemetry.io/otel/trace v1.9.0 golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa golang.org/x/sync v0.7.0 - golang.org/x/text v0.15.0 golang.org/x/time v0.3.0 google.golang.org/genproto/googleapis/api v0.0.0-20240513163218-0867130af1f8 google.golang.org/grpc v1.64.0 @@ -319,6 +318,7 @@ require ( golang.org/x/net v0.25.0 // indirect golang.org/x/sys v0.20.0 // indirect golang.org/x/term v0.20.0 // indirect + golang.org/x/text v0.15.0 // indirect golang.org/x/tools v0.21.0 // indirect google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240513163218-0867130af1f8 // indirect @@ -346,7 +346,7 @@ require ( replace ( github.com/CosmWasm/wasmd => github.com/sei-protocol/sei-wasmd v0.2.3 github.com/confio/ics23/go => github.com/cosmos/cosmos-sdk/ics23/go v0.8.0 - github.com/cosmos/cosmos-sdk => github.com/sei-protocol/sei-cosmos v0.3.31 + github.com/cosmos/cosmos-sdk => github.com/sei-protocol/sei-cosmos v0.3.33 github.com/cosmos/iavl => github.com/sei-protocol/sei-iavl v0.1.9 github.com/cosmos/ibc-go/v3 => github.com/sei-protocol/sei-ibc-go/v3 v3.3.2 github.com/ethereum/go-ethereum => github.com/sei-protocol/go-ethereum v1.13.5-sei-22 diff --git a/go.sum b/go.sum index dddd1476d..df2067481 100644 --- a/go.sum +++ b/go.sum @@ -1347,8 +1347,8 @@ github.com/sei-protocol/go-ethereum v1.13.5-sei-22 h1:t/m1qXER+DEMrcpqgoYmUxifkA github.com/sei-protocol/go-ethereum v1.13.5-sei-22/go.mod h1:kcRZmuzRn1lVejiFNTz4l4W7imnpq1bDAnuKS/RyhbQ= github.com/sei-protocol/goutils v0.0.2 h1:Bfa7Sv+4CVLNM20QcpvGb81B8C5HkQC/kW1CQpIbXDA= github.com/sei-protocol/goutils v0.0.2/go.mod h1:iYE2DuJfEnM+APPehr2gOUXfuLuPsVxorcDO+Tzq9q8= -github.com/sei-protocol/sei-cosmos v0.3.31 h1:8qnubgQd83F2/Pxx5DmNH2vnl1XtTOAFbW44cEHbeCo= -github.com/sei-protocol/sei-cosmos v0.3.31/go.mod h1:og/KbejR/zSQ8otapODEDU9zYNhFSUDbq9+tgeYePyU= +github.com/sei-protocol/sei-cosmos v0.3.33 h1:6BmEmNOqotT0OqwLFQiCyRcZTxJfG/x/CNQadljAKok= +github.com/sei-protocol/sei-cosmos v0.3.33/go.mod h1:og/KbejR/zSQ8otapODEDU9zYNhFSUDbq9+tgeYePyU= github.com/sei-protocol/sei-db v0.0.43 h1:m9kIWqSBCvKRLPGbAttlqCytIlPxVZbKchAEbVKSHHk= github.com/sei-protocol/sei-db v0.0.43/go.mod h1:F/ZKZA8HJPcUzSZPA8yt6pfwlGriJ4RDR4eHKSGLStI= github.com/sei-protocol/sei-iavl v0.1.9 h1:y4mVYftxLNRs6533zl7N0/Ch+CzRQc04JDfHolIxgBE= diff --git a/integration_test/dex_module/cancel_order_test.yaml b/integration_test/dex_module/cancel_order_test.yaml deleted file mode 100644 index 31496bd87..000000000 --- a/integration_test/dex_module/cancel_order_test.yaml +++ /dev/null @@ -1,25 +0,0 @@ -- name: Test cancel a placed order and query the cancelled order - inputs: - # Get contract address, this requires contract already deployed - - cmd: tail -1 integration_test/contracts/mars-addr.txt - env: CONTRACT_ADDR - # Prepare parameter to first place the order - - cmd: echo "LONG?1.01?5?SEI?ATOM?LIMIT?{\"leverage\":\"1\",\"position_effect\":\"Open\"}" - env: PARAMS - # Place an order and set ORDER_ID - - cmd: printf "12345678\n" | seid tx dex place-orders $CONTRACT_ADDR $PARAMS --amount=1000000000usei -y --from=admin --chain-id=sei --fees=1000000usei --gas=500000 --broadcast-mode=block --output json|jq -M -r ".logs[].events[].attributes[] | select(.key == \"order_id\").value" - env: ORDER_ID - # Prepare parameter to cancel the placed order - - cmd: echo $ORDER_ID"?LONG?1.01?SEI?ATOM" - env: PARAMS - # Cancel the order - - cmd: printf "12345678\n" | seid tx dex cancel-orders $CONTRACT_ADDR $PARAMS -y --from=admin --chain-id=sei --fees=1000000usei --gas=5000000 --broadcast-mode=block --output json - env: RES - - cmd: printf "12345678\n" | seid keys show admin --output json |jq -r .address - env: ADMIN_ADDR - # Query the order by id - - cmd: seid q dex get-orders $CONTRACT_ADDR $ADMIN_ADDR --output json |jq ".[] | length" - env: NUMORDER - verifiers: - - type: eval - expr: NUMORDER == 4 # placed from the place_order test diff --git a/integration_test/dex_module/place_order_test.yaml b/integration_test/dex_module/place_order_test.yaml deleted file mode 100644 index 168d4080c..000000000 --- a/integration_test/dex_module/place_order_test.yaml +++ /dev/null @@ -1,46 +0,0 @@ -- name: Test placing a new order and query the placed order - inputs: - # Get contract address, this requires contract already deployed - - cmd: tail -1 integration_test/contracts/mars-addr.txt - env: CONTRACT_ADDR - # Prepare parameter - - cmd: echo "LONG?1.01?5?SEI?ATOM?LIMIT?{\"leverage\":\"1\",\"position_effect\":\"Open\"}" - env: PARAMS - # Place an order and set ORDER_ID - - cmd: printf "12345678\n" | seid tx dex place-orders $CONTRACT_ADDR $PARAMS --amount=1000000000usei -y --from=admin --chain-id=sei --fees=1000000usei --gas=500000 --broadcast-mode=block --output json|jq -M -r ".logs[].events[].attributes[] | select(.key == \"order_id\").value" - env: ORDER_ID - # Query the order by id - - cmd: seid q dex get-orders-by-id $CONTRACT_ADDR SEI ATOM $ORDER_ID --output json |jq .order.status - env: RESULT - verifiers: - # Order ids should be greater or equal to 0 - - type: eval - expr: ORDER_ID >= 0 - # Order status should be something like PLACED - - type: regex - result: RESULT - expr: '^.*PLACED.*' - -- name: Test place multiple orders should give the correct asset denom - inputs: - # Get contract address, this requires contract already deployed - - cmd: tail -1 integration_test/contracts/mars-addr.txt - env: CONTRACT_ADDR - # Get admin account address - - cmd: printf "12345678\n" | seid keys show admin --output json |jq -r .address - env: ADMIN_ADDR - - cmd: seid q dex get-orders $CONTRACT_ADDR $ADMIN_ADDR --output json |jq ".[] | length" - env: ORDER_COUNT_BEFORE - # Prepare parameter - - cmd: echo "LONG?1.0?10?usei?uatom?LIMIT? LONG?3.0?3000?usei?uatomatomatom?LIMIT? LONG?3.0?1000?usei?uatomatom?LIMIT?" - env: PARAMS - # Place 3 orders - - cmd: printf "12345678\n" | seid tx dex place-orders $CONTRACT_ADDR $PARAMS --amount=1000000000usei -y --from=admin --chain-id=sei --fees=1000000usei --gas=500000 --broadcast-mode=block --output json| jq .code - - # Query all the orders - - cmd: seid q dex get-orders $CONTRACT_ADDR $ADMIN_ADDR --output json |jq ".[] | length" - env: ORDER_COUNT_AFTER - verifiers: - # Verify we should only see 3 orders - - type: eval - expr: ( ORDER_COUNT_AFTER - ORDER_COUNT_BEFORE ) == 3 diff --git a/integration_test/staking_module/staking_test.yaml b/integration_test/staking_module/staking_test.yaml index 8b07e1250..370e518d4 100644 --- a/integration_test/staking_module/staking_test.yaml +++ b/integration_test/staking_module/staking_test.yaml @@ -83,7 +83,7 @@ - cmd: seid q staking validator $SEI_NODE_1_VAL_ADDR --output json | jq -r ".tokens" env: BEFORE_STAKED_TOKENS - - cmd: printf "12345678\n" | seid tx staking unbond $SEI_NODE_1_VAL_ADDR 1sei --fees 4000usei --gas 400000 --from admin -b block -y --output json | jq -r ".code" + - cmd: printf "12345678\n" | seid tx staking unbond $SEI_NODE_1_VAL_ADDR 1sei --fees 2000usei --from admin -b block -y --output json | jq -r ".code" env: DELEGATE_RESPONSE_CODE # state after staking diff --git a/loadtest/main.go b/loadtest/main.go index 1b094892d..938b19061 100644 --- a/loadtest/main.go +++ b/loadtest/main.go @@ -39,7 +39,6 @@ import ( "github.com/sei-protocol/sei-chain/app" "github.com/sei-protocol/sei-chain/utils/metrics" - dextypes "github.com/sei-protocol/sei-chain/x/dex/types" tokenfactorytypes "github.com/sei-protocol/sei-chain/x/tokenfactory/types" ) @@ -330,10 +329,6 @@ func (c *LoadTestClient) generateMessage(key cryptotypes.PrivKey, msgType string } switch msgType { - case Vortex: - price := config.PriceDistr.Sample() - quantity := config.QuantityDistr.Sample() - msgs = c.generateVortexOrder(config, key, config.WasmMsgTypes.Vortex.NumOrdersPerTx, price, quantity) case WasmMintNft: contract := config.WasmMsgTypes.MintNftType.ContractAddr // TODO: Potentially just hard code the Funds amount here @@ -403,21 +398,6 @@ func (c *LoadTestClient) generateMessage(key cryptotypes.PrivKey, msgType string signer = adminKey gas = 10000000 fee = 1000000 - case Dex: - price := config.PriceDistr.Sample() - quantity := config.QuantityDistr.Sample() - contract := config.ContractDistr.Sample() - orderPlacements := generateDexOrderPlacements(config, key, msgPerTx, price, quantity) - amount, err := sdk.ParseCoinsNormalized(fmt.Sprintf("%d%s", price.Mul(quantity).Ceil().RoundInt64(), "usei")) - if err != nil { - panic(err) - } - msgs = []sdk.Msg{&dextypes.MsgPlaceOrders{ - Creator: sdk.AccAddress(key.PubKey().Address()).String(), - Orders: orderPlacements, - ContractAddr: contract, - Funds: amount, - }} case Staking: delegatorAddr := sdk.AccAddress(key.PubKey().Address()).String() chosenValidator := c.Validators[r.Intn(len(c.Validators))].OperatorAddress @@ -484,42 +464,6 @@ func (c *LoadTestClient) generateMessage(key cryptotypes.PrivKey, msgType string Amount: sdk.NewInt(amountUsei), }), }} - case FailureDexMalformed: - price := config.PriceDistr.InvalidSample() - quantity := config.QuantityDistr.InvalidSample() - contract := config.ContractDistr.Sample() - orderPlacements := generateDexOrderPlacements(config, key, msgPerTx, price, quantity) - amount, err := sdk.ParseCoinsNormalized(fmt.Sprintf("%d%s", price.Mul(quantity).Ceil().RoundInt64(), "usei")) - if err != nil { - panic(err) - } - msgs = []sdk.Msg{&dextypes.MsgPlaceOrders{ - Creator: sdk.AccAddress(key.PubKey().Address()).String(), - Orders: orderPlacements, - ContractAddr: contract, - Funds: amount, - }} - case FailureDexInvalid: - price := config.PriceDistr.Sample() - quantity := config.QuantityDistr.Sample() - contract := config.ContractDistr.Sample() - orderPlacements := generateDexOrderPlacements(config, key, msgPerTx, price, quantity) - var amountUsei int64 - if r.Float64() < 0.5 { - amountUsei = 10000 * price.Mul(quantity).Ceil().RoundInt64() - } else { - amountUsei = 0 - } - amount, err := sdk.ParseCoinsNormalized(fmt.Sprintf("%d%s", amountUsei, "usei")) - if err != nil { - panic(err) - } - msgs = []sdk.Msg{&dextypes.MsgPlaceOrders{ - Creator: sdk.AccAddress(key.PubKey().Address()).String(), - Orders: orderPlacements, - ContractAddr: contract, - Funds: amount, - }} case WasmOccIteratorWrite: // generate some values for indices 1-100 indices := []int{} @@ -578,51 +522,6 @@ func (c *LoadTestClient) generateMessage(key cryptotypes.PrivKey, msgType string return msgs, false, signer, gas, int64(fee) } -func sampleDexOrderType(config Config) (orderType dextypes.OrderType) { - if len(config.MessageTypes) == 1 && config.MessageTypes[0] == "failure_bank_malformed" { - orderType = -1 - } else { - msgType := config.MsgTypeDistr.SampleDexMsgs() - switch msgType { - case Limit: - orderType = dextypes.OrderType_LIMIT - case Market: - orderType = dextypes.OrderType_MARKET - default: - panic(fmt.Sprintf("Unknown message type %s\n", msgType)) - } - } - return orderType -} - -func generateDexOrderPlacements(config Config, key cryptotypes.PrivKey, msgPerTx uint64, price sdk.Dec, quantity sdk.Dec) (orderPlacements []*dextypes.Order) { - orderType := sampleDexOrderType(config) - - r := rand.New(rand.NewSource(time.Now().UnixNano())) - var direction dextypes.PositionDirection - if r.Float64() < 0.5 { - direction = dextypes.PositionDirection_LONG - } else { - direction = dextypes.PositionDirection_SHORT - } - - contract := config.ContractDistr.Sample() - for j := 0; j < int(msgPerTx); j++ { - orderPlacements = append(orderPlacements, &dextypes.Order{ - Account: sdk.AccAddress(key.PubKey().Address()).String(), - ContractAddr: contract, - PositionDirection: direction, - Price: price.Quo(FromMili), - Quantity: quantity.Quo(FromMili), - PriceDenom: "SEI", - AssetDenom: "ATOM", - OrderType: orderType, - Data: VortexData, - }) - } - return orderPlacements -} - func (c *LoadTestClient) generateStakingMsg(delegatorAddr string, chosenValidator string, srcAddr string) sdk.Msg { c.mtx.Lock() defer c.mtx.Unlock() @@ -663,71 +562,6 @@ func (c *LoadTestClient) generateStakingMsg(delegatorAddr string, chosenValidato return msg } -// generateVortexOrder generates Vortex order messages. If short order, creates a deposit message first -func (c *LoadTestClient) generateVortexOrder(config Config, key cryptotypes.PrivKey, numOrders int64, price sdk.Dec, quantity sdk.Dec) []sdk.Msg { - var msgs []sdk.Msg - contract := config.WasmMsgTypes.Vortex.ContractAddr - - r := rand.New(rand.NewSource(time.Now().UnixNano())) - // Randomly select Position Direction - var direction dextypes.PositionDirection - if r.Float64() < 0.5 { - direction = dextypes.PositionDirection_LONG - } else { - direction = dextypes.PositionDirection_SHORT - } - - orderType := sampleDexOrderType(config) - - // If placing short order on vortex, first deposit for buying power - if direction == dextypes.PositionDirection_SHORT { - // TODO: Considering depositing more up front when numOrders > 1 - amountDeposit, err := sdk.ParseCoinsNormalized(fmt.Sprintf("%d%s", price.Mul(quantity).Ceil().RoundInt64(), "usei")) - if err != nil { - panic(err) - } - vortexDeposit := &wasmtypes.MsgExecuteContract{ - Sender: sdk.AccAddress(key.PubKey().Address()).String(), - Contract: contract, - Msg: wasmtypes.RawContractMessage([]byte("{\"deposit\":{}}")), - Funds: amountDeposit, - } - msgs = append(msgs, vortexDeposit) - } - - // Create a MsgPlaceOrders with numOrders Orders - var orderPlacements []*dextypes.Order - for j := 0; j < int(numOrders); j++ { - vortexOrder := &dextypes.Order{ - Account: sdk.AccAddress(key.PubKey().Address()).String(), - ContractAddr: contract, - PositionDirection: direction, - Price: price.Quo(FromMili), - Quantity: quantity.Quo(FromMili), - PriceDenom: "SEI", - AssetDenom: "ATOM", - OrderType: orderType, - Data: VortexData, - } - orderPlacements = append(orderPlacements, vortexOrder) - } - - amount, err := sdk.ParseCoinsNormalized(fmt.Sprintf("%d%s", price.Mul(quantity).Ceil().RoundInt64(), "usei")) - if err != nil { - panic(err) - } - vortexOrderMsg := &dextypes.MsgPlaceOrders{ - Creator: sdk.AccAddress(key.PubKey().Address()).String(), - Orders: orderPlacements, - ContractAddr: contract, - Funds: amount, - } - - msgs = append(msgs, vortexOrderMsg) - - return msgs -} - // nolint func getLastHeight(blockchainEndpoint string) int { out, err := exec.Command("curl", blockchainEndpoint+"/blockchain").Output() diff --git a/occ_tests/utils/utils.go b/occ_tests/utils/utils.go index e64772664..877f92db1 100644 --- a/occ_tests/utils/utils.go +++ b/occ_tests/utils/utils.go @@ -1,7 +1,6 @@ package utils import ( - "context" "crypto/ecdsa" "encoding/hex" "math/big" @@ -32,9 +31,6 @@ import ( "github.com/sei-protocol/sei-chain/app" utils2 "github.com/sei-protocol/sei-chain/utils" - dexcache "github.com/sei-protocol/sei-chain/x/dex/cache" - dextypes "github.com/sei-protocol/sei-chain/x/dex/types" - dexutils "github.com/sei-protocol/sei-chain/x/dex/utils" "github.com/sei-protocol/sei-chain/x/evm/config" types2 "github.com/sei-protocol/sei-chain/x/evm/types" minttypes "github.com/sei-protocol/sei-chain/x/mint/types" @@ -129,7 +125,6 @@ func NewTestContext(t *testing.T, testAccts []TestAcct, blockTime time.Time, wor }) testApp := wrapper.App ctx := wrapper.Ctx - ctx = ctx.WithContext(context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(testApp.GetMemKey(dextypes.MemStoreKey)))) ctx = ctx.WithBlockHeader(tmproto.Header{Height: ctx.BlockHeader().Height, ChainID: ctx.BlockHeader().ChainID, Time: blockTime}) amounts := sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(1000000000000000)), sdk.NewCoin("uusdc", sdk.NewInt(1000000000000000))) bankkeeper := testApp.BankKeeper diff --git a/proto/dex/asset_list.proto b/proto/dex/asset_list.proto deleted file mode 100644 index b80d54f71..000000000 --- a/proto/dex/asset_list.proto +++ /dev/null @@ -1,23 +0,0 @@ -syntax = "proto3"; -package seiprotocol.seichain.dex; - -import "cosmos/bank/v1beta1/bank.proto"; -import "gogoproto/gogo.proto"; - -option go_package = "github.com/sei-protocol/sei-chain/x/dex/types"; - -message AssetIBCInfo { - string sourceChannel = 1 [(gogoproto.jsontag) = "source_channel"]; - string dstChannel = 2 [(gogoproto.jsontag) = "dst_channel"]; - string sourceDenom = 3 [(gogoproto.jsontag) = "source_denom"]; - string sourceChainID = 4 [(gogoproto.jsontag) = "source_chain_id"]; -} - -message AssetMetadata { - AssetIBCInfo ibcInfo = 1 [(gogoproto.jsontag) = "ibc_info"]; - string type_asset = 2 [(gogoproto.jsontag) = "type_asset"]; // Ex: cw20, ics20, erc20 - cosmos.bank.v1beta1.Metadata metadata = 3 [ - (gogoproto.nullable) = false, - (gogoproto.jsontag) = "metadata" - ]; -} diff --git a/proto/dex/contract.proto b/proto/dex/contract.proto deleted file mode 100644 index 11d87ceb6..000000000 --- a/proto/dex/contract.proto +++ /dev/null @@ -1,47 +0,0 @@ -syntax = "proto3"; -package seiprotocol.seichain.dex; - -option go_package = "github.com/sei-protocol/sei-chain/x/dex/types"; - -message ContractInfo { - uint64 codeId = 1; - string contractAddr = 2; - bool needHook = 3; - bool needOrderMatching = 4; - repeated ContractDependencyInfo dependencies = 5; - int64 numIncomingDependencies = 6; -} - -message ContractInfoV2 { - uint64 codeId = 1; - string contractAddr = 2; - bool needHook = 3; - bool needOrderMatching = 4; - repeated ContractDependencyInfo dependencies = 5; - int64 numIncomingDependencies = 6; - string creator = 7; - uint64 rentBalance = 8; - bool suspended = 9; - string suspensionReason = 10; -} - -// suppose A is first registered and depends on X, then B is added and depends on X, -// and then C is added and depends on X, then A is the elder sibling to B and B is -// the younger sibling to A, and B is the elder sibling to C and C is the younger to B -message ContractDependencyInfo { - string dependency = 1; - string immediateElderSibling = 2; - string immediateYoungerSibling = 3; -} - -message LegacyContractInfo { - uint64 codeId = 1; - string contractAddr = 2; - bool needHook = 3; - bool needOrderMatching = 4; - repeated string dependentContractAddrs = 5; -} - -message DownsteamContracts { - repeated string contractAddrs = 1; -} \ No newline at end of file diff --git a/proto/dex/deposit.proto b/proto/dex/deposit.proto deleted file mode 100644 index 5f09e2ffa..000000000 --- a/proto/dex/deposit.proto +++ /dev/null @@ -1,21 +0,0 @@ -syntax = "proto3"; -package seiprotocol.seichain.dex; - -import "gogoproto/gogo.proto"; - -option go_package = "github.com/sei-protocol/sei-chain/x/dex/types"; - -message DepositInfoEntry { - string creator = 1 [ - (gogoproto.jsontag) = "creator" - ]; - string denom = 2 [ - (gogoproto.jsontag) = "denom" - ]; - string amount = 3 [ - (gogoproto.moretags) = "yaml:\"amount\"", - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.nullable) = false, - (gogoproto.jsontag) = "amount" - ]; -} diff --git a/proto/dex/enums.proto b/proto/dex/enums.proto deleted file mode 100644 index 0eb89c5c0..000000000 --- a/proto/dex/enums.proto +++ /dev/null @@ -1,42 +0,0 @@ -syntax = "proto3"; -package seiprotocol.seichain.dex; - -option go_package = "github.com/sei-protocol/sei-chain/x/dex/types"; - -enum PositionDirection { - LONG = 0; - SHORT = 1; -} - -enum PositionEffect { - OPEN = 0; - CLOSE = 1; -} - -enum OrderType { - LIMIT = 0; - MARKET = 1; - FOKMARKET = 3; // fill-or-kill market order - FOKMARKETBYVALUE = 4; // fill-or-kill market by value order - STOPLOSS = 5; - STOPLIMIT = 6; -} - -enum Unit { - STANDARD = 0; - MILLI = 1; - MICRO = 2; - NANO = 3; -} - -enum OrderStatus { - PLACED = 0; - FAILED_TO_PLACE = 1; - CANCELLED = 2; - FULFILLED = 3; -} - -enum CancellationInitiator { - USER = 0; - LIQUIDATED = 1; -} diff --git a/proto/dex/genesis.proto b/proto/dex/genesis.proto deleted file mode 100644 index 5e46bc73a..000000000 --- a/proto/dex/genesis.proto +++ /dev/null @@ -1,37 +0,0 @@ -syntax = "proto3"; -package seiprotocol.seichain.dex; - -import "gogoproto/gogo.proto"; -import "dex/params.proto"; -import "dex/long_book.proto"; -import "dex/short_book.proto"; -import "dex/order.proto"; -import "dex/contract.proto"; -import "dex/pair.proto"; -import "dex/price.proto"; -// this line is used by starport scaffolding # genesis/proto/import - -option go_package = "github.com/sei-protocol/sei-chain/x/dex/types"; - -// GenesisState defines the dex module's genesis state. -message GenesisState { - Params params = 1 [(gogoproto.nullable) = false]; - repeated ContractState contractState = 2 [(gogoproto.nullable) = false]; - uint64 lastEpoch = 3; - // this line is used by starport scaffolding # genesis/proto/state -} - -message ContractState { - ContractInfoV2 contractInfo = 1 [(gogoproto.nullable) = false]; - repeated LongBook longBookList = 2 [(gogoproto.nullable) = false]; - repeated ShortBook shortBookList = 3 [(gogoproto.nullable) = false]; - repeated Order triggeredOrdersList = 4 [(gogoproto.nullable) = false]; - repeated Pair pairList = 5 [(gogoproto.nullable) = false]; - repeated ContractPairPrices priceList = 6 [(gogoproto.nullable) = false]; - uint64 nextOrderId = 7; -} - -message ContractPairPrices { - Pair pricePair = 1 [(gogoproto.nullable) = false]; - repeated Price prices = 2; -} diff --git a/proto/dex/gov.proto b/proto/dex/gov.proto deleted file mode 100644 index 4fa4d04e7..000000000 --- a/proto/dex/gov.proto +++ /dev/null @@ -1,22 +0,0 @@ -syntax = "proto3"; -package seiprotocol.seichain.dex; - -import "gogoproto/gogo.proto"; -import "dex/asset_list.proto"; - -option go_package = "github.com/sei-protocol/sei-chain/x/dex/types"; - -// AddAssetMetadataProposal is a gov Content type for adding a new asset -// to the dex module's asset list. -message AddAssetMetadataProposal { - option (gogoproto.equal) = false; - option (gogoproto.goproto_getters) = false; - option (gogoproto.goproto_stringer) = false; - - string title = 1 [ (gogoproto.moretags) = "yaml:\"title\"" ]; - string description = 2 [ (gogoproto.moretags) = "yaml:\"description\"" ]; - repeated AssetMetadata assetList = 3 [ - (gogoproto.moretags) = "yaml:\"asset_list\"", - (gogoproto.nullable) = false - ]; -} diff --git a/proto/dex/long_book.proto b/proto/dex/long_book.proto deleted file mode 100644 index c9b810f23..000000000 --- a/proto/dex/long_book.proto +++ /dev/null @@ -1,19 +0,0 @@ -syntax = "proto3"; -package seiprotocol.seichain.dex; - -option go_package = "github.com/sei-protocol/sei-chain/x/dex/types"; -import "dex/order_entry.proto"; -import "gogoproto/gogo.proto"; - -message LongBook { - string price = 1 [ - (gogoproto.moretags) = "yaml:\"price\"", - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.nullable) = false, - (gogoproto.jsontag) = "price" - ]; - OrderEntry entry = 2 [ - (gogoproto.jsontag) = "entry" - ]; - -} \ No newline at end of file diff --git a/proto/dex/match_result.proto b/proto/dex/match_result.proto deleted file mode 100644 index c6d76c807..000000000 --- a/proto/dex/match_result.proto +++ /dev/null @@ -1,15 +0,0 @@ -syntax = "proto3"; -package seiprotocol.seichain.dex; - -option go_package = "github.com/sei-protocol/sei-chain/x/dex/types"; -import "dex/order.proto"; -import "dex/settlement.proto"; -import "gogoproto/gogo.proto"; - -message MatchResult { - int64 height = 1 [(gogoproto.jsontag) = "height"]; - string contractAddr = 2 [(gogoproto.jsontag) = "contract_address"]; - repeated Order orders = 3 [(gogoproto.jsontag) = "orders"]; - repeated SettlementEntry settlements = 4 [(gogoproto.jsontag) = "settlements"]; - repeated Cancellation cancellations = 5 [(gogoproto.jsontag) = "cancellations"]; -} \ No newline at end of file diff --git a/proto/dex/order.proto b/proto/dex/order.proto deleted file mode 100644 index 8b366eb6e..000000000 --- a/proto/dex/order.proto +++ /dev/null @@ -1,108 +0,0 @@ -syntax = "proto3"; -package seiprotocol.seichain.dex; - -import "gogoproto/gogo.proto"; -import "dex/enums.proto"; - -option go_package = "github.com/sei-protocol/sei-chain/x/dex/types"; - -message Order { - uint64 id = 1 [ - (gogoproto.jsontag) = "id", - (gogoproto.nullable) = true - ]; - OrderStatus status = 2 [ - (gogoproto.jsontag) = "status", - (gogoproto.nullable) = true - ]; - string account = 3 [ - (gogoproto.jsontag) = "account", - (gogoproto.nullable) = true - ]; - string contractAddr = 4 [ - (gogoproto.jsontag) = "contract_address", - (gogoproto.nullable) = true - ]; - string price = 5 [ - (gogoproto.moretags) = "yaml:\"price\"", - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.nullable) = false, - (gogoproto.jsontag) = "price" - ]; - string quantity = 6 [ - (gogoproto.moretags) = "yaml:\"quantity\"", - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.nullable) = false, - (gogoproto.jsontag) = "quantity" - ]; - string priceDenom = 7 [ - (gogoproto.jsontag) = "price_denom" - ]; - string assetDenom = 8 [ - (gogoproto.jsontag) = "asset_denom" - ]; - OrderType orderType = 9 [ - (gogoproto.jsontag) = "order_type" - ]; - PositionDirection positionDirection = 10 [ - (gogoproto.jsontag) = "position_direction" - ]; - string data = 11 [ - (gogoproto.jsontag) = "data" - ]; - string statusDescription = 12 [ - (gogoproto.jsontag) = "status_description" - ]; - string nominal = 13 [ - (gogoproto.moretags) = "yaml:\"nominal\"", - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.nullable) = false, - (gogoproto.jsontag) = "nominal" - ]; - string triggerPrice = 14 [ - (gogoproto.moretags) = "yaml:\"trigger_price\"", - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.nullable) = false, - (gogoproto.jsontag) = "trigger_price" - ]; - bool triggerStatus = 15 [ - (gogoproto.jsontag) = "trigger_status" - ]; -} - -message Cancellation { - uint64 id = 1 [ - (gogoproto.jsontag) = "id" - ]; - CancellationInitiator initiator = 2 [ - (gogoproto.jsontag) = "initiator" - ]; - string creator = 3 [ - (gogoproto.jsontag) = "creator", - (gogoproto.nullable) = true - ]; - string contractAddr = 4 [ - (gogoproto.jsontag) = "contract_address" - ]; - string priceDenom = 5 [ - (gogoproto.jsontag) = "price_denom" - ]; - string assetDenom = 6 [ - (gogoproto.jsontag) = "asset_denom" - ]; - PositionDirection positionDirection = 7 [ - (gogoproto.jsontag) = "position_direction" - ]; - string price = 8 [ - (gogoproto.moretags) = "yaml:\"price\"", - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.nullable) = false, - (gogoproto.jsontag) = "price" - ]; -} - -message ActiveOrders { - repeated uint64 ids = 1 [ - (gogoproto.jsontag) = "ids" - ]; -} diff --git a/proto/dex/order_entry.proto b/proto/dex/order_entry.proto deleted file mode 100644 index a35d8075f..000000000 --- a/proto/dex/order_entry.proto +++ /dev/null @@ -1,46 +0,0 @@ -syntax = "proto3"; -package seiprotocol.seichain.dex; - -import "gogoproto/gogo.proto"; - -option go_package = "github.com/sei-protocol/sei-chain/x/dex/types"; - -message OrderEntry { - - string price = 1 [ - (gogoproto.moretags) = "yaml:\"price\"", - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.nullable) = false, - (gogoproto.jsontag) = "price" - ]; - string quantity = 2 [ - (gogoproto.moretags) = "yaml:\"quantity\"", - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.nullable) = false, - (gogoproto.jsontag) = "quantity" - ]; - repeated Allocation allocations = 3 [ - (gogoproto.jsontag) = "allocations" - ]; - string priceDenom = 4 [ - (gogoproto.jsontag) = "price_denom" - ]; - string assetDenom = 5 [ - (gogoproto.jsontag) = "asset_denom" - ]; -} - -message Allocation { - uint64 orderId = 1 [ - (gogoproto.jsontag) = "order_id" - ]; - string quantity = 2 [ - (gogoproto.moretags) = "yaml:\"quantity\"", - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.nullable) = false, - (gogoproto.jsontag) = "quantity" - ]; - string account = 3 [ - (gogoproto.jsontag) = "account" - ]; -} diff --git a/proto/dex/pair.proto b/proto/dex/pair.proto deleted file mode 100644 index 721e459ea..000000000 --- a/proto/dex/pair.proto +++ /dev/null @@ -1,30 +0,0 @@ -syntax = "proto3"; -package seiprotocol.seichain.dex; - -import "gogoproto/gogo.proto"; - -option go_package = "github.com/sei-protocol/sei-chain/x/dex/types"; - -message Pair { - string priceDenom = 1 [ - (gogoproto.jsontag) = "price_denom" - ]; - string assetDenom = 2 [ - (gogoproto.jsontag) = "asset_denom" - ]; - string priceTicksize = 3 [ - (gogoproto.jsontag) = "price_tick_size", - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.nullable) = true - ]; - string quantityTicksize = 4 [ - (gogoproto.jsontag) = "quantity_tick_size", - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.nullable) = true - ]; -} - -message BatchContractPair { - string contractAddr = 1 [(gogoproto.jsontag) = "contract_addr"]; - repeated Pair pairs = 2 [(gogoproto.jsontag) = "pairs"]; -} diff --git a/proto/dex/params.proto b/proto/dex/params.proto deleted file mode 100644 index de96e4790..000000000 --- a/proto/dex/params.proto +++ /dev/null @@ -1,70 +0,0 @@ -syntax = "proto3"; -package seiprotocol.seichain.dex; - -import "gogoproto/gogo.proto"; - -option go_package = "github.com/sei-protocol/sei-chain/x/dex/types"; - -// Params defines the parameters for the module. -message Params { - option (gogoproto.equal) = true; - option (gogoproto.goproto_stringer) = false; - - uint64 price_snapshot_retention = 1 [ - (gogoproto.moretags) = "yaml:\"price_snapshot_retention\"", - (gogoproto.jsontag) = "price_snapshot_retention" - ]; - string sudo_call_gas_price = 2 [ - (gogoproto.jsontag) = "sudo_call_gas_price", - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.nullable) = false - ]; - uint64 begin_block_gas_limit = 3 [ - (gogoproto.jsontag) = "begin_block_gas_limit", - (gogoproto.moretags) = "yaml:\"begin_block_gas_limit\"" - ]; - uint64 end_block_gas_limit = 4 [ - (gogoproto.jsontag) = "end_block_gas_limit", - (gogoproto.moretags) = "yaml:\"end_block_gas_limit\"" - ]; - uint64 default_gas_per_order = 5 [ - (gogoproto.jsontag) = "default_gas_per_order", - (gogoproto.moretags) = "yaml:\"default_gas_per_order\"" - ]; - uint64 default_gas_per_cancel = 6 [ - (gogoproto.jsontag) = "default_gas_per_cancel", - (gogoproto.moretags) = "yaml:\"default_gas_per_cancel\"" - ]; - uint64 min_rent_deposit = 7 [ - (gogoproto.jsontag) = "min_rent_deposit", - (gogoproto.moretags) = "yaml:\"min_rent_deposit\"" - ]; - uint64 gas_allowance_per_settlement = 8 [ - (gogoproto.jsontag) = "gas_allowance_per_settlement", - (gogoproto.moretags) = "yaml:\"gas_allowance_per_settlement\"" - ]; - uint64 min_processable_rent = 9 [ - (gogoproto.jsontag) = "min_processable_rent", - (gogoproto.moretags) = "yaml:\"min_processable_rent\"" - ]; - uint64 order_book_entries_per_load = 10 [ - (gogoproto.jsontag) = "order_book_entries_per_load", - (gogoproto.moretags) = "yaml:\"order_book_entries_per_load\"" - ]; - uint64 contract_unsuspend_cost = 11 [ - (gogoproto.jsontag) = "contract_unsuspend_cost", - (gogoproto.moretags) = "yaml:\"contract_unsuspend_cost\"" - ]; - uint64 max_order_per_price = 12 [ - (gogoproto.jsontag) = "max_order_per_price", - (gogoproto.moretags) = "yaml:\"max_order_per_price\"" - ]; - uint64 max_pairs_per_contract = 13 [ - (gogoproto.jsontag) = "max_pairs_per_contract", - (gogoproto.moretags) = "yaml:\"max_pairs_per_contract\"" - ]; - uint64 default_gas_per_order_data_byte = 14 [ - (gogoproto.jsontag) = "default_gas_per_order_data_byte", - (gogoproto.moretags) = "yaml:\"default_gas_per_order_data_byte\"" - ]; -} diff --git a/proto/dex/price.proto b/proto/dex/price.proto deleted file mode 100644 index 65b544717..000000000 --- a/proto/dex/price.proto +++ /dev/null @@ -1,52 +0,0 @@ -syntax = "proto3"; -package seiprotocol.seichain.dex; - -import "gogoproto/gogo.proto"; -import "dex/pair.proto"; - -option go_package = "github.com/sei-protocol/sei-chain/x/dex/types"; - -message Price { - - uint64 snapshotTimestampInSeconds = 1 [ - (gogoproto.jsontag) = "snapshot_timestamp_in_seconds" - ]; - string price = 2 [ - (gogoproto.moretags) = "yaml:\"price\"", - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.nullable) = false, - (gogoproto.jsontag) = "price" - ]; - Pair pair = 3 [ - (gogoproto.jsontag) = "pair" - ]; -} - -message PriceCandlestick { - uint64 beginTimestamp = 1 [ - (gogoproto.jsontag) = "begin_timestamp" - ]; - uint64 endTimestamp = 2 [ - (gogoproto.jsontag) = "end_timestamp" - ]; - string open = 3 [ - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.jsontag) = "open" - ]; - string high = 4 [ - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.jsontag) = "high" - ]; - string low = 5 [ - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.jsontag) = "low" - ]; - string close = 6 [ - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.jsontag) = "close" - ]; - string volume = 7 [ - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.jsontag) = "volume" - ]; -} diff --git a/proto/dex/query.proto b/proto/dex/query.proto deleted file mode 100644 index 4aeccce56..000000000 --- a/proto/dex/query.proto +++ /dev/null @@ -1,401 +0,0 @@ -syntax = "proto3"; -package seiprotocol.seichain.dex; - -import "gogoproto/gogo.proto"; -import "google/api/annotations.proto"; -import "cosmos/base/query/v1beta1/pagination.proto"; -import "dex/params.proto"; -import "dex/long_book.proto"; -import "dex/short_book.proto"; -import "dex/price.proto"; -import "dex/contract.proto"; -import "dex/twap.proto"; -import "dex/asset_list.proto"; -import "dex/pair.proto"; -import "dex/order.proto"; -import "dex/match_result.proto"; -import "dex/enums.proto"; -// this line is used by starport scaffolding # 1 - -option go_package = "github.com/sei-protocol/sei-chain/x/dex/types"; - -// Query defines the gRPC querier service. -service Query { - // Parameters queries the parameters of the module. - rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { - option (google.api.http).get = "/sei-protocol/seichain/dex/params"; - } - // Queries a LongBook by id. - rpc LongBook(QueryGetLongBookRequest) returns (QueryGetLongBookResponse) { - option (google.api.http).get = "/sei-protocol/seichain/dex/long_book/{contractAddr}/{priceDenom}/{assetDenom}/{price}"; - } - - // Queries a list of LongBook items. - rpc LongBookAll(QueryAllLongBookRequest) returns (QueryAllLongBookResponse) { - option (google.api.http).get = "/sei-protocol/seichain/dex/long_book/{contractAddr}/{priceDenom}/{assetDenom}"; - } - -// Queries a ShortBook by id. - rpc ShortBook(QueryGetShortBookRequest) returns (QueryGetShortBookResponse) { - option (google.api.http).get = "/sei-protocol/seichain/dex/short_book/{contractAddr}/{priceDenom}/{assetDenom}/{price}"; - } - - // Queries a list of ShortBook items. - rpc ShortBookAll(QueryAllShortBookRequest) returns (QueryAllShortBookResponse) { - option (google.api.http).get = "/sei-protocol/seichain/dex/short_book/{contractAddr}/{priceDenom}/{assetDenom}"; - } - - rpc GetPrice(QueryGetPriceRequest) returns (QueryGetPriceResponse) { - option (google.api.http).get = "/sei-protocol/seichain/dex/get_price/{contractAddr}/{priceDenom}/{assetDenom}/{timestamp}"; - } - - rpc GetLatestPrice(QueryGetLatestPriceRequest) returns (QueryGetLatestPriceResponse) { - option (google.api.http).get = "/sei-protocol/seichain/dex/get_latest_price/{contractAddr}/{priceDenom}/{assetDenom}"; - } - - rpc GetPrices(QueryGetPricesRequest) returns (QueryGetPricesResponse) { - option (google.api.http).get = "/sei-protocol/seichain/dex/get_prices/{contractAddr}/{priceDenom}/{assetDenom}"; - } - - rpc GetTwaps(QueryGetTwapsRequest) returns (QueryGetTwapsResponse) { - option (google.api.http).get = "/sei-protocol/seichain/dex/get_twaps/{contractAddr}/{lookbackSeconds}"; - } - - // Returns the metadata for a specified denom / display type - rpc AssetMetadata(QueryAssetMetadataRequest) returns (QueryAssetMetadataResponse) { - option (google.api.http).get = "/sei-protocol/seichain/dex/asset_list/{denom}"; - } - - // Returns metadata for all the assets - rpc AssetList(QueryAssetListRequest) returns (QueryAssetListResponse) { - option (google.api.http).get = "/sei-protocol/seichain/dex/asset_list"; - } - - // Returns all registered pairs for specified contract address - rpc GetRegisteredPairs(QueryRegisteredPairsRequest) returns (QueryRegisteredPairsResponse) { - option (google.api.http).get = "/sei-protocol/seichain/dex/registered_pairs"; - } - - // Returns registered contract information - rpc GetRegisteredContract(QueryRegisteredContractRequest) returns (QueryRegisteredContractResponse) { - option (google.api.http).get = "/sei-protocol/seichain/dex/registered_contract/{contractAddr}"; - } - - rpc GetOrders(QueryGetOrdersRequest) returns (QueryGetOrdersResponse) { - option (google.api.http).get = "/sei-protocol/seichain/dex/get_orders/{contractAddr}/{account}"; - } - - rpc GetOrder(QueryGetOrderByIDRequest) returns (QueryGetOrderByIDResponse) { - option (google.api.http).get = "/sei-protocol/seichain/dex/get_order_by_id/{contractAddr}/{priceDenom}/{assetDenom}/{id}"; - } - - rpc GetHistoricalPrices(QueryGetHistoricalPricesRequest) returns (QueryGetHistoricalPricesResponse) { - option (google.api.http).get = "/sei-protocol/seichain/dex/get_historical_prices/{contractAddr}/{priceDenom}/{assetDenom}/{periodLengthInSeconds}/{numOfPeriods}"; - } - - rpc GetMarketSummary(QueryGetMarketSummaryRequest) returns (QueryGetMarketSummaryResponse) { - option (google.api.http).get = "/sei-protocol/seichain/dex/get_market_summary/{contractAddr}/{priceDenom}/{assetDenom}/{lookbackInSeconds}"; - } - - rpc GetOrderSimulation(QueryOrderSimulationRequest) returns (QueryOrderSimulationResponse) {} - - rpc GetMatchResult(QueryGetMatchResultRequest) returns (QueryGetMatchResultResponse) {} - - rpc GetOrderCount(QueryGetOrderCountRequest) returns (QueryGetOrderCountResponse) {} - -// this line is used by starport scaffolding # 2 -} - -// QueryParamsRequest is request type for the Query/Params RPC method. -message QueryParamsRequest {} - -// QueryParamsResponse is response type for the Query/Params RPC method. -message QueryParamsResponse { - // params holds all the parameters of this module. - Params params = 1 [(gogoproto.nullable) = false]; -} - -message QueryGetLongBookRequest { - string price = 1; - string contractAddr = 2; - string priceDenom = 3; - string assetDenom = 4; -} - -message QueryGetLongBookResponse { - LongBook LongBook = 1 [(gogoproto.nullable) = false]; -} - -message QueryAllLongBookRequest { - cosmos.base.query.v1beta1.PageRequest pagination = 1; - string contractAddr = 2; - string priceDenom = 3; - string assetDenom = 4; -} - -message QueryAllLongBookResponse { - repeated LongBook LongBook = 1 [(gogoproto.nullable) = false]; - cosmos.base.query.v1beta1.PageResponse pagination = 2; -} - -message QueryGetShortBookRequest { - string price = 1; - string contractAddr = 2; - string priceDenom = 3; - string assetDenom = 4; -} - -message QueryGetShortBookResponse { - ShortBook ShortBook = 1 [(gogoproto.nullable) = false]; -} - -message QueryAllShortBookRequest { - cosmos.base.query.v1beta1.PageRequest pagination = 1; - string contractAddr = 2; - string priceDenom = 3; - string assetDenom = 4; -} - -message QueryAllShortBookResponse { - repeated ShortBook ShortBook = 1 [(gogoproto.nullable) = false]; - cosmos.base.query.v1beta1.PageResponse pagination = 2; -} - -message QueryGetPricesRequest { - string priceDenom = 1; - string assetDenom = 2; - string contractAddr = 3; -} - -message QueryGetPricesResponse { - repeated Price prices = 1; -} - -message QueryGetPriceRequest { - string priceDenom = 1; - string assetDenom = 2; - string contractAddr = 3; - uint64 timestamp = 4; -} - -message QueryGetPriceResponse { - Price price = 1; - bool found = 2; -} - -message QueryGetLatestPriceRequest { - string priceDenom = 1 [ - (gogoproto.jsontag) = "price_denom" - ]; - string assetDenom = 2 [ - (gogoproto.jsontag) = "asset_denom" - ]; - string contractAddr = 3 [ - (gogoproto.jsontag) = "contract_address" - ]; -} - -message QueryGetLatestPriceResponse { - Price price = 1; -} - -message QueryGetTwapsRequest { - string contractAddr = 1 [ - (gogoproto.jsontag) = "contract_address" - ]; - uint64 lookbackSeconds = 2 [ - (gogoproto.jsontag) = "lookback_seconds" - ]; - } - -message QueryGetTwapsResponse { - repeated Twap twaps = 1 [ - (gogoproto.jsontag) = "twaps" - ]; -} - -message QueryAssetListRequest {} - -message QueryAssetListResponse { - repeated AssetMetadata assetList = 1 [(gogoproto.nullable) = false]; -} - -message QueryAssetMetadataRequest { - string denom = 1; -} - -message QueryAssetMetadataResponse { - AssetMetadata metadata = 1; -} - -message QueryRegisteredPairsRequest { - string contractAddr = 1 [ - (gogoproto.jsontag) = "contract_address" - ]; -} - -message QueryRegisteredPairsResponse { - repeated Pair pairs = 1 [(gogoproto.nullable) = false]; -} - -message QueryRegisteredContractRequest { - string contractAddr = 1 [ - (gogoproto.jsontag) = "contract_address" - ]; -} - -message QueryRegisteredContractResponse { - ContractInfoV2 contract_info = 1; -} - -message QueryGetOrdersRequest{ - string contractAddr = 1 [ - (gogoproto.jsontag) = "contract_address" - ]; - string account = 2 [ - (gogoproto.jsontag) = "account" - ]; -} - -message QueryGetOrdersResponse { - repeated Order orders = 1 [ - (gogoproto.jsontag) = "orders" - ]; -} - -message QueryGetOrderByIDRequest{ - string contractAddr = 1 [ - (gogoproto.jsontag) = "contract_address" - ]; - string priceDenom = 2 [ - (gogoproto.jsontag) = "price_denom" - ]; - string assetDenom = 3 [ - (gogoproto.jsontag) = "asset_denom" - ]; - uint64 id = 4 [ - (gogoproto.jsontag) = "id" - ]; -} - -message QueryGetOrderByIDResponse { - Order order = 1 [ - (gogoproto.jsontag) = "order" - ]; -} - -message QueryGetHistoricalPricesRequest { - string contractAddr = 1 [ - (gogoproto.jsontag) = "contract_address" - ]; - string priceDenom = 2 [ - (gogoproto.jsontag) = "price_denom" - ]; - string assetDenom = 3 [ - (gogoproto.jsontag) = "asset_denom" - ]; - uint64 periodLengthInSeconds = 4 [ - (gogoproto.jsontag) = "period_length_in_seconds" - ]; - uint64 numOfPeriods = 5 [ - (gogoproto.jsontag) = "number_of_periods" - ]; -} - -message QueryGetHistoricalPricesResponse { - repeated PriceCandlestick prices = 1[ - (gogoproto.jsontag) = "prices" - ]; -} - -message QueryGetMarketSummaryRequest { - string contractAddr = 1 [ - (gogoproto.jsontag) = "contract_address" - ]; - string priceDenom = 2 [ - (gogoproto.jsontag) = "price_denom" - ]; - string assetDenom = 3 [ - (gogoproto.jsontag) = "asset_denom" - ]; - uint64 lookbackInSeconds = 4 [ - (gogoproto.jsontag) = "lookback_in_seconds" - ]; -} - -message QueryGetMarketSummaryResponse{ - string totalVolume = 1 [ - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.jsontag) = "total_volume" - ]; - string totalVolumeNotional = 2 [ - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.jsontag) = "total_volume_notional" - ]; - string highPrice = 3 [ - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.jsontag) = "high_price" - ]; - string lowPrice = 4 [ - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.jsontag) = "low_price" - ]; - string lastPrice = 5 [ - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.jsontag) = "last_price" - ]; -} - -message QueryOrderSimulationRequest { - Order order = 1 [ - (gogoproto.jsontag) = "order" - ]; - string contractAddr = 2 [ - (gogoproto.jsontag) = "contract_address" - ]; -} - -message QueryOrderSimulationResponse { - string ExecutedQuantity = 1 [ - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.jsontag) = "executed_quantity" - ]; -} - -message QueryGetMatchResultRequest { - string contractAddr = 1 [ - (gogoproto.jsontag) = "contract_address" - ]; -} - -message QueryGetMatchResultResponse { - MatchResult result = 1 [ - (gogoproto.jsontag) = "result" - ]; -} - -message QueryGetOrderCountRequest { - string contractAddr = 1 [ - (gogoproto.jsontag) = "contract_address" - ]; - string priceDenom = 2 [ - (gogoproto.jsontag) = "price_denom" - ]; - string assetDenom = 3 [ - (gogoproto.jsontag) = "asset_denom" - ]; - string price = 4 [ - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.jsontag) = "price" - ]; - PositionDirection positionDirection = 5 [ - (gogoproto.jsontag) = "position_direction" - ]; -} - -message QueryGetOrderCountResponse { - uint64 count = 1 [ - (gogoproto.jsontag) = "count" - ]; -} -// this line is used by starport scaffolding # 3 diff --git a/proto/dex/settlement.proto b/proto/dex/settlement.proto deleted file mode 100644 index 8e5487ebd..000000000 --- a/proto/dex/settlement.proto +++ /dev/null @@ -1,40 +0,0 @@ -syntax = "proto3"; -package seiprotocol.seichain.dex; - -option go_package = "github.com/sei-protocol/sei-chain/x/dex/types"; -import "gogoproto/gogo.proto"; - -message SettlementEntry { - string account = 1 [(gogoproto.jsontag) = "account"]; - string priceDenom = 2 [(gogoproto.jsontag) = "price_denom"]; - string assetDenom = 3 [(gogoproto.jsontag) = "asset_denom"]; - string quantity = 4 [ - (gogoproto.moretags) = "yaml:\"quantity\"", - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.nullable) = false, - (gogoproto.jsontag) = "quantity" - ]; - string executionCostOrProceed = 5 [ - (gogoproto.moretags) = "yaml:\"execution_cost_or_proceed\"", - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.nullable) = false, - (gogoproto.jsontag) = "execution_cost_or_proceed" - ]; - string expectedCostOrProceed = 6 [ - (gogoproto.moretags) = "yaml:\"expected_cost_or_proceed\"", - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.nullable) = false, - (gogoproto.jsontag) = "expected_cost_or_proceed" - ]; - string positionDirection = 7 [(gogoproto.jsontag) = "position_direction"]; - string orderType = 8 [(gogoproto.jsontag) = "order_type"]; - uint64 orderId = 9 [(gogoproto.jsontag) = "order_id"]; - uint64 timestamp = 10 [(gogoproto.jsontag) = "timestamp"]; - uint64 height = 11 [(gogoproto.jsontag) = "height"]; - uint64 settlementId = 12 [(gogoproto.jsontag) = "settlement_id"]; -} - -message Settlements { - int64 epoch = 1 [(gogoproto.jsontag) = "epoch"]; - repeated SettlementEntry entries = 2 [(gogoproto.jsontag) = "entries"]; -} \ No newline at end of file diff --git a/proto/dex/short_book.proto b/proto/dex/short_book.proto deleted file mode 100644 index b355c3cab..000000000 --- a/proto/dex/short_book.proto +++ /dev/null @@ -1,19 +0,0 @@ -syntax = "proto3"; -package seiprotocol.seichain.dex; - -option go_package = "github.com/sei-protocol/sei-chain/x/dex/types"; -import "dex/order_entry.proto"; -import "gogoproto/gogo.proto"; - -message ShortBook { - string price = 1 [ - (gogoproto.moretags) = "yaml:\"price\"", - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.nullable) = false, - (gogoproto.jsontag) = "price" - ]; - OrderEntry entry = 2 [ - (gogoproto.jsontag) = "entry" - ]; - -} \ No newline at end of file diff --git a/proto/dex/tick_size.proto b/proto/dex/tick_size.proto deleted file mode 100644 index 80eece546..000000000 --- a/proto/dex/tick_size.proto +++ /dev/null @@ -1,22 +0,0 @@ -syntax = "proto3"; -package seiprotocol.seichain.dex; - -option go_package = "github.com/sei-protocol/sei-chain/x/dex/types"; -import "dex/pair.proto"; -import "gogoproto/gogo.proto"; - -message TickSize { - Pair pair = 1 [ - (gogoproto.jsontag) = "pair" - ]; - string ticksize = 2 [ - (gogoproto.moretags) = "yaml:\"tick_size\"", - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.nullable) = false, - (gogoproto.jsontag) = "tick_size" - ]; - string contractAddr = 3 [ - (gogoproto.moretags) = "yaml:\"tick_size\"", - (gogoproto.jsontag) = "contract_addr" - ]; -} \ No newline at end of file diff --git a/proto/dex/twap.proto b/proto/dex/twap.proto deleted file mode 100644 index cca0836fb..000000000 --- a/proto/dex/twap.proto +++ /dev/null @@ -1,24 +0,0 @@ -syntax = "proto3"; -package seiprotocol.seichain.dex; - -import "gogoproto/gogo.proto"; -import "dex/pair.proto"; - -option go_package = "github.com/sei-protocol/sei-chain/x/dex/types"; - - -message Twap { - - Pair pair = 1 [ - (gogoproto.jsontag) = "pair" - ]; - string twap = 2 [ - (gogoproto.moretags) = "yaml:\"twap\"", - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.nullable) = false, - (gogoproto.jsontag) = "twap" - ]; - uint64 lookbackSeconds = 3 [ - (gogoproto.jsontag) = "lookback_seconds" - ]; -} diff --git a/proto/dex/tx.proto b/proto/dex/tx.proto deleted file mode 100644 index b21f5dde7..000000000 --- a/proto/dex/tx.proto +++ /dev/null @@ -1,147 +0,0 @@ -syntax = "proto3"; -package seiprotocol.seichain.dex; - -import "cosmos/base/v1beta1/coin.proto"; -import "gogoproto/gogo.proto"; -import "dex/contract.proto"; -import "dex/order.proto"; -import "dex/pair.proto"; -import "dex/tick_size.proto"; - -// this line is used by starport scaffolding # proto/tx/import - -option go_package = "github.com/sei-protocol/sei-chain/x/dex/types"; - -// Msg defines the Msg service. -service Msg { - rpc PlaceOrders(MsgPlaceOrders) returns (MsgPlaceOrdersResponse); - rpc CancelOrders(MsgCancelOrders) returns (MsgCancelOrdersResponse); - rpc RegisterContract(MsgRegisterContract) returns(MsgRegisterContractResponse); - rpc ContractDepositRent(MsgContractDepositRent) returns(MsgContractDepositRentResponse); - rpc UnregisterContract(MsgUnregisterContract) returns(MsgUnregisterContractResponse); - rpc RegisterPairs(MsgRegisterPairs) returns(MsgRegisterPairsResponse); - rpc UpdatePriceTickSize(MsgUpdatePriceTickSize) returns(MsgUpdateTickSizeResponse); - rpc UpdateQuantityTickSize(MsgUpdateQuantityTickSize) returns(MsgUpdateTickSizeResponse); - rpc UnsuspendContract(MsgUnsuspendContract) returns(MsgUnsuspendContractResponse); - // privileged endpoints below - -// this line is used by starport scaffolding # proto/tx/rpc -} - -message MsgPlaceOrders { - string creator = 1 [ - (gogoproto.jsontag) = "creator" - ]; - repeated Order orders = 2 [ - (gogoproto.jsontag) = "orders" - ]; - string contractAddr = 3 [ - (gogoproto.jsontag) = "contract_address" - ]; - repeated cosmos.base.v1beta1.Coin funds = 4 [ - (gogoproto.nullable) = false, - (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", - (gogoproto.jsontag) = "funds" - ]; -} - -message MsgPlaceOrdersResponse { - repeated uint64 orderIds = 1 [ - (gogoproto.moretags) = "yaml:\"order_ids\"", - (gogoproto.jsontag) = "order_ids" - ]; -} - -message MsgCancelOrders { - string creator = 1 [ - (gogoproto.jsontag) = "creator" - ]; - repeated Cancellation cancellations = 2 [ - (gogoproto.jsontag) = "cancellations" - ]; - string contractAddr = 3 [ - (gogoproto.jsontag) = "contract_address" - ]; -} - -message MsgCancelOrdersResponse {} - -message MsgRegisterContract { - string creator = 1; - ContractInfoV2 contract = 2; -} - -message MsgRegisterContractResponse {} - -message MsgContractDepositRent { - string contractAddr = 1 [ - (gogoproto.jsontag) = "contract_address" - ]; - uint64 amount = 2 [ - (gogoproto.jsontag) = "amount" - ]; - string sender = 3 [ - (gogoproto.jsontag) = "sender" - ]; -} - -message MsgContractDepositRentResponse {} - -message MsgUnregisterContract { - string creator = 1 [ - (gogoproto.jsontag) = "creator" - ]; - string contractAddr = 2 [ - (gogoproto.jsontag) = "contract_address" - ]; -} - -message MsgUnregisterContractResponse {} - -message MsgRegisterPairs { - string creator = 1; - repeated BatchContractPair batchcontractpair = 3 [ - (gogoproto.moretags) = "yaml:\"batch_contract_pair\"", - (gogoproto.nullable) = false, - (gogoproto.jsontag) = "batch_contract_pair" - ]; -} - -message MsgRegisterPairsResponse {} - -message MsgUpdatePriceTickSize { - string creator = 1 [ - (gogoproto.jsontag) = "creator" - ]; - repeated TickSize tickSizeList = 2 [ - (gogoproto.moretags) = "yaml:\"tick_size_list\"", - (gogoproto.nullable) = false, - (gogoproto.jsontag) = "tick_size_list" - ]; -} - -message MsgUpdateQuantityTickSize { - string creator = 1 [ - (gogoproto.jsontag) = "creator" - ]; - repeated TickSize tickSizeList = 2 [ - (gogoproto.moretags) = "yaml:\"tick_size_list\"", - (gogoproto.nullable) = false, - (gogoproto.jsontag) = "tick_size_list" - ]; -} - -message MsgUpdateTickSizeResponse {} - -message MsgUnsuspendContract { - string creator = 1 [ - (gogoproto.jsontag) = "creator" - ]; - string contractAddr = 2 [ - (gogoproto.jsontag) = "contract_address" - ]; -} - -message MsgUnsuspendContractResponse {} - -// this line is used by starport scaffolding # proto/tx/message \ No newline at end of file diff --git a/proto/mint/v1beta1/gov.proto b/proto/mint/v1beta1/gov.proto index 084b95196..1f9c2133e 100644 --- a/proto/mint/v1beta1/gov.proto +++ b/proto/mint/v1beta1/gov.proto @@ -6,8 +6,6 @@ import "mint/v1beta1/mint.proto"; option go_package = "github.com/sei-protocol/sei-chain/x/mint/types"; -// AddAssetMetadataProposal is a gov Content type for adding a new asset -// to the dex module's asset list. message UpdateMinterProposal { option (gogoproto.equal) = false; option (gogoproto.goproto_getters) = false; diff --git a/scripts/dump_app_state_for_height.sh b/scripts/dump_app_state_for_height.sh index 3107b2947..5d7d2b647 100755 --- a/scripts/dump_app_state_for_height.sh +++ b/scripts/dump_app_state_for_height.sh @@ -28,7 +28,7 @@ fi cd $HOME sudo rm -r state_$HEIGHT mkdir state_$HEIGHT -for key in dex wasm accesscontrol oracle epoch mint acc bank crisis feegrant staking distribution slashing gov params ibc upgrade evidence transfer tokenfactory +for key in wasm accesscontrol oracle epoch mint acc bank crisis feegrant staking distribution slashing gov params ibc upgrade evidence transfer tokenfactory do $HOME/go/bin/iaviewer data $HOME/.sei/data/application.db "s/k:"$key"/" $HEIGHT > $HOME/state_$HEIGHT/$key.data $HOME/go/bin/iaviewer shape $HOME/.sei/data/application.db "s/k:"$key"/" $HEIGHT > $HOME/state_$HEIGHT/$key.shape diff --git a/scripts/upload_clearing_house_contract.sh b/scripts/upload_clearing_house_contract.sh deleted file mode 100755 index cfbe49e9b..000000000 --- a/scripts/upload_clearing_house_contract.sh +++ /dev/null @@ -1,18 +0,0 @@ -# ./scripts/initialize_local.sh to spawn chain locally, endpoint is default to localhost:9090 -# build the contract to wasm with `cargo build; docker run --rm -v "$(pwd)":/code --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry cosmwasm/rust-optimizer:0.12.5` - -# upload the code -printf '00000000\n' | ./build/seid tx wasm store ../matrix-contract/clearing-house-contract/artifacts/clearing_house.wasm -y --from=alice --chain-id=sei --gas=3000000 --fees=100000usei --broadcast-mode=block -# replace addr here with an addr you have privateKey -printf '00000000\n' | ./build/seid tx wasm instantiate 1 '{"whitelist": ["sei1zywupnfk3t8lvtuzh540vls8mf53r5zuq98wkt"],"use_whitelist":false,"admin":"sei1zywupnfk3t8lvtuzh540vls8mf53r5zuq98wkt","limit_order_fee":{"decimal":"0.0001","negative":false},"market_order_fee":{"decimal":"0.0001","negative":false},"liquidation_order_fee":{"decimal":"0.0001","negative":false},"margin_ratio":{"decimal":"0.0625","negative":false},"max_leverage":{"decimal":"4","negative":false}}' -y --no-admin --chain-id=sei --gas=1500000 --fees=15000usei --broadcast-mode=block --label=dex --from=alice -# contract_address highly possible is the same, if not replace -printf '00000000\n' | ./build/seid tx dex register-contract sei14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sh9m79m 1 -y --from=alice --chain-id=sei --fees=100000usei --gas=500000 --broadcast-mode=block -# register a pair -printf '00000000\n' | ./build/seid tx dex register-pairs ./x/dex/example/register-pair-tx.json -y --from=alice --chain-id=sei --fees=10000000usei --gas=500000 --broadcast-mode=block -sleep 5 -printf '00000000\n' | ./build/seid tx dex update-tick-size ./x/dex/example/update-tick-size-tx.json -y --from=alice --chain-id=sei --fees=10000000usei --gas=500000 --broadcast-mode=block -printf '00000000\n' | ./build/seid tx gov deposit 2 10000000usei -y --from=alice --chain-id=sei --fees=10000000usei --gas=500000 --broadcast-mode=block -printf '00000000\n' | ./build/seid tx gov vote 2 yes -y --from=alice --chain-id=sei --fees=10000000usei --gas=500000 --broadcast-mode=block -# order: (position_direction, price, quantity, price_denom, asset_denom, position_effect(open/close), order_type(limit, market,..), leverage) -# need to wait for vote period close to take effect, seem no early stop implemented for vote -# ./build/seid tx dex place-orders sei14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sh9m79m Long,1.01,5,usdc,sei,Open,Limit,1 --amount=10000usei -y --from=alice --chain-id=sei --fees=10000usei --gas=50000000 --broadcast-mode=block \ No newline at end of file diff --git a/testutil/fuzzing/dex.go b/testutil/fuzzing/dex.go deleted file mode 100644 index 78070362a..000000000 --- a/testutil/fuzzing/dex.go +++ /dev/null @@ -1,228 +0,0 @@ -package fuzzing - -import ( - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -const BaselinePrice = 1234.56 - -var ValidAccountCorpus = []string{ - "sei1h9yjz89tl0dl6zu65dpxcqnxfhq60wxx8s5kag", - "sei1c2q6xm0x684rshrnlg898zm3vpwz92pcfhgmws", - "sei1ewxvf5a9wq9zk5nurtl6m9yfxpnhyp7s7uk5sl", - "sei1lllgxa294pshcsrsrteh7sj6ey0zqgty30sl8a", - "sei1vhn2p3xavts9swus27zz3n56tz98g3f6unavs2", - "sei1jpkqjfydghgrc23chmnj52xln0muz09j5huhkt", - "sei1k98zjg7scsmk6d4ye8hhrv3an6ppykvt660736", - "sei1wxpqjzdmtjm6gwg6555n0a0aqglrvnp3pqh9hs", - "sei1yuyyr3xg7jhk7pjkrp4j6h88t7gv35e29pfvmf", - "sei1vjgdad5v2euf98nj3pwg5d8agflr384k0eks43", -} - -var AccountCorpus = append([]string{ - "invalid", -}, ValidAccountCorpus...) - -var ContractCorpus = []string{ - "invalid", - "sei14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sh9m79m", - "sei1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrqms7u8a", -} - -var ( - MicroTick = sdk.MustNewDecFromStr("0.000001") - MilliTick = sdk.MustNewDecFromStr("0.001") - WholeTick = sdk.OneDec() - PairCorpus = []types.Pair{ - {}, - {PriceDenom: "SEI"}, - {AssetDenom: "ATOM"}, - { - PriceDenom: "SEI", - AssetDenom: "ATOM", - }, - { - PriceDenom: "SEI", - AssetDenom: "ATOM", - PriceTicksize: &MicroTick, - QuantityTicksize: &MicroTick, - }, - { - PriceDenom: "SEI", - AssetDenom: "ATOM", - PriceTicksize: &MilliTick, - QuantityTicksize: &MilliTick, - }, - { - PriceDenom: "SEI", - AssetDenom: "ATOM", - PriceTicksize: &WholeTick, - QuantityTicksize: &WholeTick, - }, - { - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - { - PriceDenom: "USDC", - AssetDenom: "ATOM", - PriceTicksize: &MicroTick, - QuantityTicksize: &MicroTick, - }, - { - PriceDenom: "USDC", - AssetDenom: "ATOM", - PriceTicksize: &MilliTick, - QuantityTicksize: &MilliTick, - }, - { - PriceDenom: "USDC", - AssetDenom: "ATOM", - PriceTicksize: &WholeTick, - QuantityTicksize: &WholeTick, - }, - } -) - -func GetAccount(i int) string { - ui := uint64(i) % uint64(len(AccountCorpus)) - return AccountCorpus[int(ui)] -} - -func GetValidAccount(i int) string { - ui := uint64(i) % uint64(len(ValidAccountCorpus)) - return ValidAccountCorpus[int(ui)] -} - -func GetContract(i int) string { - ui := uint64(i) % uint64(len(ContractCorpus)) - return ContractCorpus[int(ui)] -} - -func GetPair(i int) types.Pair { - ui := uint64(i) % uint64(len(PairCorpus)) - return PairCorpus[int(ui)] -} - -func GetPlacedOrders(direction types.PositionDirection, orderType types.OrderType, pair types.Pair, prices []byte, quantities []byte) []*types.Order { - // take the shorter slice's length - if len(prices) < len(quantities) { - quantities = quantities[:len(prices)] - } else { - prices = prices[:len(quantities)] - } - res := []*types.Order{} - for i, price := range prices { - var priceDec sdk.Dec - if direction == types.PositionDirection_LONG { - priceDec = sdk.MustNewDecFromStr(fmt.Sprintf("%f", BaselinePrice+float64(price))) - } else { - priceDec = sdk.MustNewDecFromStr(fmt.Sprintf("%f", BaselinePrice-float64(price))) - } - quantity := sdk.NewDec(int64(quantities[i])) - res = append(res, &types.Order{ - Id: uint64(i), - Status: types.OrderStatus_PLACED, - Price: priceDec, - Quantity: quantity, - PositionDirection: direction, - OrderType: orderType, - PriceDenom: pair.PriceDenom, - AssetDenom: pair.AssetDenom, - }) - } - return res -} - -func GetOrderBookEntries(buy bool, priceDenom string, assetDenom string, entryWeights []byte, allAccountIndices []byte, allWeights []byte) []types.OrderBookEntry { - res := []types.OrderBookEntry{} - totalPriceWeights := uint64(0) - for _, entryWeight := range entryWeights { - totalPriceWeights += uint64(entryWeight) - } - if totalPriceWeights == uint64(0) { - return res - } - sliceStartAccnt, sliceStartWeights := 0, 0 - cumWeights := uint64(0) - for i, entryWeight := range entryWeights { - var price sdk.Dec - if buy { - price = sdk.MustNewDecFromStr(fmt.Sprintf("%f", BaselinePrice-float64(i))) - } else { - price = sdk.MustNewDecFromStr(fmt.Sprintf("%f", BaselinePrice+float64(i))) - } - cumWeights += uint64(entryWeight) - nextSliceStartAccnt := int(cumWeights * uint64(len(allAccountIndices)) / totalPriceWeights) - nextSliceStartWeights := int(cumWeights * uint64(len(allWeights)) / totalPriceWeights) - entry := types.OrderEntry{ - Price: price, - Quantity: sdk.NewDec(int64(uint64((entryWeight)))), - PriceDenom: priceDenom, - AssetDenom: assetDenom, - Allocations: GetAllocations( - int64(uint64((entryWeight))), - allAccountIndices[sliceStartAccnt:nextSliceStartAccnt], - allWeights[sliceStartWeights:nextSliceStartWeights], - ), - } - if buy { - res = append(res, &types.LongBook{ - Price: price, - Entry: &entry, - }) - } else { - res = append(res, &types.ShortBook{ - Price: price, - Entry: &entry, - }) - } - sliceStartAccnt, sliceStartWeights = nextSliceStartAccnt, nextSliceStartWeights - } - return res -} - -func GetAllocations(totalQuantity int64, accountIndices []byte, weights []byte) []*types.Allocation { - // take the shorter slice's length - if len(accountIndices) < len(weights) { - weights = weights[:len(accountIndices)] - } else { - accountIndices = accountIndices[:len(weights)] - } - // dedupe and aggregate - aggregatedAccountsToWeights := map[string]uint64{} - totalWeight := uint64(0) - for i, accountIdx := range accountIndices { - account := GetValidAccount(int(accountIdx)) - weight := uint64(weights[i]) - if old, ok := aggregatedAccountsToWeights[account]; !ok { - aggregatedAccountsToWeights[account] = weight - } else { - aggregatedAccountsToWeights[account] = old + weight - } - totalWeight += weight - } - - quantityDec := sdk.NewDec(totalQuantity) - totalWeightDec := sdk.NewDec(int64(totalWeight)) - res := []*types.Allocation{} - orderID := 0 - for account, weight := range aggregatedAccountsToWeights { - var quantity sdk.Dec - if totalWeightDec.IsZero() { - quantity = sdk.ZeroDec() - } else { - quantity = quantityDec.Mul(sdk.NewDec(int64(weight))).Quo(totalWeightDec) - } - res = append(res, &types.Allocation{ - OrderId: uint64(orderID), - Account: account, - Quantity: quantity, - }) - orderID++ - } - return res -} diff --git a/testutil/keeper/dex.go b/testutil/keeper/dex.go deleted file mode 100644 index 5681676b7..000000000 --- a/testutil/keeper/dex.go +++ /dev/null @@ -1,196 +0,0 @@ -package keeper - -import ( - "context" - "testing" - - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/store" - storetypes "github.com/cosmos/cosmos-sdk/store/types" - sdk "github.com/cosmos/cosmos-sdk/types" - authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" - typesparams "github.com/cosmos/cosmos-sdk/x/params/types" - "github.com/sei-protocol/sei-chain/app" - dexcache "github.com/sei-protocol/sei-chain/x/dex/cache" - "github.com/sei-protocol/sei-chain/x/dex/keeper" - "github.com/sei-protocol/sei-chain/x/dex/types" - dexutils "github.com/sei-protocol/sei-chain/x/dex/utils" - epochkeeper "github.com/sei-protocol/sei-chain/x/epoch/keeper" - epochtypes "github.com/sei-protocol/sei-chain/x/epoch/types" - minttypes "github.com/sei-protocol/sei-chain/x/mint/types" - "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/libs/log" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - tmdb "github.com/tendermint/tm-db" -) - -const ( - TestAccount = "sei1yezq49upxhunjjhudql2fnj5dgvcwjj87pn2wx" - TestContract = "sei1ghd753shjuwexxywmgs4xz7x2q732vcnkm6h2pyv9s6ah3hylvrqladqwc" - TestAccount2 = "sei1vk2f6aps83xahv2sql4equx8fa95jgcnsdxkvr" - TestContract2 = "sei17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9jfksztgw5uh69wac2pgsrtqewe" - TestPriceDenom = "usdc" - TestAssetDenom = "atom" -) - -var ( - TestTicksize = sdk.OneDec() - TestPair = types.Pair{ - PriceDenom: TestPriceDenom, - AssetDenom: TestAssetDenom, - PriceTicksize: &TestTicksize, - QuantityTicksize: &TestTicksize, - } -) - -func TestApp() *app.App { - return app.Setup(false, false) -} - -func DexKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) { - storeKey := sdk.NewKVStoreKey(types.StoreKey) - keyAcc := sdk.NewKVStoreKey(authtypes.StoreKey) - keyBank := sdk.NewKVStoreKey(banktypes.StoreKey) - keyParams := sdk.NewKVStoreKey(typesparams.StoreKey) - tKeyParams := sdk.NewTransientStoreKey(typesparams.TStoreKey) - keyEpochs := sdk.NewKVStoreKey(epochtypes.StoreKey) - dexMemStoreKey := storetypes.NewMemoryStoreKey(types.MemStoreKey) - memStoreKey := storetypes.NewMemoryStoreKey(epochtypes.MemStoreKey) - - blackListAddrs := map[string]bool{} - - maccPerms := map[string][]string{ - types.ModuleName: nil, - minttypes.ModuleName: {authtypes.Minter}, - } - - db := tmdb.NewMemDB() - stateStore := store.NewCommitMultiStore(db) - stateStore.MountStoreWithDB(keyAcc, sdk.StoreTypeIAVL, db) - stateStore.MountStoreWithDB(keyBank, sdk.StoreTypeIAVL, db) - stateStore.MountStoreWithDB(storeKey, sdk.StoreTypeIAVL, db) - stateStore.MountStoreWithDB(memStoreKey, sdk.StoreTypeMemory, nil) - stateStore.MountStoreWithDB(dexMemStoreKey, sdk.StoreTypeMemory, nil) - stateStore.MountStoreWithDB(keyEpochs, sdk.StoreTypeIAVL, db) - stateStore.MountStoreWithDB(tKeyParams, sdk.StoreTypeTransient, db) - stateStore.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db) - require.NoError(t, stateStore.LoadLatestVersion()) - - cdc := codec.NewProtoCodec(app.MakeEncodingConfig().InterfaceRegistry) - - paramsSubspace := typesparams.NewSubspace(cdc, - types.Amino, - storeKey, - memStoreKey, - "DexParams", - ) - paramsKeeper := paramskeeper.NewKeeper(cdc, codec.NewLegacyAmino(), keyParams, tKeyParams) - accountKeeper := authkeeper.NewAccountKeeper(cdc, keyAcc, paramsKeeper.Subspace(authtypes.ModuleName), authtypes.ProtoBaseAccount, maccPerms) - bankKeeper := bankkeeper.NewBaseKeeper(cdc, keyBank, accountKeeper, paramsKeeper.Subspace(banktypes.ModuleName), blackListAddrs) - epochKeeper := epochkeeper.NewKeeper(cdc, keyEpochs, memStoreKey, paramsKeeper.Subspace(epochtypes.ModuleName)) - k := keeper.NewKeeper( - cdc, - storeKey, - dexMemStoreKey, - paramsSubspace, - *epochKeeper, - bankKeeper, - accountKeeper, - ) - - ctx := sdk.NewContext(stateStore, tmproto.Header{}, false, log.NewNopLogger()) - k.CreateModuleAccount(ctx) - - // Initialize params - k.SetParams(ctx, types.DefaultParams()) - bankParams := banktypes.DefaultParams() - bankParams.SendEnabled = []*banktypes.SendEnabled{ - { - Denom: TestPriceDenom, - Enabled: true, - }, - } - bankKeeper.SetParams(ctx, bankParams) - - return k, ctx.WithContext(context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(dexMemStoreKey))) -} - -func CreateAssetMetadata(keeper *keeper.Keeper, ctx sdk.Context) types.AssetMetadata { - ibcInfo := types.AssetIBCInfo{ - SourceChannel: "channel-1", - DstChannel: "channel-2", - SourceDenom: "uusdc", - SourceChainID: "axelar", - } - - denomUnit := banktypes.DenomUnit{ - Denom: "ibc/D189335C6E4A68B513C10AB227BF1C1D38C746766278BA3EEB4FB14124F1D858", - Exponent: 0, - Aliases: []string{"axlusdc", "usdc"}, - } - - var denomUnits []*banktypes.DenomUnit - denomUnits = append(denomUnits, &denomUnit) - - metadata := banktypes.Metadata{ - Description: "Circle's stablecoin on Axelar", - DenomUnits: denomUnits, - Base: "ibc/D189335C6E4A68B513C10AB227BF1C1D38C746766278BA3EEB4FB14124F1D858", - Name: "USD Coin", - Display: "axlusdc", - Symbol: "USDC", - } - - item := types.AssetMetadata{ - IbcInfo: &ibcInfo, - TypeAsset: "erc20", - Metadata: metadata, - } - - keeper.SetAssetMetadata(ctx, item) - - return item -} - -func SeedPriceSnapshot(ctx sdk.Context, k *keeper.Keeper, price string, timestamp uint64) { - priceSnapshot := types.Price{ - SnapshotTimestampInSeconds: timestamp, - Price: sdk.MustNewDecFromStr(price), - Pair: &TestPair, - } - k.SetPriceState(ctx, priceSnapshot, TestContract) -} - -func CreateNLongBook(keeper *keeper.Keeper, ctx sdk.Context, n int) []types.LongBook { - items := make([]types.LongBook, n) - for i := range items { - items[i].Entry = &types.OrderEntry{ - Price: sdk.NewDec(int64(i)), - Quantity: sdk.NewDec(int64(i)), - PriceDenom: TestPriceDenom, - AssetDenom: TestAssetDenom, - } - items[i].Price = sdk.NewDec(int64(i)) - keeper.SetLongBook(ctx, TestContract, items[i]) - } - return items -} - -func CreateNShortBook(keeper *keeper.Keeper, ctx sdk.Context, n int) []types.ShortBook { - items := make([]types.ShortBook, n) - for i := range items { - items[i].Entry = &types.OrderEntry{ - Price: sdk.NewDec(int64(i)), - Quantity: sdk.NewDec(int64(i)), - PriceDenom: TestPriceDenom, - AssetDenom: TestAssetDenom, - } - items[i].Price = sdk.NewDec(int64(i)) - keeper.SetShortBook(ctx, TestContract, items[i]) - } - return items -} diff --git a/testutil/keeper/epoch.go b/testutil/keeper/epoch.go index 0f5584600..57f91de84 100644 --- a/testutil/keeper/epoch.go +++ b/testutil/keeper/epoch.go @@ -9,6 +9,7 @@ import ( storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" typesparams "github.com/cosmos/cosmos-sdk/x/params/types" + "github.com/sei-protocol/sei-chain/app" "github.com/sei-protocol/sei-chain/x/epoch/keeper" "github.com/sei-protocol/sei-chain/x/epoch/types" "github.com/stretchr/testify/require" @@ -17,6 +18,10 @@ import ( tmdb "github.com/tendermint/tm-db" ) +func TestApp() *app.App { + return app.Setup(false, false) +} + func EpochKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) { storeKey := sdk.NewKVStoreKey(types.StoreKey) memStoreKey := storetypes.NewMemoryStoreKey(types.MemStoreKey) diff --git a/testutil/processblock/msgs/dex.go b/testutil/processblock/msgs/dex.go deleted file mode 100644 index 6a9e79991..000000000 --- a/testutil/processblock/msgs/dex.go +++ /dev/null @@ -1,101 +0,0 @@ -package msgs - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/utils" - dextypes "github.com/sei-protocol/sei-chain/x/dex/types" -) - -type Market struct { - contract string - priceDenom string - assetDenom string -} - -func NewMarket(contract string, priceDenom string, assetDenom string) *Market { - return &Market{ - contract: contract, - priceDenom: priceDenom, - assetDenom: assetDenom, - } -} - -func (m *Market) Register(admin sdk.AccAddress, deps []string, deposit uint64) []sdk.Msg { - pointOne := sdk.NewDecWithPrec(1, 1) - return []sdk.Msg{dextypes.NewMsgRegisterContract(admin.String(), 0, m.contract, true, utils.Map(deps, func(dep string) *dextypes.ContractDependencyInfo { - return &dextypes.ContractDependencyInfo{Dependency: dep} - }), deposit), dextypes.NewMsgRegisterPairs(admin.String(), []dextypes.BatchContractPair{{ - ContractAddr: m.contract, - Pairs: []*dextypes.Pair{{ - PriceDenom: m.priceDenom, - AssetDenom: m.assetDenom, - PriceTicksize: &pointOne, - QuantityTicksize: &pointOne, - }}, - }})} -} - -func (m *Market) LongLimitOrder(account sdk.AccAddress, price string, quantity string) *dextypes.MsgPlaceOrders { - o := m.commonOrder(account, price, quantity) - o.PositionDirection = dextypes.PositionDirection_LONG - o.OrderType = dextypes.OrderType_LIMIT - return dextypes.NewMsgPlaceOrders(account.String(), []*dextypes.Order{o}, m.contract, fundForOrder(o)) -} - -func (m *Market) ShortLimitOrder(account sdk.AccAddress, price string, quantity string) *dextypes.MsgPlaceOrders { - o := m.commonOrder(account, price, quantity) - o.PositionDirection = dextypes.PositionDirection_SHORT - o.OrderType = dextypes.OrderType_LIMIT - return dextypes.NewMsgPlaceOrders(account.String(), []*dextypes.Order{o}, m.contract, fundForOrder(o)) -} - -func (m *Market) LongMarketOrder(account sdk.AccAddress, price string, quantity string) *dextypes.MsgPlaceOrders { - o := m.commonOrder(account, price, quantity) - o.PositionDirection = dextypes.PositionDirection_LONG - o.OrderType = dextypes.OrderType_MARKET - return dextypes.NewMsgPlaceOrders(account.String(), []*dextypes.Order{o}, m.contract, fundForOrder(o)) -} - -func (m *Market) ShortMarketOrder(account sdk.AccAddress, price string, quantity string) *dextypes.MsgPlaceOrders { - o := m.commonOrder(account, price, quantity) - o.PositionDirection = dextypes.PositionDirection_SHORT - o.OrderType = dextypes.OrderType_MARKET - return dextypes.NewMsgPlaceOrders(account.String(), []*dextypes.Order{o}, m.contract, fundForOrder(o)) -} - -func (m *Market) CancelLongOrder(account sdk.AccAddress, price string, id uint64) *dextypes.MsgCancelOrders { - c := m.commonCancel(account, price, id) - c.PositionDirection = dextypes.PositionDirection_LONG - return dextypes.NewMsgCancelOrders(account.String(), []*dextypes.Cancellation{c}, m.contract) -} - -func (m *Market) CancelShortOrder(account sdk.AccAddress, price string, id uint64) *dextypes.MsgCancelOrders { - c := m.commonCancel(account, price, id) - c.PositionDirection = dextypes.PositionDirection_SHORT - return dextypes.NewMsgCancelOrders(account.String(), []*dextypes.Cancellation{c}, m.contract) -} - -func (m *Market) commonOrder(account sdk.AccAddress, price string, quantity string) *dextypes.Order { - return &dextypes.Order{ - Account: account.String(), - Price: sdk.MustNewDecFromStr(price), - Quantity: sdk.MustNewDecFromStr(quantity), - PriceDenom: m.priceDenom, - AssetDenom: m.assetDenom, - } -} - -func (m *Market) commonCancel(account sdk.AccAddress, price string, id uint64) *dextypes.Cancellation { - return &dextypes.Cancellation{ - Creator: account.String(), - Price: sdk.MustNewDecFromStr(price), - Id: id, - PriceDenom: m.priceDenom, - AssetDenom: m.assetDenom, - ContractAddr: m.contract, - } -} - -func fundForOrder(o *dextypes.Order) sdk.Coins { - return sdk.NewCoins(sdk.NewCoin("usei", o.Price.Mul(o.Quantity).RoundInt())) -} diff --git a/testutil/processblock/presets.go b/testutil/processblock/presets.go index 785046f28..27cb58cb8 100644 --- a/testutil/processblock/presets.go +++ b/testutil/processblock/presets.go @@ -9,9 +9,6 @@ import ( authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/sei-protocol/sei-chain/testutil/processblock/msgs" - "github.com/sei-protocol/sei-chain/utils" - dextypes "github.com/sei-protocol/sei-chain/x/dex/types" minttypes "github.com/sei-protocol/sei-chain/x/mint/types" ) @@ -20,8 +17,6 @@ type Preset struct { SignableAccounts []sdk.AccAddress AllAccounts []sdk.AccAddress AllValidators []sdk.ValAddress - AllContracts []sdk.AccAddress - AllDexMarkets []*msgs.Market } // 3 unsignable accounts @@ -32,7 +27,6 @@ func CommonPreset(app *App) *Preset { fmt.Printf("Distribution module: %s\n", app.AccountKeeper.GetModuleAddress(distrtypes.ModuleName).String()) fmt.Printf("Staking bonded pool: %s\n", app.AccountKeeper.GetModuleAddress(stakingtypes.BondedPoolName).String()) fmt.Printf("Staking unbonded pool: %s\n", app.AccountKeeper.GetModuleAddress(stakingtypes.NotBondedPoolName).String()) - fmt.Printf("Dex module: %s\n", app.AccountKeeper.GetModuleAddress(dextypes.ModuleName).String()) fmt.Printf("Wasm module: %s\n", app.AccountKeeper.GetModuleAddress(wasm.ModuleName).String()) p := &Preset{ Admin: app.NewSignableAccount("admin"), @@ -55,37 +49,7 @@ func CommonPreset(app *App) *Preset { return p } -func DexPreset(app *App, numAccounts int, numMarkets int) *Preset { - p := CommonPreset(app) - for i := 0; i < numAccounts; i++ { - acc := app.NewSignableAccount(fmt.Sprintf("DexPreset%d", i)) - app.FundAccount(acc, 10000000) - p.AllAccounts = append(p.AllAccounts, acc) - p.SignableAccounts = append(p.SignableAccounts, acc) - fmt.Printf("DexPreset account: %s\n", acc.String()) - } - for i := 0; i < numMarkets; i++ { - contract := app.NewContract(p.Admin, "./mars.wasm") - market := msgs.NewMarket(contract.String(), "SEI", fmt.Sprintf("ATOM%d", i)) - p.AllContracts = append(p.AllContracts, contract) - p.AllDexMarkets = append(p.AllDexMarkets, market) - fmt.Printf("DexPreset contract: %s\n", contract.String()) - } - return p -} - // always with enough fee func (p *Preset) AdminSign(app *App, msgs ...sdk.Msg) signing.Tx { return app.Sign(p.Admin, 10000000, msgs...) } - -func (p *Preset) DoRegisterMarkets(app *App) { - block := utils.Map(p.AllDexMarkets, func(m *msgs.Market) signing.Tx { - return p.AdminSign(app, m.Register(p.Admin, []string{}, 20000000)...) - }) - for i, code := range app.RunBlock(block) { - if code != 0 { - panic(fmt.Sprintf("error code %d when registering the %d-th market", code, i)) - } - } -} diff --git a/testutil/processblock/verify/bank.go b/testutil/processblock/verify/bank.go index 580ee5b85..2bd76fe9f 100644 --- a/testutil/processblock/verify/bank.go +++ b/testutil/processblock/verify/bank.go @@ -7,7 +7,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth/signing" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/sei-protocol/sei-chain/testutil/processblock" - dextypes "github.com/sei-protocol/sei-chain/x/dex/types" "github.com/stretchr/testify/require" ) @@ -32,12 +31,6 @@ func Balance(t *testing.T, app *processblock.App, f BlockRunnable, txs []signing for _, output := range m.Outputs { updateMultipleExpectedBalanceChange(expectedChanges, output.Address, output.Coins, true) } - case *dextypes.MsgPlaceOrders: - updateMultipleExpectedBalanceChange(expectedChanges, m.Creator, m.Funds, false) - updateMultipleExpectedBalanceChange(expectedChanges, m.ContractAddr, m.Funds, true) - case *dextypes.MsgRegisterContract: - funds := sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(int64(m.Contract.RentBalance)))) - updateMultipleExpectedBalanceChange(expectedChanges, m.Creator, funds, false) default: // TODO: add coverage for other balance-affecting messages to enable testing for those message types continue diff --git a/testutil/processblock/verify/dex.go b/testutil/processblock/verify/dex.go deleted file mode 100644 index cfc5a2779..000000000 --- a/testutil/processblock/verify/dex.go +++ /dev/null @@ -1,269 +0,0 @@ -package verify - -import ( - "sort" - "strings" - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth/signing" - "github.com/sei-protocol/sei-chain/testutil/processblock" - "github.com/sei-protocol/sei-chain/utils" - dexkeeper "github.com/sei-protocol/sei-chain/x/dex/keeper" - dextypes "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func DexOrders(t *testing.T, app *processblock.App, f BlockRunnable, txs []signing.Tx) BlockRunnable { - return func() []uint32 { - orderPlacementsByMarket := map[string][]*dextypes.Order{} - orderCancellationsByMarket := map[string][]*dextypes.Cancellation{} - markets := map[string]struct{}{} - for _, tx := range txs { - for _, msg := range tx.GetMsgs() { - switch m := msg.(type) { - case *dextypes.MsgPlaceOrders: - for _, o := range m.Orders { - id := strings.Join([]string{m.ContractAddr, o.PriceDenom, o.AssetDenom}, ",") - markets[id] = struct{}{} - if orders, ok := orderPlacementsByMarket[id]; ok { - o.Id = app.DexKeeper.GetNextOrderID(app.Ctx(), m.ContractAddr) + uint64(len(orders)) - orderPlacementsByMarket[id] = append(orders, o) - } else { - o.Id = app.DexKeeper.GetNextOrderID(app.Ctx(), m.ContractAddr) - orderPlacementsByMarket[id] = []*dextypes.Order{o} - } - } - case *dextypes.MsgCancelOrders: - for _, o := range m.Cancellations { - id := strings.Join([]string{m.ContractAddr, o.PriceDenom, o.AssetDenom}, ",") - markets[id] = struct{}{} - if cancels, ok := orderCancellationsByMarket[id]; ok { - orderCancellationsByMarket[id] = append(cancels, o) - } else { - orderCancellationsByMarket[id] = []*dextypes.Cancellation{o} - } - } - default: - continue - } - } - } - expectedLongBookByMarket := map[string]map[string]*dextypes.OrderEntry{} - expectedShortBookByMarket := map[string]map[string]*dextypes.OrderEntry{} - for market := range markets { - orderPlacements := []*dextypes.Order{} - if o, ok := orderPlacementsByMarket[market]; ok { - orderPlacements = o - } - orderCancellations := []*dextypes.Cancellation{} - if c, ok := orderCancellationsByMarket[market]; ok { - orderCancellations = c - } - parts := strings.Split(market, ",") - longBook, shortBook := expectedOrdersForMarket(app.Ctx(), &app.DexKeeper, orderPlacements, orderCancellations, parts[0], parts[1], parts[2]) - expectedLongBookByMarket[market] = longBook - expectedShortBookByMarket[market] = shortBook - } - - results := f() - - for market, longBook := range expectedLongBookByMarket { - parts := strings.Split(market, ",") - contract := parts[0] - priceDenom := parts[1] - assetDenom := parts[2] - require.Equal(t, len(longBook), len(app.DexKeeper.GetAllLongBookForPair(app.Ctx(), contract, priceDenom, assetDenom))) - for price, entry := range longBook { - actual, found := app.DexKeeper.GetLongOrderBookEntryByPrice(app.Ctx(), contract, sdk.MustNewDecFromStr(price), priceDenom, assetDenom) - require.True(t, found) - require.Equal(t, *entry, *(actual.GetOrderEntry())) - } - } - - for market, shortBook := range expectedShortBookByMarket { - parts := strings.Split(market, ",") - contract := parts[0] - priceDenom := parts[1] - assetDenom := parts[2] - require.Equal(t, len(shortBook), len(app.DexKeeper.GetAllShortBookForPair(app.Ctx(), contract, priceDenom, assetDenom))) - for price, entry := range shortBook { - actual, found := app.DexKeeper.GetShortOrderBookEntryByPrice(app.Ctx(), contract, sdk.MustNewDecFromStr(price), priceDenom, assetDenom) - require.True(t, found) - require.Equal(t, *entry, *(actual.GetOrderEntry())) - } - } - - return results - } -} - -// A slow but correct implementation of dex exchange logics that build the expected order book state based on the -// current state and the list of new orders/cancellations, based on dex exchange rules. -func expectedOrdersForMarket( - ctx sdk.Context, - keeper *dexkeeper.Keeper, - orderPlacements []*dextypes.Order, - orderCancellations []*dextypes.Cancellation, - contract string, - priceDenom string, - assetDenom string, -) (longEntries map[string]*dextypes.OrderEntry, shortEntries map[string]*dextypes.OrderEntry) { - longBook := toOrderBookMap(keeper.GetAllLongBookForPair(ctx, contract, priceDenom, assetDenom)) - shortBook := toOrderBookMap(keeper.GetAllShortBookForPair(ctx, contract, priceDenom, assetDenom)) - books := map[dextypes.PositionDirection]map[string]*dextypes.OrderEntry{ - dextypes.PositionDirection_LONG: longBook, - dextypes.PositionDirection_SHORT: shortBook, - } - // first, cancellation - cancelOrders(books, orderCancellations) - // then add new limit orders to book - addOrders(books, orderPlacements) - // then match market orders - matchOrders(getMarketOrderBookMap(orderPlacements, dextypes.PositionDirection_LONG), shortBook) - matchOrders(longBook, getMarketOrderBookMap(orderPlacements, dextypes.PositionDirection_SHORT)) - // finally match limit orders - matchOrders(longBook, shortBook) - return longBook, shortBook -} - -func cancelOrders( - books map[dextypes.PositionDirection]map[string]*dextypes.OrderEntry, - orderCancellations []*dextypes.Cancellation, -) { - for _, cancel := range orderCancellations { - book := books[cancel.PositionDirection] - if entry, ok := book[cancel.Price.String()]; ok { - entry.Allocations = removeMatched(entry.Allocations, func(a *dextypes.Allocation) bool { return a.OrderId == cancel.Id }) - updateEntryQuantity(entry) - if entry.Quantity.IsZero() { - delete(book, cancel.Price.String()) - } - } - } -} - -func addOrders( - books map[dextypes.PositionDirection]map[string]*dextypes.OrderEntry, - orderPlacements []*dextypes.Order, -) { - for _, o := range orderPlacements { - if o.OrderType != dextypes.OrderType_LIMIT { - continue - } - book := books[o.PositionDirection] - newAllocation := &dextypes.Allocation{ - Account: o.Account, - Quantity: o.Quantity, - OrderId: o.Id, - } - if entry, ok := book[o.Price.String()]; ok { - entry.Allocations = append(entry.Allocations, newAllocation) - updateEntryQuantity(entry) - } else { - book[o.Price.String()] = &dextypes.OrderEntry{ - Price: o.Price, - Quantity: o.Quantity, - PriceDenom: o.PriceDenom, - AssetDenom: o.AssetDenom, - Allocations: []*dextypes.Allocation{newAllocation}, - } - } - } -} - -func matchOrders( - longBook map[string]*dextypes.OrderEntry, - shortBook map[string]*dextypes.OrderEntry, -) { - buyPrices := sortedPrices(longBook, true) - sellPrices := sortedPrices(shortBook, false) - for i, j := 0, 0; i < len(buyPrices) && j < len(sellPrices) && buyPrices[i].GTE(sellPrices[j]); { - buyEntry := longBook[buyPrices[i].String()] - sellEntry := shortBook[sellPrices[j].String()] - if buyEntry.Quantity.GT(sellEntry.Quantity) { - takeLiquidity(longBook, buyPrices[i], sellEntry.Quantity) - takeLiquidity(shortBook, sellPrices[i], sellEntry.Quantity) - j++ - } else { - takeLiquidity(longBook, buyPrices[i], buyEntry.Quantity) - takeLiquidity(shortBook, sellPrices[i], buyEntry.Quantity) - i++ - } - } -} - -func toOrderBookMap(book []dextypes.OrderBookEntry) map[string]*dextypes.OrderEntry { - bookMap := map[string]*dextypes.OrderEntry{} - for _, e := range book { - bookMap[e.GetPrice().String()] = e.GetOrderEntry() - } - return bookMap -} - -func getMarketOrderBookMap(orderPlacements []*dextypes.Order, direction dextypes.PositionDirection) map[string]*dextypes.OrderEntry { - bookMap := map[string]*dextypes.OrderEntry{} - for _, o := range orderPlacements { - if o.OrderType != dextypes.OrderType_MARKET || o.PositionDirection != direction { - continue - } - bookMap[o.Price.String()] = orderToOrderEntry(o) - } - return bookMap -} - -func updateEntryQuantity(entry *dextypes.OrderEntry) { - entry.Quantity = utils.Reduce( - entry.Allocations, - func(a *dextypes.Allocation, q sdk.Dec) sdk.Dec { return q.Add(a.Quantity) }, - sdk.ZeroDec(), - ) -} - -func takeLiquidity(book map[string]*dextypes.OrderEntry, price sdk.Dec, quantity sdk.Dec) { - entry := book[price.String()] - if entry.Quantity.Equal(quantity) { - delete(book, price.String()) - return - } - if quantity.GT(entry.Quantity) { - panic("insufficient liquidity") - } - allocated := sdk.ZeroDec() - newAllocations := []*dextypes.Allocation{} - for _, a := range entry.Allocations { - switch { - case allocated.Equal(quantity): - newAllocations = append(newAllocations, a) - case allocated.Add(a.Quantity).GT(quantity): - a.Quantity = a.Quantity.Sub(quantity.Sub(allocated)) - newAllocations = append(newAllocations, a) - allocated = quantity - default: - allocated = allocated.Add(a.Quantity) - } - } - entry.Allocations = newAllocations - entry.Quantity = entry.Quantity.Sub(quantity) -} - -func sortedPrices(book map[string]*dextypes.OrderEntry, descending bool) []sdk.Dec { - prices := []sdk.Dec{} - for p := range book { - prices = append(prices, sdk.MustNewDecFromStr(p)) - } - if descending { - sort.Slice(prices, func(i, j int) bool { return prices[i].GT(prices[j]) }) - } else { - sort.Slice(prices, func(i, j int) bool { return prices[i].LT(prices[j]) }) - } - return prices -} - -func orderToOrderEntry(order *dextypes.Order) *dextypes.OrderEntry { - return &dextypes.OrderEntry{ - Price: order.Price, - Quantity: order.Quantity, - Allocations: []*dextypes.Allocation{{Quantity: order.Quantity}}, - } -} diff --git a/wasmbinding/bindings/msg.go b/wasmbinding/bindings/msg.go index 7e633640d..cb9fdff46 100644 --- a/wasmbinding/bindings/msg.go +++ b/wasmbinding/bindings/msg.go @@ -3,7 +3,6 @@ package bindings import ( sdk "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - "github.com/sei-protocol/sei-chain/x/dex/types" ) // / CreateDenom creates a new factory denom, of denomination: @@ -35,18 +34,6 @@ type BurnTokens struct { Amount sdk.Coin `json:"amount"` } -// Dex Module msgs -type PlaceOrders struct { - Orders []*types.Order `json:"orders"` - Funds sdk.Coins `json:"funds"` - ContractAddr string `json:"contract_address"` -} - -type CancelOrders struct { - Cancellations []*types.Cancellation `json:"cancellations"` - ContractAddr string `json:"contract_address"` -} - type CallEVM struct { Value *sdk.Int `json:"value"` To string `json:"to"` diff --git a/wasmbinding/encoder.go b/wasmbinding/encoder.go index 1e691b8d6..087e00279 100644 --- a/wasmbinding/encoder.go +++ b/wasmbinding/encoder.go @@ -7,14 +7,11 @@ import ( wasmvmtypes "github.com/CosmWasm/wasmvm/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - dexwasm "github.com/sei-protocol/sei-chain/x/dex/client/wasm" evmwasm "github.com/sei-protocol/sei-chain/x/evm/client/wasm" tokenfactorywasm "github.com/sei-protocol/sei-chain/x/tokenfactory/client/wasm" ) type SeiWasmMessage struct { - PlaceOrders json.RawMessage `json:"place_orders,omitempty"` - CancelOrders json.RawMessage `json:"cancel_orders,omitempty"` CreateDenom json.RawMessage `json:"create_denom,omitempty"` MintTokens json.RawMessage `json:"mint_tokens,omitempty"` BurnTokens json.RawMessage `json:"burn_tokens,omitempty"` @@ -30,10 +27,6 @@ func CustomEncoder(sender sdk.AccAddress, msg json.RawMessage, info wasmvmtypes. return []sdk.Msg{}, sdkerrors.Wrap(err, "Error parsing Sei Wasm Message") } switch { - case parsedMessage.PlaceOrders != nil: - return dexwasm.EncodeDexPlaceOrders(parsedMessage.PlaceOrders, sender) - case parsedMessage.CancelOrders != nil: - return dexwasm.EncodeDexCancelOrders(parsedMessage.CancelOrders, sender) case parsedMessage.CreateDenom != nil: return tokenfactorywasm.EncodeTokenFactoryCreateDenom(parsedMessage.CreateDenom, sender) case parsedMessage.MintTokens != nil: diff --git a/wasmbinding/queries.go b/wasmbinding/queries.go index 122bb712b..de60fed50 100644 --- a/wasmbinding/queries.go +++ b/wasmbinding/queries.go @@ -7,9 +7,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/sei-protocol/sei-chain/utils/metrics" - dexwasm "github.com/sei-protocol/sei-chain/x/dex/client/wasm" - dexbindings "github.com/sei-protocol/sei-chain/x/dex/client/wasm/bindings" - dextypes "github.com/sei-protocol/sei-chain/x/dex/types" epochwasm "github.com/sei-protocol/sei-chain/x/epoch/client/wasm" epochbindings "github.com/sei-protocol/sei-chain/x/epoch/client/wasm/bindings" epochtypes "github.com/sei-protocol/sei-chain/x/epoch/types" @@ -25,17 +22,15 @@ import ( type QueryPlugin struct { oracleHandler oraclewasm.OracleWasmQueryHandler - dexHandler dexwasm.DexWasmQueryHandler epochHandler epochwasm.EpochWasmQueryHandler tokenfactoryHandler tokenfactorywasm.TokenFactoryWasmQueryHandler evmHandler evmwasm.EVMQueryHandler } // NewQueryPlugin returns a reference to a new QueryPlugin. -func NewQueryPlugin(oh *oraclewasm.OracleWasmQueryHandler, dh *dexwasm.DexWasmQueryHandler, eh *epochwasm.EpochWasmQueryHandler, th *tokenfactorywasm.TokenFactoryWasmQueryHandler, evmh *evmwasm.EVMQueryHandler) *QueryPlugin { +func NewQueryPlugin(oh *oraclewasm.OracleWasmQueryHandler, eh *epochwasm.EpochWasmQueryHandler, th *tokenfactorywasm.TokenFactoryWasmQueryHandler, evmh *evmwasm.EVMQueryHandler) *QueryPlugin { return &QueryPlugin{ oracleHandler: *oh, - dexHandler: *dh, epochHandler: *eh, tokenfactoryHandler: *th, evmHandler: *evmh, @@ -75,72 +70,6 @@ func (qp QueryPlugin) HandleOracleQuery(ctx sdk.Context, queryData json.RawMessa } } -func (qp QueryPlugin) HandleDexQuery(ctx sdk.Context, queryData json.RawMessage) ([]byte, error) { - var parsedQuery dexbindings.SeiDexQuery - if err := json.Unmarshal(queryData, &parsedQuery); err != nil { - return nil, dextypes.ErrParsingSeiDexQuery - } - switch { - case parsedQuery.DexTwaps != nil: - res, err := qp.dexHandler.GetDexTwap(ctx, parsedQuery.DexTwaps) - if err != nil { - return nil, err - } - bz, err := json.Marshal(res) - if err != nil { - return nil, dextypes.ErrEncodingDexTwaps - } - - return bz, nil - case parsedQuery.GetOrders != nil: - res, err := qp.dexHandler.GetOrders(ctx, parsedQuery.GetOrders) - if err != nil { - return nil, err - } - bz, err := json.Marshal(res) - if err != nil { - return nil, dextypes.ErrEncodingOrders - } - - return bz, nil - case parsedQuery.GetOrderByID != nil: - res, err := qp.dexHandler.GetOrderByID(ctx, parsedQuery.GetOrderByID) - if err != nil { - return nil, err - } - bz, err := json.Marshal(res) - if err != nil { - return nil, dextypes.ErrEncodingOrder - } - - return bz, nil - case parsedQuery.GetOrderSimulation != nil: - res, err := qp.dexHandler.GetOrderSimulation(ctx, parsedQuery.GetOrderSimulation) - if err != nil { - return nil, err - } - bz, err := json.Marshal(res) - if err != nil { - return nil, dextypes.ErrEncodingOrderSimulation - } - - return bz, nil - case parsedQuery.GetLatestPrice != nil: - res, err := qp.dexHandler.GetLatestPrice(ctx, parsedQuery.GetLatestPrice) - if err != nil { - return nil, err - } - bz, err := json.Marshal(res) - if err != nil { - return nil, dextypes.ErrEncodingLatestPrice - } - - return bz, nil - default: - return nil, dextypes.ErrUnknownSeiDexQuery - } -} - func (qp QueryPlugin) HandleEpochQuery(ctx sdk.Context, queryData json.RawMessage) ([]byte, error) { var parsedQuery epochbindings.SeiEpochQuery if err := json.Unmarshal(queryData, &parsedQuery); err != nil { diff --git a/wasmbinding/query_plugin.go b/wasmbinding/query_plugin.go index db21e9404..aa24663be 100644 --- a/wasmbinding/query_plugin.go +++ b/wasmbinding/query_plugin.go @@ -10,7 +10,6 @@ import ( const ( OracleRoute = "oracle" - DexRoute = "dex" EpochRoute = "epoch" TokenFactoryRoute = "tokenfactory" EVMRoute = "evm" @@ -32,8 +31,6 @@ func CustomQuerier(qp *QueryPlugin) func(ctx sdk.Context, request json.RawMessag switch contractQuery.Route { case OracleRoute: return qp.HandleOracleQuery(ctx, contractQuery.QueryData) - case DexRoute: - return qp.HandleDexQuery(ctx, contractQuery.QueryData) case EpochRoute: return qp.HandleEpochQuery(ctx, contractQuery.QueryData) case TokenFactoryRoute: diff --git a/wasmbinding/test/encoder_test.go b/wasmbinding/test/encoder_test.go index 439c3a707..0e55393cb 100644 --- a/wasmbinding/test/encoder_test.go +++ b/wasmbinding/test/encoder_test.go @@ -6,9 +6,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/sei-protocol/sei-chain/wasmbinding/bindings" - dexwasm "github.com/sei-protocol/sei-chain/x/dex/client/wasm" - "github.com/sei-protocol/sei-chain/x/dex/types" - dextypes "github.com/sei-protocol/sei-chain/x/dex/types" tokenfactorywasm "github.com/sei-protocol/sei-chain/x/tokenfactory/client/wasm" tokenfactorytypes "github.com/sei-protocol/sei-chain/x/tokenfactory/types" "github.com/stretchr/testify/require" @@ -19,71 +16,6 @@ const ( TEST_CREATOR = "sei1y3pxq5dp900czh0mkudhjdqjq5m8cpmmps8yjw" ) -func TestEncodePlaceOrder(t *testing.T) { - contractAddr, err := sdk.AccAddressFromBech32("sei1y3pxq5dp900czh0mkudhjdqjq5m8cpmmps8yjw") - require.NoError(t, err) - order := dextypes.Order{ - PositionDirection: dextypes.PositionDirection_LONG, - OrderType: dextypes.OrderType_LIMIT, - PriceDenom: "USDC", - AssetDenom: "SEI", - Price: sdk.MustNewDecFromStr("10"), - Quantity: sdk.OneDec(), - Data: "{\"position_effect\":\"OPEN\", \"leverage\":\"1\"}", - Nominal: sdk.ZeroDec(), - TriggerPrice: sdk.ZeroDec(), - TriggerStatus: false, - } - fund := sdk.NewCoin("usei", sdk.NewInt(1000000000)) - msg := bindings.PlaceOrders{ - Orders: []*dextypes.Order{&order}, - Funds: []sdk.Coin{fund}, - ContractAddr: TEST_TARGET_CONTRACT, - } - serializedMsg, _ := json.Marshal(msg) - - decodedMsgs, err := dexwasm.EncodeDexPlaceOrders(serializedMsg, contractAddr) - require.NoError(t, err) - require.Equal(t, 1, len(decodedMsgs)) - typedDecodedMsg, ok := decodedMsgs[0].(*dextypes.MsgPlaceOrders) - require.True(t, ok) - expectedMsg := dextypes.MsgPlaceOrders{ - Creator: TEST_CREATOR, - Orders: []*dextypes.Order{&order}, - ContractAddr: TEST_TARGET_CONTRACT, - Funds: []sdk.Coin{fund}, - } - require.Equal(t, expectedMsg, *typedDecodedMsg) -} - -func TestDecodeOrderCancellation(t *testing.T) { - contractAddr, err := sdk.AccAddressFromBech32("sei1y3pxq5dp900czh0mkudhjdqjq5m8cpmmps8yjw") - require.NoError(t, err) - msg := bindings.CancelOrders{ - Cancellations: []*types.Cancellation{ - {Id: 1}, - }, - ContractAddr: TEST_TARGET_CONTRACT, - } - serializedMsg, _ := json.Marshal(msg) - - decodedMsgs, err := dexwasm.EncodeDexCancelOrders(serializedMsg, contractAddr) - require.NoError(t, err) - require.Equal(t, 1, len(decodedMsgs)) - typedDecodedMsg, ok := decodedMsgs[0].(*dextypes.MsgCancelOrders) - require.True(t, ok) - expectedMsg := dextypes.MsgCancelOrders{ - Creator: TEST_CREATOR, - Cancellations: []*types.Cancellation{ - {Id: 1, Price: sdk.ZeroDec()}, - }, - ContractAddr: TEST_TARGET_CONTRACT, - } - require.Equal(t, expectedMsg.Creator, typedDecodedMsg.Creator) - require.Equal(t, *expectedMsg.Cancellations[0], *typedDecodedMsg.Cancellations[0]) - require.Equal(t, expectedMsg.ContractAddr, typedDecodedMsg.ContractAddr) -} - func TestEncodeCreateDenom(t *testing.T) { contractAddr, err := sdk.AccAddressFromBech32("sei1y3pxq5dp900czh0mkudhjdqjq5m8cpmmps8yjw") require.NoError(t, err) diff --git a/wasmbinding/test/query_test.go b/wasmbinding/test/query_test.go index c4dd219bb..d02a72f1c 100644 --- a/wasmbinding/test/query_test.go +++ b/wasmbinding/test/query_test.go @@ -1,7 +1,6 @@ package wasmbinding import ( - "context" "encoding/json" "fmt" "testing" @@ -12,13 +11,7 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/sei-protocol/sei-chain/app" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" "github.com/sei-protocol/sei-chain/wasmbinding" - dexcache "github.com/sei-protocol/sei-chain/x/dex/cache" - dexwasm "github.com/sei-protocol/sei-chain/x/dex/client/wasm" - dexbinding "github.com/sei-protocol/sei-chain/x/dex/client/wasm/bindings" - dextypes "github.com/sei-protocol/sei-chain/x/dex/types" - dexutils "github.com/sei-protocol/sei-chain/x/dex/utils" epochwasm "github.com/sei-protocol/sei-chain/x/epoch/client/wasm" epochbinding "github.com/sei-protocol/sei-chain/x/epoch/client/wasm/bindings" epochtypes "github.com/sei-protocol/sei-chain/x/epoch/types" @@ -40,11 +33,10 @@ func SetupWasmbindingTest(t *testing.T) (*app.TestWrapper, func(ctx sdk.Context, testWrapper := app.NewTestWrapper(t, tm, valPub, false) oh := oraclewasm.NewOracleWasmQueryHandler(&testWrapper.App.OracleKeeper) - dh := dexwasm.NewDexWasmQueryHandler(&testWrapper.App.DexKeeper) eh := epochwasm.NewEpochWasmQueryHandler(&testWrapper.App.EpochKeeper) th := tokenfactorywasm.NewTokenFactoryWasmQueryHandler(&testWrapper.App.TokenFactoryKeeper) evmh := evmwasm.NewEVMQueryHandler(&testWrapper.App.EvmKeeper) - qp := wasmbinding.NewQueryPlugin(oh, dh, eh, th, evmh) + qp := wasmbinding.NewQueryPlugin(oh, eh, th, evmh) return testWrapper, wasmbinding.CustomQuerier(qp) } @@ -62,17 +54,6 @@ func TestWasmUnknownQuery(t *testing.T) { require.Error(t, err) require.Equal(t, err, oracletypes.ErrUnknownSeiOracleQuery) - dex_req := dexbinding.SeiDexQuery{} - queryData, err = json.Marshal(dex_req) - require.NoError(t, err) - query = wasmbinding.SeiQueryWrapper{Route: wasmbinding.DexRoute, QueryData: queryData} - rawQuery, err = json.Marshal(query) - require.NoError(t, err) - - _, err = customQuerier(testWrapper.Ctx, rawQuery) - require.Error(t, err) - require.Equal(t, err, dextypes.ErrUnknownSeiDexQuery) - epoch_req := epochbinding.SeiEpochQuery{} queryData, err = json.Marshal(epoch_req) require.NoError(t, err) @@ -180,116 +161,6 @@ func TestWasmGetOracleTwapsErrorHandling(t *testing.T) { require.Equal(t, err, oracletypes.ErrInvalidTwapLookback) } -func TestWasmGetDexTwaps(t *testing.T) { - testWrapper, customQuerier := SetupWasmbindingTest(t) - - req := dexbinding.SeiDexQuery{DexTwaps: &dextypes.QueryGetTwapsRequest{ - ContractAddr: app.TestContract, - LookbackSeconds: 200, - }} - queryData, err := json.Marshal(req) - require.NoError(t, err) - query := wasmbinding.SeiQueryWrapper{Route: wasmbinding.DexRoute, QueryData: queryData} - - rawQuery, err := json.Marshal(query) - require.NoError(t, err) - - testWrapper.Ctx = testWrapper.Ctx.WithBlockHeight(11).WithBlockTime(time.Unix(3600, 0)) - testWrapper.App.DexKeeper.AddRegisteredPair( - testWrapper.Ctx, - app.TestContract, - dextypes.Pair{PriceDenom: "sei", AssetDenom: "atom"}, - ) - testWrapper.App.DexKeeper.SetPriceState(testWrapper.Ctx, dextypes.Price{ - SnapshotTimestampInSeconds: 3600, - Price: sdk.NewDec(20), - Pair: &dextypes.Pair{PriceDenom: "sei", AssetDenom: "atom"}, - }, app.TestContract) - testWrapper.App.OracleKeeper.SetBaseExchangeRate(testWrapper.Ctx, oracleutils.MicroAtomDenom, sdk.NewDec(12)) - testWrapper.Ctx = testWrapper.Ctx.WithBlockHeight(14).WithBlockTime(time.Unix(3700, 0)) - - res, err := customQuerier(testWrapper.Ctx, rawQuery) - require.NoError(t, err) - - var parsedRes dextypes.QueryGetTwapsResponse - err = json.Unmarshal(res, &parsedRes) - require.NoError(t, err) - require.Equal(t, 1, len(parsedRes.Twaps)) - twap := *parsedRes.Twaps[0] - require.Equal(t, "sei", twap.Pair.PriceDenom) - require.Equal(t, "atom", twap.Pair.AssetDenom) - require.Equal(t, sdk.NewDec(20), twap.Twap) -} - -func TestWasmDexGetOrderByIdErrorHandling(t *testing.T) { - testWrapper, customQuerier := SetupWasmbindingTest(t) - - req := dexbinding.SeiDexQuery{GetOrderByID: &dextypes.QueryGetOrderByIDRequest{ - ContractAddr: keepertest.TestContract, - PriceDenom: keepertest.TestPriceDenom, - AssetDenom: keepertest.TestAssetDenom, - Id: 1, - }} - queryData, err := json.Marshal(req) - require.NoError(t, err) - query := wasmbinding.SeiQueryWrapper{Route: wasmbinding.DexRoute, QueryData: queryData} - - rawQuery, err := json.Marshal(query) - require.NoError(t, err) - - _, err = customQuerier(testWrapper.Ctx, rawQuery) - require.Error(t, err) - require.IsType(t, dextypes.ErrInvalidOrderID, err) -} - -func TestWasmGetOrderSimulation(t *testing.T) { - testWrapper, customQuerier := SetupWasmbindingTest(t) - - order := dextypes.Order{ - PositionDirection: dextypes.PositionDirection_LONG, - OrderType: dextypes.OrderType_LIMIT, - PriceDenom: "USDC", - AssetDenom: "SEI", - Price: sdk.MustNewDecFromStr("10"), - Quantity: sdk.OneDec(), - Data: "{\"position_effect\":\"OPEN\", \"leverage\":\"1\"}", - } - - req := dexbinding.SeiDexQuery{GetOrderSimulation: &dextypes.QueryOrderSimulationRequest{ - Order: &order, - }} - queryData, err := json.Marshal(req) - require.NoError(t, err) - query := wasmbinding.SeiQueryWrapper{Route: wasmbinding.DexRoute, QueryData: queryData} - - rawQuery, err := json.Marshal(query) - require.NoError(t, err) - - testWrapper.Ctx = testWrapper.Ctx.WithBlockHeight(11).WithBlockTime(time.Unix(3600, 0)) - testWrapper.Ctx = testWrapper.Ctx.WithContext(context.WithValue(testWrapper.Ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(testWrapper.App.GetMemKey(dextypes.MemStoreKey)))) - testWrapper.App.DexKeeper.AddRegisteredPair( - testWrapper.Ctx, - app.TestContract, - dextypes.Pair{PriceDenom: "sei", AssetDenom: "atom"}, - ) - testWrapper.App.DexKeeper.SetPriceState(testWrapper.Ctx, dextypes.Price{ - SnapshotTimestampInSeconds: 3600, - Price: sdk.NewDec(20), - Pair: &dextypes.Pair{PriceDenom: "sei", AssetDenom: "atom"}, - }, app.TestContract) - testWrapper.App.OracleKeeper.SetBaseExchangeRate(testWrapper.Ctx, oracleutils.MicroAtomDenom, sdk.NewDec(12)) - testWrapper.Ctx = testWrapper.Ctx.WithBlockHeight(14).WithBlockTime(time.Unix(3700, 0)) - testWrapper.Ctx = testWrapper.Ctx.WithContext(context.WithValue(testWrapper.Ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(testWrapper.App.GetMemKey(dextypes.MemStoreKey)))) - - res, err := customQuerier(testWrapper.Ctx, rawQuery) - require.NoError(t, err) - - var parsedRes dextypes.QueryOrderSimulationResponse - err = json.Unmarshal(res, &parsedRes) - require.NoError(t, err) - require.Equal(t, sdk.NewDec(0), *parsedRes.ExecutedQuantity) -} - func TestWasmGetEpoch(t *testing.T) { testWrapper, customQuerier := SetupWasmbindingTest(t) diff --git a/wasmbinding/wasm.go b/wasmbinding/wasm.go index 0d50fb0cb..bc2d492f2 100644 --- a/wasmbinding/wasm.go +++ b/wasmbinding/wasm.go @@ -7,8 +7,6 @@ import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" aclkeeper "github.com/cosmos/cosmos-sdk/x/accesscontrol/keeper" authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" - dexwasm "github.com/sei-protocol/sei-chain/x/dex/client/wasm" - dexkeeper "github.com/sei-protocol/sei-chain/x/dex/keeper" epochwasm "github.com/sei-protocol/sei-chain/x/epoch/client/wasm" epochkeeper "github.com/sei-protocol/sei-chain/x/epoch/keeper" evmwasm "github.com/sei-protocol/sei-chain/x/evm/client/wasm" @@ -21,7 +19,6 @@ import ( func RegisterCustomPlugins( oracle *oraclekeeper.Keeper, - dex *dexkeeper.Keeper, epoch *epochkeeper.Keeper, tokenfactory *tokenfactorykeeper.Keeper, _ *authkeeper.AccountKeeper, @@ -34,12 +31,11 @@ func RegisterCustomPlugins( aclKeeper aclkeeper.Keeper, evmKeeper *evmkeeper.Keeper, ) []wasmkeeper.Option { - dexHandler := dexwasm.NewDexWasmQueryHandler(dex) oracleHandler := oraclewasm.NewOracleWasmQueryHandler(oracle) epochHandler := epochwasm.NewEpochWasmQueryHandler(epoch) tokenfactoryHandler := tokenfactorywasm.NewTokenFactoryWasmQueryHandler(tokenfactory) evmHandler := evmwasm.NewEVMQueryHandler(evmKeeper) - wasmQueryPlugin := NewQueryPlugin(oracleHandler, dexHandler, epochHandler, tokenfactoryHandler, evmHandler) + wasmQueryPlugin := NewQueryPlugin(oracleHandler, epochHandler, tokenfactoryHandler, evmHandler) queryPluginOpt := wasmkeeper.WithQueryPlugins(&wasmkeeper.QueryPlugins{ Custom: CustomQuerier(wasmQueryPlugin), diff --git a/x/dex/README.md b/x/dex/README.md deleted file mode 100644 index fd623e859..000000000 --- a/x/dex/README.md +++ /dev/null @@ -1,57 +0,0 @@ -## Abstract - -Provides fast order matching for CosmWasm contracts. - -## Contents -`dex` provides order placement/cancellation/settlement capabilities for registered contracts, as well as exchange price resulting from the order matching. The implementation of the exchange logic and store writes happen at the end of each block, based on in-memory data passed on by `dex` transactions in the same block. In other words, `DeliverTx` only adds data to memory (a custom data structure, not Cosmos's cache store), and -`EndBlock` uses those in-memory data to perform batched order matching. The `EndBlock` order matching process also involves calling `Sudo` endpoints defined on the registerd contracts, as long as those endpoints conform with the expected interface, so that the registered contracts can perform custom logic based on the exchange information. - -## Concepts -Contract Registration -A contract can be registered with `MsgRegisterContract` type. There are a few related concepts: -### Order-related Sudo Calls -For `dex` to perform order matching for a registered contract, it MUST define 3 `Sudo` endpoints: -- "bulk_order_placements": payload expected can be found in [x/dex/types/order_placement.go] -- "bulk_order_cancellations": payload expected can be found in [x/dex/types/order_cancellation.go] -- "settlement": payload expected can be found in [x/dex/types/settlement.go] -If any of the three endpoints is missing, or if the endpoint is ill-defined, `dex` will skip the contract's order matching. -### Asset Pair Registration -A contract may define one or more tradable pairs with `dex`. For example, a spot trading contract may define a pair with price denomination `USDC` and asset denomination `BTC`. The exact semantics for asset pair registration can be found in the `Governance` section below. A contract with no registered pair is valid - it simply won't have any trading activity in `dex`. -### Rent -A contract must deposit a certain amount of `usei` into `dex` upon registration or through subsequent top-ups. Those `usei`, also known as rent, will be consumed when the contract's `Sudo` endpoints are called based on the gas meter reading, and distributed to Sei validators. Note that if a `Sudo` endpoint fails, it would still charge rent for whatever the gas meter has already recorded before the failure happens. -### Contract Dependencies -A contract may dispatch messages to other contracts as part of its `Sudo` call responses. If that is the case, the contract must declare those other contracts as `Dependencies` in its registration. No circular dependency is allowed. `dex` will check if a dispatched message is against a declared dependency contract, and reject it if it's not declared. -## Batch Order Matching -Orders submitted via MsgPlaceOrders are aggregated at the end of a block and matched in batch. -### Sequence -TODO -### Clearing/Settlement Rules -TODO -## State - -## Governance - -Token pairs can be whitelisted with a contract address to the `dex` module via governance. The following is an example -proposal json to whitelist a token pair. - -```json - "dex": { - "params": { - "code_upload_access": { - "permission": "Everybody" - }, - "instantiate_default_permission": "Everybody" - } - }, -``` - -## Messages - -## Events - -## Parameters - -## Transactions - -## Queries - diff --git a/x/dex/ante.go b/x/dex/ante.go deleted file mode 100644 index 07e891f42..000000000 --- a/x/dex/ante.go +++ /dev/null @@ -1,178 +0,0 @@ -package dex - -import ( - "errors" - "math/big" - - sdk "github.com/cosmos/cosmos-sdk/types" - sdkacltypes "github.com/cosmos/cosmos-sdk/types/accesscontrol" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - dexcache "github.com/sei-protocol/sei-chain/x/dex/cache" - "github.com/sei-protocol/sei-chain/x/dex/keeper" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/sei-protocol/sei-chain/x/dex/utils" -) - -// TickSizeMultipleDecorator check if the place order tx's price is multiple of -// tick size -type TickSizeMultipleDecorator struct { - dexKeeper keeper.Keeper -} - -// NewTickSizeMultipleDecorator returns new ticksize multiple check decorator instance -func NewTickSizeMultipleDecorator(dexKeeper keeper.Keeper) TickSizeMultipleDecorator { - return TickSizeMultipleDecorator{ - dexKeeper: dexKeeper, - } -} - -// AnteHandle is the interface called in RunTx() function, which CheckTx() calls with the runTxModeCheck mode -func (tsmd TickSizeMultipleDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { - if ctx.IsReCheckTx() { - return next(ctx, tx, simulate) - } - if !simulate { - if ctx.IsCheckTx() { - err := tsmd.CheckTickSizeMultiple(ctx, tx.GetMsgs()) - if err != nil { - return ctx, err - } - } - } - return next(ctx, tx, simulate) -} - -// CheckTickSizeMultiple checks whether the msgs comply with ticksize -func (tsmd TickSizeMultipleDecorator) CheckTickSizeMultiple(ctx sdk.Context, msgs []sdk.Msg) error { - for _, msg := range msgs { - switch msg.(type) { //nolint:gocritic,gosimple // the linter is telling us we can make this faster, and this should be addressed later. - case *types.MsgPlaceOrders: - msgPlaceOrders := msg.(*types.MsgPlaceOrders) //nolint:gosimple // the linter is telling us we can make this faster, and this should be addressed later. - contractAddr := msgPlaceOrders.ContractAddr - for _, order := range msgPlaceOrders.Orders { - priceTickSize, found := tsmd.dexKeeper.GetPriceTickSizeForPair(ctx, contractAddr, - types.Pair{ - PriceDenom: order.PriceDenom, - AssetDenom: order.AssetDenom, - }) - if !found { - return sdkerrors.Wrapf(sdkerrors.ErrKeyNotFound, "the pair {price:%s,asset:%s} has no price ticksize configured", order.PriceDenom, order.AssetDenom) - } - if !IsDecimalMultipleOf(order.Price, priceTickSize) { - // Allow Market Orders with Price 0 - if !(IsMarketOrder(order) && order.Price.IsZero()) { - return sdkerrors.Wrapf(errors.New("ErrPriceNotMultipleOfTickSize"), "price needs to be non-zero and multiple of price tick size") - } - } - quantityTickSize, found := tsmd.dexKeeper.GetQuantityTickSizeForPair(ctx, contractAddr, - types.Pair{ - PriceDenom: order.PriceDenom, - AssetDenom: order.AssetDenom, - }) - if !found { - return sdkerrors.Wrapf(sdkerrors.ErrKeyNotFound, "the pair {price:%s,asset:%s} has no quantity ticksize configured", order.PriceDenom, order.AssetDenom) - } - if !IsDecimalMultipleOf(order.Quantity, quantityTickSize) { - return sdkerrors.Wrapf(errors.New("ErrQuantityNotMultipleOfTickSize"), "quantity needs to be non-zero and multiple of quantity tick size") - } - } - continue - default: - // e.g. liquidation order don't come with price so always pass this check - return nil - } - } - - return nil -} - -// Check whether order is market order type -func IsMarketOrder(order *types.Order) bool { - return order.OrderType == types.OrderType_MARKET || order.OrderType == types.OrderType_FOKMARKET || order.OrderType == types.OrderType_FOKMARKETBYVALUE -} - -// Check whether decimal a is multiple of decimal b -func IsDecimalMultipleOf(a, b sdk.Dec) bool { - if a.LT(b) { - return false - } - quotient := sdk.NewDecFromBigInt(a.Quo(b).RoundInt().BigInt()) - return quotient.Mul(b).Equal(a) -} - -const DexGasFeeUnit = "usei" - -type CheckDexGasDecorator struct { - dexKeeper keeper.Keeper - checkTxMemState *dexcache.MemState -} - -func NewCheckDexGasDecorator(dexKeeper keeper.Keeper, checkTxMemState *dexcache.MemState) CheckDexGasDecorator { - return CheckDexGasDecorator{ - dexKeeper: dexKeeper, - checkTxMemState: checkTxMemState, - } -} - -// for a TX that contains dex gas-incurring messages, check if it provides enough gas based on dex params -func (d CheckDexGasDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { - if ctx.IsReCheckTx() { - return next(ctx, tx, simulate) - } - params := d.dexKeeper.GetParams(ctx) - dexGasRequired := uint64(0) - var memState *dexcache.MemState - if ctx.IsCheckTx() { - memState = d.checkTxMemState - } else { - memState = utils.GetMemState(ctx.Context()) - } - for _, msg := range tx.GetMsgs() { - switch m := msg.(type) { - case *types.MsgPlaceOrders: - numDependencies := len(memState.GetContractToDependencies(ctx, m.ContractAddr, d.dexKeeper.GetContractWithoutGasCharge)) - dexGasRequired += params.DefaultGasPerOrder * uint64(len(m.Orders)*numDependencies) - for _, order := range m.Orders { - dexGasRequired += params.DefaultGasPerOrderDataByte * uint64(len(order.Data)) - } - case *types.MsgCancelOrders: - numDependencies := len(memState.GetContractToDependencies(ctx, m.ContractAddr, d.dexKeeper.GetContractWithoutGasCharge)) - dexGasRequired += params.DefaultGasPerCancel * uint64(len(m.Cancellations)*numDependencies) - } - } - if dexGasRequired == 0 { - return next(ctx, tx, simulate) - } - dexFeeRequired := sdk.NewDecFromBigInt(new(big.Int).SetUint64(dexGasRequired)).Mul(params.SudoCallGasPrice).RoundInt() - feeTx, ok := tx.(sdk.FeeTx) - if !ok { - return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx") - } - for _, fee := range feeTx.GetFee() { - if fee.Denom == DexGasFeeUnit && fee.Amount.GTE(dexFeeRequired) { - return next(ctx, tx, simulate) - } - } - return ctx, sdkerrors.ErrInsufficientFee -} - -func (d CheckDexGasDecorator) AnteDeps(txDeps []sdkacltypes.AccessOperation, tx sdk.Tx, txIndex int, next sdk.AnteDepGenerator) (newTxDeps []sdkacltypes.AccessOperation, err error) { - deps := []sdkacltypes.AccessOperation{} - for _, msg := range tx.GetMsgs() { - // Error checking will be handled in AnteHandler - switch msg.(type) { - case *types.MsgPlaceOrders, *types.MsgCancelOrders: - deps = append(deps, []sdkacltypes.AccessOperation{ - // read the dex contract info - { - ResourceType: sdkacltypes.ResourceType_KV_DEX_CONTRACT, - AccessType: sdkacltypes.AccessType_READ, - IdentifierTemplate: "*", - }, - }...) - default: - continue - } - } - return next(append(txDeps, deps...), tx, txIndex) -} diff --git a/x/dex/ante_test.go b/x/dex/ante_test.go deleted file mode 100644 index 4d9ab4205..000000000 --- a/x/dex/ante_test.go +++ /dev/null @@ -1,283 +0,0 @@ -package dex_test - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex" - dexcache "github.com/sei-protocol/sei-chain/x/dex/cache" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -type TestTx struct { - msgs []sdk.Msg - gas uint64 - fee sdk.Coins -} - -func (tx TestTx) GetMsgs() []sdk.Msg { - return tx.msgs -} - -func (tx TestTx) ValidateBasic() error { - return nil -} - -func (tx TestTx) GetGas() uint64 { - return tx.gas -} -func (tx TestTx) GetFee() sdk.Coins { - return tx.fee -} -func (tx TestTx) FeePayer() sdk.AccAddress { - return nil -} -func (tx TestTx) FeeGranter() sdk.AccAddress { - return nil -} - -func TestIsDecimalMultipleOf(t *testing.T) { - v1, _ := sdk.NewDecFromStr("2.4") - v2, _ := sdk.NewDecFromStr("1.2") - v3, _ := sdk.NewDecFromStr("2") - v4, _ := sdk.NewDecFromStr("100.5") - v5, _ := sdk.NewDecFromStr("0.5") - v6, _ := sdk.NewDecFromStr("1.5") - v7, _ := sdk.NewDecFromStr("1.01") - v8, _ := sdk.NewDecFromStr("3") - v9, _ := sdk.NewDecFromStr("5.4") - v10, _ := sdk.NewDecFromStr("0.3") - - assert.True(t, dex.IsDecimalMultipleOf(v1, v2)) - assert.True(t, !dex.IsDecimalMultipleOf(v2, v1)) - assert.True(t, !dex.IsDecimalMultipleOf(v3, v2)) - assert.True(t, dex.IsDecimalMultipleOf(v3, v5)) - assert.True(t, !dex.IsDecimalMultipleOf(v3, v6)) - assert.True(t, dex.IsDecimalMultipleOf(v4, v5)) - assert.True(t, !dex.IsDecimalMultipleOf(v2, v1)) - assert.True(t, dex.IsDecimalMultipleOf(v6, v5)) - assert.True(t, !dex.IsDecimalMultipleOf(v7, v3)) - assert.True(t, dex.IsDecimalMultipleOf(v8, v6)) - assert.True(t, dex.IsDecimalMultipleOf(v9, v10)) -} - -func TestCheckDexGasDecorator(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - decorator := dex.NewCheckDexGasDecorator(*keeper, dexcache.NewMemState(keeper.GetMemStoreKey())) - terminator := func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, err error) { return ctx, nil } - tx := TestTx{ - msgs: []sdk.Msg{ - types.NewMsgPlaceOrders("someone", []*types.Order{{}, {}}, keepertest.TestContract, sdk.NewCoins()), - types.NewMsgCancelOrders("someone", []*types.Cancellation{{}, {}, {}}, keepertest.TestContract), - }, - fee: sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(27500))), - } - _, err := decorator.AnteHandle(ctx, tx, false, terminator) - require.Nil(t, err) - tx = TestTx{ - msgs: []sdk.Msg{ - types.NewMsgPlaceOrders("someone", []*types.Order{{}, {}}, keepertest.TestContract, sdk.NewCoins()), - types.NewMsgCancelOrders("someone", []*types.Cancellation{{}, {}, {}}, keepertest.TestContract), - }, - fee: sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(25499))), - } - _, err = decorator.AnteHandle(ctx, tx, false, terminator) - require.NotNil(t, err) - tx = TestTx{ - msgs: []sdk.Msg{ - types.NewMsgPlaceOrders("someone", []*types.Order{{}}, keepertest.TestContract, sdk.NewCoins()), - }, - } - _, err = decorator.AnteHandle(ctx, tx, false, terminator) - require.NotNil(t, err) - tx = TestTx{ - msgs: []sdk.Msg{}, - } - _, err = decorator.AnteHandle(ctx, tx, false, terminator) - require.Nil(t, err) - tx = TestTx{ - msgs: []sdk.Msg{types.NewMsgContractDepositRent(keepertest.TestContract, 10, keepertest.TestAccount)}, - } - _, err = decorator.AnteHandle(ctx, tx, false, terminator) - require.Nil(t, err) - - // with data (insufficient fee) - tx = TestTx{ - msgs: []sdk.Msg{ - types.NewMsgPlaceOrders("someone", []*types.Order{{Data: "data"}, {}}, keepertest.TestContract, sdk.NewCoins()), - }, - fee: sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(11011))), - } - _, err = decorator.AnteHandle(ctx, tx, false, terminator) - require.NotNil(t, err) - - // with data (sufficient fee) - tx = TestTx{ - msgs: []sdk.Msg{ - types.NewMsgPlaceOrders("someone", []*types.Order{{Data: "data"}, {}}, keepertest.TestContract, sdk.NewCoins()), - }, - fee: sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(11012))), - } - _, err = decorator.AnteHandle(ctx, tx, false, terminator) - require.Nil(t, err) -} - -func TestTickSizeMultipleDecorator(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - ctx = ctx.WithIsCheckTx(true) - decorator := dex.NewTickSizeMultipleDecorator(*keeper) - terminator := func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, err error) { return ctx, nil } - - keeper.AddRegisteredPair(ctx, "contract", keepertest.TestPair) - keeper.SetPriceTickSizeForPair(ctx, "contract", keepertest.TestPair, *keepertest.TestPair.PriceTicksize) - keeper.SetQuantityTickSizeForPair(ctx, "contract", keepertest.TestPair, *keepertest.TestPair.PriceTicksize) - - price, _ := sdk.NewDecFromStr("25") - quantity, _ := sdk.NewDecFromStr("5") - smallerVal, _ := sdk.NewDecFromStr("0.01") - - // Market order with price zero allowed - tx := TestTx{ - msgs: []sdk.Msg{ - types.NewMsgPlaceOrders("someone", []*types.Order{{ - ContractAddr: "contract", - PriceDenom: keepertest.TestPair.PriceDenom, - AssetDenom: keepertest.TestPair.AssetDenom, - Price: sdk.ZeroDec(), - Quantity: quantity, - OrderType: types.OrderType_MARKET, - }}, "contract", sdk.NewCoins())}, - fee: sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(27500))), - } - _, err := decorator.AnteHandle(ctx, tx, false, terminator) - require.Nil(t, err) - - tx = TestTx{ - msgs: []sdk.Msg{ - types.NewMsgPlaceOrders("someone", []*types.Order{{ - ContractAddr: "contract", - PriceDenom: keepertest.TestPair.PriceDenom, - AssetDenom: keepertest.TestPair.AssetDenom, - Price: sdk.ZeroDec(), - Quantity: quantity, - OrderType: types.OrderType_FOKMARKET, - }}, "contract", sdk.NewCoins())}, - fee: sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(27500))), - } - _, err = decorator.AnteHandle(ctx, tx, false, terminator) - require.Nil(t, err) - - tx = TestTx{ - msgs: []sdk.Msg{ - types.NewMsgPlaceOrders("someone", []*types.Order{{ - ContractAddr: "contract", - PriceDenom: keepertest.TestPair.PriceDenom, - AssetDenom: keepertest.TestPair.AssetDenom, - Price: sdk.ZeroDec(), - Quantity: quantity, - OrderType: types.OrderType_FOKMARKETBYVALUE, - }}, "contract", sdk.NewCoins())}, - fee: sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(27500))), - } - _, err = decorator.AnteHandle(ctx, tx, false, terminator) - require.Nil(t, err) - - // Non-market orders with price zero not allowed - tx = TestTx{ - msgs: []sdk.Msg{ - types.NewMsgPlaceOrders("someone", []*types.Order{{ - ContractAddr: "contract", - PriceDenom: keepertest.TestPair.PriceDenom, - AssetDenom: keepertest.TestPair.AssetDenom, - Price: sdk.ZeroDec(), - Quantity: quantity, - OrderType: types.OrderType_LIMIT, - }}, "contract", sdk.NewCoins())}, - fee: sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(27500))), - } - _, err = decorator.AnteHandle(ctx, tx, false, terminator) - require.NotNil(t, err) - - // Non-zero Priced Market Order With Divisible Price - tx = TestTx{ - msgs: []sdk.Msg{ - types.NewMsgPlaceOrders("someone", []*types.Order{{ - ContractAddr: "contract", - PriceDenom: keepertest.TestPair.PriceDenom, - AssetDenom: keepertest.TestPair.AssetDenom, - Price: price, - Quantity: quantity, - OrderType: types.OrderType_MARKET, - }}, "contract", sdk.NewCoins())}, - fee: sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(27500))), - } - _, err = decorator.AnteHandle(ctx, tx, false, terminator) - require.Nil(t, err) - - // Non-zero Priced Market Order Without Divisible Price - tx = TestTx{ - msgs: []sdk.Msg{ - types.NewMsgPlaceOrders("someone", []*types.Order{{ - ContractAddr: "contract", - PriceDenom: keepertest.TestPair.PriceDenom, - AssetDenom: keepertest.TestPair.AssetDenom, - Price: smallerVal, - Quantity: quantity, - OrderType: types.OrderType_MARKET, - }}, "contract", sdk.NewCoins())}, - fee: sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(27500))), - } - _, err = decorator.AnteHandle(ctx, tx, false, terminator) - require.NotNil(t, err) - - // Limit Order With Divisible Price - tx = TestTx{ - msgs: []sdk.Msg{ - types.NewMsgPlaceOrders("someone", []*types.Order{{ - ContractAddr: "contract", - PriceDenom: keepertest.TestPair.PriceDenom, - AssetDenom: keepertest.TestPair.AssetDenom, - Price: price, - Quantity: quantity, - OrderType: types.OrderType_LIMIT, - }}, "contract", sdk.NewCoins())}, - fee: sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(27500))), - } - _, err = decorator.AnteHandle(ctx, tx, false, terminator) - require.Nil(t, err) - - // Limit Orders without Divisible Price - tx = TestTx{ - msgs: []sdk.Msg{ - types.NewMsgPlaceOrders("someone", []*types.Order{{ - ContractAddr: "contract", - PriceDenom: keepertest.TestPair.PriceDenom, - AssetDenom: keepertest.TestPair.AssetDenom, - Price: smallerVal, - Quantity: quantity, - OrderType: types.OrderType_LIMIT, - }}, "contract", sdk.NewCoins())}, - fee: sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(27500))), - } - _, err = decorator.AnteHandle(ctx, tx, false, terminator) - require.NotNil(t, err) - - // All order quantities must be divisible by quantity tick size - tx = TestTx{ - msgs: []sdk.Msg{ - types.NewMsgPlaceOrders("someone", []*types.Order{{ - ContractAddr: "contract", - PriceDenom: keepertest.TestPair.PriceDenom, - AssetDenom: keepertest.TestPair.AssetDenom, - Price: price, - Quantity: smallerVal, - OrderType: types.OrderType_LIMIT, - }}, "contract", sdk.NewCoins())}, - fee: sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(27500))), - } - _, err = decorator.AnteHandle(ctx, tx, false, terminator) - require.NotNil(t, err) -} diff --git a/x/dex/cache/cache.go b/x/dex/cache/cache.go deleted file mode 100644 index 915843d9c..000000000 --- a/x/dex/cache/cache.go +++ /dev/null @@ -1,318 +0,0 @@ -package dex - -import ( - "fmt" - "sync" - "time" - - "github.com/cosmos/cosmos-sdk/store/prefix" - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/sei-protocol/sei-chain/utils/datastructures" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -const SynchronizationTimeoutInSeconds = 5 - -type MemState struct { - storeKey sdk.StoreKey - - // TODO: all of these need to be in the memstore - contractsToProcessMtx *sync.RWMutex - contractsToDepsMtx *sync.Mutex -} - -func NewMemState(storeKey sdk.StoreKey) *MemState { - return &MemState{ - storeKey: storeKey, - contractsToDepsMtx: &sync.Mutex{}, - contractsToProcessMtx: &sync.RWMutex{}, - } -} - -func (s *MemState) GetAllBlockOrders(ctx sdk.Context, contractAddr types.ContractAddress) (list []*types.Order) { - s.SynchronizeAccess(ctx, contractAddr) - store := prefix.NewStore( - ctx.KVStore(s.storeKey), - types.MemOrderPrefix( - string(contractAddr), - ), - ) - iterator := sdk.KVStorePrefixIterator(store, []byte{}) - - defer iterator.Close() - - for ; iterator.Valid(); iterator.Next() { - var val types.Order - if err := val.Unmarshal(iterator.Value()); err != nil { - panic(err) - } - list = append(list, &val) - } - return -} - -func (s *MemState) GetBlockOrders(ctx sdk.Context, contractAddr types.ContractAddress, pair types.Pair) *BlockOrders { - s.SynchronizeAccess(ctx, contractAddr) - return NewOrders( - prefix.NewStore( - ctx.KVStore(s.storeKey), - types.MemOrderPrefixForPair( - string(contractAddr), pair.PriceDenom, pair.AssetDenom, - ), - ), - ) -} - -func (s *MemState) GetBlockCancels(ctx sdk.Context, contractAddr types.ContractAddress, pair types.Pair) *BlockCancellations { - s.SynchronizeAccess(ctx, contractAddr) - return NewCancels( - prefix.NewStore( - ctx.KVStore(s.storeKey), - types.MemCancelPrefixForPair( - string(contractAddr), pair.PriceDenom, pair.AssetDenom, - ), - ), - ) -} - -func (s *MemState) GetDepositInfo(ctx sdk.Context, contractAddr types.ContractAddress) *DepositInfo { - s.SynchronizeAccess(ctx, contractAddr) - return NewDepositInfo( - prefix.NewStore( - ctx.KVStore(s.storeKey), - types.MemDepositPrefix(string(contractAddr)), - ), - ) -} - -func (s *MemState) GetContractToDependencies(ctx sdk.Context, contractAddress string, loader func(sdk.Context, string) (types.ContractInfoV2, error)) []string { - s.contractsToDepsMtx.Lock() - defer s.contractsToDepsMtx.Unlock() - - store := ctx.KVStore(s.storeKey) - - // GET from memstate - bz := store.Get(types.MemDownstreamContractsKey(contractAddress)) - if bz != nil { - var contracts types.DownsteamContracts - if err := contracts.Unmarshal(bz); err != nil { - panic(err) - } - return contracts.ContractAddrs - } - loadedDownstreams := GetAllDownstreamContracts(ctx, contractAddress, loader) - // if we have to get all downstreams, save them to memstate - downstreamContracts := types.DownsteamContracts{ - ContractAddrs: loadedDownstreams, - } - contractsBz, err := downstreamContracts.Marshal() - if err != nil { - panic(err) - } - store.Set(types.MemDownstreamContractsKey(contractAddress), contractsBz) - return loadedDownstreams -} - -func (s *MemState) ClearContractToDependencies(ctx sdk.Context) { - s.contractsToDepsMtx.Lock() - defer s.contractsToDepsMtx.Unlock() - DeepDelete(ctx.KVStore(s.storeKey), types.KeyPrefix(types.MemDownstreamContracts), func(_ []byte) bool { return true }) -} - -func (s *MemState) SetDownstreamsToProcess(ctx sdk.Context, contractAddress string, loader func(sdk.Context, string) (types.ContractInfoV2, error)) { - s.contractsToProcessMtx.Lock() - defer s.contractsToProcessMtx.Unlock() - contracts := s.GetContractToDependencies(ctx, contractAddress, loader) - store := ctx.KVStore(s.storeKey) - for _, contract := range contracts { - // Add each to memstate instead - simply set to 1 for some value indicating presence - store.Set(types.MemContractsToProcessKey(contract), []byte{1}) - } -} - -func (s *MemState) ContractsToProcessContains(ctx sdk.Context, contractAddress string) bool { - s.contractsToProcessMtx.RLock() - defer s.contractsToProcessMtx.RUnlock() - store := ctx.KVStore(s.storeKey) - return store.Has(types.MemContractsToProcessKey(contractAddress)) -} - -func (s *MemState) GetContractToProcessOrderedSlice(ctx sdk.Context) []string { - s.contractsToProcessMtx.RLock() - defer s.contractsToProcessMtx.RUnlock() - orderedContracts := []string{} - store := ctx.KVStore(s.storeKey) - iter := sdk.KVStorePrefixIterator(store, types.KeyPrefix(types.MemContractsToProcess)) - for ; iter.Valid(); iter.Next() { - // get key - key := iter.Key() - // because we know length prefix is 1 byte, and the rest of the key is ONLY the contract addr, this lets us get the contract address bytes - contractAddrBytes := key[len(types.KeyPrefix(types.MemContractsToProcess))+1:] - // parse contract address from key - contractAddr := sdk.AccAddress(contractAddrBytes).String() - orderedContracts = append(orderedContracts, contractAddr) - } - return orderedContracts -} - -func (s *MemState) Clear(ctx sdk.Context) { - s.contractsToProcessMtx.Lock() - defer s.contractsToProcessMtx.Unlock() - DeepDelete(ctx.KVStore(s.storeKey), types.KeyPrefix(types.MemOrderKey), func(_ []byte) bool { return true }) - DeepDelete(ctx.KVStore(s.storeKey), types.KeyPrefix(types.MemCancelKey), func(_ []byte) bool { return true }) - DeepDelete(ctx.KVStore(s.storeKey), types.KeyPrefix(types.MemDepositKey), func(_ []byte) bool { return true }) - DeepDelete(ctx.KVStore(s.storeKey), types.KeyPrefix(types.MemContractsToProcess), func(_ []byte) bool { return true }) -} - -func (s *MemState) ClearCancellationForPair(ctx sdk.Context, contractAddr types.ContractAddress, pair types.Pair) { - s.SynchronizeAccess(ctx, contractAddr) - DeepDelete(ctx.KVStore(s.storeKey), types.KeyPrefix(types.MemCancelKey), func(v []byte) bool { - var c types.Cancellation - if err := c.Unmarshal(v); err != nil { - panic(err) - } - return c.ContractAddr == string(contractAddr) && c.PriceDenom == pair.PriceDenom && c.AssetDenom == pair.AssetDenom - }) -} - -func (s *MemState) DeepCopy() *MemState { - return &MemState{ - storeKey: s.storeKey, - contractsToDepsMtx: s.contractsToDepsMtx, // passing by pointer - contractsToProcessMtx: s.contractsToProcessMtx, // passing by pointer - } -} - -func (s *MemState) DeepFilterAccount(ctx sdk.Context, account string) { - DeepDelete(ctx.KVStore(s.storeKey), types.KeyPrefix(types.MemOrderKey), func(v []byte) bool { - var o types.Order - if err := o.Unmarshal(v); err != nil { - panic(err) - } - return o.Account == account - }) - DeepDelete(ctx.KVStore(s.storeKey), types.KeyPrefix(types.MemCancelKey), func(v []byte) bool { - var c types.Cancellation - if err := c.Unmarshal(v); err != nil { - panic(err) - } - return c.Creator == account - }) - DeepDelete(ctx.KVStore(s.storeKey), types.KeyPrefix(types.MemDepositKey), func(v []byte) bool { - var d types.DepositInfoEntry - if err := d.Unmarshal(v); err != nil { - panic(err) - } - return d.Creator == account - }) -} - -func (s *MemState) SynchronizeAccess(ctx sdk.Context, contractAddr types.ContractAddress) { - executingContract := GetExecutingContract(ctx) - if executingContract == nil { - // not accessed by contract. no need to synchronize - return - } - targetContractAddr := string(contractAddr) - if executingContract.ContractAddr == targetContractAddr { - // access by the contract itself does not need synchronization - return - } - for _, dependency := range executingContract.Dependencies { - if dependency.Dependency != targetContractAddr { - continue - } - terminationSignals := GetTerminationSignals(ctx) - if terminationSignals == nil { - // synchronization should fail in the case of no termination signal to prevent race conditions. - panic("no termination signal map found in context") - } - targetChannel, ok := terminationSignals.Load(dependency.ImmediateElderSibling) - if !ok { - // synchronization should fail in the case of no termination signal to prevent race conditions. - panic(fmt.Sprintf("no termination signal channel for contract %s in context", dependency.ImmediateElderSibling)) - } - - select { - case <-targetChannel: - // since buffered channel can only be consumed once, we need to - // requeue so that it can unblock other goroutines that waits for - // the same channel. - targetChannel <- struct{}{} - case <-time.After(SynchronizationTimeoutInSeconds * time.Second): - // synchronization should fail in the case of timeout to prevent race conditions. - panic(fmt.Sprintf("timing out waiting for termination of %s", dependency.ImmediateElderSibling)) - } - - return - } - - // fail loudly so that the offending contract can be rolled back. - // eventually we will automatically de-register contracts that have to be rolled back - // so that this would not become a point of attack in terms of performance. - panic(fmt.Sprintf("Contract %s trying to access state of %s which is not a registered dependency", executingContract.ContractAddr, targetContractAddr)) -} - -func DeepDelete(kvStore sdk.KVStore, storePrefix []byte, matcher func([]byte) bool) { - store := prefix.NewStore( - kvStore, - storePrefix, - ) - // Getting all KVs first before applying `matcher` in case `matcher` contains - // store read/write logics. - // Wrapping getter into its own function to make sure iterator is always closed - // before `matcher` logic runs. - keyValuesGetter := func() ([][]byte, [][]byte) { - iterator := sdk.KVStorePrefixIterator(store, []byte{}) - defer iterator.Close() - keys, values := [][]byte{}, [][]byte{} - for ; iterator.Valid(); iterator.Next() { - keys = append(keys, iterator.Key()) - values = append(values, iterator.Value()) - } - return keys, values - } - keys, values := keyValuesGetter() - for i, key := range keys { - if matcher(values[i]) { - store.Delete(key) - } - } -} - -// BFS traversal over a acyclic graph -// Includes the root contract itself. -func GetAllDownstreamContracts(ctx sdk.Context, contractAddress string, loader func(sdk.Context, string) (types.ContractInfoV2, error)) []string { - res := []string{contractAddress} - seen := datastructures.NewSyncSet(res) - downstreams := []*types.ContractInfoV2{} - populater := func(target *types.ContractInfoV2) { - for _, dep := range target.Dependencies { - if downstream, err := loader(ctx, dep.Dependency); err == nil && !seen.Contains(downstream.ContractAddr) { - if !downstream.Suspended { - downstreams = append(downstreams, &downstream) - seen.Add(downstream.ContractAddr) - } - } else { - // either getting the dependency returned an error, or there is a cycle in the graph. Either way - // is bad and should cause the triggering tx to fail - panic(fmt.Sprintf("getting dependency %s for %s returned an error, or there is a cycle in the dependency graph", dep.Dependency, target.ContractAddr)) - } - } - } - // init first layer downstreams - if contract, err := loader(ctx, contractAddress); err == nil { - populater(&contract) - } else { - return res - } - - for len(downstreams) > 0 { - downstream := downstreams[0] - res = append(res, downstream.ContractAddr) - populater(downstream) - downstreams = downstreams[1:] - } - return res -} diff --git a/x/dex/cache/cache_test.go b/x/dex/cache/cache_test.go deleted file mode 100644 index c6603e791..000000000 --- a/x/dex/cache/cache_test.go +++ /dev/null @@ -1,225 +0,0 @@ -package dex_test - -import ( - "context" - "testing" - - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/utils/datastructures" - dex "github.com/sei-protocol/sei-chain/x/dex/cache" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/sei-protocol/sei-chain/x/store" - "github.com/stretchr/testify/require" -) - -const ( - TEST_CONTRACT = "test" -) - -func TestDeepCopy(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - stateOne := dex.NewMemState(keeper.GetMemStoreKey()) - stateOne.GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Order{ - Id: 1, - Account: "test", - ContractAddr: TEST_CONTRACT, - }) - stateTwo := stateOne.DeepCopy() - cachedCtx, _ := store.GetCachedContext(ctx) - stateTwo.GetBlockOrders(cachedCtx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Order{ - Id: 2, - Account: "test", - ContractAddr: TEST_CONTRACT, - }) - // old state must not be changed - require.Equal(t, 1, len(stateOne.GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Get())) - // new state must be changed - require.Equal(t, 2, len(stateTwo.GetBlockOrders(cachedCtx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Get())) -} - -func TestDeepFilterAccounts(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - stateOne := dex.NewMemState(keeper.GetMemStoreKey()) - stateOne.GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Order{ - Id: 1, - Account: "test", - ContractAddr: TEST_CONTRACT, - }) - stateOne.GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Order{ - Id: 2, - Account: "test2", - ContractAddr: TEST_CONTRACT, - }) - stateOne.GetBlockCancels(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Cancellation{ - Id: 1, - Creator: "test", - }) - stateOne.GetBlockCancels(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Cancellation{ - Id: 2, - Creator: "test2", - }) - stateOne.GetDepositInfo(ctx, types.ContractAddress(TEST_CONTRACT)).Add(&types.DepositInfoEntry{ - Creator: "test", - }) - stateOne.GetDepositInfo(ctx, types.ContractAddress(TEST_CONTRACT)).Add(&types.DepositInfoEntry{ - Creator: "test2", - }) - - stateOne.DeepFilterAccount(ctx, "test") - require.Equal(t, 1, len(stateOne.GetAllBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT)))) - require.Equal(t, 1, len(stateOne.GetBlockCancels(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Get())) - require.Equal(t, 1, len(stateOne.GetDepositInfo(ctx, types.ContractAddress(TEST_CONTRACT)).Get())) -} - -func TestDeepDelete(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - stateOne := dex.NewMemState(keeper.GetMemStoreKey()) - stateOne.GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Order{ - Id: 1, - Account: "test", - ContractAddr: TEST_CONTRACT, - }) - dex.DeepDelete(ctx.KVStore(keeper.GetStoreKey()), types.KeyPrefix(types.MemOrderKey), func(_ []byte) bool { return true }) -} - -func TestClear(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - stateOne := dex.NewMemState(keeper.GetMemStoreKey()) - stateOne.GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Order{ - Id: 1, - Account: "test", - ContractAddr: TEST_CONTRACT, - }) - stateOne.GetBlockCancels(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Cancellation{ - Id: 2, - ContractAddr: TEST_CONTRACT, - }) - stateOne.Clear(ctx) - require.Equal(t, 0, len(stateOne.GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Get())) - require.Equal(t, 0, len(stateOne.GetBlockCancels(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Get())) -} - -func TestClearCancellationForPair(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - stateOne := dex.NewMemState(keeper.GetMemStoreKey()) - stateOne.GetBlockCancels(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Cancellation{ - Id: 1, - ContractAddr: TEST_CONTRACT, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }) - stateOne.GetBlockCancels(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Cancellation{ - Id: 2, - ContractAddr: TEST_CONTRACT, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }) - stateOne.GetBlockCancels(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Cancellation{ - Id: 3, - ContractAddr: TEST_CONTRACT, - PriceDenom: "USDC", - AssetDenom: "SEI", - }) - stateOne.ClearCancellationForPair(ctx, TEST_CONTRACT, types.Pair{ - PriceDenom: "USDC", - AssetDenom: "ATOM", - }) - require.Equal(t, 1, len(stateOne.GetBlockCancels(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Get())) - require.Equal(t, uint64(3), stateOne.GetBlockCancels(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Get()[0].Id) -} - -func TestSynchronization(t *testing.T) { - k, ctx := keepertest.DexKeeper(t) - stateOne := dex.NewMemState(k.GetMemStoreKey()) - targetContract := types.ContractAddress(TEST_CONTRACT) - // no go context - require.NotPanics(t, func() { stateOne.SynchronizeAccess(ctx, targetContract) }) - // no executing contract - goCtx := context.Background() - ctx = ctx.WithContext(goCtx) - require.NotPanics(t, func() { stateOne.SynchronizeAccess(ctx, targetContract) }) - // executing contract same as target contract - executingContract := types.ContractInfoV2{ContractAddr: TEST_CONTRACT} - ctx = ctx.WithContext(context.WithValue(goCtx, dex.CtxKeyExecutingContract, executingContract)) - require.NotPanics(t, func() { stateOne.SynchronizeAccess(ctx, targetContract) }) - // executing contract attempting to access non-dependency - executingContract.ContractAddr = "executing" - ctx = ctx.WithContext(context.WithValue(goCtx, dex.CtxKeyExecutingContract, executingContract)) - require.Panics(t, func() { stateOne.SynchronizeAccess(ctx, targetContract) }) - // no termination map - executingContract.Dependencies = []*types.ContractDependencyInfo{ - {Dependency: TEST_CONTRACT, ImmediateElderSibling: "elder"}, - } - ctx = ctx.WithContext(context.WithValue(goCtx, dex.CtxKeyExecutingContract, executingContract)) - require.Panics(t, func() { stateOne.SynchronizeAccess(ctx, targetContract) }) - // no termination signal channel for sibling - terminationSignals := datastructures.NewTypedSyncMap[string, chan struct{}]() - goCtx = context.WithValue(goCtx, dex.CtxKeyExecutingContract, executingContract) - goCtx = context.WithValue(goCtx, dex.CtxKeyExecTermSignal, terminationSignals) - ctx = ctx.WithContext(goCtx) - require.Panics(t, func() { stateOne.SynchronizeAccess(ctx, targetContract) }) - // termination signal times out - siblingChan := make(chan struct{}, 1) - terminationSignals.Store("elder", siblingChan) - require.Panics(t, func() { stateOne.SynchronizeAccess(ctx, targetContract) }) - // termination signal sent - go func() { - siblingChan <- struct{}{} - }() - require.NotPanics(t, func() { stateOne.SynchronizeAccess(ctx, targetContract) }) - <-siblingChan // the channel should be re-populated -} - -func TestGetAllDownstreamContracts(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - keeper.SetContract(ctx, &types.ContractInfoV2{ - ContractAddr: "sei1cnuw3f076wgdyahssdkd0g3nr96ckq8cwa2mh029fn5mgf2fmcmsae2elf", - Dependencies: []*types.ContractDependencyInfo{ - { - Dependency: "sei1ery8l6jquynn9a4cz2pff6khg8c68f7urt33l5n9dng2cwzz4c4q4hncrd", - }, - }, - }) - keeper.SetContract(ctx, &types.ContractInfoV2{ - ContractAddr: "sei1ery8l6jquynn9a4cz2pff6khg8c68f7urt33l5n9dng2cwzz4c4q4hncrd", - Dependencies: []*types.ContractDependencyInfo{ - { - Dependency: "sei1wl59k23zngj34l7d42y9yltask7rjlnxgccawc7ltrknp6n52fpsj6ctln", - }, { - Dependency: "sei1udfs22xpxle475m2nz7u47jfa3vngncdegmczwwdx00cmetypa3sman25q", - }, - }, - }) - keeper.SetContract(ctx, &types.ContractInfoV2{ - ContractAddr: "sei1wl59k23zngj34l7d42y9yltask7rjlnxgccawc7ltrknp6n52fpsj6ctln", - Dependencies: []*types.ContractDependencyInfo{ - { - Dependency: "sei1stwdtk6ja0705v8qmtukcp4vd422p5vy4jr5wdc4qk44c57k955qcannhd", - }, - }, - }) - keeper.SetContract(ctx, &types.ContractInfoV2{ - ContractAddr: "sei1stwdtk6ja0705v8qmtukcp4vd422p5vy4jr5wdc4qk44c57k955qcannhd", - }) - keeper.SetContract(ctx, &types.ContractInfoV2{ - ContractAddr: "sei1udfs22xpxle475m2nz7u47jfa3vngncdegmczwwdx00cmetypa3sman25q", - Dependencies: []*types.ContractDependencyInfo{ - { - Dependency: "sei14rse3e7rkc3qt7drmlulwlkrlzqvh7hv277zv05kyfuwl74udx5s9r7lm3", - }, - }, - Suspended: true, - }) - keeper.SetContract(ctx, &types.ContractInfoV2{ - ContractAddr: "sei14rse3e7rkc3qt7drmlulwlkrlzqvh7hv277zv05kyfuwl74udx5s9r7lm3", - }) - keeper.SetContract(ctx, &types.ContractInfoV2{ - ContractAddr: "sei182jzjwdyl5fw43yujnlljddgtrkr04dpd30ywp2yn724u7qhtaqsjev6mv", - }) - - require.Equal(t, []string{ - "sei1ery8l6jquynn9a4cz2pff6khg8c68f7urt33l5n9dng2cwzz4c4q4hncrd", - "sei1wl59k23zngj34l7d42y9yltask7rjlnxgccawc7ltrknp6n52fpsj6ctln", - "sei1stwdtk6ja0705v8qmtukcp4vd422p5vy4jr5wdc4qk44c57k955qcannhd", - }, dex.GetAllDownstreamContracts(ctx, "sei1ery8l6jquynn9a4cz2pff6khg8c68f7urt33l5n9dng2cwzz4c4q4hncrd", keeper.GetContractWithoutGasCharge)) -} diff --git a/x/dex/cache/cancel.go b/x/dex/cache/cancel.go deleted file mode 100644 index ec195a46d..000000000 --- a/x/dex/cache/cancel.go +++ /dev/null @@ -1,65 +0,0 @@ -package dex - -import ( - "encoding/binary" - - "github.com/cosmos/cosmos-sdk/store/prefix" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -type BlockCancellations struct { - cancelStore *prefix.Store -} - -func NewCancels(cancelStore prefix.Store) *BlockCancellations { - return &BlockCancellations{cancelStore: &cancelStore} -} - -func (o *BlockCancellations) Has(cancel *types.Cancellation) bool { - keybz := make([]byte, 8) - binary.BigEndian.PutUint64(keybz, cancel.Id) - return o.cancelStore.Has(keybz) -} - -func (o *BlockCancellations) Get() (list []*types.Cancellation) { - iterator := sdk.KVStorePrefixIterator(o.cancelStore, []byte{}) - - defer iterator.Close() - - for ; iterator.Valid(); iterator.Next() { - var val types.Cancellation - if err := val.Unmarshal(iterator.Value()); err != nil { - panic(err) - } - list = append(list, &val) - } - - return -} - -func (o *BlockCancellations) GetIdsToCancel() (list []uint64) { - iterator := sdk.KVStorePrefixIterator(o.cancelStore, []byte{}) - - defer iterator.Close() - - for ; iterator.Valid(); iterator.Next() { - var val types.Cancellation - if err := val.Unmarshal(iterator.Value()); err != nil { - panic(err) - } - list = append(list, val.Id) - } - - return -} - -func (o *BlockCancellations) Add(newItem *types.Cancellation) { - keybz := make([]byte, 8) - binary.BigEndian.PutUint64(keybz, newItem.Id) - valbz, err := newItem.Marshal() - if err != nil { - panic(err) - } - o.cancelStore.Set(keybz, valbz) -} diff --git a/x/dex/cache/cancel_test.go b/x/dex/cache/cancel_test.go deleted file mode 100644 index 8f9d51d80..000000000 --- a/x/dex/cache/cancel_test.go +++ /dev/null @@ -1,76 +0,0 @@ -package dex_test - -import ( - "testing" - - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - dex "github.com/sei-protocol/sei-chain/x/dex/cache" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestCancelGetIdsToCancel(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - stateOne := dex.NewMemState(keeper.GetMemStoreKey()) - stateOne.GetBlockCancels(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Cancellation{ - Id: 1, - Creator: "abc", - ContractAddr: TEST_CONTRACT, - }) - ids := stateOne.GetBlockCancels(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).GetIdsToCancel() - require.Equal(t, 1, len(ids)) - require.Equal(t, uint64(1), ids[0]) -} - -func TestCancelGetCancels(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - stateOne := dex.NewMemState(keeper.GetMemStoreKey()) - stateOne.GetBlockCancels(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Cancellation{ - Id: 1, - Creator: "abc", - ContractAddr: TEST_CONTRACT, - }) - stateOne.GetBlockCancels(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Cancellation{ - Id: 2, - Creator: "def", - ContractAddr: TEST_CONTRACT, - }) - stateOne.GetBlockCancels(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Cancellation{ - Id: 3, - Creator: "efg", - ContractAddr: TEST_CONTRACT, - }) - stateOne.GetBlockCancels(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Cancellation{ - Id: 4, - Creator: "efg", - ContractAddr: TEST_CONTRACT, - }) - - cancels := stateOne.GetBlockCancels(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Get() - require.Equal(t, 4, len(cancels)) - require.True(t, stateOne.GetBlockCancels(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Has(&types.Cancellation{ - Id: 1, - Creator: "abc", - ContractAddr: TEST_CONTRACT, - })) - require.True(t, stateOne.GetBlockCancels(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Has(&types.Cancellation{ - Id: 2, - Creator: "def", - ContractAddr: TEST_CONTRACT, - })) - require.True(t, stateOne.GetBlockCancels(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Has(&types.Cancellation{ - Id: 3, - Creator: "efg", - ContractAddr: TEST_CONTRACT, - })) - require.True(t, stateOne.GetBlockCancels(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Has(&types.Cancellation{ - Id: 4, - Creator: "efg", - ContractAddr: TEST_CONTRACT, - })) - require.False(t, stateOne.GetBlockCancels(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Has(&types.Cancellation{ - Id: 5, - Creator: "efg", - ContractAddr: TEST_CONTRACT, - })) -} diff --git a/x/dex/cache/context.go b/x/dex/cache/context.go deleted file mode 100644 index 8c427f577..000000000 --- a/x/dex/cache/context.go +++ /dev/null @@ -1,44 +0,0 @@ -package dex - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/utils/datastructures" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -type CtxKeyType string - -const ( - CtxKeyExecTermSignal = CtxKeyType("execution-termination-signals") - CtxKeyExecutingContract = CtxKeyType("executing-contract") -) - -func GetExecutingContract(ctx sdk.Context) *types.ContractInfoV2 { - if ctx.Context() == nil { - return nil - } - executingContract := ctx.Context().Value(CtxKeyExecutingContract) - if executingContract == nil { - return nil - } - contract, ok := executingContract.(types.ContractInfoV2) - if !ok { - return nil - } - return &contract -} - -func GetTerminationSignals(ctx sdk.Context) *datastructures.TypedSyncMap[string, chan struct{}] { - if ctx.Context() == nil { - return nil - } - signals := ctx.Context().Value(CtxKeyExecTermSignal) - if signals == nil { - return nil - } - typedSignals, ok := signals.(*datastructures.TypedSyncMap[string, chan struct{}]) - if !ok { - return nil - } - return typedSignals -} diff --git a/x/dex/cache/deposit.go b/x/dex/cache/deposit.go deleted file mode 100644 index 1df6b2622..000000000 --- a/x/dex/cache/deposit.go +++ /dev/null @@ -1,51 +0,0 @@ -package dex - -import ( - "github.com/cosmos/cosmos-sdk/store/prefix" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -type DepositInfo struct { - store *prefix.Store -} - -func NewDepositInfo(store prefix.Store) *DepositInfo { - return &DepositInfo{store: &store} -} - -func (d *DepositInfo) Get() (list []*types.DepositInfoEntry) { - iterator := sdk.KVStorePrefixIterator(d.store, []byte{}) - - defer iterator.Close() - - for ; iterator.Valid(); iterator.Next() { - var val types.DepositInfoEntry - if err := val.Unmarshal(iterator.Value()); err != nil { - panic(err) - } - list = append(list, &val) - } - - return -} - -func (d *DepositInfo) Add(newItem *types.DepositInfoEntry) { - key := types.MemDepositSubprefix(newItem.Creator, newItem.Denom) - if val, err := newItem.Marshal(); err != nil { - panic(err) - } else if existing := d.store.Get(key); existing == nil { - d.store.Set(key, val) - } else { - existingItem := types.DepositInfoEntry{} - if err := existingItem.Unmarshal(existing); err != nil { - panic(err) - } - newItem.Amount = newItem.Amount.Add(existingItem.Amount) - newVal, err := newItem.Marshal() - if err != nil { - panic(err) - } - d.store.Set(key, newVal) - } -} diff --git a/x/dex/cache/deposit_test.go b/x/dex/cache/deposit_test.go deleted file mode 100644 index 364ffa3d1..000000000 --- a/x/dex/cache/deposit_test.go +++ /dev/null @@ -1,48 +0,0 @@ -package dex_test - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - dex "github.com/sei-protocol/sei-chain/x/dex/cache" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestDepositAdd(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - deposits := dex.NewMemState(keeper.GetMemStoreKey()).GetDepositInfo(ctx, types.ContractAddress(keepertest.TestContract)) - deposit := types.DepositInfoEntry{ - Creator: "abc", - Amount: sdk.MustNewDecFromStr("1.2"), - } - deposits.Add(&deposit) - depositsState := deposits.Get() - require.Equal(t, 1, len(depositsState)) - require.Equal(t, sdk.MustNewDecFromStr("1.2"), depositsState[0].Amount) - - deposit = types.DepositInfoEntry{ - Creator: "abc", - Amount: sdk.MustNewDecFromStr("1.3"), - } - deposits.Add(&deposit) - depositsState = deposits.Get() - require.Equal(t, 1, len(depositsState)) - require.Equal(t, sdk.MustNewDecFromStr("2.5"), depositsState[0].Amount) - - deposit = types.DepositInfoEntry{ - Creator: "def", - Amount: sdk.MustNewDecFromStr("1.1"), - } - deposits.Add(&deposit) - depositsState = deposits.Get() - require.Equal(t, 2, len(depositsState)) - if depositsState[0].Creator == "abc" { - require.Equal(t, sdk.MustNewDecFromStr("2.5"), depositsState[0].Amount) - require.Equal(t, sdk.MustNewDecFromStr("1.1"), depositsState[1].Amount) - } else { - require.Equal(t, sdk.MustNewDecFromStr("2.5"), depositsState[1].Amount) - require.Equal(t, sdk.MustNewDecFromStr("1.1"), depositsState[0].Amount) - } -} diff --git a/x/dex/cache/order.go b/x/dex/cache/order.go deleted file mode 100644 index 03fac3aec..000000000 --- a/x/dex/cache/order.go +++ /dev/null @@ -1,142 +0,0 @@ -package dex - -import ( - "encoding/binary" - "sort" - - "github.com/cosmos/cosmos-sdk/store/prefix" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -type BlockOrders struct { - orderStore *prefix.Store -} - -func NewOrders(orderStore prefix.Store) *BlockOrders { - return &BlockOrders{orderStore: &orderStore} -} - -func (o *BlockOrders) Add(newItem *types.Order) { - keybz := make([]byte, 8) - binary.BigEndian.PutUint64(keybz, newItem.Id) - valbz, err := newItem.Marshal() - if err != nil { - panic(err) - } - o.orderStore.Set(keybz, valbz) -} - -func (o *BlockOrders) GetByID(id uint64) *types.Order { - keybz := make([]byte, 8) - binary.BigEndian.PutUint64(keybz, id) - var val types.Order - if err := val.Unmarshal(o.orderStore.Get(keybz)); err != nil { - panic(err) - } - return &val -} - -func (o *BlockOrders) Get() (list []*types.Order) { - iterator := sdk.KVStorePrefixIterator(o.orderStore, []byte{}) - defer iterator.Close() - for ; iterator.Valid(); iterator.Next() { - var val types.Order - if err := val.Unmarshal(iterator.Value()); err != nil { - panic(err) - } - list = append(list, &val) - } - - return -} - -func (o *BlockOrders) MarkFailedToPlace(failedOrders []types.UnsuccessfulOrder) { - failedOrdersMap := map[uint64]types.UnsuccessfulOrder{} - for _, failedOrder := range failedOrders { - failedOrdersMap[failedOrder.ID] = failedOrder - } - - keys, vals := o.getKVsToSet(failedOrdersMap) - for i, key := range keys { - o.orderStore.Set(key, vals[i]) - } -} - -// getKVsToSet iterate through the kvstore and append the key,val items to a list. -// We should avoid writing or reading from the store directly within the iterator. -func (o *BlockOrders) getKVsToSet(failedOrdersMap map[uint64]types.UnsuccessfulOrder) ([][]byte, [][]byte) { - iterator := sdk.KVStorePrefixIterator(o.orderStore, []byte{}) - - defer iterator.Close() - - var keys [][]byte - var vals [][]byte - for ; iterator.Valid(); iterator.Next() { - var val types.Order - if err := val.Unmarshal(iterator.Value()); err != nil { - panic(err) - } - if failedOrder, ok := failedOrdersMap[val.Id]; ok { - val.Status = types.OrderStatus_FAILED_TO_PLACE - val.StatusDescription = failedOrder.Reason - } - bz, err := val.Marshal() - if err != nil { - panic(err) - } - keys = append(keys, iterator.Key()) - vals = append(vals, bz) - } - return keys, vals -} - -func (o *BlockOrders) GetSortedMarketOrders(direction types.PositionDirection) []*types.Order { - res := o.getOrdersByCriteria(types.OrderType_MARKET, direction) - res = append(res, o.getOrdersByCriteria(types.OrderType_FOKMARKET, direction)...) - res = append(res, o.getOrdersByCriteria(types.OrderType_FOKMARKETBYVALUE, direction)...) - sort.SliceStable(res, func(i, j int) bool { - // a price of 0 indicates that there is no worst price for the order, so it should - // always be ranked at the top. - if res[i].Price.IsZero() { - return true - } else if res[j].Price.IsZero() { - return false - } - switch direction { - case types.PositionDirection_LONG: - return res[i].Price.GT(res[j].Price) - case types.PositionDirection_SHORT: - return res[i].Price.LT(res[j].Price) - default: - panic("Unknown direction") - } - }) - return res -} - -func (o *BlockOrders) GetLimitOrders(direction types.PositionDirection) []*types.Order { - return o.getOrdersByCriteria(types.OrderType_LIMIT, direction) -} - -func (o *BlockOrders) getOrdersByCriteria(orderType types.OrderType, direction types.PositionDirection) []*types.Order { - res := []*types.Order{} - iterator := sdk.KVStorePrefixIterator(o.orderStore, []byte{}) - - defer iterator.Close() - - for ; iterator.Valid(); iterator.Next() { - var val types.Order - if err := val.Unmarshal(iterator.Value()); err != nil { - panic(err) - } - if val.OrderType != orderType || val.PositionDirection != direction { - continue - } - if val.Status == types.OrderStatus_FAILED_TO_PLACE { - continue - } - res = append(res, &val) - } - return res -} diff --git a/x/dex/cache/order_test.go b/x/dex/cache/order_test.go deleted file mode 100644 index b5ab03715..000000000 --- a/x/dex/cache/order_test.go +++ /dev/null @@ -1,257 +0,0 @@ -package dex_test - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - dex "github.com/sei-protocol/sei-chain/x/dex/cache" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestMarkFailedToPlace(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - stateOne := dex.NewMemState(keeper.GetMemStoreKey()) - stateOne.GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Order{ - Id: 1, - Account: "test", - ContractAddr: TEST_CONTRACT, - }) - unsuccessfulOrder := types.UnsuccessfulOrder{ - ID: 1, - Reason: "some reason", - } - stateOne.GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).MarkFailedToPlace([]types.UnsuccessfulOrder{unsuccessfulOrder}) - require.Equal(t, types.OrderStatus_FAILED_TO_PLACE, - stateOne.GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Get()[0].Status) - require.Equal(t, "some reason", - stateOne.GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Get()[0].StatusDescription) -} - -func TestGetByID(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - stateOne := dex.NewMemState(keeper.GetMemStoreKey()) - stateOne.GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Order{ - Id: 1, - Account: "test1", - ContractAddr: TEST_CONTRACT, - PositionDirection: types.PositionDirection_LONG, - OrderType: types.OrderType_LIMIT, - Price: sdk.MustNewDecFromStr("150"), - }) - stateOne.GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Order{ - Id: 2, - Account: "test2", - ContractAddr: TEST_CONTRACT, - PositionDirection: types.PositionDirection_SHORT, - OrderType: types.OrderType_MARKET, - Price: sdk.MustNewDecFromStr("100"), - }) - - order1 := stateOne.GetBlockOrders( - ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).GetByID(uint64(1)) - order2 := stateOne.GetBlockOrders( - ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).GetByID(uint64(2)) - require.Equal(t, uint64(1), order1.Id) - require.Equal(t, uint64(2), order2.Id) - require.Equal(t, "test1", order1.Account) - require.Equal(t, "test2", order2.Account) - require.Equal(t, TEST_CONTRACT, order1.ContractAddr) - require.Equal(t, TEST_CONTRACT, order2.ContractAddr) - require.Equal(t, types.PositionDirection_LONG, order1.PositionDirection) - require.Equal(t, types.PositionDirection_SHORT, order2.PositionDirection) - require.Equal(t, types.OrderType_LIMIT, order1.OrderType) - require.Equal(t, types.OrderType_MARKET, order2.OrderType) - require.Equal(t, sdk.MustNewDecFromStr("150"), order1.Price) - require.Equal(t, sdk.MustNewDecFromStr("100"), order2.Price) -} - -func TestGetSortedMarketOrders(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - stateOne := dex.NewMemState(keeper.GetMemStoreKey()) - stateOne.GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Order{ - Id: 1, - Account: "test", - ContractAddr: TEST_CONTRACT, - PositionDirection: types.PositionDirection_LONG, - OrderType: types.OrderType_MARKET, - Price: sdk.MustNewDecFromStr("150"), - }) - stateOne.GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Order{ - Id: 2, - Account: "test", - ContractAddr: TEST_CONTRACT, - PositionDirection: types.PositionDirection_LONG, - OrderType: types.OrderType_MARKET, - Price: sdk.MustNewDecFromStr("100"), - }) - stateOne.GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Order{ - Id: 3, - Account: "test", - ContractAddr: TEST_CONTRACT, - PositionDirection: types.PositionDirection_LONG, - OrderType: types.OrderType_MARKET, - Price: sdk.MustNewDecFromStr("0"), - }) - stateOne.GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Order{ - Id: 4, - Account: "test", - ContractAddr: TEST_CONTRACT, - PositionDirection: types.PositionDirection_SHORT, - OrderType: types.OrderType_MARKET, - Price: sdk.MustNewDecFromStr("100"), - }) - stateOne.GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Order{ - Id: 5, - Account: "test", - ContractAddr: TEST_CONTRACT, - PositionDirection: types.PositionDirection_SHORT, - OrderType: types.OrderType_MARKET, - Price: sdk.MustNewDecFromStr("80"), - }) - stateOne.GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Order{ - Id: 6, - Account: "test", - ContractAddr: TEST_CONTRACT, - PositionDirection: types.PositionDirection_SHORT, - OrderType: types.OrderType_MARKET, - Price: sdk.MustNewDecFromStr("0"), - }) - stateOne.GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Order{ - Id: 7, - Account: "test", - ContractAddr: TEST_CONTRACT, - PositionDirection: types.PositionDirection_LONG, - OrderType: types.OrderType_LIMIT, - Price: sdk.MustNewDecFromStr("100"), - }) - stateOne.GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Order{ - Id: 8, - Account: "test", - ContractAddr: TEST_CONTRACT, - PositionDirection: types.PositionDirection_SHORT, - OrderType: types.OrderType_LIMIT, - Price: sdk.MustNewDecFromStr("100"), - }) - stateOne.GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Order{ - Id: 9, - Account: "test", - ContractAddr: TEST_CONTRACT, - PositionDirection: types.PositionDirection_LONG, - OrderType: types.OrderType_FOKMARKET, - Price: sdk.MustNewDecFromStr("100"), - }) - stateOne.GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Order{ - Id: 10, - Account: "test", - ContractAddr: TEST_CONTRACT, - PositionDirection: types.PositionDirection_LONG, - OrderType: types.OrderType_FOKMARKET, - Price: sdk.MustNewDecFromStr("0"), - }) - stateOne.GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Order{ - Id: 11, - Account: "test", - ContractAddr: TEST_CONTRACT, - PositionDirection: types.PositionDirection_LONG, - OrderType: types.OrderType_FOKMARKET, - Price: sdk.MustNewDecFromStr("150"), - }) - stateOne.GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Order{ - Id: 12, - Account: "test", - ContractAddr: TEST_CONTRACT, - PositionDirection: types.PositionDirection_SHORT, - OrderType: types.OrderType_FOKMARKET, - Price: sdk.MustNewDecFromStr("0"), - }) - stateOne.GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Order{ - Id: 13, - Account: "test", - ContractAddr: TEST_CONTRACT, - PositionDirection: types.PositionDirection_SHORT, - OrderType: types.OrderType_FOKMARKET, - Price: sdk.MustNewDecFromStr("150"), - }) - stateOne.GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Order{ - Id: 14, - Account: "test", - ContractAddr: TEST_CONTRACT, - PositionDirection: types.PositionDirection_SHORT, - OrderType: types.OrderType_FOKMARKET, - Price: sdk.MustNewDecFromStr("100"), - }) - stateOne.GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Order{ - Id: 15, - Account: "test", - ContractAddr: TEST_CONTRACT, - PositionDirection: types.PositionDirection_LONG, - OrderType: types.OrderType_FOKMARKETBYVALUE, - Price: sdk.MustNewDecFromStr("100"), - }) - stateOne.GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Order{ - Id: 16, - Account: "test", - ContractAddr: TEST_CONTRACT, - PositionDirection: types.PositionDirection_LONG, - OrderType: types.OrderType_FOKMARKETBYVALUE, - Price: sdk.MustNewDecFromStr("0"), - }) - stateOne.GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Order{ - Id: 17, - Account: "test", - ContractAddr: TEST_CONTRACT, - PositionDirection: types.PositionDirection_LONG, - OrderType: types.OrderType_FOKMARKETBYVALUE, - Price: sdk.MustNewDecFromStr("150"), - }) - stateOne.GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Order{ - Id: 18, - Account: "test", - ContractAddr: TEST_CONTRACT, - PositionDirection: types.PositionDirection_SHORT, - OrderType: types.OrderType_FOKMARKETBYVALUE, - Price: sdk.MustNewDecFromStr("0"), - }) - stateOne.GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Order{ - Id: 19, - Account: "test", - ContractAddr: TEST_CONTRACT, - PositionDirection: types.PositionDirection_SHORT, - OrderType: types.OrderType_FOKMARKETBYVALUE, - Price: sdk.MustNewDecFromStr("150"), - }) - stateOne.GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).Add(&types.Order{ - Id: 20, - Account: "test", - ContractAddr: TEST_CONTRACT, - PositionDirection: types.PositionDirection_SHORT, - OrderType: types.OrderType_FOKMARKETBYVALUE, - Price: sdk.MustNewDecFromStr("100"), - }) - - marketBuys := stateOne.GetBlockOrders( - ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).GetSortedMarketOrders(types.PositionDirection_LONG) - require.Equal(t, uint64(16), marketBuys[0].Id) - require.Equal(t, uint64(10), marketBuys[1].Id) - require.Equal(t, uint64(3), marketBuys[2].Id) - require.Equal(t, uint64(1), marketBuys[3].Id) - require.Equal(t, uint64(11), marketBuys[4].Id) - require.Equal(t, uint64(17), marketBuys[5].Id) - require.Equal(t, uint64(2), marketBuys[6].Id) - require.Equal(t, uint64(9), marketBuys[7].Id) - require.Equal(t, uint64(15), marketBuys[8].Id) - - marketSells := stateOne.GetBlockOrders( - ctx, types.ContractAddress(TEST_CONTRACT), keepertest.TestPair).GetSortedMarketOrders(types.PositionDirection_SHORT) - require.Equal(t, uint64(18), marketSells[0].Id) - require.Equal(t, uint64(12), marketSells[1].Id) - require.Equal(t, uint64(6), marketSells[2].Id) - require.Equal(t, uint64(5), marketSells[3].Id) - require.Equal(t, uint64(4), marketSells[4].Id) - require.Equal(t, uint64(14), marketSells[5].Id) - require.Equal(t, uint64(20), marketSells[6].Id) - require.Equal(t, uint64(13), marketSells[7].Id) - require.Equal(t, uint64(19), marketSells[8].Id) -} diff --git a/x/dex/client/cli/query/query.go b/x/dex/client/cli/query/query.go deleted file mode 100644 index 9270b81c3..000000000 --- a/x/dex/client/cli/query/query.go +++ /dev/null @@ -1,48 +0,0 @@ -package query - -import ( - "fmt" - // "strings" - - "github.com/spf13/cobra" - - "github.com/cosmos/cosmos-sdk/client" - // "github.com/cosmos/cosmos-sdk/client/flags" - // sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -// GetQueryCmd returns the cli query commands for this module -func GetQueryCmd() *cobra.Command { - // Group dex queries under a subcommand - cmd := &cobra.Command{ - Use: types.ModuleName, - Short: fmt.Sprintf("Querying commands for the %s module", types.ModuleName), - DisableFlagParsing: true, - SuggestionsMinimumDistance: 2, - RunE: client.ValidateCmd, - } - - cmd.AddCommand(CmdQueryParams()) - cmd.AddCommand(CmdListLongBook()) - cmd.AddCommand(CmdShowLongBook()) - cmd.AddCommand(CmdListShortBook()) - cmd.AddCommand(CmdShowShortBook()) - cmd.AddCommand(CmdGetPrice()) - cmd.AddCommand(CmdGetLatestPrice()) - cmd.AddCommand(CmdGetPrices()) - cmd.AddCommand(CmdGetTwaps()) - cmd.AddCommand(CmdGetAssetList()) - cmd.AddCommand(CmdGetAssetMetadata()) - cmd.AddCommand(CmdGetRegisteredPairs()) - cmd.AddCommand(CmdGetRegisteredContract()) - cmd.AddCommand(CmdGetOrders()) - cmd.AddCommand(CmdGetOrdersByID()) - cmd.AddCommand(CmdGetMatchResult()) - cmd.AddCommand(CmdGetOrderCount()) - - // this line is used by starport scaffolding # 1 - - return cmd -} diff --git a/x/dex/client/cli/query/query_asset_list.go b/x/dex/client/cli/query/query_asset_list.go deleted file mode 100644 index 7615cbfed..000000000 --- a/x/dex/client/cli/query/query_asset_list.go +++ /dev/null @@ -1,80 +0,0 @@ -package query - -import ( - "strconv" - "strings" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/spf13/cobra" -) - -var _ = strconv.Itoa(0) - -func CmdGetAssetList() *cobra.Command { - cmd := &cobra.Command{ - Use: "get-asset-list", - Short: "Query Asset List", - Long: strings.TrimSpace(` - Returns the metadata for all assets. Dex asset metadata includes information such as IBC info (for IBC assets), the asset type, and standard token metadata from the bank module. - `), - Args: cobra.NoArgs, - RunE: func(cmd *cobra.Command, args []string) (err error) { - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - - queryClient := types.NewQueryClient(clientCtx) - - params := &types.QueryAssetListRequest{} - - res, err := queryClient.AssetList(cmd.Context(), params) - if err != nil { - return err - } - - return clientCtx.PrintProto(res) - }, - } - - flags.AddQueryFlagsToCmd(cmd) - - return cmd -} - -func CmdGetAssetMetadata() *cobra.Command { - cmd := &cobra.Command{ - Use: "get-asset-metadata [denom]", - Short: "Query Asset Metadata", - Long: strings.TrimSpace(` - Returns the metadata for a specific asset based on the passed in denom. Dex asset metadata includes information such as IBC info (for IBC assets), the asset type, and standard token metadata from the bank module. - `), - Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) (err error) { - denom := args[0] - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - - queryClient := types.NewQueryClient(clientCtx) - - params := &types.QueryAssetMetadataRequest{ - Denom: denom, - } - - res, err := queryClient.AssetMetadata(cmd.Context(), params) - if err != nil { - return err - } - - return clientCtx.PrintProto(res) - }, - } - - flags.AddQueryFlagsToCmd(cmd) - - return cmd -} diff --git a/x/dex/client/cli/query/query_get_latest_price.go b/x/dex/client/cli/query/query_get_latest_price.go deleted file mode 100644 index 52bbcb3f0..000000000 --- a/x/dex/client/cli/query/query_get_latest_price.go +++ /dev/null @@ -1,53 +0,0 @@ -package query - -import ( - "strconv" - "strings" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/spf13/cobra" -) - -var _ = strconv.Itoa(0) - -func CmdGetLatestPrice() *cobra.Command { - cmd := &cobra.Command{ - Use: "get-latest-price [contract-address] [price-denom] [asset-denom]", - Short: "Query getLatestPrice", - Long: strings.TrimSpace(` - Get the latest price from a dex specified by the contract-address. The price and asset denom are used to specify the dex pair for which to return the latest price. For the price at a specific timestamp use get-price instead or for all prices use get-prices. - `), - Args: cobra.ExactArgs(3), - RunE: func(cmd *cobra.Command, args []string) (err error) { - reqContractAddr := args[0] - reqPriceDenom := args[1] - reqAssetDenom := args[2] - - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - - queryClient := types.NewQueryClient(clientCtx) - - params := &types.QueryGetLatestPriceRequest{ - ContractAddr: reqContractAddr, - PriceDenom: reqPriceDenom, - AssetDenom: reqAssetDenom, - } - - res, err := queryClient.GetLatestPrice(cmd.Context(), params) - if err != nil { - return err - } - - return clientCtx.PrintProto(res) - }, - } - - flags.AddQueryFlagsToCmd(cmd) - - return cmd -} diff --git a/x/dex/client/cli/query/query_get_order_count.go b/x/dex/client/cli/query/query_get_order_count.go deleted file mode 100644 index 105fcbdaa..000000000 --- a/x/dex/client/cli/query/query_get_order_count.go +++ /dev/null @@ -1,52 +0,0 @@ -package query - -import ( - "context" - "fmt" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/spf13/cobra" -) - -func CmdGetOrderCount() *cobra.Command { - cmd := &cobra.Command{ - Use: "get-order-count [contract] [price denom] [asset denom] [LONG|SHORT] [price]", - Short: "get number of orders at a price leve", - Args: cobra.ExactArgs(5), - RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) - - queryClient := types.NewQueryClient(clientCtx) - - var direction types.PositionDirection - switch args[3] { - case "LONG": - direction = types.PositionDirection_LONG - case "SHORT": - direction = types.PositionDirection_SHORT - default: - return fmt.Errorf("unknown direction %s", args[3]) - } - price := sdk.MustNewDecFromStr(args[4]) - res, err := queryClient.GetOrderCount(context.Background(), &types.QueryGetOrderCountRequest{ - ContractAddr: args[0], - PriceDenom: args[1], - AssetDenom: args[2], - PositionDirection: direction, - Price: &price, - }) - if err != nil { - return err - } - - return clientCtx.PrintProto(res) - }, - } - - flags.AddQueryFlagsToCmd(cmd) - - return cmd -} diff --git a/x/dex/client/cli/query/query_get_price.go b/x/dex/client/cli/query/query_get_price.go deleted file mode 100644 index 06c9d9dbd..000000000 --- a/x/dex/client/cli/query/query_get_price.go +++ /dev/null @@ -1,58 +0,0 @@ -package query - -import ( - "strconv" - "strings" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/spf13/cobra" -) - -var _ = strconv.Itoa(0) - -func CmdGetPrice() *cobra.Command { - cmd := &cobra.Command{ - Use: "get-price [contract-address] [timestamp] [price-denom] [asset-denom]", - Short: "Query getPrice", - Long: strings.TrimSpace(` - Get the price for a pair from a dex specified by the contract-address. The price and asset denom are used to specify the dex pair for which to return the latest price. The timestamp is used to query the price for that specific timestamp. For the latest price use get-latest-price instead or for all prices use get-prices. - `), - Args: cobra.ExactArgs(4), - RunE: func(cmd *cobra.Command, args []string) (err error) { - reqContractAddr := args[0] - reqTimestamp, err := strconv.ParseUint(args[1], 10, 64) - if err != nil { - return err - } - reqPriceDenom := args[2] - reqAssetDenom := args[3] - - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - - queryClient := types.NewQueryClient(clientCtx) - - params := &types.QueryGetPriceRequest{ - ContractAddr: reqContractAddr, - PriceDenom: reqPriceDenom, - AssetDenom: reqAssetDenom, - Timestamp: reqTimestamp, - } - - res, err := queryClient.GetPrice(cmd.Context(), params) - if err != nil { - return err - } - - return clientCtx.PrintProto(res) - }, - } - - flags.AddQueryFlagsToCmd(cmd) - - return cmd -} diff --git a/x/dex/client/cli/query/query_get_prices.go b/x/dex/client/cli/query/query_get_prices.go deleted file mode 100644 index 7637379b0..000000000 --- a/x/dex/client/cli/query/query_get_prices.go +++ /dev/null @@ -1,53 +0,0 @@ -package query - -import ( - "strconv" - "strings" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/spf13/cobra" -) - -var _ = strconv.Itoa(0) - -func CmdGetPrices() *cobra.Command { - cmd := &cobra.Command{ - Use: "get-prices [contract-address] [price-denom] [asset-denom]", - Short: "Query getPrices", - Long: strings.TrimSpace(` - Get all the prices for a pair from a dex specified by the contract-address. The price and asset denom are used to specify the dex pair for which to return the latest price. For the latest price use get-latest-price instead or for a specific timestamp use get-price. - `), - Args: cobra.ExactArgs(3), - RunE: func(cmd *cobra.Command, args []string) (err error) { - reqContractAddr := args[0] - reqPriceDenom := args[1] - reqAssetDenom := args[2] - - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - - queryClient := types.NewQueryClient(clientCtx) - - params := &types.QueryGetPricesRequest{ - ContractAddr: reqContractAddr, - PriceDenom: reqPriceDenom, - AssetDenom: reqAssetDenom, - } - - res, err := queryClient.GetPrices(cmd.Context(), params) - if err != nil { - return err - } - - return clientCtx.PrintProto(res) - }, - } - - flags.AddQueryFlagsToCmd(cmd) - - return cmd -} diff --git a/x/dex/client/cli/query/query_get_twaps.go b/x/dex/client/cli/query/query_get_twaps.go deleted file mode 100644 index 798394b3b..000000000 --- a/x/dex/client/cli/query/query_get_twaps.go +++ /dev/null @@ -1,53 +0,0 @@ -package query - -import ( - "strconv" - "strings" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/spf13/cobra" -) - -var _ = strconv.Itoa(0) - -func CmdGetTwaps() *cobra.Command { - cmd := &cobra.Command{ - Use: "get-twaps [contract-address] [lookback]", - Short: "Query getPrice", - Long: strings.TrimSpace(` - Get the TWAPs (Time weighted average prices) for all registered dex pairs for a specific orderbook by [contract-address] with a specific lookback duration over which to compute the weighted average. - `), - Args: cobra.ExactArgs(2), - RunE: func(cmd *cobra.Command, args []string) (err error) { - reqContractAddr := args[0] - reqLookback, err := strconv.ParseUint(args[1], 10, 64) - if err != nil { - return err - } - - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - queryClient := types.NewQueryClient(clientCtx) - - params := &types.QueryGetTwapsRequest{ - ContractAddr: reqContractAddr, - LookbackSeconds: reqLookback, - } - - res, err := queryClient.GetTwaps(cmd.Context(), params) - if err != nil { - return err - } - - return clientCtx.PrintProto(res) - }, - } - - flags.AddQueryFlagsToCmd(cmd) - - return cmd -} diff --git a/x/dex/client/cli/query/query_long_book.go b/x/dex/client/cli/query/query_long_book.go deleted file mode 100644 index bf735d901..000000000 --- a/x/dex/client/cli/query/query_long_book.go +++ /dev/null @@ -1,90 +0,0 @@ -package query - -import ( - "context" - "strings" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/spf13/cobra" -) - -func CmdListLongBook() *cobra.Command { - cmd := &cobra.Command{ - Use: "list-long-book [contract address] [price denom] [asset denom]", - Short: "list all longBook", - Long: strings.TrimSpace(` - Lists all of a long book's information for a given contract address and pair specified by price denom and asset denom. - `), - Args: cobra.ExactArgs(3), - RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) - - pageReq, err := client.ReadPageRequest(cmd.Flags()) - if err != nil { - return err - } - - queryClient := types.NewQueryClient(clientCtx) - - reqPriceDenom := args[1] - reqAssetDenom := args[2] - - params := &types.QueryAllLongBookRequest{ - Pagination: pageReq, - ContractAddr: args[0], - PriceDenom: reqPriceDenom, - AssetDenom: reqAssetDenom, - } - - res, err := queryClient.LongBookAll(context.Background(), params) - if err != nil { - return err - } - - return clientCtx.PrintProto(res) - }, - } - - flags.AddPaginationFlagsToCmd(cmd, cmd.Use) - flags.AddQueryFlagsToCmd(cmd) - - return cmd -} - -func CmdShowLongBook() *cobra.Command { - cmd := &cobra.Command{ - Use: "show-long-book [contract address] [price] [price denom] [asset denom]", - Short: "shows a longBook", - Long: strings.TrimSpace(` - Gets a long book's information at a specific price for a given contract address and pair specified by price denopm and asset denom. - `), - Args: cobra.ExactArgs(4), - RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) - - queryClient := types.NewQueryClient(clientCtx) - contractAddr := args[0] - reqPriceDenom := args[2] - reqAssetDenom := args[3] - - params := &types.QueryGetLongBookRequest{ - Price: args[1], - ContractAddr: contractAddr, - PriceDenom: reqPriceDenom, - AssetDenom: reqAssetDenom, - } - res, err := queryClient.LongBook(context.Background(), params) - if err != nil { - return err - } - - return clientCtx.PrintProto(res) - }, - } - - flags.AddQueryFlagsToCmd(cmd) - - return cmd -} diff --git a/x/dex/client/cli/query/query_long_book_test.go b/x/dex/client/cli/query/query_long_book_test.go deleted file mode 100644 index cd878dc7b..000000000 --- a/x/dex/client/cli/query/query_long_book_test.go +++ /dev/null @@ -1,176 +0,0 @@ -package query_test - -import ( - "fmt" - "testing" - - "github.com/cosmos/cosmos-sdk/client/flags" - clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" - "github.com/stretchr/testify/require" - tmcli "github.com/tendermint/tendermint/libs/cli" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/testutil/network" - "github.com/sei-protocol/sei-chain/testutil/nullify" - "github.com/sei-protocol/sei-chain/x/dex/client/cli/query" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -func networkWithLongBookObjects(t *testing.T, n int) (*network.Network, []types.LongBook) { - t.Helper() - cfg := network.DefaultConfig() - state := types.GenesisState{} - longBookList := []types.LongBook{} - require.NoError(t, cfg.Codec.UnmarshalJSON(cfg.GenesisState[types.ModuleName], &state)) - - for i := 0; i < n; i++ { - longBook := types.LongBook{ - Price: sdk.NewDec(int64(1 + i)), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(int64(1 + i)), - Quantity: sdk.NewDec(int64(i)), - Allocations: []*types.Allocation{{Account: "abc", Quantity: sdk.NewDec(int64(i)), OrderId: 1}}, - PriceDenom: TEST_PAIR().PriceDenom, - AssetDenom: TEST_PAIR().AssetDenom, - }, - } - nullify.Fill(&longBook) - longBookList = append(longBookList, longBook) - } - - contractInfo := types.ContractInfoV2{ - CodeId: uint64(1), - ContractAddr: "sei1ghd753shjuwexxywmgs4xz7x2q732vcnkm6h2pyv9s6ah3hylvrqladqwc", - } - contractState := []types.ContractState{ - { - LongBookList: longBookList, - ContractInfo: contractInfo, - }, - } - state.ContractState = contractState - buf, err := cfg.Codec.MarshalJSON(&state) - require.NoError(t, err) - cfg.GenesisState[types.ModuleName] = buf - return network.New(t, cfg), state.ContractState[0].LongBookList -} - -func TestShowLongBook(t *testing.T) { - net, objs := networkWithLongBookObjects(t, 2) - - ctx := net.Validators[0].ClientCtx - common := []string{ - fmt.Sprintf("--%s=json", tmcli.OutputFlag), - } - for _, tc := range []struct { - desc string - price string - args []string - err error - obj types.LongBook - }{ - { - desc: "found", - price: objs[1].Entry.Price.String(), - args: common, - obj: objs[1], - }, - { - desc: "not found", - price: "not_found", - args: common, - err: status.Error(codes.InvalidArgument, "not found"), - }, - } { - tc := tc - t.Run(tc.desc, func(t *testing.T) { - // the longbook orders are from genesis contract as created from networkWithLongBookObjects - args := []string{"sei1ghd753shjuwexxywmgs4xz7x2q732vcnkm6h2pyv9s6ah3hylvrqladqwc", tc.price, TEST_PAIR().PriceDenom, TEST_PAIR().AssetDenom} - args = append(args, tc.args...) - out, err := clitestutil.ExecTestCLICmd(ctx, query.CmdShowLongBook(), args) - if tc.err != nil { - stat, ok := status.FromError(tc.err) - require.True(t, ok) - require.ErrorIs(t, stat.Err(), tc.err) - } else { - require.NoError(t, err) - var resp types.QueryGetLongBookResponse - require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) - require.NotNil(t, resp.LongBook) - require.Equal(t, - nullify.Fill(&tc.obj), - nullify.Fill(&resp.LongBook), - ) - } - }) - } -} - -func TestListLongBook(t *testing.T) { - net, objs := networkWithLongBookObjects(t, 5) - - ctx := net.Validators[0].ClientCtx - request := func(next []byte, offset, limit uint64, total bool) []string { - args := []string{ - "sei1ghd753shjuwexxywmgs4xz7x2q732vcnkm6h2pyv9s6ah3hylvrqladqwc", TEST_PAIR().PriceDenom, TEST_PAIR().AssetDenom, - fmt.Sprintf("--%s=json", tmcli.OutputFlag), - } - if next == nil { - args = append(args, fmt.Sprintf("--%s=%d", flags.FlagOffset, offset)) - } else { - args = append(args, fmt.Sprintf("--%s=%s", flags.FlagPageKey, next)) - } - args = append(args, fmt.Sprintf("--%s=%d", flags.FlagLimit, limit)) - if total { - args = append(args, fmt.Sprintf("--%s", flags.FlagCountTotal)) - } - return args - } - t.Run("ByOffset", func(t *testing.T) { - step := 2 - for i := 0; i < len(objs); i += step { - args := request(nil, uint64(i), uint64(step), false) - out, err := clitestutil.ExecTestCLICmd(ctx, query.CmdListLongBook(), args) - require.NoError(t, err) - var resp types.QueryAllLongBookResponse - require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) - require.LessOrEqual(t, len(resp.LongBook), step) - require.Subset(t, - nullify.Fill(objs), - nullify.Fill(resp.LongBook), - ) - } - }) - t.Run("ByKey", func(t *testing.T) { - step := 2 - var next []byte - for i := 0; i < len(objs); i += step { - args := request(next, 0, uint64(step), false) - out, err := clitestutil.ExecTestCLICmd(ctx, query.CmdListLongBook(), args) - require.NoError(t, err) - var resp types.QueryAllLongBookResponse - require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) - require.LessOrEqual(t, len(resp.LongBook), step) - require.Subset(t, - nullify.Fill(objs), - nullify.Fill(resp.LongBook), - ) - next = resp.Pagination.NextKey - } - }) - t.Run("Total", func(t *testing.T) { - args := request(nil, 0, uint64(len(objs)), true) - out, err := clitestutil.ExecTestCLICmd(ctx, query.CmdListLongBook(), args) - require.NoError(t, err) - var resp types.QueryAllLongBookResponse - require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) - require.NoError(t, err) - require.Equal(t, len(objs), int(resp.Pagination.Total)) - require.ElementsMatch(t, - nullify.Fill(objs), - nullify.Fill(resp.LongBook), - ) - }) -} diff --git a/x/dex/client/cli/query/query_match_result.go b/x/dex/client/cli/query/query_match_result.go deleted file mode 100644 index c1a3fe194..000000000 --- a/x/dex/client/cli/query/query_match_result.go +++ /dev/null @@ -1,49 +0,0 @@ -package query - -import ( - "strings" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/spf13/cobra" -) - -func CmdGetMatchResult() *cobra.Command { - cmd := &cobra.Command{ - Use: "get-match-result [contract-address]", - Short: "Query get match result by contract", - Long: strings.TrimSpace(` - Gets the match result information for an orderbook specified by the given contract address. The match result information includes the orders, settlements, and cancellations for the orderbook. - `), - Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) (err error) { - contractAddr := args[0] - if err != nil { - return err - } - - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - - queryClient := types.NewQueryClient(clientCtx) - - params := &types.QueryGetMatchResultRequest{ - ContractAddr: contractAddr, - } - - res, err := queryClient.GetMatchResult(cmd.Context(), params) - if err != nil { - return err - } - - return clientCtx.PrintProto(res) - }, - } - - flags.AddQueryFlagsToCmd(cmd) - - return cmd -} diff --git a/x/dex/client/cli/query/query_orders.go b/x/dex/client/cli/query/query_orders.go deleted file mode 100644 index 1c054c8b1..000000000 --- a/x/dex/client/cli/query/query_orders.go +++ /dev/null @@ -1,96 +0,0 @@ -package query - -import ( - "strconv" - "strings" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/spf13/cobra" -) - -var _ = strconv.Itoa(0) - -func CmdGetOrders() *cobra.Command { - cmd := &cobra.Command{ - Use: "get-orders [contract-address] [account]", - Short: "Query get orders for account", - Long: strings.TrimSpace(` - Get all orders for an account and orderbook specified by contract address. - `), - Args: cobra.ExactArgs(2), - RunE: func(cmd *cobra.Command, args []string) (err error) { - reqContractAddr := args[0] - reqAccount := args[1] - - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - - queryClient := types.NewQueryClient(clientCtx) - - params := &types.QueryGetOrdersRequest{ - ContractAddr: reqContractAddr, - Account: reqAccount, - } - - res, err := queryClient.GetOrders(cmd.Context(), params) - if err != nil { - return err - } - - return clientCtx.PrintProto(res) - }, - } - - flags.AddQueryFlagsToCmd(cmd) - - return cmd -} - -func CmdGetOrdersByID() *cobra.Command { - cmd := &cobra.Command{ - Use: "get-orders-by-id [contract-address] [price-denom] [asset-denom] [id]", - Short: "Query get order by ID", - Long: strings.TrimSpace(` - Get a specific order by ID for an account and orderbook specified by contract address. - `), - Args: cobra.ExactArgs(4), - RunE: func(cmd *cobra.Command, args []string) (err error) { - contractAddr := args[0] - priceDenom := args[1] - assetDenom := args[2] - orderID, err := strconv.ParseUint(args[3], 10, 64) - if err != nil { - return err - } - - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - - queryClient := types.NewQueryClient(clientCtx) - - params := &types.QueryGetOrderByIDRequest{ - ContractAddr: contractAddr, - PriceDenom: priceDenom, - AssetDenom: assetDenom, - Id: orderID, - } - - res, err := queryClient.GetOrder(cmd.Context(), params) - if err != nil { - return err - } - - return clientCtx.PrintProto(res) - }, - } - - flags.AddQueryFlagsToCmd(cmd) - - return cmd -} diff --git a/x/dex/client/cli/query/query_params.go b/x/dex/client/cli/query/query_params.go deleted file mode 100644 index 052866740..000000000 --- a/x/dex/client/cli/query/query_params.go +++ /dev/null @@ -1,34 +0,0 @@ -package query - -import ( - "context" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/spf13/cobra" -) - -func CmdQueryParams() *cobra.Command { - cmd := &cobra.Command{ - Use: "params", - Short: "shows the parameters of the module", - Args: cobra.NoArgs, - RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) - - queryClient := types.NewQueryClient(clientCtx) - - res, err := queryClient.Params(context.Background(), &types.QueryParamsRequest{}) - if err != nil { - return err - } - - return clientCtx.PrintProto(res) - }, - } - - flags.AddQueryFlagsToCmd(cmd) - - return cmd -} diff --git a/x/dex/client/cli/query/query_registered_contract.go b/x/dex/client/cli/query/query_registered_contract.go deleted file mode 100644 index f779c6fe3..000000000 --- a/x/dex/client/cli/query/query_registered_contract.go +++ /dev/null @@ -1,48 +0,0 @@ -package query - -import ( - "strconv" - "strings" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/spf13/cobra" -) - -var _ = strconv.Itoa(0) - -func CmdGetRegisteredContract() *cobra.Command { - cmd := &cobra.Command{ - Use: "get-registered-contract [contract address]", - Short: "Query Registered Contract", - Long: strings.TrimSpace(` - List the registered contract information specified by contract address. - `), - Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) (err error) { - contractAddr := args[0] - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - - queryClient := types.NewQueryClient(clientCtx) - - params := &types.QueryRegisteredContractRequest{ - ContractAddr: contractAddr, - } - - res, err := queryClient.GetRegisteredContract(cmd.Context(), params) - if err != nil { - return err - } - - return clientCtx.PrintProto(res) - }, - } - - flags.AddQueryFlagsToCmd(cmd) - - return cmd -} diff --git a/x/dex/client/cli/query/query_registered_pairs.go b/x/dex/client/cli/query/query_registered_pairs.go deleted file mode 100644 index 2b854976c..000000000 --- a/x/dex/client/cli/query/query_registered_pairs.go +++ /dev/null @@ -1,48 +0,0 @@ -package query - -import ( - "strconv" - "strings" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/spf13/cobra" -) - -var _ = strconv.Itoa(0) - -func CmdGetRegisteredPairs() *cobra.Command { - cmd := &cobra.Command{ - Use: "get-registered-pairs [contract address]", - Short: "Query Registered Pairs", - Long: strings.TrimSpace(` - List all of the registered pairs for an orderbook specified by contract address. - `), - Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) (err error) { - contractAddr := args[0] - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - - queryClient := types.NewQueryClient(clientCtx) - - params := &types.QueryRegisteredPairsRequest{ - ContractAddr: contractAddr, - } - - res, err := queryClient.GetRegisteredPairs(cmd.Context(), params) - if err != nil { - return err - } - - return clientCtx.PrintProto(res) - }, - } - - flags.AddQueryFlagsToCmd(cmd) - - return cmd -} diff --git a/x/dex/client/cli/query/query_short_book.go b/x/dex/client/cli/query/query_short_book.go deleted file mode 100644 index b16e477ce..000000000 --- a/x/dex/client/cli/query/query_short_book.go +++ /dev/null @@ -1,92 +0,0 @@ -package query - -import ( - "context" - "strings" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/spf13/cobra" -) - -func CmdListShortBook() *cobra.Command { - cmd := &cobra.Command{ - Use: "list-short-book [contract address] [price denom] [asset denom]", - Short: "list all shortBook", - Long: strings.TrimSpace(` - Lists all of a short book's information for a given contract address and pair specified by price denopm and asset denom. - `), - Args: cobra.ExactArgs(3), - RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) - - pageReq, err := client.ReadPageRequest(cmd.Flags()) - if err != nil { - return err - } - - reqPriceDenom := args[1] - reqAssetDenom := args[2] - - queryClient := types.NewQueryClient(clientCtx) - - params := &types.QueryAllShortBookRequest{ - Pagination: pageReq, - ContractAddr: args[0], - PriceDenom: reqPriceDenom, - AssetDenom: reqAssetDenom, - } - - res, err := queryClient.ShortBookAll(context.Background(), params) - if err != nil { - return err - } - - return clientCtx.PrintProto(res) - }, - } - - flags.AddPaginationFlagsToCmd(cmd, cmd.Use) - flags.AddQueryFlagsToCmd(cmd) - - return cmd -} - -func CmdShowShortBook() *cobra.Command { - cmd := &cobra.Command{ - Use: "show-short-book [contract address] [price] [price denom] [asset denom]", - Short: "shows a shortBook", - Long: strings.TrimSpace(` - Gets a short book's information at a specific price for a given contract address and pair specified by price denopm and asset denom. - `), - Args: cobra.ExactArgs(4), - RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) - - queryClient := types.NewQueryClient(clientCtx) - - contractAddr := args[0] - reqPriceDenom := args[2] - reqAssetDenom := args[3] - - params := &types.QueryGetShortBookRequest{ - Price: args[1], - ContractAddr: contractAddr, - PriceDenom: reqPriceDenom, - AssetDenom: reqAssetDenom, - } - - res, err := queryClient.ShortBook(context.Background(), params) - if err != nil { - return err - } - - return clientCtx.PrintProto(res) - }, - } - - flags.AddQueryFlagsToCmd(cmd) - - return cmd -} diff --git a/x/dex/client/cli/query/query_short_book_test.go b/x/dex/client/cli/query/query_short_book_test.go deleted file mode 100644 index 1bfe5bbbb..000000000 --- a/x/dex/client/cli/query/query_short_book_test.go +++ /dev/null @@ -1,181 +0,0 @@ -package query_test - -import ( - "fmt" - "testing" - - "github.com/cosmos/cosmos-sdk/client/flags" - clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/testutil/network" - "github.com/sei-protocol/sei-chain/testutil/nullify" - "github.com/sei-protocol/sei-chain/x/dex/client/cli/query" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" - tmcli "github.com/tendermint/tendermint/libs/cli" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" -) - -func TEST_PAIR() types.Pair { - return types.Pair{ - PriceDenom: "usdc", - AssetDenom: "atom", - } -} - -func networkWithShortBookObjects(t *testing.T, n int) (*network.Network, []types.ShortBook) { - t.Helper() - cfg := network.DefaultConfig() - state := types.GenesisState{} - shortBookList := []types.ShortBook{} - require.NoError(t, cfg.Codec.UnmarshalJSON(cfg.GenesisState[types.ModuleName], &state)) - - for i := 0; i < n; i++ { - shortBook := types.ShortBook{ - Price: sdk.NewDec(int64(1 + i)), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(int64(1 + i)), - Quantity: sdk.NewDec(int64(i)), - Allocations: []*types.Allocation{{Account: "abc", Quantity: sdk.NewDec(int64(i)), OrderId: 1}}, - PriceDenom: TEST_PAIR().PriceDenom, - AssetDenom: TEST_PAIR().AssetDenom, - }, - } - nullify.Fill(&shortBook) - shortBookList = append(shortBookList, shortBook) - } - - contractInfo := types.ContractInfoV2{ - CodeId: uint64(1), - ContractAddr: "sei1ghd753shjuwexxywmgs4xz7x2q732vcnkm6h2pyv9s6ah3hylvrqladqwc", - } - contractState := []types.ContractState{ - { - ShortBookList: shortBookList, - ContractInfo: contractInfo, - }, - } - state.ContractState = contractState - buf, err := cfg.Codec.MarshalJSON(&state) - require.NoError(t, err) - cfg.GenesisState[types.ModuleName] = buf - return network.New(t, cfg), state.ContractState[0].ShortBookList -} - -func TestShowShortBook(t *testing.T) { - net, objs := networkWithShortBookObjects(t, 2) - - ctx := net.Validators[0].ClientCtx - common := []string{ - fmt.Sprintf("--%s=json", tmcli.OutputFlag), - } - for _, tc := range []struct { - desc string - price string - args []string - err error - obj types.ShortBook - }{ - { - desc: "found", - price: objs[1].Entry.Price.String(), - args: common, - obj: objs[1], - }, - { - desc: "not found", - price: "not_found", - args: common, - err: status.Error(codes.InvalidArgument, "not found"), - }, - } { - tc := tc - t.Run(tc.desc, func(t *testing.T) { - args := []string{"sei1ghd753shjuwexxywmgs4xz7x2q732vcnkm6h2pyv9s6ah3hylvrqladqwc", tc.price, TEST_PAIR().PriceDenom, TEST_PAIR().AssetDenom} - args = append(args, tc.args...) - out, err := clitestutil.ExecTestCLICmd(ctx, query.CmdShowShortBook(), args) - if tc.err != nil { - stat, ok := status.FromError(tc.err) - require.True(t, ok) - require.ErrorIs(t, stat.Err(), tc.err) - } else { - require.NoError(t, err) - var resp types.QueryGetShortBookResponse - require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) - require.NotNil(t, resp.ShortBook) - require.Equal(t, - nullify.Fill(&tc.obj), - nullify.Fill(&resp.ShortBook), - ) - } - }) - } -} - -func TestListShortBook(t *testing.T) { - net, objs := networkWithShortBookObjects(t, 5) - - ctx := net.Validators[0].ClientCtx - request := func(next []byte, offset, limit uint64, total bool) []string { - args := []string{ - "sei1ghd753shjuwexxywmgs4xz7x2q732vcnkm6h2pyv9s6ah3hylvrqladqwc", TEST_PAIR().PriceDenom, TEST_PAIR().AssetDenom, - fmt.Sprintf("--%s=json", tmcli.OutputFlag), - } - if next == nil { - args = append(args, fmt.Sprintf("--%s=%d", flags.FlagOffset, offset)) - } else { - args = append(args, fmt.Sprintf("--%s=%s", flags.FlagPageKey, next)) - } - args = append(args, fmt.Sprintf("--%s=%d", flags.FlagLimit, limit)) - if total { - args = append(args, fmt.Sprintf("--%s", flags.FlagCountTotal)) - } - return args - } - t.Run("ByOffset", func(t *testing.T) { - step := 2 - for i := 0; i < len(objs); i += step { - args := request(nil, uint64(i), uint64(step), false) - out, err := clitestutil.ExecTestCLICmd(ctx, query.CmdListShortBook(), args) - require.NoError(t, err) - var resp types.QueryAllShortBookResponse - require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) - require.LessOrEqual(t, len(resp.ShortBook), step) - require.Subset(t, - nullify.Fill(objs), - nullify.Fill(resp.ShortBook), - ) - } - }) - t.Run("ByKey", func(t *testing.T) { - step := 2 - var next []byte - for i := 0; i < len(objs); i += step { - args := request(next, 0, uint64(step), false) - out, err := clitestutil.ExecTestCLICmd(ctx, query.CmdListShortBook(), args) - require.NoError(t, err) - var resp types.QueryAllShortBookResponse - require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) - require.LessOrEqual(t, len(resp.ShortBook), step) - require.Subset(t, - nullify.Fill(objs), - nullify.Fill(resp.ShortBook), - ) - next = resp.Pagination.NextKey - } - }) - t.Run("Total", func(t *testing.T) { - args := request(nil, 0, uint64(len(objs)), true) - out, err := clitestutil.ExecTestCLICmd(ctx, query.CmdListShortBook(), args) - require.NoError(t, err) - var resp types.QueryAllShortBookResponse - require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) - require.NoError(t, err) - require.Equal(t, len(objs), int(resp.Pagination.Total)) - require.ElementsMatch(t, - nullify.Fill(objs), - nullify.Fill(resp.ShortBook), - ) - }) -} diff --git a/x/dex/client/cli/tx/gov_tx.go b/x/dex/client/cli/tx/gov_tx.go deleted file mode 100644 index 92e2c018a..000000000 --- a/x/dex/client/cli/tx/gov_tx.go +++ /dev/null @@ -1,60 +0,0 @@ -package tx - -import ( - "strings" - - "github.com/sei-protocol/sei-chain/x/dex/types" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/client/tx" - sdk "github.com/cosmos/cosmos-sdk/types" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" - cutils "github.com/sei-protocol/sei-chain/x/dex/client/utils" - - "github.com/spf13/cobra" -) - -// NewAddAssetProposalTxCmd returns a CLI command handler for creating -// a add asset proposal governance transaction. -func NewAddAssetProposalTxCmd() *cobra.Command { - cmd := &cobra.Command{ - Use: "add-asset-proposal [proposal-file]", - Args: cobra.ExactArgs(1), - Short: "Submit an add asset proposal", - Long: strings.TrimSpace(` - Submit a proposal to add a list of assets and corresponding metadata to dex assets. - `), - RunE: func(cmd *cobra.Command, args []string) error { - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - proposal, err := cutils.ParseAddAssetMetadataProposalJSON(clientCtx.LegacyAmino, args[0]) - if err != nil { - return err - } - - // Convert proposal to RegisterPairsProposal Type - from := clientCtx.GetFromAddress() - - content := types.AddAssetMetadataProposal{Title: proposal.Title, Description: proposal.Description, AssetList: proposal.AssetList} - - deposit, err := sdk.ParseCoinsNormalized(proposal.Deposit) - if err != nil { - return err - } - - msg, err := govtypes.NewMsgSubmitProposal(&content, deposit, from) - if err != nil { - return err - } - - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) - }, - } - - flags.AddTxFlagsToCmd(cmd) - - return cmd -} diff --git a/x/dex/client/cli/tx/tx.go b/x/dex/client/cli/tx/tx.go deleted file mode 100644 index 9c7ab93e8..000000000 --- a/x/dex/client/cli/tx/tx.go +++ /dev/null @@ -1,40 +0,0 @@ -package tx - -import ( - "fmt" - - "github.com/spf13/cobra" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -//nolint:deadcode,unused // I assume we'll use this later. -const ( - flagPacketTimeoutTimestamp = "packet-timeout-timestamp" - listSeparator = "," -) - -// GetTxCmd returns the transaction commands for this module -func GetTxCmd() *cobra.Command { - cmd := &cobra.Command{ - Use: types.ModuleName, - Short: fmt.Sprintf("%s transactions subcommands", types.ModuleName), - DisableFlagParsing: true, - SuggestionsMinimumDistance: 2, - RunE: client.ValidateCmd, - } - cmd.AddCommand(CmdPlaceOrders()) - cmd.AddCommand(CmdCancelOrders()) - cmd.AddCommand(CmdRegisterContract()) - cmd.AddCommand(CmdRegisterPairs()) - cmd.AddCommand(CmdUnregisterContract()) - cmd.AddCommand(CmdContractDepositRent()) - cmd.AddCommand(CmdUpdatePriceTickSize()) - cmd.AddCommand(CmdUpdateQuantityTickSize()) - cmd.AddCommand(NewAddAssetProposalTxCmd()) - cmd.AddCommand(CmdUnsuspendContract()) - // this line is used by starport scaffolding # 1 - - return cmd -} diff --git a/x/dex/client/cli/tx/tx_cancel_orders.go b/x/dex/client/cli/tx/tx_cancel_orders.go deleted file mode 100644 index 9ba16b5d5..000000000 --- a/x/dex/client/cli/tx/tx_cancel_orders.go +++ /dev/null @@ -1,75 +0,0 @@ -package tx - -import ( - "strconv" - "strings" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/client/tx" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/spf13/cobra" -) - -var _ = strconv.Itoa(0) - -func CmdCancelOrders() *cobra.Command { - cmd := &cobra.Command{ - Use: "cancel-orders [contract address] [cancellations...]", - Short: "Bulk cancel orders", - Long: strings.TrimSpace(` - Cancel orders placed on an orderbook specified by contract-address. Cancellations are represented as strings with the cancellation details separated by "?". Cancellation details format is OrderID?PositionDirection?Price?PriceDenom?AssetDenom. - - Example: "1234?LONG?1.01?USDC?ATOM" - `), - Args: cobra.MinimumNArgs(2), - RunE: func(cmd *cobra.Command, args []string) (err error) { - argContractAddr := args[0] - if err != nil { - return err - } - cancellations := []*types.Cancellation{} - for _, cancellation := range args[1:] { - newCancel := types.Cancellation{} - cancelDetails := strings.Split(cancellation, "?") - newCancel.Id, err = strconv.ParseUint(cancelDetails[0], 10, 64) - if err != nil { - return err - } - argPositionDir, err := types.GetPositionDirectionFromStr(cancelDetails[1]) - if err != nil { - return err - } - newCancel.PositionDirection = argPositionDir - argPrice, err := sdk.NewDecFromStr(cancelDetails[2]) - if err != nil { - return err - } - newCancel.Price = argPrice - newCancel.PriceDenom = cancelDetails[3] - newCancel.AssetDenom = cancelDetails[4] - cancellations = append(cancellations, &newCancel) - } - - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - - msg := types.NewMsgCancelOrders( - clientCtx.GetFromAddress().String(), - cancellations, - argContractAddr, - ) - if err := msg.ValidateBasic(); err != nil { - return err - } - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) - }, - } - - flags.AddTxFlagsToCmd(cmd) - - return cmd -} diff --git a/x/dex/client/cli/tx/tx_contract_deposit_rent.go b/x/dex/client/cli/tx/tx_contract_deposit_rent.go deleted file mode 100644 index fd24176eb..000000000 --- a/x/dex/client/cli/tx/tx_contract_deposit_rent.go +++ /dev/null @@ -1,52 +0,0 @@ -package tx - -import ( - "strconv" - "strings" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/client/tx" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/spf13/cast" - "github.com/spf13/cobra" -) - -var _ = strconv.Itoa(0) - -func CmdContractDepositRent() *cobra.Command { - cmd := &cobra.Command{ - Use: "contract-deposit-rent [contract address] [amount]", - Short: "Contract deposit rent", - Long: strings.TrimSpace(` - Deposit rent for an orderbook specified by contract-address. This rent allows the contract to be executed via dex hooks for calculating order updates and position settlement. - `), - Args: cobra.ExactArgs(2), - RunE: func(cmd *cobra.Command, args []string) (err error) { - argContractAddr := args[0] - argDeposit, err := cast.ToUint64E(args[1]) - if err != nil { - return err - } - - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - - msg := types.NewMsgContractDepositRent( - argContractAddr, - argDeposit, - clientCtx.GetFromAddress().String(), - ) - if err := msg.ValidateBasic(); err != nil { - return err - } - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) - }, - } - - flags.AddTxFlagsToCmd(cmd) - - return cmd -} diff --git a/x/dex/client/cli/tx/tx_place_orders.go b/x/dex/client/cli/tx/tx_place_orders.go deleted file mode 100644 index 183a0efa2..000000000 --- a/x/dex/client/cli/tx/tx_place_orders.go +++ /dev/null @@ -1,98 +0,0 @@ -package tx - -import ( - "strconv" - "strings" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/client/tx" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/spf13/cobra" -) - -var _ = strconv.Itoa(0) - -const ( - flagAmount = "amount" -) - -func CmdPlaceOrders() *cobra.Command { - cmd := &cobra.Command{ - Use: "place-orders [contract address] [orders...] --amount [coins,optional]", - Short: "Bulk place orders", - Long: strings.TrimSpace(` - Place orders on an orderbook specified by contract-address. Orders are represented as strings with the order details separated by "?". Cancellation details format is OrderDirection?Quantity?Price?PriceAsset?QuoteAsset?OrderType?OrderData?AdditionalParams. - More info here: https://docs.seinetwork.io/smart-contracts-and-local-development/dex-module-tutorial#placeorders - `), - Args: cobra.MinimumNArgs(2), - RunE: func(cmd *cobra.Command, args []string) (err error) { - argContractAddr := args[0] - orders := []*types.Order{} - for _, order := range args[1:] { - newOrder := types.Order{} - orderDetails := strings.Split(order, "?") - argPositionDir, err := types.GetPositionDirectionFromStr(orderDetails[0]) - if err != nil { - return err - } - newOrder.PositionDirection = argPositionDir - argPrice, err := sdk.NewDecFromStr(orderDetails[1]) - if err != nil { - return err - } - newOrder.Price = argPrice - argQuantity, err := sdk.NewDecFromStr(orderDetails[2]) - if err != nil { - return err - } - newOrder.Quantity = argQuantity - newOrder.PriceDenom = orderDetails[3] - newOrder.AssetDenom = orderDetails[4] - argOrderType, err := types.GetOrderTypeFromStr(orderDetails[5]) - if err != nil { - return err - } - newOrder.OrderType = argOrderType - newOrder.Data = orderDetails[6] - if newOrder.OrderType == types.OrderType_FOKMARKETBYVALUE { - argNominal, err := sdk.NewDecFromStr(orderDetails[7]) - if err != nil { - return err - } - newOrder.Nominal = argNominal - } - orders = append(orders, &newOrder) - } - - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - - amountStr, err := cmd.Flags().GetString(flagAmount) - if err != nil { - return err - } - - amount, err := sdk.ParseCoinsNormalized(amountStr) - if err != nil { - return err - } - - msg := types.NewMsgPlaceOrders( - clientCtx.GetFromAddress().String(), - orders, - argContractAddr, - amount, - ) - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) - }, - } - - cmd.Flags().String(flagAmount, "", "Coins to send to the contract along with command") - flags.AddTxFlagsToCmd(cmd) - - return cmd -} diff --git a/x/dex/client/cli/tx/tx_register_contract.go b/x/dex/client/cli/tx/tx_register_contract.go deleted file mode 100644 index 312435ab9..000000000 --- a/x/dex/client/cli/tx/tx_register_contract.go +++ /dev/null @@ -1,68 +0,0 @@ -package tx - -import ( - "strconv" - "strings" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/client/tx" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/spf13/cast" - "github.com/spf13/cobra" -) - -var _ = strconv.Itoa(0) - -func CmdRegisterContract() *cobra.Command { - cmd := &cobra.Command{ - Use: "register-contract [contract address] [code id] [(deprecated)] [need order matching] [deposit] [dependency1,dependency2,...]", - Short: "Register exchange contract", - Long: strings.TrimSpace(` - Register a contract with the dex module for order matching hooks. The available order matching functions are BulkOrderPlacements, BulkOrderCancellations, Settlement. A deposit can also be specified as the initial rent to allocate for the execution of the order matching. - Other orderbooks that are dependencies can also be specified so that dex orderbook processing can be performed in the appropriate order. - `), - Args: cobra.MinimumNArgs(5), - RunE: func(cmd *cobra.Command, args []string) (err error) { - argContractAddr := args[0] - argCodeID, err := cast.ToUint64E(args[1]) - if err != nil { - return err - } - argNeedMatching, err := strconv.ParseBool(args[3]) - if err != nil { - return err - } - argDeposit, err := cast.ToUint64E(args[4]) - if err != nil { - return err - } - var dependencies []*types.ContractDependencyInfo - for _, dependency := range args[5:] { - dependencies = append(dependencies, &types.ContractDependencyInfo{Dependency: dependency}) - } - - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - - msg := types.NewMsgRegisterContract( - clientCtx.GetFromAddress().String(), - argCodeID, - argContractAddr, - argNeedMatching, - dependencies, - argDeposit, - ) - if err := msg.ValidateBasic(); err != nil { - return err - } - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) - }, - } - - flags.AddTxFlagsToCmd(cmd) - - return cmd -} diff --git a/x/dex/client/cli/tx/tx_register_pairs.go b/x/dex/client/cli/tx/tx_register_pairs.go deleted file mode 100644 index 61411c52c..000000000 --- a/x/dex/client/cli/tx/tx_register_pairs.go +++ /dev/null @@ -1,54 +0,0 @@ -package tx - -import ( - "strconv" - "strings" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/client/tx" - cutils "github.com/sei-protocol/sei-chain/x/dex/client/utils" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/spf13/cobra" -) - -var _ = strconv.Itoa(0) - -func CmdRegisterPairs() *cobra.Command { - cmd := &cobra.Command{ - Use: "register-pairs [register-pairs-file]", - Short: "Register pairs for a contract", - Long: strings.TrimSpace(` - This allows for registering new pairs with a json file representing the various pairs to be registered. The pairs are specified within the file using the contract address for the orderbook along with pair information. - `), - Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) (err error) { - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - registerTx, err := cutils.ParseRegisterPairsTxJSON(clientCtx.LegacyAmino, args[0]) - if err != nil { - return err - } - - txBatchContractPair, err := registerTx.BatchContractPair.ToMultipleBatchContractPair() - if err != nil { - return err - } - - msg := types.NewMsgRegisterPairs( - clientCtx.GetFromAddress().String(), - txBatchContractPair, - ) - if err := msg.ValidateBasic(); err != nil { - return err - } - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) - }, - } - - flags.AddTxFlagsToCmd(cmd) - - return cmd -} diff --git a/x/dex/client/cli/tx/tx_unregister_contract.go b/x/dex/client/cli/tx/tx_unregister_contract.go deleted file mode 100644 index 08c187658..000000000 --- a/x/dex/client/cli/tx/tx_unregister_contract.go +++ /dev/null @@ -1,46 +0,0 @@ -package tx - -import ( - "strconv" - "strings" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/client/tx" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/spf13/cobra" -) - -var _ = strconv.Itoa(0) - -func CmdUnregisterContract() *cobra.Command { - cmd := &cobra.Command{ - Use: "unregister-contract [contract address]", - Short: "Unregister exchange contract", - Long: strings.TrimSpace(` - Unregisters an exchange contract so it no longer receives the execution hooks or order matching hooks. - `), - Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) (err error) { - argContractAddr := args[0] - - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - - msg := types.NewMsgUnregisterContract( - clientCtx.GetFromAddress().String(), - argContractAddr, - ) - if err := msg.ValidateBasic(); err != nil { - return err - } - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) - }, - } - - flags.AddTxFlagsToCmd(cmd) - - return cmd -} diff --git a/x/dex/client/cli/tx/tx_unsuspend_contract.go b/x/dex/client/cli/tx/tx_unsuspend_contract.go deleted file mode 100644 index ce9203ca9..000000000 --- a/x/dex/client/cli/tx/tx_unsuspend_contract.go +++ /dev/null @@ -1,46 +0,0 @@ -package tx - -import ( - "strconv" - "strings" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/client/tx" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/spf13/cobra" -) - -var _ = strconv.Itoa(0) - -func CmdUnsuspendContract() *cobra.Command { - cmd := &cobra.Command{ - Use: "unsuspend-contract [contract address]", - Short: "Unsuspend exchange contract", - Long: strings.TrimSpace(` - Unsuspend an exchange contract which was suspended due to Sudo malfunctioning, at a cost to its rent. - `), - Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) (err error) { - argContractAddr := args[0] - - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - - msg := types.NewMsgUnsuspendContract( - clientCtx.GetFromAddress().String(), - argContractAddr, - ) - if err := msg.ValidateBasic(); err != nil { - return err - } - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) - }, - } - - flags.AddTxFlagsToCmd(cmd) - - return cmd -} diff --git a/x/dex/client/cli/tx/tx_update_price_tick_size.go b/x/dex/client/cli/tx/tx_update_price_tick_size.go deleted file mode 100644 index 44dfedfe8..000000000 --- a/x/dex/client/cli/tx/tx_update_price_tick_size.go +++ /dev/null @@ -1,54 +0,0 @@ -package tx - -import ( - "strconv" - "strings" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/client/tx" - cutils "github.com/sei-protocol/sei-chain/x/dex/client/utils" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/spf13/cobra" -) - -var _ = strconv.Itoa(0) - -func CmdUpdatePriceTickSize() *cobra.Command { - cmd := &cobra.Command{ - Use: "update-price-tick-size [update-price-tick-size-file]", - Short: "Update price tick size for a market", - Long: strings.TrimSpace(` - Updates the price tick size for a specific pair for an orderbook specified by contract address. The file contains a list of pair info, new tick size, and contract addresses to allow for updating multiple tick sizes in one transaction. - `), - Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) (err error) { - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - tickTx, err := cutils.ParseUpdateTickSizeTxJSON(clientCtx.LegacyAmino, args[0]) - if err != nil { - return err - } - - txTick, err := tickTx.TickSizes.ToTickSizes() - if err != nil { - return err - } - - msg := types.NewMsgUpdatePriceTickSize( - clientCtx.GetFromAddress().String(), - txTick, - ) - if err := msg.ValidateBasic(); err != nil { - return err - } - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) - }, - } - - flags.AddTxFlagsToCmd(cmd) - - return cmd -} diff --git a/x/dex/client/cli/tx/tx_update_quantity_tick_size.go b/x/dex/client/cli/tx/tx_update_quantity_tick_size.go deleted file mode 100644 index 5e46f50a0..000000000 --- a/x/dex/client/cli/tx/tx_update_quantity_tick_size.go +++ /dev/null @@ -1,54 +0,0 @@ -package tx - -import ( - "strconv" - "strings" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/client/tx" - cutils "github.com/sei-protocol/sei-chain/x/dex/client/utils" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/spf13/cobra" -) - -var _ = strconv.Itoa(0) - -func CmdUpdateQuantityTickSize() *cobra.Command { - cmd := &cobra.Command{ - Use: "update-quantity-tick-size [update-quantity-tick-size-file]", - Short: "Update quantity tick size for a market", - Long: strings.TrimSpace(` - Updates the quantity tick size for a specific pair for an orderbook specified by contract address. The file contains a list of pair info, new tick size, and contract addresses to allow for updating multiple tick sizes in one transaction. - `), - Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) (err error) { - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - tickTx, err := cutils.ParseUpdateTickSizeTxJSON(clientCtx.LegacyAmino, args[0]) - if err != nil { - return err - } - - txTick, err := tickTx.TickSizes.ToTickSizes() - if err != nil { - return err - } - - msg := types.NewMsgUpdateQuantityTickSize( - clientCtx.GetFromAddress().String(), - txTick, - ) - if err := msg.ValidateBasic(); err != nil { - return err - } - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) - }, - } - - flags.AddTxFlagsToCmd(cmd) - - return cmd -} diff --git a/x/dex/client/utils/utils.go b/x/dex/client/utils/utils.go deleted file mode 100644 index a151b652c..000000000 --- a/x/dex/client/utils/utils.go +++ /dev/null @@ -1,203 +0,0 @@ -package utils - -import ( - "errors" - "os" - - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - dextypes "github.com/sei-protocol/sei-chain/x/dex/types" -) - -type ( - PairJSON struct { - PriceDenom string `json:"price_denom" yaml:"price_denom"` - AssetDenom string `json:"asset_denom" yaml:"asset_denom"` - PriceTickSize string `json:"price_tick_size" yaml:"tick_size"` - QuantityTickSize string `json:"quantity_tick_size" yaml:"tick_size"` - } - - TickSizeJSON struct { - Pair PairJSON `json:"pair" yaml:"pair"` - TickSize sdk.Dec `json:"tick_size" yaml:"tick_size"` - ContractAddr string `json:"contract_addr" yaml:"contract_addr"` - } - - PairsJSON []PairJSON - TickSizesJSON []TickSizeJSON - AssetListJSON []dextypes.AssetMetadata - - // ParamChangeJSON defines a parameter change used in JSON input. This - // allows values to be specified in raw JSON instead of being string encoded. - BatchContractPairJSON struct { - ContractAddr string `json:"contract_addr" yaml:"contract_addr"` - Pairs PairsJSON `json:"pairs" yaml:"pairs"` - } - - MultipleBatchContractPairJSON []BatchContractPairJSON - - // RegisterPairsTxJSON defines a RegisterPairsTx - // to parse register pair tx's from a JSON file. - RegisterPairsTxJSON struct { - BatchContractPair MultipleBatchContractPairJSON `json:"batch_contract_pair" yaml:"batch_contract_pair"` - } - - UpdateTickSizeTxJSON struct { - TickSizes TickSizesJSON `json:"tick_size_list" yaml:"tick_size_list"` - } - - AddAssetMetadataProposalJSON struct { - Title string `json:"title" yaml:"title"` - Description string `json:"description" yaml:"description"` - AssetList AssetListJSON `json:"asset_list" yaml:"asset_list"` - Deposit string `json:"deposit" yaml:"deposit"` - } -) - -// TODO: ADD utils to convert Each type to dex/type (string to denom) -func NewPair(pair PairJSON) (dextypes.Pair, error) { - PriceDenom := pair.PriceDenom - AssetDenom := pair.AssetDenom - priceTicksize, err := sdk.NewDecFromStr(pair.PriceTickSize) - if err != nil { - return dextypes.Pair{}, errors.New("price ticksize: str to decimal conversion err") - } - if priceTicksize.LTE(sdk.ZeroDec()) { - return dextypes.Pair{}, errors.New("price ticksize: value cannot be zero or negative") - } - quantityTicksize, err := sdk.NewDecFromStr(pair.QuantityTickSize) - if err != nil { - return dextypes.Pair{}, errors.New("quantity ticksize: str to decimal conversion err") - } - if quantityTicksize.LTE(sdk.ZeroDec()) { - return dextypes.Pair{}, errors.New("quantity ticksize: value cannot be zero or negative") - } - return dextypes.Pair{PriceDenom: PriceDenom, AssetDenom: AssetDenom, PriceTicksize: &priceTicksize, QuantityTicksize: &quantityTicksize}, nil -} - -// ToParamChange converts a ParamChangeJSON object to ParamChange. -func (bcp BatchContractPairJSON) ToBatchContractPair() (dextypes.BatchContractPair, error) { - pairs := make([]*dextypes.Pair, len(bcp.Pairs)) - for i, p := range bcp.Pairs { - newPair, err := NewPair(p) - if err != nil { - return dextypes.BatchContractPair{}, nil - } - pairs[i] = &newPair - } - return dextypes.BatchContractPair{ContractAddr: bcp.ContractAddr, Pairs: pairs}, nil -} - -func (ts TickSizeJSON) ToTickSize() (dextypes.TickSize, error) { - // validate the tick size here - pair, err := NewPair(ts.Pair) - if err != nil { - return dextypes.TickSize{}, err - } - return dextypes.TickSize{ - Pair: &pair, - Ticksize: ts.TickSize, - ContractAddr: ts.ContractAddr, - }, nil -} - -// ToParamChanges converts a slice of ParamChangeJSON objects to a slice of -// ParamChange. -func (mbcp MultipleBatchContractPairJSON) ToMultipleBatchContractPair() ([]dextypes.BatchContractPair, error) { - res := make([]dextypes.BatchContractPair, len(mbcp)) - for i, bcp := range mbcp { - newBatch, err := bcp.ToBatchContractPair() - if err != nil { - return res, nil - } - res[i] = newBatch - } - return res, nil -} - -func (tss TickSizesJSON) ToTickSizes() ([]dextypes.TickSize, error) { - res := make([]dextypes.TickSize, len(tss)) - for i, ts := range tss { - ticksize, err := ts.ToTickSize() - if err != nil { - return res, nil - } - res[i] = ticksize - } - return res, nil -} - -// ParseRegisterPairsTxJSON reads and parses a RegisterPairsTxJSON from -// a file. -func ParseRegisterPairsTxJSON(cdc *codec.LegacyAmino, txFile string) (RegisterPairsTxJSON, error) { - registerTx := RegisterPairsTxJSON{} - - contents, err := os.ReadFile(txFile) - if err != nil { - return registerTx, err - } - - if err := cdc.UnmarshalJSON(contents, ®isterTx); err != nil { - return registerTx, err - } - - return registerTx, nil -} - -// ParseUpdateTickSizeTxJSON reads and parses a UpdateTickSizeTxJSON from -// a file. -func ParseUpdateTickSizeTxJSON(cdc *codec.LegacyAmino, txFile string) (UpdateTickSizeTxJSON, error) { - tickTx := UpdateTickSizeTxJSON{} - - contents, err := os.ReadFile(txFile) - if err != nil { - return tickTx, err - } - - if err := cdc.UnmarshalJSON(contents, &tickTx); err != nil { - return tickTx, err - } - - return tickTx, nil -} - -// ParseAddAssetMetadataProposalJSON reads and parses an AddAssetMetadataProposalJSON from -// a file. -func ParseAddAssetMetadataProposalJSON(cdc *codec.LegacyAmino, proposalFile string) (AddAssetMetadataProposalJSON, error) { - proposal := AddAssetMetadataProposalJSON{} - - contents, err := os.ReadFile(proposalFile) - if err != nil { - return proposal, err - } - - if err := cdc.UnmarshalJSON(contents, &proposal); err != nil { - return proposal, err - } - - // Verify base denoms specified in proposal are well formed - // Additionally verify that the asset "display" field is included in denom unit - for _, asset := range proposal.AssetList { - err := sdk.ValidateDenom(asset.Metadata.Base) - if err != nil { - return AddAssetMetadataProposalJSON{}, err - } - - // The display denom must have an associated DenomUnit field - display := asset.Metadata.Display - found := false - for _, denomUnit := range asset.Metadata.DenomUnits { - if denomUnit.Denom == display { - found = true - break - } - } - - if !found { - return AddAssetMetadataProposalJSON{}, errors.New("Display denom " + display + " has no associated DenomUnit in Metadata.") - } - - } - - return proposal, nil -} diff --git a/x/dex/client/wasm/bindings/queries.go b/x/dex/client/wasm/bindings/queries.go deleted file mode 100644 index 12fbe2a10..000000000 --- a/x/dex/client/wasm/bindings/queries.go +++ /dev/null @@ -1,12 +0,0 @@ -package bindings - -import "github.com/sei-protocol/sei-chain/x/dex/types" - -type SeiDexQuery struct { - // queries the dex TWAPs - DexTwaps *types.QueryGetTwapsRequest `json:"dex_twaps,omitempty"` - GetOrders *types.QueryGetOrdersRequest `json:"get_orders,omitempty"` - GetOrderByID *types.QueryGetOrderByIDRequest `json:"get_order_by_id,omitempty"` - GetOrderSimulation *types.QueryOrderSimulationRequest `json:"order_simulation,omitempty"` - GetLatestPrice *types.QueryGetLatestPriceRequest `json:"get_latest_price,omitempty"` -} diff --git a/x/dex/client/wasm/encoder.go b/x/dex/client/wasm/encoder.go deleted file mode 100644 index 0a56156a4..000000000 --- a/x/dex/client/wasm/encoder.go +++ /dev/null @@ -1,36 +0,0 @@ -package wasm - -import ( - "encoding/json" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/wasmbinding/bindings" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -func EncodeDexPlaceOrders(rawMsg json.RawMessage, sender sdk.AccAddress) ([]sdk.Msg, error) { - encodedPlaceOrdersMsg := bindings.PlaceOrders{} - if err := json.Unmarshal(rawMsg, &encodedPlaceOrdersMsg); err != nil { - return []sdk.Msg{}, types.ErrEncodeDexPlaceOrders - } - placeOrdersMsg := types.MsgPlaceOrders{ - Creator: sender.String(), - Orders: encodedPlaceOrdersMsg.Orders, - ContractAddr: encodedPlaceOrdersMsg.ContractAddr, - Funds: encodedPlaceOrdersMsg.Funds, - } - return []sdk.Msg{&placeOrdersMsg}, nil -} - -func EncodeDexCancelOrders(rawMsg json.RawMessage, sender sdk.AccAddress) ([]sdk.Msg, error) { - encodedCancelOrdersMsg := bindings.CancelOrders{} - if err := json.Unmarshal(rawMsg, &encodedCancelOrdersMsg); err != nil { - return []sdk.Msg{}, types.ErrEncodeDexCancelOrders - } - cancelOrdersMsg := types.MsgCancelOrders{ - Creator: sender.String(), - Cancellations: encodedCancelOrdersMsg.Cancellations, - ContractAddr: encodedCancelOrdersMsg.ContractAddr, - } - return []sdk.Msg{&cancelOrdersMsg}, nil -} diff --git a/x/dex/client/wasm/query.go b/x/dex/client/wasm/query.go deleted file mode 100644 index 41f86f162..000000000 --- a/x/dex/client/wasm/query.go +++ /dev/null @@ -1,48 +0,0 @@ -package wasm - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/keeper" - "github.com/sei-protocol/sei-chain/x/dex/keeper/query" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -type DexWasmQueryHandler struct { - dexKeeper keeper.Keeper -} - -func NewDexWasmQueryHandler(keeper *keeper.Keeper) *DexWasmQueryHandler { - return &DexWasmQueryHandler{ - dexKeeper: *keeper, - } -} - -func (handler DexWasmQueryHandler) GetDexTwap(ctx sdk.Context, req *types.QueryGetTwapsRequest) (*types.QueryGetTwapsResponse, error) { - c := sdk.WrapSDKContext(ctx) - wrapper := query.KeeperWrapper{Keeper: &handler.dexKeeper} - return wrapper.GetTwaps(c, req) -} - -func (handler DexWasmQueryHandler) GetOrders(ctx sdk.Context, req *types.QueryGetOrdersRequest) (*types.QueryGetOrdersResponse, error) { - c := sdk.WrapSDKContext(ctx) - wrapper := query.KeeperWrapper{Keeper: &handler.dexKeeper} - return wrapper.GetOrders(c, req) -} - -func (handler DexWasmQueryHandler) GetOrderByID(ctx sdk.Context, req *types.QueryGetOrderByIDRequest) (*types.QueryGetOrderByIDResponse, error) { - c := sdk.WrapSDKContext(ctx) - wrapper := query.KeeperWrapper{Keeper: &handler.dexKeeper} - return wrapper.GetOrder(c, req) -} - -func (handler DexWasmQueryHandler) GetOrderSimulation(ctx sdk.Context, req *types.QueryOrderSimulationRequest) (*types.QueryOrderSimulationResponse, error) { - c := sdk.WrapSDKContext(ctx) - wrapper := query.KeeperWrapper{Keeper: &handler.dexKeeper} - return wrapper.GetOrderSimulation(c, req) -} - -func (handler DexWasmQueryHandler) GetLatestPrice(ctx sdk.Context, req *types.QueryGetLatestPriceRequest) (*types.QueryGetLatestPriceResponse, error) { - c := sdk.WrapSDKContext(ctx) - wrapper := query.KeeperWrapper{Keeper: &handler.dexKeeper} - return wrapper.GetLatestPrice(c, req) -} diff --git a/x/dex/contract/abci.go b/x/dex/contract/abci.go deleted file mode 100644 index 712c01c67..000000000 --- a/x/dex/contract/abci.go +++ /dev/null @@ -1,323 +0,0 @@ -package contract - -import ( - "context" - "errors" - "fmt" - "sync" - "time" - - "github.com/cosmos/cosmos-sdk/telemetry" - "github.com/cosmos/cosmos-sdk/utils/tracing" - "github.com/sei-protocol/sei-chain/utils/logging" - - sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" - "github.com/sei-protocol/sei-chain/store/whitelist/multi" - seisync "github.com/sei-protocol/sei-chain/sync" - "github.com/sei-protocol/sei-chain/utils/datastructures" - dexcache "github.com/sei-protocol/sei-chain/x/dex/cache" - "github.com/sei-protocol/sei-chain/x/dex/keeper" - dexkeeperabci "github.com/sei-protocol/sei-chain/x/dex/keeper/abci" - dexkeeperutils "github.com/sei-protocol/sei-chain/x/dex/keeper/utils" - "github.com/sei-protocol/sei-chain/x/dex/types" - dexutils "github.com/sei-protocol/sei-chain/x/dex/utils" - "github.com/sei-protocol/sei-chain/x/store" - otrace "go.opentelemetry.io/otel/trace" -) - -const LogRunnerRunAfter = 10 * time.Second -const LogExecSigSendAfter = 2 * time.Second - -type environment struct { - validContractsInfo []types.ContractInfoV2 - failedContractAddressesToErrors *datastructures.TypedSyncMap[string, error] - outOfRentContractAddresses datastructures.SyncSet[string] - settlementsByContract *datastructures.TypedSyncMap[string, []*types.SettlementEntry] - executionTerminationSignals *datastructures.TypedSyncMap[string, chan struct{}] - registeredPairs *datastructures.TypedSyncMap[string, []types.Pair] - orderBooks *datastructures.TypedNestedSyncMap[string, types.PairString, *types.OrderBook] - - finalizeMsgMutex *sync.Mutex - eventManagerMutex *sync.Mutex -} - -func EndBlockerAtomic(ctx sdk.Context, keeper *keeper.Keeper, validContractsInfo []types.ContractInfoV2, tracingInfo *tracing.Info) ([]types.ContractInfoV2, []types.ContractInfoV2, map[string]string, sdk.Context, bool) { - tracer := tracingInfo.Tracer - spanCtx, span := tracingInfo.Start("DexEndBlockerAtomic") - defer span.End() - defer telemetry.MeasureSince(time.Now(), "dex", "end_blocker_atomic") - - env := newEnv(ctx, validContractsInfo, keeper) - cachedCtx, msCached := cacheContext(ctx, env) - memStateCopy := dexutils.GetMemState(cachedCtx.Context()).DeepCopy() - contractsToProcess := memStateCopy.GetContractToProcessOrderedSlice(cachedCtx) - preRunRents := keeper.GetRentsForContracts(cachedCtx, contractsToProcess) - - handleDeposits(spanCtx, cachedCtx, env, keeper, tracer) - - runner := NewParallelRunner(func(contract types.ContractInfoV2) { - OrderMatchingRunnable(spanCtx, cachedCtx, env, keeper, contract, tracer) - }, validContractsInfo, cachedCtx) - - _, err := logging.LogIfNotDoneAfter(ctx.Logger(), func() (struct{}, error) { - runner.Run() - return struct{}{}, nil - }, LogRunnerRunAfter, "runner run") - if err != nil { - // this should never happen - panic(err) - } - - handleSettlements(spanCtx, cachedCtx, env, keeper, tracer) - handleUnfulfilledMarketOrders(spanCtx, cachedCtx, env, keeper, tracer) - - telemetry.IncrCounter(float32(env.failedContractAddressesToErrors.Len()), "dex", "total_failed_contracts") - // No error is thrown for any contract. This should happen most of the time. - if env.failedContractAddressesToErrors.Len() == 0 { - postRunRents := keeper.GetRentsForContracts(cachedCtx, contractsToProcess) - TransferRentFromDexToCollector(cachedCtx, keeper.BankKeeper, preRunRents, postRunRents) - msCached.Write() - return env.validContractsInfo, []types.ContractInfoV2{}, map[string]string{}, ctx, true - } - - failedContractsToReasons := map[string]string{} - failedContractsPreRents := map[string]uint64{} - failedContractsPostRents := map[string]uint64{} - // persistent contract rent charges for failed contracts and discard everything else - env.failedContractAddressesToErrors.Range(func(failedContractAddress string, failedReason error) bool { - cachedContract, err := keeper.GetContract(cachedCtx, failedContractAddress) - if err != nil { - ctx.Logger().Error(fmt.Sprintf("error %s when getting updated contract %s to persist rent balance", err, failedContractAddress)) - return true - } - contract, err := keeper.GetContract(ctx, failedContractAddress) - if err != nil { - ctx.Logger().Error(fmt.Sprintf("error %s when getting contract %s to persist rent balance", err, failedContractAddress)) - return true - } - contract.RentBalance = cachedContract.RentBalance - failedContractsPreRents[failedContractAddress] = preRunRents[failedContractAddress] - failedContractsPostRents[failedContractAddress] = contract.RentBalance - err = keeper.SetContract(ctx, &contract) - if err != nil { - ctx.Logger().Error(fmt.Sprintf("error %s when persisting contract %s's rent balance", err, failedContractAddress)) - return true - } - failedContractsToReasons[failedContractAddress] = dexutils.GetTruncatedErrors(failedReason) - return true - }) - TransferRentFromDexToCollector(ctx, keeper.BankKeeper, failedContractsPreRents, failedContractsPostRents) - - // restore keeper in-memory state - newGoContext := context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, memStateCopy) - return filterNewValidContracts(ctx, env), getOutOfRentContracts(env), failedContractsToReasons, ctx.WithContext(newGoContext), false -} - -func newEnv(ctx sdk.Context, validContractsInfo []types.ContractInfoV2, keeper *keeper.Keeper) *environment { - settlementsByContract := datastructures.NewTypedSyncMap[string, []*types.SettlementEntry]() - executionTerminationSignals := datastructures.NewTypedSyncMap[string, chan struct{}]() - registeredPairs := datastructures.NewTypedSyncMap[string, []types.Pair]() - allContractAndPairs := map[string][]types.Pair{} - for _, contract := range validContractsInfo { - settlementsByContract.Store(contract.ContractAddr, []*types.SettlementEntry{}) - executionTerminationSignals.Store(contract.ContractAddr, make(chan struct{}, 1)) - contractPairs := keeper.GetAllRegisteredPairs(ctx, contract.ContractAddr) - registeredPairs.Store(contract.ContractAddr, contractPairs) - allContractAndPairs[contract.ContractAddr] = contractPairs - } - // Parallelize populating orderbooks for performance improvements - orderBooks := dexkeeperutils.PopulateAllOrderbooks(ctx, keeper, allContractAndPairs) - return &environment{ - validContractsInfo: validContractsInfo, - failedContractAddressesToErrors: datastructures.NewTypedSyncMap[string, error](), - outOfRentContractAddresses: datastructures.NewSyncSet([]string{}), - settlementsByContract: settlementsByContract, - executionTerminationSignals: executionTerminationSignals, - registeredPairs: registeredPairs, - orderBooks: orderBooks, - finalizeMsgMutex: &sync.Mutex{}, - eventManagerMutex: &sync.Mutex{}, - } -} - -func (e *environment) addError(contractAddr string, err error) { - if err == types.ErrInsufficientRent { - e.outOfRentContractAddresses.Add(contractAddr) - return - } - e.failedContractAddressesToErrors.Store(contractAddr, err) -} - -func cacheContext(ctx sdk.Context, env *environment) (sdk.Context, sdk.CacheMultiStore) { - cachedCtx, msCached := store.GetCachedContext(ctx) - goCtx := context.WithValue(cachedCtx.Context(), dexcache.CtxKeyExecTermSignal, env.executionTerminationSignals) - cachedCtx = cachedCtx.WithContext(goCtx) - return cachedCtx, msCached -} - -func decorateContextForContract(ctx sdk.Context, contractInfo types.ContractInfoV2) sdk.Context { - goCtx := context.WithValue(ctx.Context(), dexcache.CtxKeyExecutingContract, contractInfo) - whitelistedStore := multi.NewStore(ctx.MultiStore(), GetWhitelistMap(contractInfo.ContractAddr)) - newEventManager := sdk.NewEventManager() - return ctx.WithContext(goCtx).WithMultiStore(whitelistedStore).WithEventManager(newEventManager).WithGasMeter( - seisync.NewGasWrapper(sdk.NewInfiniteGasMeterWithMultiplier(ctx)), - ) -} - -func handleDeposits(spanCtx context.Context, ctx sdk.Context, env *environment, keeper *keeper.Keeper, tracer *otrace.Tracer) { - // Handle deposit sequentially since they mutate `bank` state which is shared by all contracts - _, span := (*tracer).Start(spanCtx, "handleDeposits") - defer span.End() - defer telemetry.MeasureSince(time.Now(), "dex", "handle_deposits") - keeperWrapper := dexkeeperabci.KeeperWrapper{Keeper: keeper} - for _, contract := range env.validContractsInfo { - if !dexutils.GetMemState(ctx.Context()).ContractsToProcessContains(ctx, contract.ContractAddr) { - continue - } - if !contract.NeedOrderMatching { - continue - } - if err := keeperWrapper.HandleEBDeposit(spanCtx, ctx, tracer, contract.ContractAddr); err != nil { - env.addError(contract.ContractAddr, err) - } - } -} - -func handleSettlements(ctx context.Context, sdkCtx sdk.Context, env *environment, keeper *keeper.Keeper, tracer *otrace.Tracer) { - _, span := (*tracer).Start(ctx, "DexEndBlockerHandleSettlements") - defer span.End() - defer telemetry.MeasureSince(time.Now(), "dex", "handle_settlements") - contractsNeedOrderMatching := datastructures.NewSyncSet([]string{}) - for _, contract := range env.validContractsInfo { - if contract.NeedOrderMatching { - contractsNeedOrderMatching.Add(contract.ContractAddr) - } - } - env.settlementsByContract.Range(func(contractAddr string, settlements []*types.SettlementEntry) bool { - if !contractsNeedOrderMatching.Contains(contractAddr) { - return true - } - if err := HandleSettlements(sdkCtx, contractAddr, keeper, settlements); err != nil { - sdkCtx.Logger().Error(fmt.Sprintf("Error handling settlements for %s", contractAddr)) - env.addError(contractAddr, err) - } - return true - }) -} - -func handleUnfulfilledMarketOrders(ctx context.Context, sdkCtx sdk.Context, env *environment, keeper *keeper.Keeper, tracer *otrace.Tracer) { - // Cancel unfilled market orders - defer telemetry.MeasureSince(time.Now(), "dex", "handle_unfulfilled_market_orders") - for _, contract := range env.validContractsInfo { - if !dexutils.GetMemState(sdkCtx.Context()).ContractsToProcessContains(sdkCtx, contract.ContractAddr) { - return - } - if contract.NeedOrderMatching { - registeredPairs, found := env.registeredPairs.Load(contract.ContractAddr) - if !found { - continue - } - if err := CancelUnfulfilledMarketOrders(ctx, sdkCtx, contract.ContractAddr, keeper, registeredPairs, tracer); err != nil { - sdkCtx.Logger().Error(fmt.Sprintf("Error cancelling unfulfilled market orders for %s", contract.ContractAddr)) - env.addError(contract.ContractAddr, err) - } - } - } -} - -func OrderMatchingRunnable(ctx context.Context, sdkContext sdk.Context, env *environment, keeper *keeper.Keeper, contractInfo types.ContractInfoV2, tracer *otrace.Tracer) { - defer func() { - if err := recover(); err != nil { - telemetry.IncrCounter(1, "recovered_panics") - msg := fmt.Sprintf("PANIC RECOVERED during order matching: %s", err) - sdkContext.Logger().Error(msg) - if env != nil { - env.addError(contractInfo.ContractAddr, errors.New(msg)) - } - } - }() - _, span := (*tracer).Start(ctx, "OrderMatchingRunnable") - defer span.End() - defer telemetry.MeasureSince(time.Now(), "dex", "order_matching_runnable") - defer func() { - if channel, ok := env.executionTerminationSignals.Load(contractInfo.ContractAddr); ok { - _, err := logging.LogIfNotDoneAfter(sdkContext.Logger(), func() (struct{}, error) { - channel <- struct{}{} - return struct{}{}, nil - }, LogExecSigSendAfter, fmt.Sprintf("send execution terminal signal for %s", contractInfo.ContractAddr)) - if err != nil { - // this should never happen - panic(err) - } - } - }() - if !dexutils.GetMemState(sdkContext.Context()).ContractsToProcessContains(sdkContext, contractInfo.ContractAddr) { - return - } - if !contractInfo.NeedOrderMatching { - return - } - parentSdkContext := sdkContext - sdkContext = decorateContextForContract(sdkContext, contractInfo) - sdkContext.Logger().Debug(fmt.Sprintf("End block for %s with balance of %d", contractInfo.ContractAddr, contractInfo.RentBalance)) - pairs, pairFound := env.registeredPairs.Load(contractInfo.ContractAddr) - orderBooks, found := env.orderBooks.Load(contractInfo.ContractAddr) - - if !pairFound || !found { - sdkContext.Logger().Error(fmt.Sprintf("No pair or order book for %s", contractInfo.ContractAddr)) - env.addError(contractInfo.ContractAddr, errors.New("no pair found (internal error)")) - } else if settlements, err := HandleExecutionForContract(ctx, sdkContext, contractInfo, keeper, pairs, orderBooks, tracer); err != nil { - sdkContext.Logger().Error(fmt.Sprintf("Error for EndBlock of %s", contractInfo.ContractAddr)) - env.addError(contractInfo.ContractAddr, err) - } else { - env.settlementsByContract.Store(contractInfo.ContractAddr, settlements) - } - - // ordering of events doesn't matter since events aren't part of consensus - env.eventManagerMutex.Lock() - defer env.eventManagerMutex.Unlock() - parentSdkContext.EventManager().EmitEvents(sdkContext.EventManager().Events()) -} - -func filterNewValidContracts(ctx sdk.Context, env *environment) []types.ContractInfoV2 { - newValidContracts := []types.ContractInfoV2{} - for _, contract := range env.validContractsInfo { - if _, ok := env.failedContractAddressesToErrors.Load(contract.ContractAddr); !ok && !env.outOfRentContractAddresses.Contains(contract.ContractAddr) { - newValidContracts = append(newValidContracts, contract) - } - } - env.failedContractAddressesToErrors.Range(func(failedContractAddress string, _ error) bool { - dexutils.GetMemState(ctx.Context()).DeepFilterAccount(ctx, failedContractAddress) - return true - }) - for _, outOfRentContractAddress := range env.outOfRentContractAddresses.ToOrderedSlice(datastructures.StringComparator) { - dexutils.GetMemState(ctx.Context()).DeepFilterAccount(ctx, outOfRentContractAddress) - } - return newValidContracts -} - -func getOutOfRentContracts(env *environment) []types.ContractInfoV2 { - outOfRentContracts := []types.ContractInfoV2{} - for _, contract := range env.validContractsInfo { - if env.outOfRentContractAddresses.Contains(contract.ContractAddr) { - outOfRentContracts = append(outOfRentContracts, contract) - } - } - return outOfRentContracts -} - -func TransferRentFromDexToCollector(ctx sdk.Context, bankKeeper bankkeeper.Keeper, preRents map[string]uint64, postRents map[string]uint64) { - total := uint64(0) - for addr, preRent := range preRents { - if postRent, ok := postRents[addr]; ok { - total += preRent - postRent - } else { - total += preRent - } - } - if err := bankKeeper.SendCoinsFromModuleToModule(ctx, types.ModuleName, authtypes.FeeCollectorName, sdk.NewCoins(sdk.NewCoin("usei", sdk.NewIntFromUint64(total)))); err != nil { - ctx.Logger().Error("sending coins from dex to fee collector failed due to %s", err) - } -} diff --git a/x/dex/contract/abci_test.go b/x/dex/contract/abci_test.go deleted file mode 100644 index 3d0b7650b..000000000 --- a/x/dex/contract/abci_test.go +++ /dev/null @@ -1,43 +0,0 @@ -package contract_test - -import ( - "context" - "testing" - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex/contract" - "github.com/sei-protocol/sei-chain/x/dex/types" - minttypes "github.com/sei-protocol/sei-chain/x/mint/types" - "github.com/stretchr/testify/require" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" -) - -func TestTransferRentFromDexToCollector(t *testing.T) { - preRents := map[string]uint64{"abc": 100, "def": 50} - postRents := map[string]uint64{"abc": 70} - - // expected total is (100 - 70) + 50 = 80 - testApp := keepertest.TestApp() - ctx := testApp.BaseApp.NewContext(false, tmproto.Header{Time: time.Now()}) - bankkeeper := testApp.BankKeeper - err := bankkeeper.MintCoins(ctx, minttypes.ModuleName, sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(100)))) - require.Nil(t, err) - err = bankkeeper.SendCoinsFromModuleToModule(ctx, minttypes.ModuleName, types.ModuleName, sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(100)))) - require.Nil(t, err) - contract.TransferRentFromDexToCollector(ctx, bankkeeper, preRents, postRents) - dexBalance := bankkeeper.GetBalance(ctx, testApp.AccountKeeper.GetModuleAddress(types.ModuleName), "usei") - require.Equal(t, int64(20), dexBalance.Amount.Int64()) - collectorBalance := bankkeeper.GetBalance(ctx, testApp.AccountKeeper.GetModuleAddress(authtypes.FeeCollectorName), "usei") - require.Equal(t, int64(80), collectorBalance.Amount.Int64()) -} - -func TestOrderMatchingRunnablePanicHandler(t *testing.T) { - testApp := keepertest.TestApp() - ctx := testApp.BaseApp.NewContext(false, tmproto.Header{Time: time.Now()}) - require.NotPanics(t, func() { - contract.OrderMatchingRunnable(context.Background(), ctx, nil, nil, types.ContractInfoV2{}, nil) - }) -} diff --git a/x/dex/contract/dag.go b/x/dex/contract/dag.go deleted file mode 100644 index 761a9d7c2..000000000 --- a/x/dex/contract/dag.go +++ /dev/null @@ -1,78 +0,0 @@ -package contract - -import ( - "github.com/sei-protocol/sei-chain/utils/datastructures" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -type node struct { - contractAddr string - incomingNodes *datastructures.SyncSet[string] -} - -// Kahn's algorithm -func TopologicalSortContractInfo(contracts []types.ContractInfoV2) ([]types.ContractInfoV2, error) { - contractAddrToContractInfo := map[string]types.ContractInfoV2{} - for _, contract := range contracts { - contractAddrToContractInfo[contract.ContractAddr] = contract - } - - res := []types.ContractInfoV2{} - nodes := initNodes(contracts) - frontierNodes, nonFrontierNodes := splitNodesByFrontier(nodes) - for len(frontierNodes) > 0 { - for _, frontierNode := range frontierNodes { - if contract, ok := contractAddrToContractInfo[frontierNode.contractAddr]; ok { - res = append(res, contract) - } - for _, nonFrontierNode := range nonFrontierNodes { - nonFrontierNode.incomingNodes.Remove(frontierNode.contractAddr) - } - } - frontierNodes, nonFrontierNodes = splitNodesByFrontier(nonFrontierNodes) - } - if len(nonFrontierNodes) > 0 { - return []types.ContractInfoV2{}, types.ErrCircularContractDependency - } - return res, nil -} - -func initNodes(contracts []types.ContractInfoV2) map[string]node { - res := map[string]node{} - for _, contract := range contracts { - if _, ok := res[contract.ContractAddr]; !ok { - emptyIncomingNodes := datastructures.NewSyncSet([]string{}) - res[contract.ContractAddr] = node{ - contractAddr: contract.ContractAddr, - incomingNodes: &emptyIncomingNodes, - } - } - if contract.Dependencies == nil { - continue - } - for _, dependentContract := range contract.Dependencies { - dependentAddr := dependentContract.Dependency - if _, ok := res[dependentAddr]; !ok { - emptyIncomingNodes := datastructures.NewSyncSet([]string{}) - res[dependentAddr] = node{ - contractAddr: dependentAddr, - incomingNodes: &emptyIncomingNodes, - } - } - res[dependentAddr].incomingNodes.Add(contract.ContractAddr) - } - } - return res -} - -func splitNodesByFrontier(nodes map[string]node) (map[string]node, map[string]node) { - frontierNodes, nonFrontierNodes := map[string]node{}, map[string]node{} - for contractAddr, node := range nodes { - if node.incomingNodes.Size() == 0 { - frontierNodes[contractAddr] = node - } else { - nonFrontierNodes[contractAddr] = node - } - } - return frontierNodes, nonFrontierNodes -} diff --git a/x/dex/contract/dag_test.go b/x/dex/contract/dag_test.go deleted file mode 100644 index a5842ca21..000000000 --- a/x/dex/contract/dag_test.go +++ /dev/null @@ -1,110 +0,0 @@ -package contract_test - -import ( - "testing" - - "github.com/sei-protocol/sei-chain/x/dex/contract" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -// A -> B -> C -func TestTopologicalSortContractInfoSimple(t *testing.T) { - a := types.ContractInfoV2{ - ContractAddr: "A", - Dependencies: []*types.ContractDependencyInfo{ - { - Dependency: "B", - }, - }, - } - b := types.ContractInfoV2{ - ContractAddr: "B", - Dependencies: []*types.ContractDependencyInfo{ - { - Dependency: "C", - }, - }, - } - c := types.ContractInfoV2{ - ContractAddr: "C", - } - res, err := contract.TopologicalSortContractInfo([]types.ContractInfoV2{b, c, a}) - require.Nil(t, err) - require.Equal(t, "A", res[0].ContractAddr) - require.Equal(t, "B", res[1].ContractAddr) - require.Equal(t, "C", res[2].ContractAddr) -} - -// A -> B, C -> D -func TestTopologicalSortContractInfoIsolated(t *testing.T) { - a := types.ContractInfoV2{ - ContractAddr: "A", - Dependencies: []*types.ContractDependencyInfo{ - { - Dependency: "B", - }, - }, - } - b := types.ContractInfoV2{ - ContractAddr: "B", - } - c := types.ContractInfoV2{ - ContractAddr: "C", - Dependencies: []*types.ContractDependencyInfo{ - { - Dependency: "D", - }, - }, - } - d := types.ContractInfoV2{ - ContractAddr: "D", - } - res, err := contract.TopologicalSortContractInfo([]types.ContractInfoV2{b, c, a, d}) - require.Nil(t, err) - aidx, bidx, cidx, didx := -1, -1, -1, -1 - for i, c := range res { - if c.ContractAddr == "A" { - aidx = i - } else if c.ContractAddr == "B" { - bidx = i - } else if c.ContractAddr == "C" { - cidx = i - } else if c.ContractAddr == "D" { - didx = i - } - } - require.True(t, aidx != -1 && aidx < bidx) - require.True(t, cidx != -1 && cidx < didx) -} - -// A -> B -> C -> A -func TestTopologicalSortContractInfoCircular(t *testing.T) { - a := types.ContractInfoV2{ - ContractAddr: "A", - Dependencies: []*types.ContractDependencyInfo{ - { - Dependency: "B", - }, - }, - } - b := types.ContractInfoV2{ - ContractAddr: "B", - Dependencies: []*types.ContractDependencyInfo{ - { - Dependency: "C", - }, - }, - } - c := types.ContractInfoV2{ - ContractAddr: "C", - Dependencies: []*types.ContractDependencyInfo{ - { - Dependency: "A", - }, - }, - } - res, err := contract.TopologicalSortContractInfo([]types.ContractInfoV2{b, c, a}) - require.NotNil(t, err) - require.Equal(t, 0, len(res)) -} diff --git a/x/dex/contract/execution.go b/x/dex/contract/execution.go deleted file mode 100644 index 2c1614f1e..000000000 --- a/x/dex/contract/execution.go +++ /dev/null @@ -1,219 +0,0 @@ -package contract - -import ( - "context" - "fmt" - "time" - - otrace "go.opentelemetry.io/otel/trace" - - "github.com/cosmos/cosmos-sdk/telemetry" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/store/whitelist/multi" - "github.com/sei-protocol/sei-chain/utils/datastructures" - "github.com/sei-protocol/sei-chain/x/dex/exchange" - "github.com/sei-protocol/sei-chain/x/dex/keeper" - dexkeeperabci "github.com/sei-protocol/sei-chain/x/dex/keeper/abci" - dexkeeperutils "github.com/sei-protocol/sei-chain/x/dex/keeper/utils" - "github.com/sei-protocol/sei-chain/x/dex/types" - dexutils "github.com/sei-protocol/sei-chain/x/dex/utils" - "go.opentelemetry.io/otel/attribute" -) - -func CallPreExecutionHooks( - ctx context.Context, - sdkCtx sdk.Context, - contractAddr string, - dexkeeper *keeper.Keeper, - registeredPairs []types.Pair, - tracer *otrace.Tracer, -) error { - spanCtx, span := (*tracer).Start(ctx, "PreExecutionHooks") - defer span.End() - span.SetAttributes(attribute.String("contract", contractAddr)) - abciWrapper := dexkeeperabci.KeeperWrapper{Keeper: dexkeeper} - if err := abciWrapper.HandleEBCancelOrders(spanCtx, sdkCtx, tracer, contractAddr, registeredPairs); err != nil { - return err - } - return abciWrapper.HandleEBPlaceOrders(spanCtx, sdkCtx, tracer, contractAddr, registeredPairs) -} - -func ExecutePair( - ctx sdk.Context, - contractAddr string, - pair types.Pair, - dexkeeper *keeper.Keeper, - orderbook *types.OrderBook, -) []*types.SettlementEntry { - typedContractAddr := types.ContractAddress(contractAddr) - - // First cancel orders - cancelForPair(ctx, dexkeeper, typedContractAddr, pair) - // Add all limit orders to the orderbook - orders := dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, typedContractAddr, pair) - limitBuys := orders.GetLimitOrders(types.PositionDirection_LONG) - limitSells := orders.GetLimitOrders(types.PositionDirection_SHORT) - exchange.AddOutstandingLimitOrdersToOrderbook(ctx, dexkeeper, limitBuys, limitSells) - // Fill market orders - marketOrderOutcome := matchMarketOrderForPair(ctx, typedContractAddr, pair, orderbook) - // Fill limit orders - limitOrderOutcome := exchange.MatchLimitOrders(ctx, orderbook) - totalOutcome := marketOrderOutcome.Merge(&limitOrderOutcome) - - dexkeeperutils.SetPriceStateFromExecutionOutcome(ctx, dexkeeper, typedContractAddr, pair, totalOutcome) - - return totalOutcome.Settlements -} - -func cancelForPair( - ctx sdk.Context, - keeper *keeper.Keeper, - contractAddress types.ContractAddress, - pair types.Pair, -) { - cancels := dexutils.GetMemState(ctx.Context()).GetBlockCancels(ctx, contractAddress, pair) - exchange.CancelOrders(ctx, keeper, contractAddress, pair, cancels.Get()) -} - -func matchMarketOrderForPair( - ctx sdk.Context, - typedContractAddr types.ContractAddress, - pair types.Pair, - orderbook *types.OrderBook, -) exchange.ExecutionOutcome { - orders := dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, typedContractAddr, pair) - marketBuys := orders.GetSortedMarketOrders(types.PositionDirection_LONG) - marketSells := orders.GetSortedMarketOrders(types.PositionDirection_SHORT) - marketBuyOutcome := exchange.MatchMarketOrders( - ctx, - marketBuys, - orderbook.Shorts, - types.PositionDirection_LONG, - orders, - ) - marketSellOutcome := exchange.MatchMarketOrders( - ctx, - marketSells, - orderbook.Longs, - types.PositionDirection_SHORT, - orders, - ) - return marketBuyOutcome.Merge(&marketSellOutcome) -} - -func GetMatchResults( - ctx sdk.Context, - typedContractAddr types.ContractAddress, - pair types.Pair, -) ([]*types.Order, []*types.Cancellation) { - orderResults := dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, typedContractAddr, pair).Get() - cancelResults := dexutils.GetMemState(ctx.Context()).GetBlockCancels(ctx, typedContractAddr, pair).Get() - return orderResults, cancelResults -} - -func GetOrderIDToSettledQuantities(settlements []*types.SettlementEntry) map[uint64]sdk.Dec { - res := map[uint64]sdk.Dec{} - for _, settlement := range settlements { - if _, ok := res[settlement.OrderId]; !ok { - res[settlement.OrderId] = sdk.ZeroDec() - } - res[settlement.OrderId] = res[settlement.OrderId].Add(settlement.Quantity) - } - return res -} - -func ExecutePairsInParallel(ctx sdk.Context, contractAddr string, dexkeeper *keeper.Keeper, registeredPairs []types.Pair, orderBooks *datastructures.TypedSyncMap[types.PairString, *types.OrderBook]) []*types.SettlementEntry { - typedContractAddr := types.ContractAddress(contractAddr) - orderResults := []*types.Order{} - cancelResults := []*types.Cancellation{} - settlements := []*types.SettlementEntry{} - - // mu := sync.Mutex{} - // wg := sync.WaitGroup{} - - for _, pair := range registeredPairs { - // wg.Add(1) - - pair := pair - pairCtx := ctx.WithMultiStore(multi.NewStore(ctx.MultiStore(), GetPerPairWhitelistMap(contractAddr, pair))).WithEventManager(sdk.NewEventManager()) - // go func() { - func() { - // defer wg.Done() - pairCopy := pair - pairStr := types.GetPairString(&pairCopy) - orderbook, found := orderBooks.Load(pairStr) - if !found { - panic(fmt.Sprintf("Orderbook not found for %s", pairCopy.String())) - } - pairSettlements := ExecutePair(pairCtx, contractAddr, pair, dexkeeper, orderbook) - orderIDToSettledQuantities := GetOrderIDToSettledQuantities(pairSettlements) - PrepareCancelUnfulfilledMarketOrders(pairCtx, typedContractAddr, pairCopy, orderIDToSettledQuantities) - - // mu.Lock() - // defer mu.Unlock() - orders, cancels := GetMatchResults(ctx, typedContractAddr, pairCopy) - orderResults = append(orderResults, orders...) - cancelResults = append(cancelResults, cancels...) - settlements = append(settlements, pairSettlements...) - // ordering of events doesn't matter since events aren't part of consensus - ctx.EventManager().EmitEvents(pairCtx.EventManager().Events()) - }() - } - // wg.Wait() - dexkeeper.SetMatchResult(ctx, contractAddr, types.NewMatchResult(orderResults, cancelResults, settlements)) - - return settlements -} - -func HandleExecutionForContract( - ctx context.Context, - sdkCtx sdk.Context, - contract types.ContractInfoV2, - dexkeeper *keeper.Keeper, - registeredPairs []types.Pair, - orderBooks *datastructures.TypedSyncMap[types.PairString, *types.OrderBook], - tracer *otrace.Tracer, -) ([]*types.SettlementEntry, error) { - executionStart := time.Now() - defer telemetry.ModuleMeasureSince(types.ModuleName, executionStart, "handle_execution_for_contract_ms") - contractAddr := contract.ContractAddr - - // Call contract hooks so that contracts can do internal bookkeeping - if err := CallPreExecutionHooks(ctx, sdkCtx, contractAddr, dexkeeper, registeredPairs, tracer); err != nil { - return []*types.SettlementEntry{}, err - } - settlements := ExecutePairsInParallel(sdkCtx, contractAddr, dexkeeper, registeredPairs, orderBooks) - defer EmitSettlementMetrics(settlements) - - return settlements, nil -} - -// Emit metrics for settlements -func EmitSettlementMetrics(settlements []*types.SettlementEntry) { - if len(settlements) > 0 { - telemetry.ModuleSetGauge( - types.ModuleName, - float32(len(settlements)), - "num_settlements", - ) - for _, s := range settlements { - telemetry.IncrCounter( - 1, - "num_settlements_order_type_"+s.GetOrderType(), - ) - telemetry.IncrCounter( - 1, - "num_settlements_position_direction"+s.GetPositionDirection(), - ) - telemetry.IncrCounter( - 1, - "num_settlements_asset_denom_"+s.GetAssetDenom(), - ) - telemetry.IncrCounter( - 1, - "num_settlements_price_denom_"+s.GetPriceDenom(), - ) - } - } -} diff --git a/x/dex/contract/execution_test.go b/x/dex/contract/execution_test.go deleted file mode 100644 index fea46b35f..000000000 --- a/x/dex/contract/execution_test.go +++ /dev/null @@ -1,373 +0,0 @@ -package contract_test - -import ( - "testing" - "time" - - "github.com/sei-protocol/sei-chain/utils/datastructures" - dexutil "github.com/sei-protocol/sei-chain/x/dex/utils" - - sdk "github.com/cosmos/cosmos-sdk/types" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex/contract" - keeperutil "github.com/sei-protocol/sei-chain/x/dex/keeper/utils" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TEST_PAIR() types.Pair { - return types.Pair{ - PriceDenom: "usdc", - AssetDenom: "atom", - } -} - -const ( - TEST_ACCOUNT = "test_account" - TEST_CONTRACT = "test" - TestTimestamp uint64 = 10000 - TestHeight uint64 = 1 -) - -func TestExecutePair(t *testing.T) { - pair := types.Pair{ - PriceDenom: "USDC", - AssetDenom: "ATOM", - } - dexkeeper, ctx := keepertest.DexKeeper(t) - ctx = ctx.WithBlockHeight(int64(TestHeight)).WithBlockTime(time.Unix(int64(TestTimestamp), 0)) - longBook := []types.OrderBookEntry{ - &types.LongBook{ - Price: sdk.NewDec(98), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(98), - Quantity: sdk.NewDec(5), - Allocations: []*types.Allocation{{ - OrderId: 5, - Account: "abc", - Quantity: sdk.NewDec(5), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - &types.LongBook{ - Price: sdk.NewDec(100), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(3), - Allocations: []*types.Allocation{{ - OrderId: 6, - Account: "def", - Quantity: sdk.NewDec(3), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - } - for _, l := range longBook { - dexkeeper.SetLongOrderBookEntry(ctx, keepertest.TestContract, l) - } - shortBook := []types.OrderBookEntry{ - &types.ShortBook{ - Price: sdk.NewDec(101), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(101), - Quantity: sdk.NewDec(5), - Allocations: []*types.Allocation{{ - OrderId: 7, - Account: "abc", - Quantity: sdk.NewDec(5), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - &types.ShortBook{ - Price: sdk.NewDec(115), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(115), - Quantity: sdk.NewDec(3), - Allocations: []*types.Allocation{{ - OrderId: 8, - Account: "def", - Quantity: sdk.NewDec(3), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - } - for _, s := range shortBook { - dexkeeper.SetShortOrderBookEntry(ctx, keepertest.TestContract, s) - } - orderbook := keeperutil.PopulateOrderbook(ctx, dexkeeper, types.ContractAddress(keepertest.TestContract), types.Pair{PriceDenom: "USDC", AssetDenom: "ATOM"}) - - settlements := contract.ExecutePair( - ctx, - TEST_CONTRACT, - pair, - dexkeeper, - orderbook, - ) - require.Equal(t, len(settlements), 0) - - // add Market orders to the orderbook - dexutil.GetMemState(ctx.Context()).GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), pair).Add( - &types.Order{ - Id: 1, - Account: TEST_ACCOUNT, - ContractAddr: TEST_CONTRACT, - Price: sdk.MustNewDecFromStr("97"), - Quantity: sdk.MustNewDecFromStr("1"), - PriceDenom: pair.PriceDenom, - AssetDenom: pair.AssetDenom, - OrderType: types.OrderType_LIMIT, - PositionDirection: types.PositionDirection_LONG, - Data: "{\"position_effect\":\"Open\",\"leverage\":\"1\"}", - }, - ) - dexutil.GetMemState(ctx.Context()).GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), pair).Add( - &types.Order{ - Id: 2, - Account: TEST_ACCOUNT, - ContractAddr: TEST_CONTRACT, - Price: sdk.MustNewDecFromStr("100"), - Quantity: sdk.MustNewDecFromStr("1"), - PriceDenom: pair.PriceDenom, - AssetDenom: pair.AssetDenom, - OrderType: types.OrderType_LIMIT, - PositionDirection: types.PositionDirection_LONG, - Data: "{\"position_effect\":\"Open\",\"leverage\":\"1\"}", - }, - ) - dexutil.GetMemState(ctx.Context()).GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), pair).Add( - &types.Order{ - Id: 3, - Account: TEST_ACCOUNT, - ContractAddr: TEST_CONTRACT, - Price: sdk.MustNewDecFromStr("200"), - Quantity: sdk.MustNewDecFromStr("1"), - PriceDenom: pair.PriceDenom, - AssetDenom: pair.AssetDenom, - OrderType: types.OrderType_MARKET, - PositionDirection: types.PositionDirection_LONG, - Data: "{\"position_effect\":\"Open\",\"leverage\":\"1\"}", - }, - ) - - settlements = contract.ExecutePair( - ctx, - TEST_CONTRACT, - pair, - dexkeeper, - orderbook, - ) - - require.Equal(t, 2, len(settlements)) - require.Equal(t, uint64(7), settlements[0].OrderId) - require.Equal(t, uint64(3), settlements[1].OrderId) - - // get match results - matches, cancels := contract.GetMatchResults( - ctx, - TEST_CONTRACT, - pair, - ) - require.Equal(t, 3, len(matches)) - require.Equal(t, 0, len(cancels)) -} - -func TestExecutePairInParallel(t *testing.T) { - pair := types.Pair{ - PriceDenom: "USDC", - AssetDenom: "ATOM", - } - dexkeeper, ctx := keepertest.DexKeeper(t) - ctx = ctx.WithBlockHeight(int64(TestHeight)).WithBlockTime(time.Unix(int64(TestTimestamp), 0)) - longBook := []types.OrderBookEntry{ - &types.LongBook{ - Price: sdk.NewDec(98), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(98), - Quantity: sdk.NewDec(5), - Allocations: []*types.Allocation{{ - OrderId: 5, - Account: "abc", - Quantity: sdk.NewDec(5), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - &types.LongBook{ - Price: sdk.NewDec(100), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(3), - Allocations: []*types.Allocation{{ - OrderId: 6, - Account: "def", - Quantity: sdk.NewDec(3), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - } - for _, l := range longBook { - dexkeeper.SetLongOrderBookEntry(ctx, TEST_CONTRACT, l) - } - shortBook := []types.OrderBookEntry{ - &types.ShortBook{ - Price: sdk.NewDec(101), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(101), - Quantity: sdk.NewDec(5), - Allocations: []*types.Allocation{{ - OrderId: 7, - Account: "abc", - Quantity: sdk.NewDec(5), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - &types.ShortBook{ - Price: sdk.NewDec(115), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(115), - Quantity: sdk.NewDec(3), - Allocations: []*types.Allocation{{ - OrderId: 8, - Account: "def", - Quantity: sdk.NewDec(3), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - } - for _, s := range shortBook { - dexkeeper.SetShortOrderBookEntry(ctx, TEST_CONTRACT, s) - } - orderbook := keeperutil.PopulateOrderbook(ctx, dexkeeper, types.ContractAddress(TEST_CONTRACT), types.Pair{PriceDenom: "USDC", AssetDenom: "ATOM"}) - - // execute in parallel simple path - orderbooks := datastructures.NewTypedSyncMap[types.PairString, *types.OrderBook]() - orderbooks.Store(types.GetPairString(&pair), orderbook) - settlements := contract.ExecutePairsInParallel( - ctx, - TEST_CONTRACT, - dexkeeper, - []types.Pair{pair}, - orderbooks, - ) - - require.Equal(t, len(settlements), 0) - - // add Market orders to the orderbook - dexutil.GetMemState(ctx.Context()).GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), pair).Add( - &types.Order{ - Id: 1, - Account: TEST_ACCOUNT, - ContractAddr: TEST_CONTRACT, - Price: sdk.MustNewDecFromStr("97"), - Quantity: sdk.MustNewDecFromStr("1"), - PriceDenom: pair.PriceDenom, - AssetDenom: pair.AssetDenom, - OrderType: types.OrderType_LIMIT, - PositionDirection: types.PositionDirection_LONG, - Data: "{\"position_effect\":\"Open\",\"leverage\":\"1\"}", - }, - ) - dexutil.GetMemState(ctx.Context()).GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), pair).Add( - &types.Order{ - Id: 2, - Account: TEST_ACCOUNT, - ContractAddr: TEST_CONTRACT, - Price: sdk.MustNewDecFromStr("100"), - Quantity: sdk.MustNewDecFromStr("1"), - PriceDenom: pair.PriceDenom, - AssetDenom: pair.AssetDenom, - OrderType: types.OrderType_LIMIT, - PositionDirection: types.PositionDirection_LONG, - Data: "{\"position_effect\":\"Open\",\"leverage\":\"1\"}", - }, - ) - dexutil.GetMemState(ctx.Context()).GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), pair).Add( - &types.Order{ - Id: 3, - Account: TEST_ACCOUNT, - ContractAddr: TEST_CONTRACT, - Price: sdk.MustNewDecFromStr("200"), - Quantity: sdk.MustNewDecFromStr("1"), - PriceDenom: pair.PriceDenom, - AssetDenom: pair.AssetDenom, - OrderType: types.OrderType_MARKET, - PositionDirection: types.PositionDirection_LONG, - Data: "{\"position_effect\":\"Open\",\"leverage\":\"1\"}", - }, - ) - dexutil.GetMemState(ctx.Context()).GetBlockOrders(ctx, types.ContractAddress(TEST_CONTRACT), pair).Add( - &types.Order{ - Id: 11, - Account: TEST_ACCOUNT, - ContractAddr: TEST_CONTRACT, - Price: sdk.MustNewDecFromStr("20"), - Quantity: sdk.MustNewDecFromStr("1"), - PriceDenom: pair.PriceDenom, - AssetDenom: pair.AssetDenom, - OrderType: types.OrderType_MARKET, - PositionDirection: types.PositionDirection_LONG, - Data: "{\"position_effect\":\"Open\",\"leverage\":\"1\"}", - }, - ) - - settlements = contract.ExecutePairsInParallel( - ctx, - TEST_CONTRACT, - dexkeeper, - []types.Pair{pair}, - orderbooks, - ) - - require.Equal(t, 2, len(settlements)) - require.Equal(t, uint64(7), settlements[0].OrderId) - require.Equal(t, uint64(3), settlements[1].OrderId) -} - -func TestGetOrderIDToSettledQuantities(t *testing.T) { - settlements := []*types.SettlementEntry{ - { - OrderId: 1, - Quantity: sdk.MustNewDecFromStr("100"), - }, - { - OrderId: 2, - Quantity: sdk.MustNewDecFromStr("200"), - }, - } - - idMapping := contract.GetOrderIDToSettledQuantities(settlements) - - require.Equal(t, 2, len(idMapping)) - require.Equal(t, sdk.MustNewDecFromStr("100"), idMapping[1]) - require.Equal(t, sdk.MustNewDecFromStr("200"), idMapping[2]) -} - -func TestEmitSettlementMetrics(t *testing.T) { - settlements := []*types.SettlementEntry{ - { - OrderId: 1, - Quantity: sdk.MustNewDecFromStr("100"), - }, - { - OrderId: 2, - Quantity: sdk.MustNewDecFromStr("200"), - }, - } - - require.NotPanics(t, func() { contract.EmitSettlementMetrics(settlements) }) -} diff --git a/x/dex/contract/market_order.go b/x/dex/contract/market_order.go deleted file mode 100644 index 3901f83e8..000000000 --- a/x/dex/contract/market_order.go +++ /dev/null @@ -1,68 +0,0 @@ -package contract - -import ( - "context" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/keeper" - dexkeeperabci "github.com/sei-protocol/sei-chain/x/dex/keeper/abci" - "github.com/sei-protocol/sei-chain/x/dex/types" - dexutils "github.com/sei-protocol/sei-chain/x/dex/utils" - "go.opentelemetry.io/otel/attribute" - otrace "go.opentelemetry.io/otel/trace" -) - -func PrepareCancelUnfulfilledMarketOrders( - ctx sdk.Context, - typedContractAddr types.ContractAddress, - pair types.Pair, - orderIDToSettledQuantities map[uint64]sdk.Dec, -) { - dexutils.GetMemState(ctx.Context()).ClearCancellationForPair(ctx, typedContractAddr, pair) - for _, marketOrderID := range getUnfulfilledPlacedMarketOrderIds(ctx, typedContractAddr, pair, orderIDToSettledQuantities) { - dexutils.GetMemState(ctx.Context()).GetBlockCancels(ctx, typedContractAddr, pair).Add(&types.Cancellation{ - Id: marketOrderID, - Initiator: types.CancellationInitiator_USER, - }) - } -} - -func getUnfulfilledPlacedMarketOrderIds( - ctx sdk.Context, - typedContractAddr types.ContractAddress, - pair types.Pair, - orderIDToSettledQuantities map[uint64]sdk.Dec, -) []uint64 { - res := []uint64{} - for _, order := range dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, typedContractAddr, pair).Get() { - if order.Status == types.OrderStatus_FAILED_TO_PLACE { - continue - } - if order.OrderType == types.OrderType_MARKET || order.OrderType == types.OrderType_FOKMARKET { - if settledQuantity, ok := orderIDToSettledQuantities[order.Id]; !ok || settledQuantity.LT(order.Quantity) { - res = append(res, order.Id) - } - } else if order.OrderType == types.OrderType_FOKMARKETBYVALUE { - // cancel market order by nominal if zero quantity is executed - if _, ok := orderIDToSettledQuantities[order.Id]; !ok { - res = append(res, order.Id) - } - } - } - return res -} - -func CancelUnfulfilledMarketOrders( - ctx context.Context, - sdkCtx sdk.Context, - contractAddr string, - dexkeeper *keeper.Keeper, - registeredPairs []types.Pair, - tracer *otrace.Tracer, -) error { - spanCtx, span := (*tracer).Start(ctx, "CancelUnfulfilledMarketOrders") - span.SetAttributes(attribute.String("contract", contractAddr)) - defer span.End() - abciWrapper := dexkeeperabci.KeeperWrapper{Keeper: dexkeeper} - return abciWrapper.HandleEBCancelOrders(spanCtx, sdkCtx, tracer, contractAddr, registeredPairs) -} diff --git a/x/dex/contract/runner.go b/x/dex/contract/runner.go deleted file mode 100644 index 6e3797f3f..000000000 --- a/x/dex/contract/runner.go +++ /dev/null @@ -1,178 +0,0 @@ -package contract - -import ( - "fmt" - "sync/atomic" - "time" - - "github.com/cosmos/cosmos-sdk/telemetry" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/utils/datastructures" - "github.com/sei-protocol/sei-chain/utils/logging" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -const LogAfter = 10 * time.Second - -type ParallelRunner struct { - runnable func(contract types.ContractInfoV2) - - contractAddrToInfo *datastructures.TypedSyncMap[types.ContractAddress, *types.ContractInfoV2] - readyContracts *datastructures.TypedSyncMap[types.ContractAddress, struct{}] - readyCnt int64 - inProgressCnt int64 - someContractFinished chan struct{} - done chan struct{} - sdkCtx sdk.Context -} - -func NewParallelRunner(runnable func(contract types.ContractInfoV2), contracts []types.ContractInfoV2, ctx sdk.Context) ParallelRunner { - contractAddrToInfo := datastructures.NewTypedSyncMap[types.ContractAddress, *types.ContractInfoV2]() - contractsFrontier := datastructures.NewTypedSyncMap[types.ContractAddress, struct{}]() - for _, contract := range contracts { - // runner will mutate ContractInfo fields - copyContract := contract - typedContractAddr := types.ContractAddress(contract.ContractAddr) - contractAddrToInfo.Store(typedContractAddr, ©Contract) - if copyContract.NumIncomingDependencies == 0 { - contractsFrontier.Store(typedContractAddr, struct{}{}) - } - } - return ParallelRunner{ - runnable: runnable, - contractAddrToInfo: contractAddrToInfo, - readyContracts: contractsFrontier, - readyCnt: int64(contractsFrontier.Len()), - inProgressCnt: 0, - someContractFinished: make(chan struct{}), - done: make(chan struct{}, 1), - sdkCtx: ctx, - } -} - -// We define "frontier contract" as a contract which: -// 1. Has not finished running yet, and -// 2. either: -// a. has no other contracts depending on it, or -// b. for which all contracts that depend on it have already finished. -// -// Consequently, the set of frontier contracts will mutate throughout the -// `Run` method, until all contracts finish their runs. -// The key principle here is that at any moment, we can have all frontier -// contracts running concurrently, since there must be no ancestral -// relationships among them due to the definition above. -// The simplest implementation would be: -// ``` -// while there is any contract left: -// -// run all frontier contracts concurrently -// wait for all runs to finish -// update the frontier set -// -// ``` -// We can illustrate why this implementation is not optimal with the following -// example: -// -// Suppose we have four contracts, where A depends on B, and C depends on -// D. The run for A, B, C, D takes 5s, 5s, 8s, 2s, respectively. -// With the implementation above, the first iteration would take 8s since -// it runs A and C, and the second iteration would take 5s since it runs -// B and D. However C doesn't actually need to wait for B to finish, and -// if C runs immediately after A finishes, the whole process would take -// max(5 + 5, 8 + 2) = 10s, which is 3s faster than the implementation -// above. -// -// So we can optimize the implementation to be: -// ``` -// while there is any contract left: -// -// run all frontier contracts concurrently -// wait for any existing run (could be from previous iteration) to finish -// update the frontier set -// -// ``` -// With the example above, the whole process would take 3 iterations: -// Iter 1 (A, C run): 5s since it finishes when A finishes -// Iter 2 (B run): 3s since it finishes when C finishes -// Iter 3 (D run): 2s since it finishes when B, D finish -// -// The following `Run` method implements the pseudocode above. -func (r *ParallelRunner) Run() { - if atomic.LoadInt64(&r.inProgressCnt) == 0 && atomic.LoadInt64(&r.readyCnt) == 0 { - return - } - // The ordering of the two conditions below matters, since readyCnt - // is updated before inProgressCnt. - for atomic.LoadInt64(&r.inProgressCnt) > 0 || atomic.LoadInt64(&r.readyCnt) > 0 { - // r.readyContracts represent all frontier contracts that have - // not started running yet. - r.readyContracts.Range(func(key types.ContractAddress, _ struct{}) bool { - atomic.AddInt64(&r.inProgressCnt, 1) - go r.wrapRunnable(key) - // Since the frontier contract has started running, we need - // to remove it from r.readyContracts so that it won't - // double-run. - r.readyContracts.Delete(key) - // The reason we use a separate readyCnt is because `sync.Map` - // doesn't provide an atomic way to get its length. - atomic.AddInt64(&r.readyCnt, -1) - return true - }) - // This corresponds to the "wait for any existing run (could be - // from previous iteration) to finish" part in the pseudocode above. - _, err := logging.LogIfNotDoneAfter(r.sdkCtx.Logger(), func() (struct{}, error) { - <-r.someContractFinished - return struct{}{}, nil - }, LogAfter, "dex_parallel_runner_wait") - if err != nil { - // this should never happen - panic(err) - } - } - - // make sure there is no orphaned goroutine blocked on channel send - r.done <- struct{}{} -} - -func (r *ParallelRunner) wrapRunnable(contractAddr types.ContractAddress) { - defer func() { - if err := recover(); err != nil { - telemetry.IncrCounter(1, "recovered_panics") - r.sdkCtx.Logger().Error(fmt.Sprintf("panic in parallel runner recovered: %s", err)) - } - - atomic.AddInt64(&r.inProgressCnt, -1) // this has to happen after any potential increment to readyCnt - select { - case r.someContractFinished <- struct{}{}: - case <-r.done: - // make sure other goroutines can also receive from 'done' - r.done <- struct{}{} - } - }() - - contractInfo, _ := r.contractAddrToInfo.Load(contractAddr) - r.runnable(*contractInfo) - - // Check if there is any contract that should be promoted to the frontier set. - if contractInfo.Dependencies != nil { - for _, dependency := range contractInfo.Dependencies { - dependentContract := dependency.Dependency - typedDependentContract := types.ContractAddress(dependentContract) - dependentInfo, ok := r.contractAddrToInfo.Load(typedDependentContract) - if !ok { - // If we cannot find the dependency in the contract address info, then it's not a valid contract in this round - r.sdkCtx.Logger().Error(fmt.Sprintf("Couldn't find dependency %s of contract %s in the contract address info", contractInfo.ContractAddr, dependentContract)) - continue - } - // It's okay to mutate ContractInfo here since it's a copy made in the runner's - // constructor. - newNumIncomingPaths := atomic.AddInt64(&dependentInfo.NumIncomingDependencies, -1) - // This corresponds to the "for which all contracts that depend on it have - // already finished." definition for frontier contract. - if newNumIncomingPaths == 0 { - r.readyContracts.Store(typedDependentContract, struct{}{}) - atomic.AddInt64(&r.readyCnt, 1) - } - } - } -} diff --git a/x/dex/contract/runner_test.go b/x/dex/contract/runner_test.go deleted file mode 100644 index bf7e8c1d7..000000000 --- a/x/dex/contract/runner_test.go +++ /dev/null @@ -1,141 +0,0 @@ -package contract_test - -import ( - "sync" - "sync/atomic" - "testing" - "time" - - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex/contract" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" -) - -var ( - counter int64 = 0 - dependencyCheck = sync.Map{} - testApp = keepertest.TestApp() - sdkCtx = testApp.BaseApp.NewContext(false, tmproto.Header{Time: time.Now()}) -) - -func noopRunnable(_ types.ContractInfoV2) { - atomic.AddInt64(&counter, 1) -} - -func idleRunnable(_ types.ContractInfoV2) { - time.Sleep(5 * time.Second) - atomic.AddInt64(&counter, 1) -} - -func panicRunnable(_ types.ContractInfoV2) { - panic("") -} - -func dependencyCheckRunnable(contractInfo types.ContractInfoV2) { - if contractInfo.ContractAddr == "C" { - _, hasA := dependencyCheck.Load("A") - _, hasB := dependencyCheck.Load("B") - if !hasA || !hasB { - return - } - } - dependencyCheck.Store(contractInfo.ContractAddr, struct{}{}) -} - -func TestRunnerSingleContract(t *testing.T) { - counter = 0 - contractInfo := types.ContractInfoV2{ - ContractAddr: "A", - NumIncomingDependencies: 0, - } - runner := contract.NewParallelRunner(noopRunnable, []types.ContractInfoV2{contractInfo}, sdkCtx) - runner.Run() - require.Equal(t, int64(1), counter) -} - -func TestRunnerParallelContract(t *testing.T) { - counter = 0 - contractInfoA := types.ContractInfoV2{ - ContractAddr: "A", - NumIncomingDependencies: 0, - } - contractInfoB := types.ContractInfoV2{ - ContractAddr: "B", - NumIncomingDependencies: 0, - } - runner := contract.NewParallelRunner(idleRunnable, []types.ContractInfoV2{contractInfoA, contractInfoB}, sdkCtx) - start := time.Now() - runner.Run() - end := time.Now() - duration := end.Sub(start) - require.Equal(t, int64(2), counter) - require.True(t, duration.Seconds() < 10) // would not be flaky unless it's running on really slow hardware -} - -func TestRunnerParallelContractWithDependency(t *testing.T) { - counter = 0 - contractInfoA := types.ContractInfoV2{ - ContractAddr: "A", - NumIncomingDependencies: 0, - Dependencies: []*types.ContractDependencyInfo{ - { - Dependency: "C", - }, - }, - } - contractInfoB := types.ContractInfoV2{ - ContractAddr: "B", - NumIncomingDependencies: 0, - Dependencies: []*types.ContractDependencyInfo{ - { - Dependency: "C", - }, - }, - } - contractInfoC := types.ContractInfoV2{ - ContractAddr: "C", - NumIncomingDependencies: 2, - } - runner := contract.NewParallelRunner(dependencyCheckRunnable, []types.ContractInfoV2{contractInfoC, contractInfoB, contractInfoA}, sdkCtx) - runner.Run() - _, hasC := dependencyCheck.Load("C") - require.True(t, hasC) -} - -func TestRunnerParallelContractWithInvalidDependency(t *testing.T) { - dependencyCheck = sync.Map{} - counter = 0 - contractInfoA := types.ContractInfoV2{ - ContractAddr: "A", - NumIncomingDependencies: 0, - Dependencies: []*types.ContractDependencyInfo{ - { - Dependency: "C", - }, - }, - } - contractInfoB := types.ContractInfoV2{ - ContractAddr: "B", - NumIncomingDependencies: 0, - Dependencies: []*types.ContractDependencyInfo{ - { - Dependency: "C", - }, - }, - } - runner := contract.NewParallelRunner(dependencyCheckRunnable, []types.ContractInfoV2{contractInfoB, contractInfoA}, sdkCtx) - runner.Run() - _, hasC := dependencyCheck.Load("C") - require.False(t, hasC) -} - -func TestRunnerPanicContract(t *testing.T) { - contractInfo := types.ContractInfoV2{ - ContractAddr: "A", - NumIncomingDependencies: 0, - } - runner := contract.NewParallelRunner(panicRunnable, []types.ContractInfoV2{contractInfo}, sdkCtx) - require.NotPanics(t, runner.Run) -} diff --git a/x/dex/contract/settlement.go b/x/dex/contract/settlement.go deleted file mode 100644 index e840388e4..000000000 --- a/x/dex/contract/settlement.go +++ /dev/null @@ -1,39 +0,0 @@ -package contract - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/keeper" - dexkeeperutils "github.com/sei-protocol/sei-chain/x/dex/keeper/utils" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -func HandleSettlements( - ctx sdk.Context, - contractAddr string, - dexkeeper *keeper.Keeper, - settlements []*types.SettlementEntry, -) error { - return callSettlementHook(ctx, contractAddr, dexkeeper, settlements) -} - -func callSettlementHook( - ctx sdk.Context, - contractAddr string, - dexkeeper *keeper.Keeper, - settlementEntries []*types.SettlementEntry, -) error { - if len(settlementEntries) == 0 { - return nil - } - _, currentEpoch := dexkeeper.IsNewEpoch(ctx) - nativeSettlementMsg := types.SudoSettlementMsg{ - Settlement: types.Settlements{ - Epoch: int64(currentEpoch), - Entries: settlementEntries, - }, - } - if _, err := dexkeeperutils.CallContractSudo(ctx, dexkeeper, contractAddr, nativeSettlementMsg, dexkeeper.GetSettlementGasAllowance(ctx, len(settlementEntries))); err != nil { - return err - } - return nil -} diff --git a/x/dex/contract/whitelist.go b/x/dex/contract/whitelist.go deleted file mode 100644 index d6ab9a8a9..000000000 --- a/x/dex/contract/whitelist.go +++ /dev/null @@ -1,91 +0,0 @@ -package contract - -import ( - wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" - storetypes "github.com/cosmos/cosmos-sdk/store/types" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/utils" - "github.com/sei-protocol/sei-chain/x/dex/keeper" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -var DexWhitelistedKeys = []string{ - types.LongBookKey, - types.ShortBookKey, - types.OrderKey, - types.AccountActiveOrdersKey, - types.CancelKey, - types.TwapKey, - types.PriceKey, - types.NextOrderIDKey, - types.MatchResultKey, - types.LongOrderCountKey, - types.ShortOrderCountKey, - keeper.ContractPrefixKey, -} - -var DexMemWhitelistedKeys = []string{ - types.MemOrderKey, - types.MemDepositKey, - types.MemCancelKey, -} - -var WasmWhitelistedKeys = []string{ - string(wasmtypes.ContractStorePrefix), -} - -func GetWhitelistMap(contractAddr string) map[string][]string { - res := map[string][]string{} - res[storetypes.NewKVStoreKey(types.StoreKey).Name()] = GetDexWhitelistedPrefixes(contractAddr) - res[storetypes.NewKVStoreKey(wasmtypes.StoreKey).Name()] = GetWasmWhitelistedPrefixes(contractAddr) - res[storetypes.NewKVStoreKey(types.MemStoreKey).Name()] = GetDexMemWhitelistedPrefixes(contractAddr) - return res -} - -func GetPerPairWhitelistMap(contractAddr string, pair types.Pair) map[string][]string { - res := map[string][]string{} - res[storetypes.NewKVStoreKey(types.StoreKey).Name()] = GetDexPerPairWhitelistedPrefixes(contractAddr, pair) - res[storetypes.NewKVStoreKey(types.MemStoreKey).Name()] = GetDexMemPerPairWhitelistedPrefixes(contractAddr, pair) - return res -} - -func GetDexWhitelistedPrefixes(contractAddr string) []string { - return utils.Map(DexWhitelistedKeys, func(key string) string { - return string(append( - types.KeyPrefix(key), types.AddressKeyPrefix(contractAddr)..., - )) - }) -} - -func GetDexMemWhitelistedPrefixes(contractAddr string) []string { - return utils.Map(DexMemWhitelistedKeys, func(key string) string { - return string(append( - types.KeyPrefix(key), types.AddressKeyPrefix(contractAddr)..., - )) - }) -} - -func GetWasmWhitelistedPrefixes(contractAddr string) []string { - addr, _ := sdk.AccAddressFromBech32(contractAddr) - return utils.Map(WasmWhitelistedKeys, func(key string) string { - return string(append( - []byte(key), addr..., - )) - }) -} - -func GetDexPerPairWhitelistedPrefixes(contractAddr string, pair types.Pair) []string { - return utils.Map(DexWhitelistedKeys, func(key string) string { - return string(append(append( - types.KeyPrefix(key), types.AddressKeyPrefix(contractAddr)..., - ), types.PairPrefix(pair.PriceDenom, pair.AssetDenom)...)) - }) -} - -func GetDexMemPerPairWhitelistedPrefixes(contractAddr string, pair types.Pair) []string { - return utils.Map(DexMemWhitelistedKeys, func(key string) string { - return string(append(append( - types.KeyPrefix(key), types.AddressKeyPrefix(contractAddr)..., - ), types.PairPrefix(pair.PriceDenom, pair.AssetDenom)...)) - }) -} diff --git a/x/dex/contract/whitelist_test.go b/x/dex/contract/whitelist_test.go deleted file mode 100644 index 79fb70174..000000000 --- a/x/dex/contract/whitelist_test.go +++ /dev/null @@ -1,28 +0,0 @@ -package contract_test - -import ( - "encoding/hex" - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/contract" - "github.com/stretchr/testify/require" -) - -func TestGetWasmPrefixes(t *testing.T) { - wasmWhitelistedPrefixes := contract.GetWasmWhitelistedPrefixes("sei14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sh9m79m") - - wasmPrefixBytes, _ := hex.DecodeString("03" + "ade4a5f5803a439835c636395a8d648dee57b2fc90d98dc17fa887159b69638b") - require.Equal(t, []byte(wasmWhitelistedPrefixes[0]), wasmPrefixBytes) -} - -func TestGetDexPrefixes(t *testing.T) { - dexWhitelistedPrefixes := contract.GetDexWhitelistedPrefixes("sei14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sh9m79m") - addr, _ := sdk.AccAddressFromBech32("sei14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sh9m79m") - - for i, dexKeys := range contract.DexWhitelistedKeys { - len := []byte{byte(32)} - prefix := append(append([]byte(dexKeys), len...), addr...) - require.Equal(t, string(prefix), dexWhitelistedPrefixes[i]) - } -} diff --git a/x/dex/example/add-asset-metadata-proposal.json b/x/dex/example/add-asset-metadata-proposal.json deleted file mode 100644 index 80365fad2..000000000 --- a/x/dex/example/add-asset-metadata-proposal.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "title": "Add usdc asset to asset list", - "description": "gov proposal to update asset list", - "asset_list": [ - { - "ibc_info": { - "source_channel": "channel-1", - "dst_channel": "channel-2", - "source_denom": "uusdc", - "source_chain_id": "axelar" - }, - "type_asset": "erc20", - "metadata": { - "description": "Circle's stablecoin on Axelar", - "denom_units": [ - { - "denom": "ibc/D189335C6E4A68B513C10AB227BF1C1D38C746766278BA3EEB4FB14124F1D858", - "exponent": 0, - "aliases": ["uusdc"] - }, - { - "denom": "axlusdc", - "exponent": 6 - } - ], - "base": "ibc/D189335C6E4A68B513C10AB227BF1C1D38C746766278BA3EEB4FB14124F1D858", - "name": "USD Coin", - "display": "axlusdc", - "symbol": "USDC" - } - }, - { - "type_asset": "native", - "metadata": { - "description": "Native token of Sei Network", - "denom_units": [ - { - "denom": "usei", - "exponent": 0, - "aliases": ["usei"] - }, - { - "denom": "sei", - "exponent": 6 - } - ], - "base": "SEI", - "name": "sei", - "display": "usei", - "symbol": "SEI" - } - } - ], - "deposit": "500000usei" -} diff --git a/x/dex/example/register-pair-tx.json b/x/dex/example/register-pair-tx.json deleted file mode 100644 index 61d285599..000000000 --- a/x/dex/example/register-pair-tx.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "batch_contract_pair": [ - { - "contract_addr": "sei14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sh9m79m", - "pairs": [ - { - "price_denom": "usei", - "asset_denom": "uatom", - "price_tick_size": "0.0000001", - "quantity_tick_size": "0.0000001" - } - ] - } - ] -} \ No newline at end of file diff --git a/x/dex/example/update-tick-size-tx.json b/x/dex/example/update-tick-size-tx.json deleted file mode 100644 index 746e819d2..000000000 --- a/x/dex/example/update-tick-size-tx.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "tick_size_list": [ - { - "pair": { - "price_denom": "uatom", - "asset_denom": "usei" - }, - "tick_size": "1.5", - "contract_addr": "sei14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sh9m79m" - } - ] -} \ No newline at end of file diff --git a/x/dex/exchange/cancel_order.go b/x/dex/exchange/cancel_order.go deleted file mode 100644 index c50d6be96..000000000 --- a/x/dex/exchange/cancel_order.go +++ /dev/null @@ -1,53 +0,0 @@ -package exchange - -import ( - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/keeper" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -func CancelOrders( - ctx sdk.Context, keeper *keeper.Keeper, contract types.ContractAddress, pair types.Pair, - cancels []*types.Cancellation, -) { - for _, cancel := range cancels { - cancelOrder(ctx, keeper, cancel, contract, pair) - } -} - -func cancelOrder(ctx sdk.Context, keeper *keeper.Keeper, cancellation *types.Cancellation, contract types.ContractAddress, pair types.Pair) { - getter, setter, deleter := keeper.GetLongOrderBookEntryByPrice, keeper.SetLongOrderBookEntry, keeper.RemoveLongBookByPrice - if cancellation.PositionDirection == types.PositionDirection_SHORT { - getter, setter, deleter = keeper.GetShortOrderBookEntryByPrice, keeper.SetShortOrderBookEntry, keeper.RemoveShortBookByPrice - } - entry, found := getter(ctx, string(contract), cancellation.Price, pair.PriceDenom, pair.AssetDenom) - if !found { - return - } - newEntry := *entry.GetOrderEntry() - newAllocations := []*types.Allocation{} - newQuantity := sdk.ZeroDec() - for _, allocation := range newEntry.Allocations { - if allocation.OrderId != cancellation.Id { - newAllocations = append(newAllocations, allocation) - newQuantity = newQuantity.Add(allocation.Quantity) - } - } - numAllocationsRemoved := len(newEntry.Allocations) - len(newAllocations) - if numAllocationsRemoved > 0 { - err := keeper.DecreaseOrderCount(ctx, string(contract), pair.PriceDenom, pair.AssetDenom, cancellation.PositionDirection, entry.GetPrice(), uint64(numAllocationsRemoved)) - if err != nil { - ctx.Logger().Error(fmt.Sprintf("error decreasing order count: %s", err)) - } - } - if newQuantity.IsZero() { - deleter(ctx, string(contract), entry.GetPrice(), pair.PriceDenom, pair.AssetDenom) - return - } - newEntry.Quantity = newQuantity - newEntry.Allocations = newAllocations - entry.SetEntry(&newEntry) - setter(ctx, string(contract), entry) -} diff --git a/x/dex/exchange/cancel_order_test.go b/x/dex/exchange/cancel_order_test.go deleted file mode 100644 index 43701f9f6..000000000 --- a/x/dex/exchange/cancel_order_test.go +++ /dev/null @@ -1,105 +0,0 @@ -package exchange_test - -import ( - "testing" - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/exchange" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" -) - -func TestCancelOrder(t *testing.T) { - dexkeeper, ctx := keepertest.DexKeeper(t) - ctx = ctx.WithBlockHeight(int64(TestHeight)).WithBlockTime(time.Unix(int64(TestTimestamp), 0)) - longBook := []types.OrderBookEntry{ - &types.LongBook{ - Price: sdk.NewDec(98), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(98), - Quantity: sdk.NewDec(5), - Allocations: []*types.Allocation{{ - OrderId: 5, - Account: "abc", - Quantity: sdk.NewDec(5), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - } - for _, s := range longBook { - dexkeeper.SetLongOrderBookEntry(ctx, "test", s) - } - shortBook := []types.OrderBookEntry{ - &types.ShortBook{ - Price: sdk.NewDec(101), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(101), - Quantity: sdk.NewDec(12), - Allocations: []*types.Allocation{{ - OrderId: 7, - Account: "abc", - Quantity: sdk.NewDec(5), - }, { - OrderId: 8, - Account: "def", - Quantity: sdk.NewDec(7), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - } - for _, s := range shortBook { - dexkeeper.SetShortOrderBookEntry(ctx, "test", s) - } - - // Allocations before cancellation contains id 5 - assert.Equal(t, (*longBook[0].GetOrderEntry()).Allocations, []*types.Allocation{{ - OrderId: 5, - Account: "abc", - Quantity: sdk.NewDec(5), - }}) - - // Cancel Long Id 5 - cancellation := types.Cancellation{ - Id: 5, - Creator: "abc", - ContractAddr: "test", - PriceDenom: "USDC", - AssetDenom: "ATOM", - PositionDirection: types.PositionDirection_LONG, - Price: sdk.NewDec(98), - } - // Cancel short Id 7 - cancellationShort := types.Cancellation{ - Id: 7, - Creator: "abc", - ContractAddr: "test", - PriceDenom: "USDC", - AssetDenom: "ATOM", - PositionDirection: types.PositionDirection_SHORT, - Price: sdk.NewDec(101), - } - cancels := []*types.Cancellation{&cancellation, &cancellationShort} - exchange.CancelOrders(ctx, dexkeeper, types.ContractAddress("test"), types.Pair{PriceDenom: "USDC", AssetDenom: "ATOM"}, - cancels, - ) - - // No allocations after cancellation - _, found := dexkeeper.GetLongBookByPrice(ctx, "test", sdk.NewDec(98), "USDC", "ATOM") - require.False(t, found) - entry, found := dexkeeper.GetShortBookByPrice(ctx, "test", sdk.NewDec(101), "USDC", "ATOM") - require.True(t, found) - require.Equal(t, sdk.NewDec(7), entry.GetOrderEntry().Quantity) - require.Equal(t, []*types.Allocation{{ - OrderId: 8, - Account: "def", - Quantity: sdk.NewDec(7), - }}, entry.GetOrderEntry().Allocations) -} diff --git a/x/dex/exchange/helpers.go b/x/dex/exchange/helpers.go deleted file mode 100644 index eeb39a8ee..000000000 --- a/x/dex/exchange/helpers.go +++ /dev/null @@ -1,24 +0,0 @@ -package exchange - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -type ExecutionOutcome struct { - TotalNotional sdk.Dec - TotalQuantity sdk.Dec - Settlements []*types.SettlementEntry - MinPrice sdk.Dec // deprecate? - MaxPrice sdk.Dec // deprecate? -} - -func (o *ExecutionOutcome) Merge(other *ExecutionOutcome) ExecutionOutcome { - return ExecutionOutcome{ - TotalNotional: o.TotalNotional.Add(other.TotalNotional), - TotalQuantity: o.TotalQuantity.Add(other.TotalQuantity), - Settlements: append(o.Settlements, other.Settlements...), - MinPrice: sdk.MinDec(o.MinPrice, other.MinPrice), - MaxPrice: sdk.MaxDec(o.MaxPrice, other.MaxPrice), - } -} diff --git a/x/dex/exchange/helpers_test.go b/x/dex/exchange/helpers_test.go deleted file mode 100644 index 3b271c389..000000000 --- a/x/dex/exchange/helpers_test.go +++ /dev/null @@ -1,64 +0,0 @@ -package exchange_test - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/exchange" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestMergeExecutionOutcomes(t *testing.T) { - s1 := types.SettlementEntry{ - PositionDirection: "Long", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(5), - ExecutionCostOrProceed: sdk.NewDec(100), - ExpectedCostOrProceed: sdk.NewDec(100), - Account: "abc", - OrderType: "Limit", - OrderId: 1, - Timestamp: TestTimestamp, - Height: TestHeight, - } - - s2 := types.SettlementEntry{ - PositionDirection: "Short", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(5), - ExecutionCostOrProceed: sdk.NewDec(100), - ExpectedCostOrProceed: sdk.NewDec(100), - Account: "def", - OrderType: "Limit", - OrderId: 2, - Timestamp: TestTimestamp, - Height: TestHeight, - } - - e1 := exchange.ExecutionOutcome{ - TotalNotional: sdk.MustNewDecFromStr("1"), - TotalQuantity: sdk.MustNewDecFromStr("2"), - Settlements: []*types.SettlementEntry{&s1, &s2, &s1}, - MinPrice: sdk.MustNewDecFromStr("1"), - MaxPrice: sdk.MustNewDecFromStr("4"), - } - - e2 := exchange.ExecutionOutcome{ - TotalNotional: sdk.MustNewDecFromStr("4"), - TotalQuantity: sdk.MustNewDecFromStr("4"), - Settlements: []*types.SettlementEntry{&s1, &s2}, - MinPrice: sdk.MustNewDecFromStr("0.5"), - MaxPrice: sdk.MustNewDecFromStr("3"), - } - - outcome := e1.Merge(&e2) - - require.Equal(t, outcome.TotalNotional, sdk.MustNewDecFromStr("5")) - require.Equal(t, outcome.TotalQuantity, sdk.MustNewDecFromStr("6")) - require.Equal(t, len(outcome.Settlements), 5) - require.Equal(t, outcome.MinPrice, sdk.MustNewDecFromStr("0.5")) - require.Equal(t, outcome.MaxPrice, sdk.MustNewDecFromStr("4")) -} diff --git a/x/dex/exchange/limit_order.go b/x/dex/exchange/limit_order.go deleted file mode 100644 index 65f249d02..000000000 --- a/x/dex/exchange/limit_order.go +++ /dev/null @@ -1,103 +0,0 @@ -package exchange - -import ( - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/keeper" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -func MatchLimitOrders( - ctx sdk.Context, - orderbook *types.OrderBook, -) ExecutionOutcome { - settlements := []*types.SettlementEntry{} - totalExecuted, totalPrice := sdk.ZeroDec(), sdk.ZeroDec() - minPrice, maxPrice := sdk.OneDec().Neg(), sdk.OneDec().Neg() - - for longEntry, shortEntry := orderbook.Longs.Next(ctx), orderbook.Shorts.Next(ctx); longEntry != nil && shortEntry != nil && longEntry.GetPrice().GTE(shortEntry.GetPrice()); longEntry, shortEntry = orderbook.Longs.Next(ctx), orderbook.Shorts.Next(ctx) { - var executed sdk.Dec - if longEntry.GetOrderEntry().Quantity.LT(shortEntry.GetOrderEntry().Quantity) { - executed = longEntry.GetOrderEntry().Quantity - } else { - executed = shortEntry.GetOrderEntry().Quantity - } - totalExecuted = totalExecuted.Add(executed).Add(executed) - totalPrice = totalPrice.Add( - executed.Mul( - longEntry.GetPrice().Add(shortEntry.GetPrice()), - ), - ) - if minPrice.IsNegative() || minPrice.GT(shortEntry.GetPrice()) { - minPrice = shortEntry.GetPrice() - } - maxPrice = sdk.MaxDec(maxPrice, longEntry.GetPrice()) - - newSettlements := SettleFromBook( - ctx, - orderbook, - executed, - longEntry.GetPrice(), - shortEntry.GetPrice(), - ) - settlements = append(settlements, newSettlements...) - } - - orderbook.Longs.Flush(ctx) - orderbook.Shorts.Flush(ctx) - return ExecutionOutcome{ - TotalNotional: totalPrice, - TotalQuantity: totalExecuted, - Settlements: settlements, - MinPrice: minPrice, - MaxPrice: maxPrice, - } -} - -func addOrderToOrderBookEntry( - ctx sdk.Context, keeper *keeper.Keeper, - order *types.Order, -) { - getter, setter := keeper.GetLongOrderBookEntryByPrice, keeper.SetLongOrderBookEntry - if order.PositionDirection == types.PositionDirection_SHORT { - getter, setter = keeper.GetShortOrderBookEntryByPrice, keeper.SetShortOrderBookEntry - } - entry, exist := getter(ctx, order.ContractAddr, order.Price, order.PriceDenom, order.AssetDenom) - orderEntry := entry.GetOrderEntry() - if !exist { - orderEntry = &types.OrderEntry{ - Price: order.Price, - PriceDenom: order.PriceDenom, - AssetDenom: order.AssetDenom, - Quantity: sdk.ZeroDec(), - } - } - orderEntry.Quantity = orderEntry.Quantity.Add(order.Quantity) - orderEntry.Allocations = append(orderEntry.Allocations, &types.Allocation{ - OrderId: order.Id, - Quantity: order.Quantity, - Account: order.Account, - }) - entry.SetPrice(order.Price) - entry.SetEntry(orderEntry) - setter(ctx, order.ContractAddr, entry) - - err := keeper.IncreaseOrderCount(ctx, order.ContractAddr, order.PriceDenom, order.AssetDenom, order.PositionDirection, order.Price, 1) - if err != nil { - ctx.Logger().Error(fmt.Sprintf("error increasing order count: %s", err)) - } -} - -func AddOutstandingLimitOrdersToOrderbook( - ctx sdk.Context, keeper *keeper.Keeper, - limitBuys []*types.Order, - limitSells []*types.Order, -) { - for _, order := range limitBuys { - addOrderToOrderBookEntry(ctx, keeper, order) - } - for _, order := range limitSells { - addOrderToOrderBookEntry(ctx, keeper, order) - } -} diff --git a/x/dex/exchange/limit_order_fuzz_test.go b/x/dex/exchange/limit_order_fuzz_test.go deleted file mode 100644 index 3e14f3184..000000000 --- a/x/dex/exchange/limit_order_fuzz_test.go +++ /dev/null @@ -1,55 +0,0 @@ -package exchange_test - -import ( - "testing" - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/testutil/fuzzing" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex/exchange" - "github.com/sei-protocol/sei-chain/x/dex/keeper" - keeperutil "github.com/sei-protocol/sei-chain/x/dex/keeper/utils" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/libs/log" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" -) - -var TestFuzzLimitCtx = sdk.NewContext(nil, tmproto.Header{}, false, log.NewNopLogger()) -var TestFuzzLimitKeeper keeper.Keeper - -func FuzzMatchLimitOrders(f *testing.F) { - TestFuzzLimitCtx = TestFuzzLimitCtx.WithBlockHeight(1).WithBlockTime(time.Now()) - f.Fuzz(fuzzTargetMatchLimitOrders) -} - -func fuzzTargetMatchLimitOrders( - t *testing.T, - buyPrices []byte, - sellPrices []byte, - buyQuantities []byte, - sellQuantities []byte, - buyEntryWeights []byte, - sellEntryWeights []byte, - buyAccountIndices []byte, - sellAccountIndices []byte, - buyAllocationWeights []byte, - sellAllocationWeights []byte, -) { - dexkeeper, ctx := keepertest.DexKeeper(t) - ctx = ctx.WithBlockHeight(1).WithBlockTime(time.Now()) - buyEntries := fuzzing.GetOrderBookEntries(true, keepertest.TestPriceDenom, keepertest.TestAssetDenom, buyEntryWeights, buyAccountIndices, buyAllocationWeights) - for _, entry := range buyEntries { - dexkeeper.SetLongOrderBookEntry(ctx, keepertest.TestContract, entry) - } - sellEntries := fuzzing.GetOrderBookEntries(false, keepertest.TestPriceDenom, keepertest.TestAssetDenom, sellEntryWeights, sellAccountIndices, sellAllocationWeights) - for _, entry := range sellEntries { - dexkeeper.SetShortOrderBookEntry(ctx, keepertest.TestContract, entry) - } - buyOrders := fuzzing.GetPlacedOrders(types.PositionDirection_LONG, types.OrderType_LIMIT, keepertest.TestPair, buyPrices, buyQuantities) - sellOrders := fuzzing.GetPlacedOrders(types.PositionDirection_SHORT, types.OrderType_LIMIT, keepertest.TestPair, sellPrices, sellQuantities) - exchange.AddOutstandingLimitOrdersToOrderbook(ctx, dexkeeper, buyOrders, sellOrders) - orderBook := keeperutil.PopulateOrderbook(ctx, dexkeeper, types.ContractAddress(keepertest.TestContract), types.Pair{PriceDenom: keepertest.TestPriceDenom, AssetDenom: keepertest.TestAssetDenom}) - require.NotPanics(t, func() { exchange.MatchLimitOrders(ctx, orderBook) }) -} diff --git a/x/dex/exchange/limit_order_test.go b/x/dex/exchange/limit_order_test.go deleted file mode 100644 index f904ab91c..000000000 --- a/x/dex/exchange/limit_order_test.go +++ /dev/null @@ -1,1165 +0,0 @@ -package exchange_test - -import ( - "testing" - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/exchange" - keeperutil "github.com/sei-protocol/sei-chain/x/dex/keeper/utils" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/assert" - - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" -) - -func TEST_PAIR() types.Pair { - return types.Pair{ - PriceDenom: "usdc", - AssetDenom: "atom", - } -} - -func TestMatchSingleOrder(t *testing.T) { - dexkeeper, ctx := keepertest.DexKeeper(t) - ctx = ctx.WithBlockHeight(int64(TestHeight)).WithBlockTime(time.Unix(int64(TestTimestamp), 0)) - longOrders := []*types.Order{ - { - Id: 1, - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(5), - Account: "abc", - PositionDirection: types.PositionDirection_LONG, - ContractAddr: "test", - PriceDenom: "USDC", - AssetDenom: "ATOM", - OrderType: types.OrderType_LIMIT, - }, - } - shortOrders := []*types.Order{ - { - Id: 2, - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(5), - Account: "def", - PositionDirection: types.PositionDirection_SHORT, - ContractAddr: "test", - PriceDenom: "USDC", - AssetDenom: "ATOM", - OrderType: types.OrderType_LIMIT, - }, - } - longBook := []types.OrderBookEntry{} - shortBook := []types.OrderBookEntry{} - exchange.AddOutstandingLimitOrdersToOrderbook(ctx, dexkeeper, longOrders, shortOrders) - orderbook := keeperutil.PopulateOrderbook(ctx, dexkeeper, types.ContractAddress("test"), types.Pair{PriceDenom: "USDC", AssetDenom: "ATOM"}) - outcome := exchange.MatchLimitOrders( - ctx, orderbook, - ) - totalPrice := outcome.TotalNotional - totalExecuted := outcome.TotalQuantity - settlements := outcome.Settlements - assert.Equal(t, totalPrice, sdk.NewDec(1000)) - assert.Equal(t, totalExecuted, sdk.NewDec(10)) - assert.Equal(t, outcome.MaxPrice, sdk.NewDec(100)) - assert.Equal(t, outcome.MinPrice, sdk.NewDec(100)) - longBook = dexkeeper.GetAllLongBookForPair(ctx, "test", "USDC", "ATOM") - shortBook = dexkeeper.GetAllShortBookForPair(ctx, "test", "USDC", "ATOM") - assert.Equal(t, len(longBook), 0) - assert.Equal(t, len(shortBook), 0) - assert.Equal(t, len(settlements), 2) - assert.Equal(t, *settlements[0], types.SettlementEntry{ - PositionDirection: "Long", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(5), - ExecutionCostOrProceed: sdk.NewDec(100), - ExpectedCostOrProceed: sdk.NewDec(100), - Account: "abc", - OrderType: "Limit", - OrderId: 1, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, *settlements[1], types.SettlementEntry{ - PositionDirection: "Short", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(5), - ExecutionCostOrProceed: sdk.NewDec(100), - ExpectedCostOrProceed: sdk.NewDec(100), - Account: "def", - OrderType: "Limit", - OrderId: 2, - Timestamp: TestTimestamp, - Height: TestHeight, - }) -} - -func TestAddOrders(t *testing.T) { - dexkeeper, ctx := keepertest.DexKeeper(t) - ctx = ctx.WithBlockHeight(int64(TestHeight)).WithBlockTime(time.Unix(int64(TestTimestamp), 0)) - longOrders := []*types.Order{ - { - Id: 1, - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(5), - Account: "def", - PositionDirection: types.PositionDirection_LONG, - ContractAddr: "test", - PriceDenom: "USDC", - AssetDenom: "ATOM", - OrderType: types.OrderType_LIMIT, - }, - { - Id: 2, - Price: sdk.NewDec(95), - Quantity: sdk.NewDec(3), - Account: "def", - PositionDirection: types.PositionDirection_LONG, - ContractAddr: "test", - PriceDenom: "USDC", - AssetDenom: "ATOM", - OrderType: types.OrderType_LIMIT, - }, - } - shortOrders := []*types.Order{ - { - Id: 3, - Price: sdk.NewDec(105), - Quantity: sdk.NewDec(10), - Account: "ghi", - PositionDirection: types.PositionDirection_SHORT, - ContractAddr: "test", - PriceDenom: "USDC", - AssetDenom: "ATOM", - OrderType: types.OrderType_LIMIT, - }, - { - Id: 4, - Price: sdk.NewDec(115), - Quantity: sdk.NewDec(2), - Account: "mno", - PositionDirection: types.PositionDirection_SHORT, - ContractAddr: "test", - PriceDenom: "USDC", - AssetDenom: "ATOM", - OrderType: types.OrderType_LIMIT, - }, - } - longBook := []types.OrderBookEntry{ - &types.LongBook{ - Price: sdk.NewDec(98), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(98), - Quantity: sdk.NewDec(5), - Allocations: []*types.Allocation{{ - OrderId: 5, - Account: "abc", - Quantity: sdk.NewDec(5), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - &types.LongBook{ - Price: sdk.NewDec(100), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(3), - Allocations: []*types.Allocation{{ - OrderId: 6, - Account: "def", - Quantity: sdk.NewDec(3), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - } - shortBook := []types.OrderBookEntry{ - &types.ShortBook{ - Price: sdk.NewDec(101), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(101), - Quantity: sdk.NewDec(5), - Allocations: []*types.Allocation{{ - OrderId: 7, - Account: "abc", - Quantity: sdk.NewDec(5), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - &types.ShortBook{ - Price: sdk.NewDec(115), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(115), - Quantity: sdk.NewDec(3), - Allocations: []*types.Allocation{{ - OrderId: 8, - Account: "def", - Quantity: sdk.NewDec(3), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - } - for _, e := range longBook { - dexkeeper.SetLongOrderBookEntry(ctx, "test", e) - } - for _, e := range shortBook { - dexkeeper.SetShortOrderBookEntry(ctx, "test", e) - } - exchange.AddOutstandingLimitOrdersToOrderbook(ctx, dexkeeper, longOrders, shortOrders) - orderbook := keeperutil.PopulateOrderbook(ctx, dexkeeper, types.ContractAddress("test"), types.Pair{PriceDenom: "USDC", AssetDenom: "ATOM"}) - outcome := exchange.MatchLimitOrders( - ctx, orderbook, - ) - totalPrice := outcome.TotalNotional - totalExecuted := outcome.TotalQuantity - settlements := outcome.Settlements - assert.Equal(t, totalPrice, sdk.NewDec(0)) - assert.Equal(t, totalExecuted, sdk.NewDec(0)) - longBook = dexkeeper.GetAllLongBookForPair(ctx, "test", "USDC", "ATOM") - shortBook = dexkeeper.GetAllShortBookForPair(ctx, "test", "USDC", "ATOM") - assert.Equal(t, len(longBook), 3) - assert.Equal(t, longBook[0].GetPrice(), sdk.NewDec(95)) - assert.Equal(t, *longBook[0].GetOrderEntry(), types.OrderEntry{ - Price: sdk.NewDec(95), - Quantity: sdk.NewDec(3), - Allocations: []*types.Allocation{{ - OrderId: 2, - Account: "def", - Quantity: sdk.NewDec(3), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }) - assert.Equal(t, longBook[1].GetPrice(), sdk.NewDec(98)) - assert.Equal(t, *longBook[1].GetOrderEntry(), types.OrderEntry{ - Price: sdk.NewDec(98), - Quantity: sdk.NewDec(5), - Allocations: []*types.Allocation{{ - OrderId: 5, - Account: "abc", - Quantity: sdk.NewDec(5), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }) - assert.Equal(t, longBook[2].GetPrice(), sdk.NewDec(100)) - assert.Equal(t, *longBook[2].GetOrderEntry(), types.OrderEntry{ - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(8), - Allocations: []*types.Allocation{{ - OrderId: 6, - Account: "def", - Quantity: sdk.NewDec(3), - }, { - OrderId: 1, - Account: "def", - Quantity: sdk.NewDec(5), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }) - assert.Equal(t, len(shortBook), 3) - assert.Equal(t, shortBook[0].GetPrice(), sdk.NewDec(101)) - assert.Equal(t, *shortBook[0].GetOrderEntry(), types.OrderEntry{ - Price: sdk.NewDec(101), - Quantity: sdk.NewDec(5), - Allocations: []*types.Allocation{{ - OrderId: 7, - Account: "abc", - Quantity: sdk.NewDec(5), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }) - assert.Equal(t, shortBook[1].GetPrice(), sdk.NewDec(105)) - assert.Equal(t, *shortBook[1].GetOrderEntry(), types.OrderEntry{ - Price: sdk.NewDec(105), - Quantity: sdk.NewDec(10), - Allocations: []*types.Allocation{{ - OrderId: 3, - Account: "ghi", - Quantity: sdk.NewDec(10), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }) - assert.Equal(t, shortBook[2].GetPrice(), sdk.NewDec(115)) - assert.Equal(t, *shortBook[2].GetOrderEntry(), types.OrderEntry{ - Price: sdk.NewDec(115), - Quantity: sdk.NewDec(5), - Allocations: []*types.Allocation{{ - OrderId: 8, - Account: "def", - Quantity: sdk.NewDec(3), - }, { - OrderId: 4, - Account: "mno", - Quantity: sdk.NewDec(2), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }) - assert.Equal(t, len(settlements), 0) -} - -func TestMatchSingleOrderFromShortBook(t *testing.T) { - dexkeeper, ctx := keepertest.DexKeeper(t) - ctx = ctx.WithBlockHeight(int64(TestHeight)).WithBlockTime(time.Unix(int64(TestTimestamp), 0)) - longOrders := []*types.Order{ - { - Id: 1, - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(5), - Account: "abc", - PositionDirection: types.PositionDirection_LONG, - ContractAddr: "test", - PriceDenom: "USDC", - AssetDenom: "ATOM", - OrderType: types.OrderType_LIMIT, - }, - } - shortOrders := []*types.Order{} - longBook := []types.OrderBookEntry{} - shortBook := []types.OrderBookEntry{ - &types.ShortBook{ - Price: sdk.NewDec(100), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(5), - Allocations: []*types.Allocation{{ - OrderId: 2, - Account: "def", - Quantity: sdk.NewDec(5), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - } - for _, e := range longBook { - dexkeeper.SetLongOrderBookEntry(ctx, "test", e) - } - for _, e := range shortBook { - dexkeeper.SetShortOrderBookEntry(ctx, "test", e) - } - exchange.AddOutstandingLimitOrdersToOrderbook(ctx, dexkeeper, longOrders, shortOrders) - orderbook := keeperutil.PopulateOrderbook(ctx, dexkeeper, types.ContractAddress("test"), types.Pair{PriceDenom: "USDC", AssetDenom: "ATOM"}) - outcome := exchange.MatchLimitOrders( - ctx, orderbook, - ) - totalPrice := outcome.TotalNotional - totalExecuted := outcome.TotalQuantity - settlements := outcome.Settlements - assert.Equal(t, totalPrice, sdk.NewDec(1000)) - assert.Equal(t, totalExecuted, sdk.NewDec(10)) - longBook = dexkeeper.GetAllLongBookForPair(ctx, "test", "USDC", "ATOM") - shortBook = dexkeeper.GetAllShortBookForPair(ctx, "test", "USDC", "ATOM") - assert.Equal(t, len(longBook), 0) - assert.Equal(t, len(shortBook), 0) - assert.Equal(t, len(settlements), 2) - assert.Equal(t, *settlements[0], types.SettlementEntry{ - PositionDirection: "Long", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(5), - ExecutionCostOrProceed: sdk.NewDec(100), - ExpectedCostOrProceed: sdk.NewDec(100), - Account: "abc", - OrderType: "Limit", - OrderId: 1, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, *settlements[1], types.SettlementEntry{ - PositionDirection: "Short", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(5), - ExecutionCostOrProceed: sdk.NewDec(100), - ExpectedCostOrProceed: sdk.NewDec(100), - Account: "def", - OrderType: "Limit", - OrderId: 2, - Timestamp: TestTimestamp, - Height: TestHeight, - }) -} - -func TestMatchSingleOrderFromLongBook(t *testing.T) { - dexkeeper, ctx := keepertest.DexKeeper(t) - ctx = ctx.WithBlockHeight(int64(TestHeight)).WithBlockTime(time.Unix(int64(TestTimestamp), 0)) - longOrders := []*types.Order{} - shortOrders := []*types.Order{ - { - Id: 1, - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(5), - Account: "def", - PositionDirection: types.PositionDirection_SHORT, - ContractAddr: "test", - PriceDenom: "USDC", - AssetDenom: "ATOM", - OrderType: types.OrderType_LIMIT, - }, - } - longBook := []types.OrderBookEntry{ - &types.LongBook{ - Price: sdk.NewDec(100), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(5), - Allocations: []*types.Allocation{{ - OrderId: 2, - Account: "abc", - Quantity: sdk.NewDec(5), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - } - shortBook := []types.OrderBookEntry{} - for _, e := range longBook { - dexkeeper.SetLongOrderBookEntry(ctx, "test", e) - } - for _, e := range shortBook { - dexkeeper.SetShortOrderBookEntry(ctx, "test", e) - } - exchange.AddOutstandingLimitOrdersToOrderbook(ctx, dexkeeper, longOrders, shortOrders) - orderbook := keeperutil.PopulateOrderbook(ctx, dexkeeper, types.ContractAddress("test"), types.Pair{PriceDenom: "USDC", AssetDenom: "ATOM"}) - outcome := exchange.MatchLimitOrders( - ctx, orderbook, - ) - totalPrice := outcome.TotalNotional - totalExecuted := outcome.TotalQuantity - settlements := outcome.Settlements - assert.Equal(t, totalPrice, sdk.NewDec(1000)) - assert.Equal(t, totalExecuted, sdk.NewDec(10)) - longBook = dexkeeper.GetAllLongBookForPair(ctx, "test", "USDC", "ATOM") - shortBook = dexkeeper.GetAllShortBookForPair(ctx, "test", "USDC", "ATOM") - assert.Equal(t, len(longBook), 0) - assert.Equal(t, len(shortBook), 0) - assert.Equal(t, len(settlements), 2) - assert.Equal(t, *settlements[0], types.SettlementEntry{ - PositionDirection: "Long", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(5), - ExecutionCostOrProceed: sdk.NewDec(100), - ExpectedCostOrProceed: sdk.NewDec(100), - Account: "abc", - OrderType: "Limit", - OrderId: 2, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, *settlements[1], types.SettlementEntry{ - PositionDirection: "Short", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(5), - ExecutionCostOrProceed: sdk.NewDec(100), - ExpectedCostOrProceed: sdk.NewDec(100), - Account: "def", - OrderType: "Limit", - OrderId: 1, - Timestamp: TestTimestamp, - Height: TestHeight, - }) -} - -func TestMatchSingleOrderFromMultipleShortBook(t *testing.T) { - dexkeeper, ctx := keepertest.DexKeeper(t) - ctx = ctx.WithBlockHeight(int64(TestHeight)).WithBlockTime(time.Unix(int64(TestTimestamp), 0)) - longOrders := []*types.Order{ - { - Id: 1, - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(5), - Account: "abc", - PositionDirection: types.PositionDirection_LONG, - ContractAddr: "test", - PriceDenom: "USDC", - AssetDenom: "ATOM", - OrderType: types.OrderType_LIMIT, - }, - } - shortOrders := []*types.Order{} - longBook := []types.OrderBookEntry{} - shortBook := []types.OrderBookEntry{ - &types.ShortBook{ - Price: sdk.NewDec(90), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(90), - Quantity: sdk.NewDec(2), - Allocations: []*types.Allocation{{ - OrderId: 2, - Account: "def", - Quantity: sdk.NewDec(2), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - &types.ShortBook{ - Price: sdk.NewDec(100), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(6), - Allocations: []*types.Allocation{{ - OrderId: 3, - Account: "def", - Quantity: sdk.NewDec(4), - }, { - OrderId: 4, - Account: "ghi", - Quantity: sdk.NewDec(2), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - } - for _, e := range longBook { - dexkeeper.SetLongOrderBookEntry(ctx, "test", e) - } - for _, e := range shortBook { - dexkeeper.SetShortOrderBookEntry(ctx, "test", e) - } - exchange.AddOutstandingLimitOrdersToOrderbook(ctx, dexkeeper, longOrders, shortOrders) - orderbook := keeperutil.PopulateOrderbook(ctx, dexkeeper, types.ContractAddress("test"), types.Pair{PriceDenom: "USDC", AssetDenom: "ATOM"}) - outcome := exchange.MatchLimitOrders( - ctx, orderbook, - ) - totalPrice := outcome.TotalNotional - totalExecuted := outcome.TotalQuantity - settlements := outcome.Settlements - assert.Equal(t, totalPrice, sdk.NewDec(980)) - assert.Equal(t, totalExecuted, sdk.NewDec(10)) - longBook = dexkeeper.GetAllLongBookForPair(ctx, "test", "USDC", "ATOM") - shortBook = dexkeeper.GetAllShortBookForPair(ctx, "test", "USDC", "ATOM") - assert.Equal(t, len(longBook), 0) - assert.Equal(t, len(shortBook), 1) - assert.Equal(t, shortBook[0].GetPrice(), sdk.NewDec(100)) - assert.Equal(t, *shortBook[0].GetOrderEntry(), types.OrderEntry{ - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(3), - Allocations: []*types.Allocation{{ - OrderId: 3, - Account: "def", - Quantity: sdk.NewDec(1), - }, { - OrderId: 4, - Account: "ghi", - Quantity: sdk.NewDec(2), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }) - assert.Equal(t, len(settlements), 4) - assert.Equal(t, *settlements[0], types.SettlementEntry{ - PositionDirection: "Long", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(2), - ExecutionCostOrProceed: sdk.NewDec(95), - ExpectedCostOrProceed: sdk.NewDec(100), - Account: "abc", - OrderType: "Limit", - OrderId: 1, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, *settlements[1], types.SettlementEntry{ - PositionDirection: "Short", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(2), - ExecutionCostOrProceed: sdk.NewDec(95), - ExpectedCostOrProceed: sdk.NewDec(90), - Account: "def", - OrderType: "Limit", - OrderId: 2, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, *settlements[2], types.SettlementEntry{ - PositionDirection: "Long", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(3), - ExecutionCostOrProceed: sdk.NewDec(100), - ExpectedCostOrProceed: sdk.NewDec(100), - Account: "abc", - OrderType: "Limit", - OrderId: 1, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, *settlements[3], types.SettlementEntry{ - PositionDirection: "Short", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(3), - ExecutionCostOrProceed: sdk.NewDec(100), - ExpectedCostOrProceed: sdk.NewDec(100), - Account: "def", - OrderType: "Limit", - OrderId: 3, - Timestamp: TestTimestamp, - Height: TestHeight, - }) -} - -func TestMatchSingleOrderFromMultipleLongBook(t *testing.T) { - dexkeeper, ctx := keepertest.DexKeeper(t) - ctx = ctx.WithBlockHeight(int64(TestHeight)).WithBlockTime(time.Unix(int64(TestTimestamp), 0)) - longOrders := []*types.Order{} - shortOrders := []*types.Order{ - { - Id: 1, - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(5), - Account: "def", - PositionDirection: types.PositionDirection_SHORT, - ContractAddr: "test", - PriceDenom: "USDC", - AssetDenom: "ATOM", - OrderType: types.OrderType_LIMIT, - }, - } - longBook := []types.OrderBookEntry{ - &types.LongBook{ - Price: sdk.NewDec(100), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(6), - Allocations: []*types.Allocation{{ - OrderId: 2, - Account: "abc", - Quantity: sdk.NewDec(4), - }, { - OrderId: 3, - Account: "ghi", - Quantity: sdk.NewDec(2), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - &types.LongBook{ - Price: sdk.NewDec(110), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(110), - Quantity: sdk.NewDec(2), - Allocations: []*types.Allocation{{ - OrderId: 4, - Account: "abc", - Quantity: sdk.NewDec(2), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - } - shortBook := []types.OrderBookEntry{} - for _, e := range longBook { - dexkeeper.SetLongOrderBookEntry(ctx, "test", e) - } - for _, e := range shortBook { - dexkeeper.SetShortOrderBookEntry(ctx, "test", e) - } - exchange.AddOutstandingLimitOrdersToOrderbook(ctx, dexkeeper, longOrders, shortOrders) - orderbook := keeperutil.PopulateOrderbook(ctx, dexkeeper, types.ContractAddress("test"), types.Pair{PriceDenom: "USDC", AssetDenom: "ATOM"}) - outcome := exchange.MatchLimitOrders( - ctx, orderbook, - ) - totalPrice := outcome.TotalNotional - totalExecuted := outcome.TotalQuantity - settlements := outcome.Settlements - assert.Equal(t, totalPrice, sdk.NewDec(1020)) - assert.Equal(t, totalExecuted, sdk.NewDec(10)) - longBook = dexkeeper.GetAllLongBookForPair(ctx, "test", "USDC", "ATOM") - shortBook = dexkeeper.GetAllShortBookForPair(ctx, "test", "USDC", "ATOM") - assert.Equal(t, len(longBook), 1) - assert.Equal(t, longBook[0].GetPrice(), sdk.NewDec(100)) - assert.Equal(t, *longBook[0].GetOrderEntry(), types.OrderEntry{ - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(3), - Allocations: []*types.Allocation{{ - OrderId: 2, - Account: "abc", - Quantity: sdk.NewDec(1), - }, { - OrderId: 3, - Account: "ghi", - Quantity: sdk.NewDec(2), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }) - assert.Equal(t, len(shortBook), 0) - assert.Equal(t, len(settlements), 4) - assert.Equal(t, *settlements[0], types.SettlementEntry{ - PositionDirection: "Long", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(2), - ExecutionCostOrProceed: sdk.NewDec(105), - ExpectedCostOrProceed: sdk.NewDec(110), - Account: "abc", - OrderType: "Limit", - OrderId: 4, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, *settlements[1], types.SettlementEntry{ - PositionDirection: "Short", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(2), - ExecutionCostOrProceed: sdk.NewDec(105), - ExpectedCostOrProceed: sdk.NewDec(100), - Account: "def", - OrderType: "Limit", - OrderId: 1, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, *settlements[2], types.SettlementEntry{ - PositionDirection: "Long", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(3), - ExecutionCostOrProceed: sdk.NewDec(100), - ExpectedCostOrProceed: sdk.NewDec(100), - Account: "abc", - OrderType: "Limit", - OrderId: 2, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, *settlements[3], types.SettlementEntry{ - PositionDirection: "Short", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(3), - ExecutionCostOrProceed: sdk.NewDec(100), - ExpectedCostOrProceed: sdk.NewDec(100), - Account: "def", - OrderType: "Limit", - OrderId: 1, - Timestamp: TestTimestamp, - Height: TestHeight, - }) -} - -func TestMatchMultipleOrderFromMultipleShortBook(t *testing.T) { - dexkeeper, ctx := keepertest.DexKeeper(t) - ctx = ctx.WithBlockHeight(int64(TestHeight)).WithBlockTime(time.Unix(int64(TestTimestamp), 0)) - longOrders := []*types.Order{ - { - Id: 1, - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(5), - Account: "abc", - PositionDirection: types.PositionDirection_LONG, - ContractAddr: "test", - PriceDenom: "USDC", - AssetDenom: "ATOM", - OrderType: types.OrderType_LIMIT, - }, - { - Id: 2, - Price: sdk.NewDec(104), - Quantity: sdk.NewDec(1), - Account: "jkl", - PositionDirection: types.PositionDirection_LONG, - ContractAddr: "test", - PriceDenom: "USDC", - AssetDenom: "ATOM", - OrderType: types.OrderType_LIMIT, - }, - { - Id: 3, - Price: sdk.NewDec(98), - Quantity: sdk.NewDec(2), - Account: "mno", - PositionDirection: types.PositionDirection_LONG, - ContractAddr: "test", - PriceDenom: "USDC", - AssetDenom: "ATOM", - OrderType: types.OrderType_LIMIT, - }, - } - shortOrders := []*types.Order{} - longBook := []types.OrderBookEntry{} - shortBook := []types.OrderBookEntry{ - &types.ShortBook{ - Price: sdk.NewDec(90), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(90), - Quantity: sdk.NewDec(2), - Allocations: []*types.Allocation{{ - OrderId: 4, - Account: "def", - Quantity: sdk.NewDec(2), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - &types.ShortBook{ - Price: sdk.NewDec(100), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(6), - Allocations: []*types.Allocation{{ - OrderId: 5, - Account: "def", - Quantity: sdk.NewDec(4), - }, { - OrderId: 6, - Account: "ghi", - Quantity: sdk.NewDec(2), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - } - for _, e := range longBook { - dexkeeper.SetLongOrderBookEntry(ctx, "test", e) - } - for _, e := range shortBook { - dexkeeper.SetShortOrderBookEntry(ctx, "test", e) - } - exchange.AddOutstandingLimitOrdersToOrderbook(ctx, dexkeeper, longOrders, shortOrders) - orderbook := keeperutil.PopulateOrderbook(ctx, dexkeeper, types.ContractAddress("test"), types.Pair{PriceDenom: "USDC", AssetDenom: "ATOM"}) - outcome := exchange.MatchLimitOrders( - ctx, orderbook, - ) - totalPrice := outcome.TotalNotional - totalExecuted := outcome.TotalQuantity - settlements := outcome.Settlements - assert.Equal(t, totalPrice, sdk.NewDec(1184)) - assert.Equal(t, totalExecuted, sdk.NewDec(12)) - longBook = dexkeeper.GetAllLongBookForPair(ctx, "test", "USDC", "ATOM") - shortBook = dexkeeper.GetAllShortBookForPair(ctx, "test", "USDC", "ATOM") - assert.Equal(t, len(longBook), 1) - assert.Equal(t, longBook[0].GetPrice(), sdk.NewDec(98)) - assert.Equal(t, *longBook[0].GetOrderEntry(), types.OrderEntry{ - Price: sdk.NewDec(98), - Quantity: sdk.NewDec(2), - Allocations: []*types.Allocation{{ - OrderId: 3, - Account: "mno", - Quantity: sdk.NewDec(2), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }) - assert.Equal(t, len(shortBook), 1) - assert.Equal(t, shortBook[0].GetPrice(), sdk.NewDec(100)) - assert.Equal(t, *shortBook[0].GetOrderEntry(), types.OrderEntry{ - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(2), - Allocations: []*types.Allocation{{ - OrderId: 6, - Account: "ghi", - Quantity: sdk.NewDec(2), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }) - assert.Equal(t, len(settlements), 6) - assert.Equal(t, *settlements[0], types.SettlementEntry{ - PositionDirection: "Long", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(1), - ExecutionCostOrProceed: sdk.NewDec(97), - ExpectedCostOrProceed: sdk.NewDec(104), - Account: "jkl", - OrderType: "Limit", - OrderId: 2, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, *settlements[1], types.SettlementEntry{ - PositionDirection: "Short", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(1), - ExecutionCostOrProceed: sdk.NewDec(97), - ExpectedCostOrProceed: sdk.NewDec(90), - Account: "def", - OrderType: "Limit", - OrderId: 4, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, *settlements[2], types.SettlementEntry{ - PositionDirection: "Long", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(1), - ExecutionCostOrProceed: sdk.NewDec(95), - ExpectedCostOrProceed: sdk.NewDec(100), - Account: "abc", - OrderType: "Limit", - OrderId: 1, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, *settlements[3], types.SettlementEntry{ - PositionDirection: "Short", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(1), - ExecutionCostOrProceed: sdk.NewDec(95), - ExpectedCostOrProceed: sdk.NewDec(90), - Account: "def", - OrderType: "Limit", - OrderId: 4, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, *settlements[4], types.SettlementEntry{ - PositionDirection: "Long", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(4), - ExecutionCostOrProceed: sdk.NewDec(100), - ExpectedCostOrProceed: sdk.NewDec(100), - Account: "abc", - OrderType: "Limit", - OrderId: 1, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, *settlements[5], types.SettlementEntry{ - PositionDirection: "Short", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(4), - ExecutionCostOrProceed: sdk.NewDec(100), - ExpectedCostOrProceed: sdk.NewDec(100), - Account: "def", - OrderType: "Limit", - OrderId: 5, - Timestamp: TestTimestamp, - Height: TestHeight, - }) -} - -func TestMatchMultipleOrderFromMultipleLongBook(t *testing.T) { - dexkeeper, ctx := keepertest.DexKeeper(t) - ctx = ctx.WithBlockHeight(int64(TestHeight)).WithBlockTime(time.Unix(int64(TestTimestamp), 0)) - longOrders := []*types.Order{} - shortOrders := []*types.Order{ - { - Id: 1, - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(5), - Account: "abc", - PositionDirection: types.PositionDirection_SHORT, - ContractAddr: "test", - PriceDenom: "USDC", - AssetDenom: "ATOM", - OrderType: types.OrderType_LIMIT, - }, - { - Id: 2, - Price: sdk.NewDec(96), - Quantity: sdk.NewDec(1), - Account: "jkl", - PositionDirection: types.PositionDirection_SHORT, - ContractAddr: "test", - PriceDenom: "USDC", - AssetDenom: "ATOM", - OrderType: types.OrderType_LIMIT, - }, - { - Id: 3, - Price: sdk.NewDec(102), - Quantity: sdk.NewDec(2), - Account: "mno", - PositionDirection: types.PositionDirection_SHORT, - ContractAddr: "test", - PriceDenom: "USDC", - AssetDenom: "ATOM", - OrderType: types.OrderType_LIMIT, - }, - } - longBook := []types.OrderBookEntry{ - &types.LongBook{ - Price: sdk.NewDec(100), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(6), - Allocations: []*types.Allocation{{ - OrderId: 4, - Account: "abc", - Quantity: sdk.NewDec(4), - }, { - OrderId: 5, - Account: "ghi", - Quantity: sdk.NewDec(2), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - &types.LongBook{ - Price: sdk.NewDec(110), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(110), - Quantity: sdk.NewDec(2), - Allocations: []*types.Allocation{{ - OrderId: 6, - Account: "abc", - Quantity: sdk.NewDec(2), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - } - shortBook := []types.OrderBookEntry{} - for _, e := range longBook { - dexkeeper.SetLongOrderBookEntry(ctx, "test", e) - } - for _, e := range shortBook { - dexkeeper.SetShortOrderBookEntry(ctx, "test", e) - } - exchange.AddOutstandingLimitOrdersToOrderbook(ctx, dexkeeper, longOrders, shortOrders) - orderbook := keeperutil.PopulateOrderbook(ctx, dexkeeper, types.ContractAddress("test"), types.Pair{PriceDenom: "USDC", AssetDenom: "ATOM"}) - outcome := exchange.MatchLimitOrders( - ctx, orderbook, - ) - totalPrice := outcome.TotalNotional - totalExecuted := outcome.TotalQuantity - settlements := outcome.Settlements - minPrice := outcome.MinPrice - maxPrice := outcome.MaxPrice - assert.Equal(t, totalPrice, sdk.NewDec(1216)) - assert.Equal(t, totalExecuted, sdk.NewDec(12)) - assert.Equal(t, minPrice, sdk.NewDec(96)) - assert.Equal(t, maxPrice, sdk.NewDec(110)) - longBook = dexkeeper.GetAllLongBookForPair(ctx, "test", "USDC", "ATOM") - shortBook = dexkeeper.GetAllShortBookForPair(ctx, "test", "USDC", "ATOM") - assert.Equal(t, len(longBook), 1) - assert.Equal(t, longBook[0].GetPrice(), sdk.NewDec(100)) - assert.Equal(t, *longBook[0].GetOrderEntry(), types.OrderEntry{ - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(2), - Allocations: []*types.Allocation{{ - OrderId: 5, - Account: "ghi", - Quantity: sdk.NewDec(2), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }) - assert.Equal(t, len(shortBook), 1) - assert.Equal(t, shortBook[0].GetPrice(), sdk.NewDec(102)) - assert.Equal(t, *shortBook[0].GetOrderEntry(), types.OrderEntry{ - Price: sdk.NewDec(102), - Quantity: sdk.NewDec(2), - Allocations: []*types.Allocation{{ - OrderId: 3, - Account: "mno", - Quantity: sdk.NewDec(2), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }) - assert.Equal(t, len(settlements), 6) - assert.Equal(t, *settlements[0], types.SettlementEntry{ - PositionDirection: "Long", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(1), - ExecutionCostOrProceed: sdk.NewDec(103), - ExpectedCostOrProceed: sdk.NewDec(110), - Account: "abc", - OrderType: "Limit", - OrderId: 6, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, *settlements[1], types.SettlementEntry{ - PositionDirection: "Short", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(1), - ExecutionCostOrProceed: sdk.NewDec(103), - ExpectedCostOrProceed: sdk.NewDec(96), - Account: "jkl", - OrderType: "Limit", - OrderId: 2, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, *settlements[2], types.SettlementEntry{ - PositionDirection: "Long", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(1), - ExecutionCostOrProceed: sdk.NewDec(105), - ExpectedCostOrProceed: sdk.NewDec(110), - Account: "abc", - OrderType: "Limit", - OrderId: 6, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, *settlements[3], types.SettlementEntry{ - PositionDirection: "Short", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(1), - ExecutionCostOrProceed: sdk.NewDec(105), - ExpectedCostOrProceed: sdk.NewDec(100), - Account: "abc", - OrderType: "Limit", - OrderId: 1, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, *settlements[4], types.SettlementEntry{ - PositionDirection: "Long", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(4), - ExecutionCostOrProceed: sdk.NewDec(100), - ExpectedCostOrProceed: sdk.NewDec(100), - Account: "abc", - OrderType: "Limit", - OrderId: 4, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, *settlements[5], types.SettlementEntry{ - PositionDirection: "Short", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(4), - ExecutionCostOrProceed: sdk.NewDec(100), - ExpectedCostOrProceed: sdk.NewDec(100), - Account: "abc", - OrderType: "Limit", - OrderId: 1, - Timestamp: TestTimestamp, - Height: TestHeight, - }) -} diff --git a/x/dex/exchange/market_order.go b/x/dex/exchange/market_order.go deleted file mode 100644 index c557ded25..000000000 --- a/x/dex/exchange/market_order.go +++ /dev/null @@ -1,273 +0,0 @@ -package exchange - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - cache "github.com/sei-protocol/sei-chain/x/dex/cache" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -func MatchMarketOrders( - ctx sdk.Context, - marketOrders []*types.Order, - orderBookEntries *types.CachedSortedOrderBookEntries, - direction types.PositionDirection, - blockOrders *cache.BlockOrders, -) ExecutionOutcome { - totalExecuted, totalPrice := sdk.ZeroDec(), sdk.ZeroDec() - minPrice, maxPrice := sdk.OneDec().Neg(), sdk.OneDec().Neg() - settlements := []*types.SettlementEntry{} - allTakerSettlements := []*types.SettlementEntry{} - for _, marketOrder := range marketOrders { - switch marketOrder.OrderType { - case types.OrderType_FOKMARKETBYVALUE: - settlements, allTakerSettlements = MatchByValueFOKMarketOrder( - ctx, marketOrder, orderBookEntries, direction, &totalExecuted, &totalPrice, &minPrice, &maxPrice, settlements, allTakerSettlements, blockOrders) - case types.OrderType_FOKMARKET: - settlements, allTakerSettlements = MatchFOKMarketOrder( - ctx, marketOrder, orderBookEntries, direction, &totalExecuted, &totalPrice, &minPrice, &maxPrice, settlements, allTakerSettlements, blockOrders) - default: - settlements, allTakerSettlements = MatchMarketOrder( - ctx, marketOrder, orderBookEntries, direction, &totalExecuted, &totalPrice, &minPrice, &maxPrice, settlements, allTakerSettlements, blockOrders) - } - } - - if totalExecuted.IsPositive() { - clearingPrice := totalPrice.Quo(totalExecuted) - for _, settlement := range allTakerSettlements { - settlement.ExecutionCostOrProceed = clearingPrice - } - minPrice, maxPrice = clearingPrice, clearingPrice - settlements = append(settlements, allTakerSettlements...) - } - return ExecutionOutcome{ - TotalNotional: totalPrice, - TotalQuantity: totalExecuted, - Settlements: settlements, - MinPrice: minPrice, - MaxPrice: maxPrice, - } -} - -func MatchMarketOrder( - ctx sdk.Context, - marketOrder *types.Order, - orderBookEntries *types.CachedSortedOrderBookEntries, - direction types.PositionDirection, - totalExecuted *sdk.Dec, - totalPrice *sdk.Dec, - minPrice *sdk.Dec, - maxPrice *sdk.Dec, - settlements []*types.SettlementEntry, - allTakerSettlements []*types.SettlementEntry, - blockOrders *cache.BlockOrders, -) ([]*types.SettlementEntry, []*types.SettlementEntry) { - remainingQuantity := marketOrder.Quantity - for entry := orderBookEntries.Next(ctx); entry != nil; entry = orderBookEntries.Next(ctx) { - // If price is zero, it means the order sender - // doesn't want to specify a worst price, so - // we don't need to perform price check for such orders - if !marketOrder.Price.IsZero() { - // Check if worst price can be matched against order book - if (direction == types.PositionDirection_LONG && marketOrder.Price.LT(entry.GetPrice())) || - (direction == types.PositionDirection_SHORT && marketOrder.Price.GT(entry.GetPrice())) { - break - } - } - var executed sdk.Dec - if remainingQuantity.LTE(entry.GetOrderEntry().Quantity) { - executed = remainingQuantity - } else { - executed = entry.GetOrderEntry().Quantity - } - remainingQuantity = remainingQuantity.Sub(executed) - *totalExecuted = totalExecuted.Add(executed) - *totalPrice = totalPrice.Add( - executed.Mul(entry.GetPrice()), - ) - if minPrice.IsNegative() || minPrice.GT(entry.GetPrice()) { - *minPrice = entry.GetPrice() - } - *maxPrice = sdk.MaxDec(*maxPrice, entry.GetPrice()) - - takerSettlements, makerSettlements := Settle( - ctx, - marketOrder, - executed, - orderBookEntries, - marketOrder.Price, - entry.GetPrice(), - ) - // update the status of order in the memState - UpdateOrderData(marketOrder, executed, blockOrders) - settlements = append(settlements, makerSettlements...) - // taker settlements' clearing price will need to be adjusted after all market order executions finish - allTakerSettlements = append(allTakerSettlements, takerSettlements...) - if remainingQuantity.IsZero() { - break - } - } - - orderBookEntries.Flush(ctx) - - return settlements, allTakerSettlements -} - -func MatchFOKMarketOrder( - ctx sdk.Context, - marketOrder *types.Order, - orderBookEntries *types.CachedSortedOrderBookEntries, - direction types.PositionDirection, - totalExecuted *sdk.Dec, - totalPrice *sdk.Dec, - minPrice *sdk.Dec, - maxPrice *sdk.Dec, - settlements []*types.SettlementEntry, - allTakerSettlements []*types.SettlementEntry, - blockOrders *cache.BlockOrders, -) ([]*types.SettlementEntry, []*types.SettlementEntry) { - // check if there is enough liquidity for fill-or-kill market order, if not skip them - remainingQuantity := marketOrder.Quantity - newSettlements, newTakerSettlements := []*types.SettlementEntry{}, []*types.SettlementEntry{} - orders, executedQuantities, entryPrices := []*types.Order{}, []sdk.Dec{}, []sdk.Dec{} - for entry := orderBookEntries.Next(ctx); entry != nil; entry = orderBookEntries.Next(ctx) { - if !marketOrder.Price.IsZero() { - if (direction == types.PositionDirection_LONG && marketOrder.Price.LT(entry.GetPrice())) || - (direction == types.PositionDirection_SHORT && marketOrder.Price.GT(entry.GetPrice())) { - break - } - } - - var executed sdk.Dec - if remainingQuantity.LTE(entry.GetOrderEntry().Quantity) { - executed = remainingQuantity - } else { - executed = entry.GetOrderEntry().Quantity - } - remainingQuantity = remainingQuantity.Sub(executed) - - takerSettlements, makerSettlements := Settle( - ctx, - marketOrder, - executed, - orderBookEntries, - marketOrder.Price, - entry.GetPrice(), - ) - newSettlements = append(newSettlements, makerSettlements...) - newTakerSettlements = append(newTakerSettlements, takerSettlements...) - orders = append(orders, marketOrder) - executedQuantities = append(executedQuantities, executed) - entryPrices = append(entryPrices, entry.GetPrice()) - - if remainingQuantity.IsZero() { - break - } - } - - if remainingQuantity.IsZero() { - orderBookEntries.Flush(ctx) - settlements = append(settlements, newSettlements...) - allTakerSettlements = append(allTakerSettlements, newTakerSettlements...) - for i, order := range orders { - UpdateOrderData(order, executedQuantities[i], blockOrders) - *totalExecuted = totalExecuted.Add(executedQuantities[i]) - *totalPrice = totalPrice.Add( - executedQuantities[i].Mul(entryPrices[i]), - ) - if minPrice.IsNegative() || minPrice.GT(entryPrices[i]) { - *minPrice = entryPrices[i] - } - *maxPrice = sdk.MaxDec(*maxPrice, entryPrices[i]) - } - } else { - orderBookEntries.Refresh(ctx) - } - - return settlements, allTakerSettlements -} - -func MatchByValueFOKMarketOrder( - ctx sdk.Context, - marketOrder *types.Order, - orderBookEntries *types.CachedSortedOrderBookEntries, - direction types.PositionDirection, - totalExecuted *sdk.Dec, - totalPrice *sdk.Dec, - minPrice *sdk.Dec, - maxPrice *sdk.Dec, - settlements []*types.SettlementEntry, - allTakerSettlements []*types.SettlementEntry, - blockOrders *cache.BlockOrders, -) ([]*types.SettlementEntry, []*types.SettlementEntry) { - remainingFund := marketOrder.Nominal - remainingQuantity := marketOrder.Quantity - newSettlements, newTakerSettlements := []*types.SettlementEntry{}, []*types.SettlementEntry{} - orders, executedQuantities, entryPrices := []*types.Order{}, []sdk.Dec{}, []sdk.Dec{} - for entry := orderBookEntries.Next(ctx); entry != nil; entry = orderBookEntries.Next(ctx) { - if !marketOrder.Price.IsZero() { - if (direction == types.PositionDirection_LONG && marketOrder.Price.LT(entry.GetPrice())) || - (direction == types.PositionDirection_SHORT && marketOrder.Price.GT(entry.GetPrice())) { - break - } - } - var executed sdk.Dec - if remainingFund.LTE(entry.GetOrderEntry().Quantity.Mul(entry.GetPrice())) { - executed = remainingFund.Quo(entry.GetPrice()) - remainingFund = sdk.ZeroDec() - } else { - executed = entry.GetOrderEntry().Quantity - remainingFund = remainingFund.Sub(executed.Mul(entry.GetPrice())) - } - remainingQuantity = remainingQuantity.Sub(executed) - - takerSettlements, makerSettlements := Settle( - ctx, - marketOrder, - executed, - orderBookEntries, - marketOrder.Price, - entry.GetPrice(), - ) - newSettlements = append(newSettlements, makerSettlements...) - newTakerSettlements = MergeByNominalTakerSettlements(append(newTakerSettlements, takerSettlements...)) - orders = append(orders, marketOrder) - executedQuantities = append(executedQuantities, executed) - entryPrices = append(entryPrices, entry.GetPrice()) - if remainingFund.IsZero() || remainingQuantity.LTE(sdk.ZeroDec()) { - break - } - } - - // settle orders only when all fund are used - if remainingFund.IsZero() && remainingQuantity.GTE(sdk.ZeroDec()) { - orderBookEntries.Flush(ctx) - settlements = append(settlements, newSettlements...) - allTakerSettlements = append(allTakerSettlements, newTakerSettlements...) - for i, order := range orders { - UpdateOrderData(order, executedQuantities[i], blockOrders) - *totalExecuted = totalExecuted.Add(executedQuantities[i]) - *totalPrice = totalPrice.Add( - executedQuantities[i].Mul(entryPrices[i]), - ) - if minPrice.IsNegative() || minPrice.GT(entryPrices[i]) { - *minPrice = entryPrices[i] - } - *maxPrice = sdk.MaxDec(*maxPrice, entryPrices[i]) - } - } else { - orderBookEntries.Refresh(ctx) - } - - return settlements, allTakerSettlements -} - -func MergeByNominalTakerSettlements(settlements []*types.SettlementEntry) []*types.SettlementEntry { - aggregatedSettlement := types.SettlementEntry{Quantity: sdk.ZeroDec()} - for _, settlement := range settlements { - quantity := settlement.Quantity.Add(aggregatedSettlement.Quantity) - aggregatedSettlement = *settlement - aggregatedSettlement.Quantity = quantity - } - - return []*types.SettlementEntry{&aggregatedSettlement} -} diff --git a/x/dex/exchange/market_order_fuzz_test.go b/x/dex/exchange/market_order_fuzz_test.go deleted file mode 100644 index 2cc64f446..000000000 --- a/x/dex/exchange/market_order_fuzz_test.go +++ /dev/null @@ -1,92 +0,0 @@ -package exchange_test - -import ( - "sort" - "testing" - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/testutil/fuzzing" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex/exchange" - keeperutil "github.com/sei-protocol/sei-chain/x/dex/keeper/utils" - "github.com/sei-protocol/sei-chain/x/dex/types" - dexutils "github.com/sei-protocol/sei-chain/x/dex/utils" - "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/libs/log" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" -) - -var TestFuzzMarketCtx = sdk.NewContext(nil, tmproto.Header{}, false, log.NewNopLogger()) - -func FuzzMatchMarketOrders(f *testing.F) { - f.Fuzz(fuzzTargetMatchMarketOrders) -} - -func fuzzTargetMatchMarketOrders( - t *testing.T, - takerLong bool, - orderSorted bool, - orderbookSorted bool, - prices []byte, - quantities []byte, - entryWeights []byte, - accountIndices []byte, - allocationWeights []byte, -) { - dexkeeper, TestFuzzMarketCtx := keepertest.DexKeeper(t) - TestFuzzMarketCtx = TestFuzzMarketCtx.WithBlockHeight(1).WithBlockTime(time.Now()) - blockOrders := dexutils.GetMemState(TestFuzzMarketCtx.Context()).GetBlockOrders(TestFuzzMarketCtx, "testAccount", types.Pair{PriceDenom: "USDC", AssetDenom: "ATOM"}) - entries := fuzzing.GetOrderBookEntries(!takerLong, keepertest.TestPriceDenom, keepertest.TestAssetDenom, entryWeights, accountIndices, allocationWeights) - for _, entry := range entries { - if takerLong { - dexkeeper.SetShortOrderBookEntry(TestFuzzMarketCtx, keepertest.TestContract, entry) - } else { - dexkeeper.SetLongOrderBookEntry(TestFuzzMarketCtx, keepertest.TestContract, entry) - } - } - var direction types.PositionDirection - if takerLong { - direction = types.PositionDirection_LONG - } else { - direction = types.PositionDirection_SHORT - } - orders := fuzzing.GetPlacedOrders(direction, types.OrderType_MARKET, keepertest.TestPair, prices, quantities) - for _, order := range orders { - blockOrders.Add(order) - } - - if orderSorted { - sort.Slice(orders, func(i, j int) bool { - // a price of 0 indicates that there is no worst price for the order, so it should - // always be ranked at the top. - if orders[i].Price.IsZero() { - return true - } else if orders[j].Price.IsZero() { - return false - } - switch direction { - case types.PositionDirection_LONG: - return orders[i].Price.GT(orders[j].Price) - case types.PositionDirection_SHORT: - return orders[i].Price.LT(orders[j].Price) - default: - panic("Unknown direction") - } - }) - } - if orderbookSorted { - sort.Slice(entries, func(i, j int) bool { - return entries[i].GetPrice().LT(entries[j].GetPrice()) - }) - } - - require.NotPanics(t, func() { - orderbook := keeperutil.PopulateOrderbook(TestFuzzMarketCtx, dexkeeper, types.ContractAddress(keepertest.TestContract), types.Pair{PriceDenom: keepertest.TestPriceDenom, AssetDenom: keepertest.TestAssetDenom}) - book := orderbook.Longs - if takerLong { - book = orderbook.Shorts - } - exchange.MatchMarketOrders(TestFuzzMarketCtx, orders, book, direction, blockOrders) - }) -} diff --git a/x/dex/exchange/market_order_test.go b/x/dex/exchange/market_order_test.go deleted file mode 100644 index 86339654b..000000000 --- a/x/dex/exchange/market_order_test.go +++ /dev/null @@ -1,1175 +0,0 @@ -package exchange_test - -import ( - "testing" - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" - dex "github.com/sei-protocol/sei-chain/x/dex/cache" - "github.com/sei-protocol/sei-chain/x/dex/exchange" - keeperutil "github.com/sei-protocol/sei-chain/x/dex/keeper/utils" - "github.com/sei-protocol/sei-chain/x/dex/types" - dexutils "github.com/sei-protocol/sei-chain/x/dex/utils" - "github.com/stretchr/testify/assert" - - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" -) - -const ( - TestTimestamp uint64 = 10000 - TestHeight uint64 = 1 -) - -func TestMatchFoKMarketOrderFromShortBookNotEnoughLiquidity(t *testing.T) { - dexkeeper, ctx := keepertest.DexKeeper(t) - ctx = ctx.WithBlockHeight(int64(TestHeight)).WithBlockTime(time.Unix(int64(TestTimestamp), 0)) - longOrders := []*types.Order{ - { - Id: 1, - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(5), - Account: "abc", - PositionDirection: types.PositionDirection_LONG, - ContractAddr: "test", - PriceDenom: "USDC", - AssetDenom: "ATOM", - OrderType: types.OrderType_FOKMARKET, - }, - } - shortBook := []types.OrderBookEntry{ - &types.ShortBook{ - Price: sdk.NewDec(100), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(4), - Allocations: []*types.Allocation{{ - OrderId: 5, - Account: "def", - Quantity: sdk.NewDec(4), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - } - blockOrders := dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, "testAccount", types.Pair{PriceDenom: "USDC", AssetDenom: "ATOM"}) - blockOrders.Add(&types.Order{ - Id: 1, - Account: "abc", - ContractAddr: "test", - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(5), - PriceDenom: "USDC", - AssetDenom: "ATOM", - OrderType: types.OrderType_FOKMARKET, - PositionDirection: types.PositionDirection_LONG, - Data: "{\"position_effect\":\"Open\",\"leverage\":\"1\"}", - }) - - for _, e := range shortBook { - dexkeeper.SetShortOrderBookEntry(ctx, "test", e) - } - orderbook := keeperutil.PopulateOrderbook(ctx, dexkeeper, types.ContractAddress("test"), types.Pair{PriceDenom: "USDC", AssetDenom: "ATOM"}) - entries := orderbook.Shorts - outcome := exchange.MatchMarketOrders( - ctx, longOrders, entries, types.PositionDirection_LONG, blockOrders, - ) - totalPrice := outcome.TotalNotional - totalExecuted := outcome.TotalQuantity - settlements := outcome.Settlements - - shortBook = dexkeeper.GetAllShortBookForPair(ctx, "test", "USDC", "ATOM") - assert.Equal(t, totalPrice, sdk.ZeroDec()) - assert.Equal(t, totalExecuted, sdk.ZeroDec()) - assert.Equal(t, len(shortBook), 1) - assert.Equal(t, shortBook[0].GetPrice(), sdk.NewDec(100)) - assert.Equal(t, shortBook[0].GetOrderEntry().Quantity, sdk.NewDec(4)) - assert.Equal(t, len(settlements), 0) - assert.Equal(t, blockOrders.Get()[0].Quantity, sdk.NewDec(5)) - assert.Equal(t, blockOrders.Get()[0].Status, types.OrderStatus_PLACED) -} - -func TestMatchFoKMarketOrderFromShortBookHappyPath(t *testing.T) { - dexkeeper, ctx := keepertest.DexKeeper(t) - ctx = ctx.WithBlockHeight(int64(TestHeight)).WithBlockTime(time.Unix(int64(TestTimestamp), 0)) - longOrders := []*types.Order{ - { - Id: 1, - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(5), - Account: "abc", - PositionDirection: types.PositionDirection_LONG, - ContractAddr: "test", - PriceDenom: "USDC", - AssetDenom: "ATOM", - OrderType: types.OrderType_FOKMARKET, - }, - } - shortBook := []types.OrderBookEntry{ - &types.ShortBook{ - Price: sdk.NewDec(100), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(5), - Allocations: []*types.Allocation{{ - OrderId: 5, - Account: "def", - Quantity: sdk.NewDec(5), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - } - for _, e := range shortBook { - dexkeeper.SetShortOrderBookEntry(ctx, "test", e) - } - orderbook := keeperutil.PopulateOrderbook(ctx, dexkeeper, types.ContractAddress("test"), types.Pair{PriceDenom: "USDC", AssetDenom: "ATOM"}) - entries := orderbook.Shorts - blockOrders := dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, "testAccount", types.Pair{PriceDenom: "USDC", AssetDenom: "ATOM"}) - blockOrders.Add(&types.Order{ - Id: 1, - Account: "abc", - ContractAddr: "test", - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(5), - PriceDenom: "USDC", - AssetDenom: "ATOM", - OrderType: types.OrderType_FOKMARKET, - PositionDirection: types.PositionDirection_LONG, - Data: "{\"position_effect\":\"Open\",\"leverage\":\"1\"}", - }) - outcome := exchange.MatchMarketOrders( - ctx, longOrders, entries, types.PositionDirection_LONG, blockOrders, - ) - totalPrice := outcome.TotalNotional - totalExecuted := outcome.TotalQuantity - settlements := outcome.Settlements - - shortBook = dexkeeper.GetAllShortBookForPair(ctx, "test", "USDC", "ATOM") - assert.Equal(t, totalPrice, sdk.NewDec(500)) - assert.Equal(t, totalExecuted, sdk.NewDec(5)) - assert.Equal(t, len(shortBook), 0) - assert.Equal(t, len(settlements), 2) - assert.Equal(t, *settlements[0], types.SettlementEntry{ - PositionDirection: "Short", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(5), - ExecutionCostOrProceed: sdk.NewDec(100), - ExpectedCostOrProceed: sdk.NewDec(100), - Account: "def", - OrderType: "Limit", - OrderId: 5, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, *settlements[1], types.SettlementEntry{ - PositionDirection: "Long", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(5), - ExecutionCostOrProceed: sdk.NewDec(100), - ExpectedCostOrProceed: sdk.NewDec(100), - Account: "abc", - OrderType: "Fokmarket", - OrderId: 1, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, blockOrders.Get()[0].Quantity, sdk.ZeroDec()) - assert.Equal(t, blockOrders.Get()[0].Status, types.OrderStatus_FULFILLED) -} - -func TestMatchByValueFOKMarketOrderFromShortBookNotEnoughLiquidity(t *testing.T) { - dexkeeper, ctx := keepertest.DexKeeper(t) - ctx = ctx.WithBlockHeight(int64(TestHeight)).WithBlockTime(time.Unix(int64(TestTimestamp), 0)) - longOrders := []*types.Order{ - { - Id: 1, - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(5), - Account: "abc", - PositionDirection: types.PositionDirection_LONG, - ContractAddr: "test", - PriceDenom: "USDC", - AssetDenom: "ATOM", - OrderType: types.OrderType_FOKMARKETBYVALUE, - Nominal: sdk.NewDec(500), - }, - } - shortBook := []types.OrderBookEntry{ - &types.ShortBook{ - Price: sdk.NewDec(90), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(90), - Quantity: sdk.NewDec(5), - Allocations: []*types.Allocation{{ - OrderId: 4, - Account: "def", - Quantity: sdk.NewDec(5), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - &types.ShortBook{ - Price: sdk.NewDec(100), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(100), - Quantity: sdk.MustNewDecFromStr("0.4"), - Allocations: []*types.Allocation{{ - OrderId: 5, - Account: "def", - Quantity: sdk.MustNewDecFromStr("0.4"), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - } - blockOrders := dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, "testAccount", types.Pair{PriceDenom: "USDC", AssetDenom: "ATOM"}) - blockOrders.Add(longOrders[0]) - for _, e := range shortBook { - dexkeeper.SetShortOrderBookEntry(ctx, "test", e) - } - orderbook := keeperutil.PopulateOrderbook(ctx, dexkeeper, types.ContractAddress("test"), types.Pair{PriceDenom: "USDC", AssetDenom: "ATOM"}) - entries := orderbook.Shorts - outcome := exchange.MatchMarketOrders( - ctx, longOrders, entries, types.PositionDirection_LONG, &dex.BlockOrders{}, - ) - totalPrice := outcome.TotalNotional - totalExecuted := outcome.TotalQuantity - settlements := outcome.Settlements - shortBook = dexkeeper.GetAllShortBookForPair(ctx, "test", "USDC", "ATOM") - assert.Equal(t, totalPrice, sdk.ZeroDec()) - assert.Equal(t, totalExecuted, sdk.ZeroDec()) - assert.Equal(t, len(shortBook), 2) - assert.Equal(t, shortBook[0].GetPrice(), sdk.NewDec(90)) - assert.Equal(t, shortBook[0].GetOrderEntry().Price, sdk.NewDec(90)) - assert.Equal(t, shortBook[0].GetOrderEntry().Quantity, sdk.NewDec(5)) - assert.Equal(t, len(settlements), 0) - assert.Equal(t, blockOrders.Get()[0].Quantity, sdk.NewDec(5)) - assert.Equal(t, blockOrders.Get()[0].Status, types.OrderStatus_PLACED) -} - -func TestMatchByValueFOKMarketOrderFromShortBookHappyPath(t *testing.T) { - dexkeeper, ctx := keepertest.DexKeeper(t) - ctx = ctx.WithBlockHeight(int64(TestHeight)).WithBlockTime(time.Unix(int64(TestTimestamp), 0)) - longOrders := []*types.Order{ - { - Id: 1, - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(6), - Account: "abc", - PositionDirection: types.PositionDirection_LONG, - ContractAddr: "test", - PriceDenom: "USDC", - AssetDenom: "ATOM", - OrderType: types.OrderType_FOKMARKETBYVALUE, - Nominal: sdk.NewDec(500), - }, - } - shortBook := []types.OrderBookEntry{ - &types.ShortBook{ - Price: sdk.NewDec(90), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(90), - Quantity: sdk.NewDec(5), - Allocations: []*types.Allocation{{ - OrderId: 4, - Account: "def", - Quantity: sdk.NewDec(5), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - &types.ShortBook{ - Price: sdk.NewDec(100), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(100), - Quantity: sdk.MustNewDecFromStr("0.6"), - Allocations: []*types.Allocation{{ - OrderId: 5, - Account: "def", - Quantity: sdk.MustNewDecFromStr("0.6"), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - } - blockOrders := dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, "testAccount", types.Pair{PriceDenom: "USDC", AssetDenom: "ATOM"}) - blockOrders.Add(longOrders[0]) - for _, e := range shortBook { - dexkeeper.SetShortOrderBookEntry(ctx, "test", e) - } - orderbook := keeperutil.PopulateOrderbook(ctx, dexkeeper, types.ContractAddress("test"), types.Pair{PriceDenom: "USDC", AssetDenom: "ATOM"}) - entries := orderbook.Shorts - outcome := exchange.MatchMarketOrders( - ctx, longOrders, entries, types.PositionDirection_LONG, blockOrders, - ) - totalPrice := outcome.TotalNotional - totalExecuted := outcome.TotalQuantity - settlements := outcome.Settlements - shortBook = dexkeeper.GetAllShortBookForPair(ctx, "test", "USDC", "ATOM") - assert.Equal(t, totalPrice, sdk.NewDec(500)) - assert.Equal(t, totalExecuted, sdk.MustNewDecFromStr("5.5")) - assert.Equal(t, len(shortBook), 1) - assert.Equal(t, len(settlements), 3) - assert.Equal(t, *settlements[0], types.SettlementEntry{ - PositionDirection: "Short", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(5), - ExecutionCostOrProceed: sdk.NewDec(90), - ExpectedCostOrProceed: sdk.NewDec(90), - Account: "def", - OrderType: "Limit", - OrderId: 4, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, *settlements[1], types.SettlementEntry{ - PositionDirection: "Short", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.MustNewDecFromStr("0.5"), - ExecutionCostOrProceed: sdk.NewDec(100), - ExpectedCostOrProceed: sdk.NewDec(100), - Account: "def", - OrderType: "Limit", - OrderId: 5, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, blockOrders.Get()[0].Quantity, sdk.MustNewDecFromStr("0.5")) - assert.Equal(t, blockOrders.Get()[0].Status, types.OrderStatus_FULFILLED) -} - -func TestMatchSingleMarketOrderFromShortBook(t *testing.T) { - dexkeeper, ctx := keepertest.DexKeeper(t) - ctx = ctx.WithBlockHeight(int64(TestHeight)).WithBlockTime(time.Unix(int64(TestTimestamp), 0)) - longOrders := []*types.Order{ - { - Id: 1, - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(5), - Account: "abc", - PositionDirection: types.PositionDirection_LONG, - ContractAddr: "test", - PriceDenom: "USDC", - AssetDenom: "ATOM", - OrderType: types.OrderType_MARKET, - }, - } - shortBook := []types.OrderBookEntry{ - &types.ShortBook{ - Price: sdk.NewDec(100), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(5), - Allocations: []*types.Allocation{{ - OrderId: 5, - Account: "def", - Quantity: sdk.NewDec(5), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - } - blockOrders := dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, "testAccount", types.Pair{PriceDenom: "USDC", AssetDenom: "ATOM"}) - blockOrders.Add(longOrders[0]) - for _, e := range shortBook { - dexkeeper.SetShortOrderBookEntry(ctx, "test", e) - } - orderbook := keeperutil.PopulateOrderbook(ctx, dexkeeper, types.ContractAddress("test"), types.Pair{PriceDenom: "USDC", AssetDenom: "ATOM"}) - entries := orderbook.Shorts - outcome := exchange.MatchMarketOrders( - ctx, longOrders, entries, types.PositionDirection_LONG, blockOrders, - ) - totalPrice := outcome.TotalNotional - totalExecuted := outcome.TotalQuantity - settlements := outcome.Settlements - shortBook = dexkeeper.GetAllShortBookForPair(ctx, "test", "USDC", "ATOM") - assert.Equal(t, totalPrice, sdk.NewDec(500)) - assert.Equal(t, totalExecuted, sdk.NewDec(5)) - assert.Equal(t, len(shortBook), 0) - assert.Equal(t, len(settlements), 2) - assert.Equal(t, *settlements[0], types.SettlementEntry{ - PositionDirection: "Short", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(5), - ExecutionCostOrProceed: sdk.NewDec(100), - ExpectedCostOrProceed: sdk.NewDec(100), - Account: "def", - OrderType: "Limit", - OrderId: 5, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, *settlements[1], types.SettlementEntry{ - PositionDirection: "Long", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(5), - ExecutionCostOrProceed: sdk.NewDec(100), - ExpectedCostOrProceed: sdk.NewDec(100), - Account: "abc", - OrderType: "Market", - OrderId: 1, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, blockOrders.Get()[0].Quantity, sdk.ZeroDec()) - assert.Equal(t, blockOrders.Get()[0].Status, types.OrderStatus_FULFILLED) -} - -func TestMatchSingleMarketOrderFromLongBook(t *testing.T) { - dexkeeper, ctx := keepertest.DexKeeper(t) - ctx = ctx.WithBlockHeight(int64(TestHeight)).WithBlockTime(time.Unix(int64(TestTimestamp), 0)) - shortOrders := []*types.Order{ - { - Id: 1, - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(5), - Account: "abc", - PositionDirection: types.PositionDirection_SHORT, - ContractAddr: "test", - PriceDenom: "USDC", - AssetDenom: "ATOM", - OrderType: types.OrderType_MARKET, - }, - } - longBook := []types.OrderBookEntry{ - &types.LongBook{ - Price: sdk.NewDec(100), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(5), - Allocations: []*types.Allocation{{ - OrderId: 5, - Account: "def", - Quantity: sdk.NewDec(5), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - } - blockOrders := dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, "testAccount", types.Pair{PriceDenom: "USDC", AssetDenom: "ATOM"}) - blockOrders.Add(shortOrders[0]) - for _, e := range longBook { - dexkeeper.SetLongOrderBookEntry(ctx, "test", e) - } - orderbook := keeperutil.PopulateOrderbook(ctx, dexkeeper, types.ContractAddress("test"), types.Pair{PriceDenom: "USDC", AssetDenom: "ATOM"}) - entries := orderbook.Longs - outcome := exchange.MatchMarketOrders( - ctx, shortOrders, entries, types.PositionDirection_SHORT, blockOrders, - ) - totalPrice := outcome.TotalNotional - totalExecuted := outcome.TotalQuantity - settlements := outcome.Settlements - longBook = dexkeeper.GetAllLongBookForPair(ctx, "test", "USDC", "ATOM") - assert.Equal(t, totalPrice, sdk.NewDec(500)) - assert.Equal(t, totalExecuted, sdk.NewDec(5)) - assert.Equal(t, len(longBook), 0) - assert.Equal(t, len(settlements), 2) - assert.Equal(t, *settlements[0], types.SettlementEntry{ - PositionDirection: "Long", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(5), - ExecutionCostOrProceed: sdk.NewDec(100), - ExpectedCostOrProceed: sdk.NewDec(100), - Account: "def", - OrderType: "Limit", - OrderId: 5, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, *settlements[1], types.SettlementEntry{ - PositionDirection: "Short", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(5), - ExecutionCostOrProceed: sdk.NewDec(100), - ExpectedCostOrProceed: sdk.NewDec(100), - Account: "abc", - OrderType: "Market", - OrderId: 1, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, blockOrders.Get()[0].Quantity, sdk.ZeroDec()) - assert.Equal(t, blockOrders.Get()[0].Status, types.OrderStatus_FULFILLED) -} - -func TestMatchSingleMarketOrderFromMultipleShortBook(t *testing.T) { - dexkeeper, ctx := keepertest.DexKeeper(t) - ctx = ctx.WithBlockHeight(int64(TestHeight)).WithBlockTime(time.Unix(int64(TestTimestamp), 0)) - longOrders := []*types.Order{ - { - Id: 1, - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(5), - Account: "abc", - PositionDirection: types.PositionDirection_LONG, - ContractAddr: "test", - PriceDenom: "USDC", - AssetDenom: "ATOM", - OrderType: types.OrderType_MARKET, - }, - } - shortBook := []types.OrderBookEntry{ - &types.ShortBook{ - Price: sdk.NewDec(90), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(90), - Quantity: sdk.NewDec(2), - Allocations: []*types.Allocation{{ - OrderId: 5, - Account: "def", - Quantity: sdk.NewDec(2), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - &types.ShortBook{ - Price: sdk.NewDec(100), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(6), - Allocations: []*types.Allocation{{ - OrderId: 6, - Account: "def", - Quantity: sdk.NewDec(4), - }, { - OrderId: 7, - Account: "ghi", - Quantity: sdk.NewDec(2), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - } - blockOrders := dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, "testAccount", types.Pair{PriceDenom: "USDC", AssetDenom: "ATOM"}) - blockOrders.Add(longOrders[0]) - for _, e := range shortBook { - dexkeeper.SetShortOrderBookEntry(ctx, "test", e) - } - orderbook := keeperutil.PopulateOrderbook(ctx, dexkeeper, types.ContractAddress("test"), types.Pair{PriceDenom: "USDC", AssetDenom: "ATOM"}) - entries := orderbook.Shorts - outcome := exchange.MatchMarketOrders( - ctx, longOrders, entries, types.PositionDirection_LONG, blockOrders, - ) - totalPrice := outcome.TotalNotional - totalExecuted := outcome.TotalQuantity - settlements := outcome.Settlements - shortBook = dexkeeper.GetAllShortBookForPair(ctx, "test", "USDC", "ATOM") - assert.Equal(t, totalPrice, sdk.NewDec(480)) - assert.Equal(t, totalExecuted, sdk.NewDec(5)) - assert.Equal(t, len(shortBook), 1) - assert.Equal(t, shortBook[0].GetPrice(), sdk.NewDec(100)) - assert.Equal(t, *shortBook[0].GetOrderEntry(), types.OrderEntry{ - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(3), - Allocations: []*types.Allocation{{ - OrderId: 6, - Account: "def", - Quantity: sdk.NewDec(1), - }, { - OrderId: 7, - Account: "ghi", - Quantity: sdk.NewDec(2), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }) - assert.Equal(t, len(settlements), 4) - assert.Equal(t, *settlements[0], types.SettlementEntry{ - PositionDirection: "Short", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(2), - ExecutionCostOrProceed: sdk.NewDec(90), - ExpectedCostOrProceed: sdk.NewDec(90), - Account: "def", - OrderType: "Limit", - OrderId: 5, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, *settlements[1], types.SettlementEntry{ - PositionDirection: "Short", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(3), - ExecutionCostOrProceed: sdk.NewDec(100), - ExpectedCostOrProceed: sdk.NewDec(100), - Account: "def", - OrderType: "Limit", - OrderId: 6, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, *settlements[2], types.SettlementEntry{ - PositionDirection: "Long", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(2), - ExecutionCostOrProceed: sdk.NewDec(96), - ExpectedCostOrProceed: sdk.NewDec(100), - Account: "abc", - OrderType: "Market", - OrderId: 1, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, *settlements[3], types.SettlementEntry{ - PositionDirection: "Long", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(3), - ExecutionCostOrProceed: sdk.NewDec(96), - ExpectedCostOrProceed: sdk.NewDec(100), - Account: "abc", - OrderType: "Market", - OrderId: 1, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, blockOrders.Get()[0].Quantity, sdk.ZeroDec()) - assert.Equal(t, blockOrders.Get()[0].Status, types.OrderStatus_FULFILLED) -} - -func TestMatchSingleMarketOrderFromMultipleLongBook(t *testing.T) { - dexkeeper, ctx := keepertest.DexKeeper(t) - ctx = ctx.WithBlockHeight(int64(TestHeight)).WithBlockTime(time.Unix(int64(TestTimestamp), 0)) - shortOrders := []*types.Order{ - { - Id: 1, - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(5), - Account: "def", - PositionDirection: types.PositionDirection_SHORT, - ContractAddr: "test", - PriceDenom: "USDC", - AssetDenom: "ATOM", - OrderType: types.OrderType_MARKET, - }, - } - longBook := []types.OrderBookEntry{ - &types.LongBook{ - Price: sdk.NewDec(100), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(6), - Allocations: []*types.Allocation{{ - OrderId: 6, - Account: "abc", - Quantity: sdk.NewDec(4), - }, { - OrderId: 7, - Account: "ghi", - Quantity: sdk.NewDec(2), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - &types.LongBook{ - Price: sdk.NewDec(110), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(110), - Quantity: sdk.NewDec(2), - Allocations: []*types.Allocation{{ - OrderId: 5, - Account: "abc", - Quantity: sdk.NewDec(2), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - } - blockOrders := dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, "testAccount", types.Pair{PriceDenom: "USDC", AssetDenom: "ATOM"}) - blockOrders.Add(shortOrders[0]) - for _, e := range longBook { - dexkeeper.SetLongOrderBookEntry(ctx, "test", e) - } - orderbook := keeperutil.PopulateOrderbook(ctx, dexkeeper, types.ContractAddress("test"), types.Pair{PriceDenom: "USDC", AssetDenom: "ATOM"}) - entries := orderbook.Longs - outcome := exchange.MatchMarketOrders( - ctx, shortOrders, entries, types.PositionDirection_SHORT, blockOrders, - ) - totalPrice := outcome.TotalNotional - totalExecuted := outcome.TotalQuantity - settlements := outcome.Settlements - longBook = dexkeeper.GetAllLongBookForPair(ctx, "test", "USDC", "ATOM") - assert.Equal(t, totalPrice, sdk.NewDec(520)) - assert.Equal(t, totalExecuted, sdk.NewDec(5)) - assert.Equal(t, len(longBook), 1) - assert.Equal(t, longBook[0].GetPrice(), sdk.NewDec(100)) - assert.Equal(t, *longBook[0].GetOrderEntry(), types.OrderEntry{ - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(3), - Allocations: []*types.Allocation{{ - OrderId: 6, - Account: "abc", - Quantity: sdk.NewDec(1), - }, { - OrderId: 7, - Account: "ghi", - Quantity: sdk.NewDec(2), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }) - assert.Equal(t, len(settlements), 4) - assert.Equal(t, *settlements[0], types.SettlementEntry{ - PositionDirection: "Long", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(2), - ExecutionCostOrProceed: sdk.NewDec(110), - ExpectedCostOrProceed: sdk.NewDec(110), - Account: "abc", - OrderType: "Limit", - OrderId: 5, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, *settlements[1], types.SettlementEntry{ - PositionDirection: "Long", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(3), - ExecutionCostOrProceed: sdk.NewDec(100), - ExpectedCostOrProceed: sdk.NewDec(100), - Account: "abc", - OrderType: "Limit", - OrderId: 6, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, *settlements[2], types.SettlementEntry{ - PositionDirection: "Short", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(2), - ExecutionCostOrProceed: sdk.NewDec(104), - ExpectedCostOrProceed: sdk.NewDec(100), - Account: "def", - OrderType: "Market", - OrderId: 1, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, *settlements[3], types.SettlementEntry{ - PositionDirection: "Short", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(3), - ExecutionCostOrProceed: sdk.NewDec(104), - ExpectedCostOrProceed: sdk.NewDec(100), - Account: "def", - OrderType: "Market", - OrderId: 1, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, blockOrders.Get()[0].Quantity, sdk.ZeroDec()) - assert.Equal(t, blockOrders.Get()[0].Status, types.OrderStatus_FULFILLED) -} - -func TestMatchMultipleMarketOrderFromMultipleShortBook(t *testing.T) { - dexkeeper, ctx := keepertest.DexKeeper(t) - ctx = ctx.WithBlockHeight(int64(TestHeight)).WithBlockTime(time.Unix(int64(TestTimestamp), 0)) - longOrders := []*types.Order{ - { - Id: 1, - Price: sdk.NewDec(104), - Quantity: sdk.NewDec(1), - Account: "jkl", - PositionDirection: types.PositionDirection_LONG, - ContractAddr: "test", - PriceDenom: "USDC", - AssetDenom: "ATOM", - OrderType: types.OrderType_MARKET, - }, - { - Id: 2, - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(5), - Account: "abc", - PositionDirection: types.PositionDirection_LONG, - ContractAddr: "test", - PriceDenom: "USDC", - AssetDenom: "ATOM", - OrderType: types.OrderType_MARKET, - }, - { - Id: 3, - Price: sdk.NewDec(98), - Quantity: sdk.NewDec(2), - Account: "mno", - PositionDirection: types.PositionDirection_LONG, - ContractAddr: "test", - PriceDenom: "USDC", - AssetDenom: "ATOM", - OrderType: types.OrderType_MARKET, - }, - } - shortBook := []types.OrderBookEntry{ - &types.ShortBook{ - Price: sdk.NewDec(90), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(90), - Quantity: sdk.NewDec(2), - Allocations: []*types.Allocation{{ - OrderId: 4, - Account: "def", - Quantity: sdk.NewDec(2), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - &types.ShortBook{ - Price: sdk.NewDec(100), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(6), - Allocations: []*types.Allocation{{ - OrderId: 5, - Account: "def", - Quantity: sdk.NewDec(4), - }, { - OrderId: 6, - Account: "ghi", - Quantity: sdk.NewDec(2), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - } - blockOrders := dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, "testAccount", types.Pair{PriceDenom: "USDC", AssetDenom: "ATOM"}) - blockOrders.Add(longOrders[0]) - blockOrders.Add(longOrders[1]) - blockOrders.Add(longOrders[2]) - for _, e := range shortBook { - dexkeeper.SetShortOrderBookEntry(ctx, "test", e) - } - orderbook := keeperutil.PopulateOrderbook(ctx, dexkeeper, types.ContractAddress("test"), types.Pair{PriceDenom: "USDC", AssetDenom: "ATOM"}) - entries := orderbook.Shorts - outcome := exchange.MatchMarketOrders( - ctx, longOrders, entries, types.PositionDirection_LONG, blockOrders, - ) - totalPrice := outcome.TotalNotional - totalExecuted := outcome.TotalQuantity - settlements := outcome.Settlements - - shortBook = dexkeeper.GetAllShortBookForPair(ctx, "test", "USDC", "ATOM") - assert.Equal(t, totalPrice, sdk.NewDec(580)) - assert.Equal(t, totalExecuted, sdk.NewDec(6)) - assert.Equal(t, len(shortBook), 1) - assert.Equal(t, shortBook[0].GetPrice(), sdk.NewDec(100)) - assert.Equal(t, *shortBook[0].GetOrderEntry(), types.OrderEntry{ - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(2), - Allocations: []*types.Allocation{{ - OrderId: 6, - Account: "ghi", - Quantity: sdk.NewDec(2), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }) - assert.Equal(t, len(settlements), 6) - assert.Equal(t, *settlements[0], types.SettlementEntry{ - PositionDirection: "Short", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(1), - ExecutionCostOrProceed: sdk.NewDec(90), - ExpectedCostOrProceed: sdk.NewDec(90), - Account: "def", - OrderType: "Limit", - OrderId: 4, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, *settlements[1], types.SettlementEntry{ - PositionDirection: "Short", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(1), - ExecutionCostOrProceed: sdk.NewDec(90), - ExpectedCostOrProceed: sdk.NewDec(90), - Account: "def", - OrderType: "Limit", - OrderId: 4, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, *settlements[2], types.SettlementEntry{ - PositionDirection: "Short", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(4), - ExecutionCostOrProceed: sdk.NewDec(100), - ExpectedCostOrProceed: sdk.NewDec(100), - Account: "def", - OrderType: "Limit", - OrderId: 5, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, *settlements[3], types.SettlementEntry{ - PositionDirection: "Long", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(1), - ExecutionCostOrProceed: sdk.MustNewDecFromStr("96.666666666666666667"), - ExpectedCostOrProceed: sdk.NewDec(104), - Account: "jkl", - OrderType: "Market", - OrderId: 1, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, *settlements[4], types.SettlementEntry{ - PositionDirection: "Long", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(1), - ExecutionCostOrProceed: sdk.MustNewDecFromStr("96.666666666666666667"), - ExpectedCostOrProceed: sdk.NewDec(100), - Account: "abc", - OrderType: "Market", - OrderId: 2, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, *settlements[5], types.SettlementEntry{ - PositionDirection: "Long", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(4), - ExecutionCostOrProceed: sdk.MustNewDecFromStr("96.666666666666666667"), - ExpectedCostOrProceed: sdk.NewDec(100), - Account: "abc", - OrderType: "Market", - OrderId: 2, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, blockOrders.Get()[0].Quantity, sdk.ZeroDec()) - assert.Equal(t, blockOrders.Get()[0].Status, types.OrderStatus_FULFILLED) - assert.Equal(t, blockOrders.Get()[1].Quantity, sdk.ZeroDec()) - assert.Equal(t, blockOrders.Get()[1].Status, types.OrderStatus_FULFILLED) - assert.Equal(t, blockOrders.Get()[2].Quantity, sdk.NewDec(2)) - assert.Equal(t, blockOrders.Get()[2].Status, types.OrderStatus_PLACED) -} - -func TestMatchMultipleMarketOrderFromMultipleLongBook(t *testing.T) { - dexkeeper, ctx := keepertest.DexKeeper(t) - ctx = ctx.WithBlockHeight(int64(TestHeight)).WithBlockTime(time.Unix(int64(TestTimestamp), 0)) - shortOrders := []*types.Order{ - { - Id: 1, - Price: sdk.NewDec(96), - Quantity: sdk.NewDec(1), - Account: "jkl", - PositionDirection: types.PositionDirection_SHORT, - ContractAddr: "test", - PriceDenom: "USDC", - AssetDenom: "ATOM", - OrderType: types.OrderType_MARKET, - }, - { - Id: 2, - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(5), - Account: "abc", - PositionDirection: types.PositionDirection_SHORT, - ContractAddr: "test", - PriceDenom: "USDC", - AssetDenom: "ATOM", - OrderType: types.OrderType_MARKET, - }, - { - Id: 3, - Price: sdk.NewDec(102), - Quantity: sdk.NewDec(2), - Account: "mno", - PositionDirection: types.PositionDirection_SHORT, - ContractAddr: "test", - PriceDenom: "USDC", - AssetDenom: "ATOM", - OrderType: types.OrderType_MARKET, - }, - } - longBook := []types.OrderBookEntry{ - &types.LongBook{ - Price: sdk.NewDec(100), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(6), - Allocations: []*types.Allocation{{ - OrderId: 5, - Account: "abc", - Quantity: sdk.NewDec(4), - }, { - OrderId: 6, - Account: "ghi", - Quantity: sdk.NewDec(2), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - &types.LongBook{ - Price: sdk.NewDec(110), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(110), - Quantity: sdk.NewDec(2), - Allocations: []*types.Allocation{{ - OrderId: 4, - Account: "abc", - Quantity: sdk.NewDec(2), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - } - blockOrders := dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, "testAccount", types.Pair{PriceDenom: "USDC", AssetDenom: "ATOM"}) - blockOrders.Add(shortOrders[0]) - blockOrders.Add(shortOrders[1]) - blockOrders.Add(shortOrders[2]) - for _, e := range longBook { - dexkeeper.SetLongOrderBookEntry(ctx, "test", e) - } - orderbook := keeperutil.PopulateOrderbook(ctx, dexkeeper, types.ContractAddress("test"), types.Pair{PriceDenom: "USDC", AssetDenom: "ATOM"}) - entries := orderbook.Longs - outcome := exchange.MatchMarketOrders( - ctx, shortOrders, entries, types.PositionDirection_SHORT, blockOrders, - ) - totalPrice := outcome.TotalNotional - totalExecuted := outcome.TotalQuantity - settlements := outcome.Settlements - minPrice := outcome.MinPrice - maxPrice := outcome.MaxPrice - - longBook = dexkeeper.GetAllLongBookForPair(ctx, "test", "USDC", "ATOM") - assert.Equal(t, totalPrice, sdk.NewDec(620)) - assert.Equal(t, totalExecuted, sdk.NewDec(6)) - assert.Equal(t, minPrice, sdk.MustNewDecFromStr("103.333333333333333333")) - assert.Equal(t, maxPrice, sdk.MustNewDecFromStr("103.333333333333333333")) - assert.Equal(t, len(longBook), 1) - assert.Equal(t, longBook[0].GetPrice(), sdk.NewDec(100)) - assert.Equal(t, *longBook[0].GetOrderEntry(), types.OrderEntry{ - Price: sdk.NewDec(100), - Quantity: sdk.NewDec(2), - Allocations: []*types.Allocation{{ - OrderId: 6, - Account: "ghi", - Quantity: sdk.NewDec(2), - }}, - PriceDenom: "USDC", - AssetDenom: "ATOM", - }) - assert.Equal(t, len(settlements), 6) - assert.Equal(t, *settlements[0], types.SettlementEntry{ - PositionDirection: "Long", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(1), - ExecutionCostOrProceed: sdk.NewDec(110), - ExpectedCostOrProceed: sdk.NewDec(110), - Account: "abc", - OrderType: "Limit", - OrderId: 4, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, *settlements[1], types.SettlementEntry{ - PositionDirection: "Long", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(1), - ExecutionCostOrProceed: sdk.NewDec(110), - ExpectedCostOrProceed: sdk.NewDec(110), - Account: "abc", - OrderType: "Limit", - OrderId: 4, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, *settlements[2], types.SettlementEntry{ - PositionDirection: "Long", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(4), - ExecutionCostOrProceed: sdk.NewDec(100), - ExpectedCostOrProceed: sdk.NewDec(100), - Account: "abc", - OrderType: "Limit", - OrderId: 5, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, *settlements[3], types.SettlementEntry{ - PositionDirection: "Short", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(1), - ExecutionCostOrProceed: sdk.MustNewDecFromStr("103.333333333333333333"), - ExpectedCostOrProceed: sdk.NewDec(96), - Account: "jkl", - OrderType: "Market", - OrderId: 1, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, *settlements[4], types.SettlementEntry{ - PositionDirection: "Short", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(1), - ExecutionCostOrProceed: sdk.MustNewDecFromStr("103.333333333333333333"), - ExpectedCostOrProceed: sdk.NewDec(100), - Account: "abc", - OrderType: "Market", - OrderId: 2, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, *settlements[5], types.SettlementEntry{ - PositionDirection: "Short", - PriceDenom: "USDC", - AssetDenom: "ATOM", - Quantity: sdk.NewDec(4), - ExecutionCostOrProceed: sdk.MustNewDecFromStr("103.333333333333333333"), - ExpectedCostOrProceed: sdk.NewDec(100), - Account: "abc", - OrderType: "Market", - OrderId: 2, - Timestamp: TestTimestamp, - Height: TestHeight, - }) - assert.Equal(t, blockOrders.Get()[0].Quantity, sdk.ZeroDec()) - assert.Equal(t, blockOrders.Get()[0].Status, types.OrderStatus_FULFILLED) - assert.Equal(t, blockOrders.Get()[1].Quantity, sdk.ZeroDec()) - assert.Equal(t, blockOrders.Get()[1].Status, types.OrderStatus_FULFILLED) - assert.Equal(t, blockOrders.Get()[2].Quantity, sdk.NewDec(2)) - assert.Equal(t, blockOrders.Get()[2].Status, types.OrderStatus_PLACED) -} diff --git a/x/dex/exchange/settlement.go b/x/dex/exchange/settlement.go deleted file mode 100644 index fe049808e..000000000 --- a/x/dex/exchange/settlement.go +++ /dev/null @@ -1,129 +0,0 @@ -package exchange - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - cache "github.com/sei-protocol/sei-chain/x/dex/cache" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -// this function helps to settle market orders -func Settle( - ctx sdk.Context, - takerOrder *types.Order, - quantityTaken sdk.Dec, - orderbook *types.CachedSortedOrderBookEntries, - worstPrice sdk.Dec, - makerPrice sdk.Dec, -) ([]*types.SettlementEntry, []*types.SettlementEntry) { - // settlement of one liquidity taker's order is allocated on a FIFO basis - takerSettlements := []*types.SettlementEntry{} - makerSettlements := []*types.SettlementEntry{} - if quantityTaken.IsZero() { - return takerSettlements, makerSettlements - } - newToSettle, _ := orderbook.SettleQuantity(ctx, quantityTaken) - for _, toSettle := range newToSettle { - takerSettlements = append(takerSettlements, types.NewSettlementEntry( - ctx, - takerOrder.Id, - takerOrder.Account, - takerOrder.PositionDirection, - takerOrder.PriceDenom, - takerOrder.AssetDenom, - toSettle.Amount, - worstPrice, - worstPrice, - takerOrder.OrderType, - )) - makerSettlements = append(makerSettlements, types.NewSettlementEntry( - ctx, - toSettle.OrderID, - toSettle.Account, - types.OppositePositionDirection[takerOrder.PositionDirection], - takerOrder.PriceDenom, - takerOrder.AssetDenom, - toSettle.Amount, - makerPrice, - makerPrice, - types.OrderType_LIMIT, - )) - } - - return takerSettlements, makerSettlements -} - -// this function update the order data in the memState -// to be noted that the order status will only reflect for market orders that are settled -func UpdateOrderData( - takerOrder *types.Order, - quantityTaken sdk.Dec, - blockOrders *cache.BlockOrders, -) { - // update order data in the memstate - orderStored := blockOrders.GetByID(takerOrder.Id) - orderStored.Quantity = orderStored.Quantity.Sub(quantityTaken) - if orderStored.OrderType == types.OrderType_FOKMARKET || orderStored.OrderType == types.OrderType_FOKMARKETBYVALUE || orderStored.Quantity.IsZero() { - orderStored.Status = types.OrderStatus_FULFILLED - } - blockOrders.Add(orderStored) -} - -func SettleFromBook( - ctx sdk.Context, - orderbook *types.OrderBook, - executedQuantity sdk.Dec, - longPrice sdk.Dec, - shortPrice sdk.Dec, -) []*types.SettlementEntry { - // settlement from within the order book is also allocated on a FIFO basis - settlements := []*types.SettlementEntry{} - if executedQuantity.IsZero() { - return settlements - } - newLongToSettle, _ := orderbook.Longs.SettleQuantity(ctx, executedQuantity) - newShortToSettle, _ := orderbook.Shorts.SettleQuantity(ctx, executedQuantity) - avgPrice := longPrice.Add(shortPrice).Quo(sdk.NewDec(2)) - longPtr, shortPtr := 0, 0 - for longPtr < len(newLongToSettle) && shortPtr < len(newShortToSettle) { - longToSettle := newLongToSettle[longPtr] - shortToSettle := newShortToSettle[shortPtr] - var quantity sdk.Dec - if longToSettle.Amount.LT(shortToSettle.Amount) { - quantity = longToSettle.Amount - } else { - quantity = shortToSettle.Amount - } - settlements = append(settlements, types.NewSettlementEntry( - ctx, - longToSettle.OrderID, - longToSettle.Account, - types.PositionDirection_LONG, - orderbook.Pair.PriceDenom, - orderbook.Pair.AssetDenom, - quantity, - avgPrice, - longPrice, - types.OrderType_LIMIT, - ), types.NewSettlementEntry( - ctx, - shortToSettle.OrderID, - shortToSettle.Account, - types.PositionDirection_SHORT, - orderbook.Pair.PriceDenom, - orderbook.Pair.AssetDenom, - quantity, - avgPrice, - shortPrice, - types.OrderType_LIMIT, - )) - newLongToSettle[longPtr] = types.ToSettle{Account: longToSettle.Account, Amount: longToSettle.Amount.Sub(quantity), OrderID: longToSettle.OrderID} - newShortToSettle[shortPtr] = types.ToSettle{Account: shortToSettle.Account, Amount: shortToSettle.Amount.Sub(quantity), OrderID: shortToSettle.OrderID} - if newLongToSettle[longPtr].Amount.IsZero() { - longPtr++ - } - if newShortToSettle[shortPtr].Amount.IsZero() { - shortPtr++ - } - } - return settlements -} diff --git a/x/dex/exchange/settlement_fuzz_test.go b/x/dex/exchange/settlement_fuzz_test.go deleted file mode 100644 index afa1df5fb..000000000 --- a/x/dex/exchange/settlement_fuzz_test.go +++ /dev/null @@ -1,118 +0,0 @@ -package exchange_test - -import ( - "testing" - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/testutil/fuzzing" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex/exchange" - keeperutil "github.com/sei-protocol/sei-chain/x/dex/keeper/utils" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/libs/log" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" -) - -var TestFuzzSettleCtx = sdk.NewContext(nil, tmproto.Header{}, false, log.NewNopLogger()) - -func FuzzSettleMarketOrder(f *testing.F) { - TestFuzzSettleCtx = TestFuzzSettleCtx.WithBlockHeight(1).WithBlockTime(time.Now()) - f.Fuzz(fuzzTargetMatchMarketOrders) -} - -func fuzzTargetSettle( - t *testing.T, - long bool, - prices []byte, - quantities []byte, - entryWeights []byte, - accountIndices []byte, - allocationWeights []byte, - priceI int64, - priceIsNil bool, - quantityI int64, - quantityIsNil bool, -) { - dexkeeper, ctx := keepertest.DexKeeper(t) - ctx = ctx.WithBlockHeight(1).WithBlockTime(time.Now()) - entries := fuzzing.GetOrderBookEntries(!long, keepertest.TestPriceDenom, keepertest.TestAssetDenom, entryWeights, accountIndices, allocationWeights) - for _, entry := range entries { - if long { - dexkeeper.SetShortOrderBookEntry(ctx, keepertest.TestContract, entry) - } else { - dexkeeper.SetLongOrderBookEntry(ctx, keepertest.TestContract, entry) - } - } - var direction types.PositionDirection - if long { - direction = types.PositionDirection_LONG - } else { - direction = types.PositionDirection_SHORT - } - orders := fuzzing.GetPlacedOrders(direction, types.OrderType_MARKET, keepertest.TestPair, prices, quantities) - - price := fuzzing.FuzzDec(priceI, priceIsNil) - quantity := fuzzing.FuzzDec(quantityI, quantityIsNil) - - if len(entries) > len(orders) { - entries = entries[:len(orders)] - } else { - orders = orders[:len(entries)] - } - - orderbook := keeperutil.PopulateOrderbook(ctx, dexkeeper, types.ContractAddress(keepertest.TestContract), types.Pair{PriceDenom: keepertest.TestPriceDenom, AssetDenom: keepertest.TestAssetDenom}) - book := orderbook.Longs - if long { - book = orderbook.Shorts - } - for i, entry := range entries { - require.NotPanics(t, func() { - exchange.Settle(ctx, orders[i], quantity, book, price, entry.GetPrice()) - }) - } -} - -func FuzzSettleLimitOrder(f *testing.F) { - TestFuzzSettleCtx = TestFuzzSettleCtx.WithBlockHeight(1).WithBlockTime(time.Now()) - f.Fuzz(fuzzTargetMatchMarketOrders) -} - -func fuzzTargetSettleFromBook( - t *testing.T, - buyEntryWeights []byte, - sellEntryWeights []byte, - buyAccountIndices []byte, - sellAccountIndices []byte, - buyAllocationWeights []byte, - sellAllocationWeights []byte, - quantityI int64, - quantityIsNil bool, -) { - dexkeeper, ctx := keepertest.DexKeeper(t) - ctx = ctx.WithBlockHeight(1).WithBlockTime(time.Now()) - buyEntries := fuzzing.GetOrderBookEntries(true, keepertest.TestPriceDenom, keepertest.TestAssetDenom, buyEntryWeights, buyAccountIndices, buyAllocationWeights) - for _, entry := range buyEntries { - dexkeeper.SetLongOrderBookEntry(ctx, keepertest.TestContract, entry) - } - sellEntries := fuzzing.GetOrderBookEntries(false, keepertest.TestPriceDenom, keepertest.TestAssetDenom, sellEntryWeights, sellAccountIndices, sellAllocationWeights) - for _, entry := range sellEntries { - dexkeeper.SetShortOrderBookEntry(ctx, keepertest.TestContract, entry) - } - - quantity := fuzzing.FuzzDec(quantityI, quantityIsNil) - - if len(buyEntries) > len(sellEntries) { - buyEntries = buyEntries[:len(sellEntries)] - } else { - sellEntries = sellEntries[:len(buyEntries)] - } - - orderbook := keeperutil.PopulateOrderbook(ctx, dexkeeper, types.ContractAddress(keepertest.TestContract), types.Pair{PriceDenom: keepertest.TestPriceDenom, AssetDenom: keepertest.TestAssetDenom}) - for i, longEntry := range buyEntries { - require.NotPanics(t, func() { - exchange.SettleFromBook(ctx, orderbook, quantity, longEntry.GetPrice(), sellEntries[i].GetPrice()) - }) - } -} diff --git a/x/dex/genesis.go b/x/dex/genesis.go deleted file mode 100644 index d5ef5c729..000000000 --- a/x/dex/genesis.go +++ /dev/null @@ -1,85 +0,0 @@ -package dex - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/keeper" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -// InitGenesis initializes the dex module's state from a provided genesis -// state. -func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) { - k.CreateModuleAccount(ctx) - - // Set all the longBook - for _, contractState := range genState.ContractState { - - contractInfo := contractState.ContractInfo - err := k.SetContract(ctx, &contractInfo) - if err != nil { - panic(err) - } - - for _, elem := range contractState.PairList { - k.AddRegisteredPair(ctx, contractState.ContractInfo.ContractAddr, elem) - } - - for _, elem := range contractState.LongBookList { - k.SetLongBook(ctx, contractState.ContractInfo.ContractAddr, elem) - } - - for _, elem := range contractState.ShortBookList { - k.SetShortBook(ctx, contractState.ContractInfo.ContractAddr, elem) - } - - for _, elem := range contractState.PriceList { - for _, priceElem := range elem.Prices { - k.SetPriceState(ctx, *priceElem, contractState.ContractInfo.ContractAddr) - } - } - - k.SetNextOrderID(ctx, contractState.ContractInfo.ContractAddr, contractState.NextOrderId) - - } - - // this line is used by starport scaffolding # genesis/module/init - k.SetParams(ctx, genState.Params) - - k.SetEpoch(ctx, genState.LastEpoch) -} - -// ExportGenesis returns the dex module's exported genesis. -func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState { - genesis := types.DefaultGenesis() - genesis.Params = k.GetParams(ctx) - - allContractInfo := k.GetAllContractInfo(ctx) - contractStates := make([]types.ContractState, len(allContractInfo)) - for i, contractInfo := range allContractInfo { - contractAddr := contractInfo.ContractAddr - registeredPairs := k.GetAllRegisteredPairs(ctx, contractAddr) - // Save all price info for contract, for all its pairs - contractPrices := []types.ContractPairPrices{} - for _, elem := range registeredPairs { - pairPrices := k.GetAllPrices(ctx, contractAddr, elem) - contractPrices = append(contractPrices, types.ContractPairPrices{ - PricePair: elem, - Prices: pairPrices, - }) - } - contractStates[i] = types.ContractState{ - ContractInfo: contractInfo, - LongBookList: k.GetAllLongBook(ctx, contractAddr), - ShortBookList: k.GetAllShortBook(ctx, contractAddr), - PairList: registeredPairs, - PriceList: contractPrices, - NextOrderId: k.GetNextOrderID(ctx, contractAddr), - } - } - genesis.ContractState = contractStates - - _, currentEpoch := k.IsNewEpoch(ctx) - genesis.LastEpoch = currentEpoch - - return genesis -} diff --git a/x/dex/genesis_test.go b/x/dex/genesis_test.go deleted file mode 100644 index 4cbf0cf21..000000000 --- a/x/dex/genesis_test.go +++ /dev/null @@ -1,105 +0,0 @@ -package dex_test - -import ( - "testing" - - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - -func TEST_PAIR() types.Pair { - return types.Pair{ - PriceDenom: "USDC", - AssetDenom: "ATOM", - } -} - -func TestGenesis(t *testing.T) { - contractList := []types.ContractState{} - contractDependencies := []*types.ContractDependencyInfo{ - { - Dependency: "dependency1", - }, - { - Dependency: "dependency2", - }, - } - - contractInfo := types.ContractInfoV2{ - CodeId: uint64(1), - ContractAddr: "sei14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sh9m79m", - Dependencies: contractDependencies, - } - - pairList := []types.Pair{ - { - PriceDenom: "USDC", - AssetDenom: "SEI", - PriceTicksize: &keepertest.TestTicksize, - QuantityTicksize: &keepertest.TestTicksize, - }, - } - - priceList := []types.ContractPairPrices{ - { - PricePair: pairList[0], - Prices: []*types.Price{ - { - SnapshotTimestampInSeconds: 2, - Pair: &(pairList[0]), - Price: sdk.MustNewDecFromStr("101"), - }, - }, - }, - } - - contractState := types.ContractState{ - LongBookList: []types.LongBook{ - { - Price: sdk.NewDec(1), - Entry: &types.OrderEntry{ - Price: sdk.ZeroDec(), - }, - }, - }, - ShortBookList: []types.ShortBook{ - { - Price: sdk.NewDec(1), - Entry: &types.OrderEntry{ - Price: sdk.ZeroDec(), - }, - }, - }, - ContractInfo: contractInfo, - PairList: pairList, - PriceList: priceList, - NextOrderId: 10, - } - contractList = append(contractList, contractState) - - genesisState := types.GenesisState{ - Params: types.DefaultParams(), - // this line is used by starport scaffolding # genesis/test/state - ContractState: contractList, - } - - k, ctx := keepertest.DexKeeper(t) - k.SetContract(ctx, &contractInfo) - dex.InitGenesis(ctx, *k, genesisState) - got := dex.ExportGenesis(ctx, *k) - require.NotNil(t, got) - - require.ElementsMatch(t, genesisState.ContractState[0].LongBookList, got.ContractState[0].LongBookList) - require.ElementsMatch(t, genesisState.ContractState[0].ShortBookList, got.ContractState[0].ShortBookList) - require.ElementsMatch(t, genesisState.ContractState[0].PairList, got.ContractState[0].PairList) - require.Equal(t, genesisState.ContractState[0].ContractInfo.CodeId, got.ContractState[0].ContractInfo.CodeId) - require.Equal(t, genesisState.ContractState[0].ContractInfo.ContractAddr, got.ContractState[0].ContractInfo.ContractAddr) - require.ElementsMatch(t, genesisState.ContractState[0].ContractInfo.Dependencies, got.ContractState[0].ContractInfo.Dependencies) - require.ElementsMatch(t, genesisState.ContractState[0].PriceList, got.ContractState[0].PriceList) - require.Equal(t, genesisState.ContractState[0].NextOrderId, got.ContractState[0].NextOrderId) - // this line is used by starport scaffolding # genesis/test/assert -} diff --git a/x/dex/gov.go b/x/dex/gov.go deleted file mode 100644 index 62fd39283..000000000 --- a/x/dex/gov.go +++ /dev/null @@ -1,14 +0,0 @@ -package dex - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/keeper" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -func HandleAddAssetMetadataProposal(ctx sdk.Context, k *keeper.Keeper, p *types.AddAssetMetadataProposal) error { - for _, asset := range p.AssetList { - k.SetAssetMetadata(ctx, asset) - } - return nil -} diff --git a/x/dex/handler.go b/x/dex/handler.go deleted file mode 100644 index 623062b50..000000000 --- a/x/dex/handler.go +++ /dev/null @@ -1,67 +0,0 @@ -package dex - -import ( - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" - - "github.com/sei-protocol/sei-chain/x/dex/keeper" - "github.com/sei-protocol/sei-chain/x/dex/keeper/msgserver" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -// NewHandler ... -func NewHandler(k keeper.Keeper) sdk.Handler { - msgServer := msgserver.NewMsgServerImpl(k) - - return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { - ctx = ctx.WithEventManager(sdk.NewEventManager()) - - switch msg := msg.(type) { - case *types.MsgPlaceOrders: - res, err := msgServer.PlaceOrders(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgCancelOrders: - res, err := msgServer.CancelOrders(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgRegisterContract: - res, err := msgServer.RegisterContract(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgRegisterPairs: - res, err := msgServer.RegisterPairs(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgUpdatePriceTickSize: - res, err := msgServer.UpdatePriceTickSize(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgUpdateQuantityTickSize: - res, err := msgServer.UpdateQuantityTickSize(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgUnregisterContract: - res, err := msgServer.UnregisterContract(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgContractDepositRent: - res, err := msgServer.ContractDepositRent(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgUnsuspendContract: - res, err := msgServer.UnsuspendContract(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - // this line is used by starport scaffolding # 1 - default: - errMsg := fmt.Sprintf("unrecognized %s message type: %T", types.ModuleName, msg) - return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, errMsg) - } - } -} - -func NewProposalHandler(k keeper.Keeper) govtypes.Handler { - return func(ctx sdk.Context, content govtypes.Content) error { - switch c := content.(type) { - case *types.AddAssetMetadataProposal: - return HandleAddAssetMetadataProposal(ctx, &k, c) - default: - return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized dex proposal content type: %T", c) - } - } -} diff --git a/x/dex/keeper/abci/end_block_cancel_orders.go b/x/dex/keeper/abci/end_block_cancel_orders.go deleted file mode 100644 index 8c471124c..000000000 --- a/x/dex/keeper/abci/end_block_cancel_orders.go +++ /dev/null @@ -1,45 +0,0 @@ -package abci - -import ( - "context" - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/keeper/utils" - "github.com/sei-protocol/sei-chain/x/dex/types" - dexutils "github.com/sei-protocol/sei-chain/x/dex/utils" - "go.opentelemetry.io/otel/attribute" - otrace "go.opentelemetry.io/otel/trace" -) - -func (w KeeperWrapper) HandleEBCancelOrders(ctx context.Context, sdkCtx sdk.Context, tracer *otrace.Tracer, contractAddr string, registeredPairs []types.Pair) error { - _, span := (*tracer).Start(ctx, "SudoCancelOrders") - span.SetAttributes(attribute.String("contractAddr", contractAddr)) - - typedContractAddr := types.ContractAddress(contractAddr) - msg := w.getCancelSudoMsg(sdkCtx, typedContractAddr, registeredPairs) - if len(msg.OrderCancellations.IdsToCancel) == 0 { - return nil - } - userProvidedGas := w.GetParams(sdkCtx).DefaultGasPerCancel * uint64(len(msg.OrderCancellations.IdsToCancel)) - if _, err := utils.CallContractSudo(sdkCtx, w.Keeper, contractAddr, msg, userProvidedGas); err != nil { - sdkCtx.Logger().Error(fmt.Sprintf("Error during cancellation: %s", err.Error())) - return err - } - span.End() - return nil -} - -func (w KeeperWrapper) getCancelSudoMsg(sdkCtx sdk.Context, typedContractAddr types.ContractAddress, registeredPairs []types.Pair) types.SudoOrderCancellationMsg { - idsToCancel := []uint64{} - for _, pair := range registeredPairs { - for _, cancel := range dexutils.GetMemState(sdkCtx.Context()).GetBlockCancels(sdkCtx, typedContractAddr, pair).Get() { - idsToCancel = append(idsToCancel, cancel.Id) - } - } - return types.SudoOrderCancellationMsg{ - OrderCancellations: types.OrderCancellationMsgDetails{ - IdsToCancel: idsToCancel, - }, - } -} diff --git a/x/dex/keeper/abci/end_block_deposit.go b/x/dex/keeper/abci/end_block_deposit.go deleted file mode 100644 index c0216e482..000000000 --- a/x/dex/keeper/abci/end_block_deposit.go +++ /dev/null @@ -1,58 +0,0 @@ -package abci - -import ( - "context" - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" - seiutils "github.com/sei-protocol/sei-chain/utils" - "github.com/sei-protocol/sei-chain/x/dex/keeper/utils" - "github.com/sei-protocol/sei-chain/x/dex/types" - dexutils "github.com/sei-protocol/sei-chain/x/dex/utils" - "go.opentelemetry.io/otel/attribute" - otrace "go.opentelemetry.io/otel/trace" -) - -func (w KeeperWrapper) HandleEBDeposit(ctx context.Context, sdkCtx sdk.Context, tracer *otrace.Tracer, contractAddr string) error { - _, span := (*tracer).Start(ctx, "SudoDeposit") - span.SetAttributes(attribute.String("contractAddr", contractAddr)) - defer span.End() - - typedContractAddr := types.ContractAddress(contractAddr) - msg := w.GetDepositSudoMsg(sdkCtx, typedContractAddr) - if msg.IsEmpty() { - return nil - } - _, err := utils.CallContractSudo(sdkCtx, w.Keeper, contractAddr, msg, 0) // deposit - if err != nil { - sdkCtx.Logger().Error(fmt.Sprintf("Error during deposit: %s", err.Error())) - return err - } - - return nil -} - -func (w KeeperWrapper) GetDepositSudoMsg(ctx sdk.Context, typedContractAddr types.ContractAddress) types.SudoOrderPlacementMsg { - depositMemState := dexutils.GetMemState(ctx.Context()).GetDepositInfo(ctx, typedContractAddr).Get() - contractDepositInfo := seiutils.Map( - depositMemState, - func(d *types.DepositInfoEntry) types.ContractDepositInfo { return d.ToContractDepositInfo() }, - ) - escrowed := sdk.NewCoins() - for _, deposit := range depositMemState { - escrowed = escrowed.Add(sdk.NewCoin(deposit.Denom, deposit.Amount.TruncateInt())) - } - contractAddr, err := sdk.AccAddressFromBech32(string(typedContractAddr)) - if err != nil { - panic(err) - } - if err := w.BankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, contractAddr, escrowed); err != nil { - panic(err) - } - return types.SudoOrderPlacementMsg{ - OrderPlacements: types.OrderPlacementMsgDetails{ - Orders: []types.Order{}, - Deposits: contractDepositInfo, - }, - } -} diff --git a/x/dex/keeper/abci/end_block_place_orders.go b/x/dex/keeper/abci/end_block_place_orders.go deleted file mode 100644 index 8ab95c6e3..000000000 --- a/x/dex/keeper/abci/end_block_place_orders.go +++ /dev/null @@ -1,83 +0,0 @@ -package abci - -import ( - "context" - "encoding/json" - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/keeper/utils" - "github.com/sei-protocol/sei-chain/x/dex/types" - dexutils "github.com/sei-protocol/sei-chain/x/dex/utils" - "go.opentelemetry.io/otel/attribute" - otrace "go.opentelemetry.io/otel/trace" -) - -// There is a limit on how many bytes can be passed to wasm VM in a single call, -// so we shouldn't bump this number unless there is an upgrade to wasm VM -const MaxOrdersPerSudoCall = 50000 - -func (w KeeperWrapper) HandleEBPlaceOrders(ctx context.Context, sdkCtx sdk.Context, tracer *otrace.Tracer, contractAddr string, registeredPairs []types.Pair) error { - _, span := (*tracer).Start(ctx, "SudoPlaceOrders") - span.SetAttributes(attribute.String("contractAddr", contractAddr)) - defer span.End() - - typedContractAddr := types.ContractAddress(contractAddr) - msgs := w.GetPlaceSudoMsg(sdkCtx, typedContractAddr, registeredPairs) - - responses := []types.SudoOrderPlacementResponse{} - - for _, msg := range msgs { - if msg.IsEmpty() { - continue - } - userProvidedGas := w.GetParams(sdkCtx).DefaultGasPerOrder * uint64(len(msg.OrderPlacements.Orders)) - data, err := utils.CallContractSudo(sdkCtx, w.Keeper, contractAddr, msg, userProvidedGas) - if err != nil { - sdkCtx.Logger().Error(fmt.Sprintf("Error during order placement: %s", err.Error())) - return err - } - response := types.SudoOrderPlacementResponse{} - if err := json.Unmarshal(data, &response); err != nil { - sdkCtx.Logger().Error("Failed to parse order placement response") - return err - } - if len(response.UnsuccessfulOrders) > 0 { - sdkCtx.Logger().Info(fmt.Sprintf("%s has %d unsuccessful order placements", contractAddr, len(response.UnsuccessfulOrders))) - } - responses = append(responses, response) - } - - for _, pair := range registeredPairs { - for _, response := range responses { - dexutils.GetMemState(sdkCtx.Context()).GetBlockOrders(sdkCtx, typedContractAddr, pair).MarkFailedToPlace(response.UnsuccessfulOrders) - } - } - return nil -} - -func (w KeeperWrapper) GetPlaceSudoMsg(ctx sdk.Context, typedContractAddr types.ContractAddress, registeredPairs []types.Pair) []types.SudoOrderPlacementMsg { - msgs := []types.SudoOrderPlacementMsg{} - contractOrderPlacements := []types.Order{} - for _, pair := range registeredPairs { - for _, order := range dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, typedContractAddr, pair).Get() { - contractOrderPlacements = append(contractOrderPlacements, *order) - if len(contractOrderPlacements) == MaxOrdersPerSudoCall { - msgs = append(msgs, types.SudoOrderPlacementMsg{ - OrderPlacements: types.OrderPlacementMsgDetails{ - Orders: contractOrderPlacements, - Deposits: []types.ContractDepositInfo{}, - }, - }) - contractOrderPlacements = []types.Order{} - } - } - } - msgs = append(msgs, types.SudoOrderPlacementMsg{ - OrderPlacements: types.OrderPlacementMsgDetails{ - Orders: contractOrderPlacements, - Deposits: []types.ContractDepositInfo{}, - }, - }) - return msgs -} diff --git a/x/dex/keeper/abci/end_block_place_orders_test.go b/x/dex/keeper/abci/end_block_place_orders_test.go deleted file mode 100644 index 556c3119c..000000000 --- a/x/dex/keeper/abci/end_block_place_orders_test.go +++ /dev/null @@ -1,67 +0,0 @@ -package abci_test - -import ( - "context" - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - dexcache "github.com/sei-protocol/sei-chain/x/dex/cache" - "github.com/sei-protocol/sei-chain/x/dex/keeper/abci" - "github.com/sei-protocol/sei-chain/x/dex/types" - dextypes "github.com/sei-protocol/sei-chain/x/dex/types" - dexutils "github.com/sei-protocol/sei-chain/x/dex/utils" - minttypes "github.com/sei-protocol/sei-chain/x/mint/types" - "github.com/stretchr/testify/require" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" -) - -func TestGetPlaceSudoMsg(t *testing.T) { - pair := types.Pair{PriceDenom: keepertest.TestPriceDenom, AssetDenom: keepertest.TestAssetDenom} - keeper, ctx := keepertest.DexKeeper(t) - dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, keepertest.TestContract, pair).Add( - &types.Order{ - Id: 1, - Price: sdk.OneDec(), - Quantity: sdk.OneDec(), - PriceDenom: "USDC", - AssetDenom: "ATOM", - OrderType: types.OrderType_LIMIT, - PositionDirection: types.PositionDirection_LONG, - Data: "{\"position_effect\":\"OPEN\",\"leverage\":\"1\"}", - }, - ) - wrapper := abci.KeeperWrapper{Keeper: keeper} - msgs := wrapper.GetPlaceSudoMsg(ctx, keepertest.TestContract, []types.Pair{pair}) - require.Equal(t, 1, len(msgs)) -} - -func TestGetDepositSudoMsg(t *testing.T) { - testApp := keepertest.TestApp() - ctx := testApp.BaseApp.NewContext(false, tmproto.Header{}) - ctx = ctx.WithContext(context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(testApp.GetMemKey(types.MemStoreKey)))) - testAccount, _ := sdk.AccAddressFromBech32("sei1yezq49upxhunjjhudql2fnj5dgvcwjj87pn2wx") - amounts := sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(1000000))) - bankkeeper := testApp.BankKeeper - bankkeeper.MintCoins(ctx, minttypes.ModuleName, amounts) - err := bankkeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, testAccount, amounts) - require.Nil(t, err) - // this send would happen in msg server - err = bankkeeper.SendCoinsFromAccountToModule(ctx, testAccount, dextypes.ModuleName, amounts) - require.Nil(t, err) - keeper := testApp.DexKeeper - dexutils.GetMemState(ctx.Context()).GetDepositInfo(ctx, keepertest.TestContract).Add( - &types.DepositInfoEntry{ - Creator: testAccount.String(), - Denom: amounts[0].Denom, - Amount: sdk.NewDec(amounts[0].Amount.Int64()), - }, - ) - wrapper := abci.KeeperWrapper{Keeper: &keeper} - msgs := wrapper.GetDepositSudoMsg(ctx, keepertest.TestContract) - require.Equal(t, 1, len(msgs.OrderPlacements.Deposits)) - - contractAddr, _ := sdk.AccAddressFromBech32(keepertest.TestContract) - contractBalance := testApp.BankKeeper.GetBalance(ctx, contractAddr, "usei") - require.Equal(t, contractBalance.Amount.Int64(), int64(1000000)) -} diff --git a/x/dex/keeper/abci/keeper_wrapper.go b/x/dex/keeper/abci/keeper_wrapper.go deleted file mode 100644 index ee20698ad..000000000 --- a/x/dex/keeper/abci/keeper_wrapper.go +++ /dev/null @@ -1,9 +0,0 @@ -package abci - -import ( - "github.com/sei-protocol/sei-chain/x/dex/keeper" -) - -type KeeperWrapper struct { - *keeper.Keeper -} diff --git a/x/dex/keeper/asset_list.go b/x/dex/keeper/asset_list.go deleted file mode 100644 index d62b39ed0..000000000 --- a/x/dex/keeper/asset_list.go +++ /dev/null @@ -1,43 +0,0 @@ -package keeper - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -func (k Keeper) SetAssetMetadata(ctx sdk.Context, assetMetadata types.AssetMetadata) { - store := ctx.KVStore(k.storeKey) - // Have one base denom for a canonical “display”. - // Even if asset exists already, overwrite the store with new metadata - // Asset list is decided through governance - b := k.Cdc.MustMarshal(&assetMetadata) - - store.Set(types.AssetListPrefix(assetMetadata.Metadata.Display), b) -} - -func (k Keeper) GetAssetMetadataByDenom(ctx sdk.Context, assetDenom string) (val types.AssetMetadata, found bool) { - store := ctx.KVStore(k.storeKey) - b := store.Get(types.AssetListPrefix(assetDenom)) - if b == nil { - return types.AssetMetadata{}, false - } - metadata := types.AssetMetadata{} - k.Cdc.MustUnmarshal(b, &metadata) - return metadata, true -} - -func (k Keeper) GetAllAssetMetadata(ctx sdk.Context) []types.AssetMetadata { - store := ctx.KVStore(k.storeKey) - iterator := sdk.KVStorePrefixIterator(store, types.KeyPrefix(types.AssetListKey)) - - list := []types.AssetMetadata{} - defer iterator.Close() - - for ; iterator.Valid(); iterator.Next() { - var val types.AssetMetadata - k.Cdc.MustUnmarshal(iterator.Value(), &val) - list = append(list, val) - } - - return list -} diff --git a/x/dex/keeper/asset_list_test.go b/x/dex/keeper/asset_list_test.go deleted file mode 100644 index 70348e6f3..000000000 --- a/x/dex/keeper/asset_list_test.go +++ /dev/null @@ -1,35 +0,0 @@ -package keeper_test - -import ( - "testing" - - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/testutil/nullify" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestAssetListGet(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - item := keepertest.CreateAssetMetadata(keeper, ctx) - - var expected_asset_list []types.AssetMetadata - expected_asset_list = append(expected_asset_list, item) - - asset_list := keeper.GetAllAssetMetadata(ctx) - - // First test get all asset list - require.ElementsMatch(t, - nullify.Fill(expected_asset_list), - nullify.Fill(asset_list), - ) - - // Test not found asset Denom - _, found := keeper.GetAssetMetadataByDenom(ctx, "denomNotInAssetList123") - require.False(t, found) - - // Test get specific Denom - val, found := keeper.GetAssetMetadataByDenom(ctx, "axlusdc") - require.True(t, found) - require.Equal(t, item, val) -} diff --git a/x/dex/keeper/common.go b/x/dex/keeper/common.go deleted file mode 100644 index f5ba9b961..000000000 --- a/x/dex/keeper/common.go +++ /dev/null @@ -1,22 +0,0 @@ -package keeper - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" -) - -func (k Keeper) removeAllForPrefix(ctx sdk.Context, prefix []byte) { - store := ctx.KVStore(k.storeKey) - for _, key := range k.getAllKeysForPrefix(store, prefix) { - store.Delete(key) - } -} - -func (k Keeper) getAllKeysForPrefix(store sdk.KVStore, prefix []byte) [][]byte { - keys := [][]byte{} - iter := sdk.KVStorePrefixIterator(store, prefix) - defer iter.Close() - for ; iter.Valid(); iter.Next() { - keys = append(keys, iter.Key()) - } - return keys -} diff --git a/x/dex/keeper/contract.go b/x/dex/keeper/contract.go deleted file mode 100644 index dd2596254..000000000 --- a/x/dex/keeper/contract.go +++ /dev/null @@ -1,244 +0,0 @@ -package keeper - -import ( - "errors" - "math" - "math/big" - "time" - - "github.com/cosmos/cosmos-sdk/store/prefix" - "github.com/cosmos/cosmos-sdk/telemetry" - sdk "github.com/cosmos/cosmos-sdk/types" - appparams "github.com/sei-protocol/sei-chain/app/params" - "github.com/sei-protocol/sei-chain/utils" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -const ContractPrefixKey = "x-wasm-contract" - -func (k Keeper) SetContract(ctx sdk.Context, contract *types.ContractInfoV2) error { - store := prefix.NewStore( - ctx.KVStore(k.storeKey), - []byte(ContractPrefixKey), - ) - bz, err := contract.Marshal() - if err != nil { - return errors.New("failed to marshal contract info") - } - store.Set(types.ContractKey(contract.ContractAddr), bz) - return nil -} - -func (k Keeper) DeleteContract(ctx sdk.Context, contractAddr string) { - store := prefix.NewStore( - ctx.KVStore(k.storeKey), - []byte(ContractPrefixKey), - ) - key := types.ContractKey(contractAddr) - store.Delete(key) -} - -func (k Keeper) GetContract(ctx sdk.Context, contractAddr string) (types.ContractInfoV2, error) { - store := prefix.NewStore( - ctx.KVStore(k.storeKey), - []byte(ContractPrefixKey), - ) - key := types.ContractKey(contractAddr) - res := types.ContractInfoV2{} - if !store.Has(key) { - return res, types.ErrContractNotExists - } - if err := res.Unmarshal(store.Get(key)); err != nil { - return res, types.ErrParsingContractInfo - } - return res, nil -} - -func (k Keeper) GetContractWithoutGasCharge(ctx sdk.Context, contractAddr string) (types.ContractInfoV2, error) { - return k.GetContract(ctx.WithGasMeter(sdk.NewInfiniteGasMeterWithMultiplier(ctx)), contractAddr) -} - -func (k Keeper) GetContractGasLimit(ctx sdk.Context, contractAddr sdk.AccAddress) (uint64, error) { - bech32ContractAddr := contractAddr.String() - contract, err := k.GetContract(ctx, bech32ContractAddr) - if err != nil { - return 0, err - } - rentBalance := contract.RentBalance - gasPrice := k.GetParams(ctx).SudoCallGasPrice - if gasPrice.LTE(sdk.ZeroDec()) { - return 0, errors.New("invalid gas price: must be positive") - } - gasDec := sdk.NewDecFromBigInt(new(big.Int).SetUint64(rentBalance)).Quo(gasPrice) - if gasDec.GT(sdk.NewDecFromBigInt(new(big.Int).SetUint64(math.MaxUint64))) { - return math.MaxUint64, nil - } - return gasDec.TruncateInt().Uint64(), nil // round down -} - -func (k Keeper) GetAllContractInfo(ctx sdk.Context) []types.ContractInfoV2 { - store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(ContractPrefixKey)) - iterator := sdk.KVStorePrefixIterator(store, []byte{}) - - defer iterator.Close() - - list := []types.ContractInfoV2{} - for ; iterator.Valid(); iterator.Next() { - contract := types.ContractInfoV2{} - if err := contract.Unmarshal(iterator.Value()); err == nil { - list = append(list, contract) - } - } - - return list -} - -// Reduce `RentBalance` of a contract if `userProvidedGas` cannot cover `gasUsed` -func (k Keeper) ChargeRentForGas(ctx sdk.Context, contractAddr string, gasUsed uint64, gasAllowance uint64) error { - if gasUsed <= gasAllowance { - // Allowance can fully cover the consumed gas. Doing nothing - return nil - } - gasUsed -= gasAllowance - contract, err := k.GetContract(ctx, contractAddr) - if err != nil { - return err - } - params := k.GetParams(ctx) - gasFeeDec := sdk.NewDecFromBigInt(new(big.Int).SetUint64(gasUsed)).Mul(params.SudoCallGasPrice) - if gasFeeDec.GT(sdk.NewDecFromBigInt(new(big.Int).SetUint64(math.MaxUint64))) { - gasFeeDec = sdk.NewDecFromBigInt(new(big.Int).SetUint64(math.MaxUint64)) - } - gasFee := gasFeeDec.RoundInt().Uint64() - if gasFee > contract.RentBalance { - contract.RentBalance = 0 - if err := k.SetContract(ctx, &contract); err != nil { - return err - } - return types.ErrInsufficientRent - } - contract.RentBalance -= gasFee - return k.SetContract(ctx, &contract) -} - -func (k Keeper) GetRentsForContracts(ctx sdk.Context, contractAddrs []string) map[string]uint64 { - res := map[string]uint64{} - for _, contractAddr := range contractAddrs { - if contract, err := k.GetContract(ctx, contractAddr); err == nil { - res[contractAddr] = contract.RentBalance - } - } - return res -} - -// Unregistrate and refund the creator -func (k Keeper) DoUnregisterContractWithRefund(ctx sdk.Context, contract types.ContractInfoV2) error { - k.DoUnregisterContract(ctx, contract) - creatorAddr, _ := sdk.AccAddressFromBech32(contract.Creator) - return k.BankKeeper.SendCoins(ctx, k.AccountKeeper.GetModuleAddress(types.ModuleName), creatorAddr, sdk.NewCoins(sdk.NewCoin(appparams.BaseCoinUnit, sdk.NewIntFromBigInt(new(big.Int).SetUint64(contract.RentBalance))))) -} - -// Contract unregistration will remove all orderbook data stored for the contract -func (k Keeper) DoUnregisterContract(ctx sdk.Context, contract types.ContractInfoV2) { - k.DeleteContract(ctx, contract.ContractAddr) - k.ClearDependenciesForContract(ctx, contract) - k.RemoveAllLongBooksForContract(ctx, contract.ContractAddr) - k.RemoveAllShortBooksForContract(ctx, contract.ContractAddr) - k.RemoveAllPricesForContract(ctx, contract.ContractAddr) - k.DeleteMatchResultState(ctx, contract.ContractAddr) - k.DeleteNextOrderID(ctx, contract.ContractAddr) - k.DeleteAllRegisteredPairsForContract(ctx, contract.ContractAddr) -} - -func (k Keeper) SuspendContract(ctx sdk.Context, contractAddress string, reason string) error { - contract, err := k.GetContract(ctx, contractAddress) - if err != nil { - return err - } - contract.Suspended = true - contract.SuspensionReason = reason - return k.SetContract(ctx, &contract) -} - -func (k Keeper) ClearDependenciesForContract(ctx sdk.Context, removedContract types.ContractInfoV2) { - // handle upstreams - allContracts := k.GetAllContractInfo(ctx) - for _, c := range allContracts { - contract := c - dependsOnRemovedContract := false - for _, dep := range contract.Dependencies { - if dep.Dependency == removedContract.ContractAddr { - dependsOnRemovedContract = true - break - } - } - if !dependsOnRemovedContract { - continue - } - contract.Dependencies = utils.Filter(contract.Dependencies, func(dep *types.ContractDependencyInfo) bool { return dep.Dependency != removedContract.ContractAddr }) - _ = k.SetContract(ctx, &contract) - } - - // handle downstreams - allContractsMap := map[string]types.ContractInfoV2{} - for _, contract := range allContracts { - allContractsMap[contract.ContractAddr] = contract - } - for _, dep := range removedContract.Dependencies { - if dependedContract, ok := allContractsMap[dep.Dependency]; ok { - dependedContract.NumIncomingDependencies-- - _ = k.SetContract(ctx, &dependedContract) - } - - if dep.ImmediateElderSibling != "" { - if immediateElderSibling, ok := allContractsMap[dep.ImmediateElderSibling]; ok { - newDependencies := []*types.ContractDependencyInfo{} - for _, elderSiblingDep := range immediateElderSibling.Dependencies { - if elderSiblingDep.Dependency != dep.Dependency { - newDependencies = append(newDependencies, elderSiblingDep) - } else { - newDependencies = append(newDependencies, &types.ContractDependencyInfo{ - Dependency: elderSiblingDep.Dependency, - ImmediateElderSibling: elderSiblingDep.ImmediateElderSibling, - ImmediateYoungerSibling: dep.ImmediateYoungerSibling, - }) - } - } - immediateElderSibling.Dependencies = newDependencies - _ = k.SetContract(ctx, &immediateElderSibling) - } - } - - if dep.ImmediateYoungerSibling != "" { - if immediateYoungerSibling, ok := allContractsMap[dep.ImmediateYoungerSibling]; ok { - newDependencies := []*types.ContractDependencyInfo{} - for _, youngerSiblingDep := range immediateYoungerSibling.Dependencies { - if youngerSiblingDep.Dependency != dep.Dependency { - newDependencies = append(newDependencies, youngerSiblingDep) - } else { - newDependencies = append(newDependencies, &types.ContractDependencyInfo{ - Dependency: youngerSiblingDep.Dependency, - ImmediateElderSibling: dep.ImmediateElderSibling, - ImmediateYoungerSibling: youngerSiblingDep.ImmediateYoungerSibling, - }) - } - } - immediateYoungerSibling.Dependencies = newDependencies - _ = k.SetContract(ctx, &immediateYoungerSibling) - } - } - } -} - -func (k Keeper) GetAllProcessableContractInfo(ctx sdk.Context) []types.ContractInfoV2 { - // Do not process any contract that has zero rent balance, suspended, or not require matching - defer telemetry.MeasureSince(time.Now(), types.ModuleName, "get_all_contract_info") - allRegisteredContracts := k.GetAllContractInfo(ctx) - validContracts := utils.Filter(allRegisteredContracts, func(c types.ContractInfoV2) bool { - return c.NeedOrderMatching && !c.Suspended && c.RentBalance > k.GetMinProcessableRent(ctx) - }) - telemetry.SetGauge(float32(len(allRegisteredContracts)), types.ModuleName, "num_of_registered_contracts") - telemetry.SetGauge(float32(len(validContracts)), types.ModuleName, "num_of_valid_contracts") - telemetry.SetGauge(float32(len(allRegisteredContracts)-len(validContracts)), types.ModuleName, "num_of_zero_balance_contracts") - return validContracts -} diff --git a/x/dex/keeper/contract_test.go b/x/dex/keeper/contract_test.go deleted file mode 100644 index 8dae31c24..000000000 --- a/x/dex/keeper/contract_test.go +++ /dev/null @@ -1,368 +0,0 @@ -package keeper_test - -import ( - "math" - "testing" - - "github.com/cosmos/cosmos-sdk/store/prefix" - - sdk "github.com/cosmos/cosmos-sdk/types" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestChargeRentForGas(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - keeper.SetParams(ctx, types.Params{SudoCallGasPrice: sdk.NewDecWithPrec(1, 1), PriceSnapshotRetention: 1}) - err := keeper.SetContract(ctx, &types.ContractInfoV2{ - Creator: keepertest.TestAccount, - ContractAddr: keepertest.TestContract, - CodeId: 1, - RentBalance: 1000000, - }) - require.Nil(t, err) - err = keeper.ChargeRentForGas(ctx, keepertest.TestContract, 5000000, 0) - require.Nil(t, err) - contract, err := keeper.GetContract(ctx, keepertest.TestContract) - require.Nil(t, err) - require.Equal(t, uint64(500000), contract.RentBalance) - err = keeper.ChargeRentForGas(ctx, keepertest.TestContract, 6000000, 0) - require.NotNil(t, err) - contract, err = keeper.GetContract(ctx, keepertest.TestContract) - require.Nil(t, err) - require.Equal(t, uint64(0), contract.RentBalance) - err = keeper.SetContract(ctx, &types.ContractInfoV2{ - Creator: keepertest.TestAccount, - ContractAddr: keepertest.TestContract, - CodeId: 1, - RentBalance: 1000000, - }) - require.Nil(t, err) - err = keeper.ChargeRentForGas(ctx, keepertest.TestContract, 5000000, 4000000) - require.Nil(t, err) - contract, err = keeper.GetContract(ctx, keepertest.TestContract) - require.Nil(t, err) - require.Equal(t, uint64(900000), contract.RentBalance) - err = keeper.ChargeRentForGas(ctx, keepertest.TestContract, 5000000, 6000000) - require.Nil(t, err) - contract, err = keeper.GetContract(ctx, keepertest.TestContract) - require.Nil(t, err) - require.Equal(t, uint64(900000), contract.RentBalance) - - // delete contract - keeper.DeleteContract(ctx, keepertest.TestContract) - _, err = keeper.GetContract(ctx, keepertest.TestContract) - require.NotNil(t, err) -} - -func TestGetContractInfo(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - keeper.SetParams(ctx, types.Params{SudoCallGasPrice: sdk.NewDecWithPrec(1, 1), PriceSnapshotRetention: 1}) - keeper.SetContract(ctx, &types.ContractInfoV2{ - Creator: keepertest.TestAccount, - ContractAddr: keepertest.TestContract, - CodeId: 1, - RentBalance: 1000000, - }) - // Successfully get a contract - contract, err := keeper.GetContract(ctx, keepertest.TestContract) - require.Equal(t, uint64(1000000), contract.RentBalance) - require.Equal(t, uint64(1), contract.CodeId) - require.Equal(t, keepertest.TestAccount, contract.Creator) - - // Getting a non exist contract should throw error for contract not exist - _, err = keeper.GetContract(ctx, keepertest.TestContract2) - require.Error(t, err) - require.Equal(t, err, types.ErrContractNotExists) - - // Getting a corrupted record should throw error for unable to parse - store := prefix.NewStore( - ctx.KVStore(keeper.GetStoreKey()), - []byte("x-wasm-contract"), - ) - bz := []byte("bad_contract") - store.Set(types.ContractKey(keepertest.TestContract), bz) - _, err = keeper.GetContract(ctx, keepertest.TestContract) - require.Error(t, err) - require.Equal(t, err, types.ErrParsingContractInfo) -} - -func TestGetAllContractInfo(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - keeper.SetParams(ctx, types.Params{SudoCallGasPrice: sdk.NewDecWithPrec(1, 1), PriceSnapshotRetention: 1}) - keeper.SetContract(ctx, &types.ContractInfoV2{ - Creator: keepertest.TestAccount, - ContractAddr: keepertest.TestContract, - CodeId: 1, - RentBalance: 1000000, - }) - keeper.SetContract(ctx, &types.ContractInfoV2{ - Creator: keepertest.TestAccount2, - ContractAddr: keepertest.TestContract2, - CodeId: 2, - RentBalance: 1000000, - }) - contracts := keeper.GetAllContractInfo(ctx) - require.Equal(t, uint64(1000000), contracts[0].RentBalance) - require.Equal(t, uint64(1000000), contracts[1].RentBalance) - require.Equal(t, uint64(1), contracts[0].CodeId) - require.Equal(t, uint64(2), contracts[1].CodeId) - require.Equal(t, keepertest.TestAccount, contracts[0].Creator) - require.Equal(t, keepertest.TestContract, contracts[0].ContractAddr) - require.Equal(t, keepertest.TestAccount2, contracts[1].Creator) - require.Equal(t, keepertest.TestContract2, contracts[1].ContractAddr) -} - -func TestGetContractGasLimit(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - contractAddr := sdk.MustAccAddressFromBech32("sei1suhgf5svhu4usrurvxzlgn54ksxmn8gljarjtxqnapv8kjnp4nrsgshtdj") - keeper.SetParams(ctx, types.Params{SudoCallGasPrice: sdk.NewDecWithPrec(1, 1), PriceSnapshotRetention: 1}) - keeper.SetContract(ctx, &types.ContractInfoV2{ - Creator: keepertest.TestAccount, - ContractAddr: "sei1suhgf5svhu4usrurvxzlgn54ksxmn8gljarjtxqnapv8kjnp4nrsgshtdj", - CodeId: 1, - RentBalance: 1000000, - }) - gasLimit, err := keeper.GetContractGasLimit(ctx, contractAddr) - require.Nil(t, err) - require.Equal(t, uint64(10000000), gasLimit) - - params := keeper.GetParams(ctx) - params.SudoCallGasPrice = sdk.NewDecWithPrec(1, 1) // 0.1 - keeper.SetParams(ctx, params) - keeper.SetContract(ctx, &types.ContractInfoV2{ - Creator: keepertest.TestAccount, - ContractAddr: "sei1suhgf5svhu4usrurvxzlgn54ksxmn8gljarjtxqnapv8kjnp4nrsgshtdj", - CodeId: 1, - RentBalance: math.MaxUint64, - }) - gasLimit, err = keeper.GetContractGasLimit(ctx, contractAddr) - require.Nil(t, err) - // max uint64 / 0.1 would cause overflow so we cap it at max - require.Equal(t, uint64(math.MaxUint64), gasLimit) -} - -func TestGetRentsForContracts(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - addr := "sei1suhgf5svhu4usrurvxzlgn54ksxmn8gljarjtxqnapv8kjnp4nrsgshtdj" - require.Equal(t, 0, len(keeper.GetRentsForContracts(ctx, []string{addr}))) - - keeper.SetContract(ctx, &types.ContractInfoV2{ - Creator: keepertest.TestAccount, - ContractAddr: addr, - CodeId: 1, - RentBalance: 100, - }) - require.Equal(t, map[string]uint64{addr: uint64(100)}, keeper.GetRentsForContracts(ctx, []string{addr})) -} - -func TestClearDependenciesForContract(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - - // no dependency whatsoever - contract := types.ContractInfoV2{ - ContractAddr: keepertest.TestContract, - } - keeper.SetContract(ctx, &contract) - require.NotPanics(t, func() { keeper.ClearDependenciesForContract(ctx, contract) }) - - // has upstreams - contract = types.ContractInfoV2{ - ContractAddr: keepertest.TestContract, - NumIncomingDependencies: 2, - } - keptContract := types.ContractInfoV2{ - ContractAddr: "sei1yum4v0v5l92jkxn8xpn9mjg7wuldk784ctg424ue8gqvdp88qzlqt6zc4h", - NumIncomingDependencies: 2, - } - upA := types.ContractInfoV2{ - ContractAddr: "sei105y5ssrsr8p8erkteagrguea6wcdgehlaamfup4lhrlm0y6eyhdsckcxdh", - Dependencies: []*types.ContractDependencyInfo{ - { - Dependency: keepertest.TestContract, - ImmediateYoungerSibling: "sei1y8ghk8q8d2rswrf3gv7hv2lfsewu8tvp6ysnlkzspu7k0aqkthdqwdqvk0", - }, - { - Dependency: "sei1yum4v0v5l92jkxn8xpn9mjg7wuldk784ctg424ue8gqvdp88qzlqt6zc4h", - ImmediateYoungerSibling: "sei193dzcmy7lwuj4eda3zpwwt9ejal00xva0vawcvhgsyyp5cfh6jyqj2vsuv", - }, - }, - } - upB := types.ContractInfoV2{ - ContractAddr: "sei1y8ghk8q8d2rswrf3gv7hv2lfsewu8tvp6ysnlkzspu7k0aqkthdqwdqvk0", - Dependencies: []*types.ContractDependencyInfo{ - { - Dependency: keepertest.TestContract, - ImmediateElderSibling: "sei105y5ssrsr8p8erkteagrguea6wcdgehlaamfup4lhrlm0y6eyhdsckcxdh", - }, - }, - } - upC := types.ContractInfoV2{ - ContractAddr: "sei193dzcmy7lwuj4eda3zpwwt9ejal00xva0vawcvhgsyyp5cfh6jyqj2vsuv", - Dependencies: []*types.ContractDependencyInfo{ - { - Dependency: "sei1yum4v0v5l92jkxn8xpn9mjg7wuldk784ctg424ue8gqvdp88qzlqt6zc4h", - ImmediateElderSibling: "sei105y5ssrsr8p8erkteagrguea6wcdgehlaamfup4lhrlm0y6eyhdsckcxdh", - }, - }, - } - keeper.SetContract(ctx, &contract) - keeper.SetContract(ctx, &keptContract) - keeper.SetContract(ctx, &upA) - keeper.SetContract(ctx, &upB) - keeper.SetContract(ctx, &upC) - require.NotPanics(t, func() { keeper.ClearDependenciesForContract(ctx, contract) }) - upA, err := keeper.GetContract(ctx, upA.ContractAddr) - require.Nil(t, err) - require.Equal(t, 1, len(upA.Dependencies)) - upB, err = keeper.GetContract(ctx, upB.ContractAddr) - require.Nil(t, err) - require.Equal(t, 0, len(upB.Dependencies)) - upC, err = keeper.GetContract(ctx, upC.ContractAddr) - require.Nil(t, err) - require.Equal(t, 1, len(upC.Dependencies)) - - // has downstreams - contract = types.ContractInfoV2{ - ContractAddr: keepertest.TestContract, - Dependencies: []*types.ContractDependencyInfo{ - { - Dependency: "sei1ehyucudueas79h0zwufcnxtv7s2sfmwc6rt0v0hzczdgvyr3p56qhprg6n", - ImmediateElderSibling: "sei1uyprmp0lu8w8z8kwxp7mxanrtrgn4lp7j557pxe4v8sczzdzl7ysk832hh", - ImmediateYoungerSibling: "sei1yum4v0v5l92jkxn8xpn9mjg7wuldk784ctg424ue8gqvdp88qzlqt6zc4h", - }, { - Dependency: "sei1n23ymwg2y7m55x5vwf2qk0als9cr592q4uc5de08c6qmaeryet4qye4w77", - }, - }, - } - keptContractA := types.ContractInfoV2{ - ContractAddr: "sei1yum4v0v5l92jkxn8xpn9mjg7wuldk784ctg424ue8gqvdp88qzlqt6zc4h", - Dependencies: []*types.ContractDependencyInfo{ - { - Dependency: "sei1ehyucudueas79h0zwufcnxtv7s2sfmwc6rt0v0hzczdgvyr3p56qhprg6n", - ImmediateElderSibling: keepertest.TestContract, - }, - }, - } - keptContractB := types.ContractInfoV2{ - ContractAddr: "sei1uyprmp0lu8w8z8kwxp7mxanrtrgn4lp7j557pxe4v8sczzdzl7ysk832hh", - Dependencies: []*types.ContractDependencyInfo{ - { - Dependency: "sei1ehyucudueas79h0zwufcnxtv7s2sfmwc6rt0v0hzczdgvyr3p56qhprg6n", - ImmediateYoungerSibling: keepertest.TestContract, - }, - }, - } - downA := types.ContractInfoV2{ - ContractAddr: "sei1ehyucudueas79h0zwufcnxtv7s2sfmwc6rt0v0hzczdgvyr3p56qhprg6n", - NumIncomingDependencies: 3, - } - downB := types.ContractInfoV2{ - ContractAddr: "sei1n23ymwg2y7m55x5vwf2qk0als9cr592q4uc5de08c6qmaeryet4qye4w77", - NumIncomingDependencies: 1, - } - keeper.SetContract(ctx, &contract) - keeper.SetContract(ctx, &keptContractA) - keeper.SetContract(ctx, &keptContractB) - keeper.SetContract(ctx, &downA) - keeper.SetContract(ctx, &downB) - - require.NotPanics(t, func() { keeper.ClearDependenciesForContract(ctx, contract) }) - keptContractA, err = keeper.GetContract(ctx, keptContractA.ContractAddr) - require.Nil(t, err) - require.Equal(t, types.ContractInfoV2{ - ContractAddr: "sei1yum4v0v5l92jkxn8xpn9mjg7wuldk784ctg424ue8gqvdp88qzlqt6zc4h", - Dependencies: []*types.ContractDependencyInfo{ - { - Dependency: "sei1ehyucudueas79h0zwufcnxtv7s2sfmwc6rt0v0hzczdgvyr3p56qhprg6n", - ImmediateElderSibling: "sei1uyprmp0lu8w8z8kwxp7mxanrtrgn4lp7j557pxe4v8sczzdzl7ysk832hh", - }, - }, - }, keptContractA) - keptContractB, err = keeper.GetContract(ctx, keptContractB.ContractAddr) - require.Nil(t, err) - require.Equal(t, types.ContractInfoV2{ - ContractAddr: "sei1uyprmp0lu8w8z8kwxp7mxanrtrgn4lp7j557pxe4v8sczzdzl7ysk832hh", - Dependencies: []*types.ContractDependencyInfo{ - { - Dependency: "sei1ehyucudueas79h0zwufcnxtv7s2sfmwc6rt0v0hzczdgvyr3p56qhprg6n", - ImmediateYoungerSibling: "sei1yum4v0v5l92jkxn8xpn9mjg7wuldk784ctg424ue8gqvdp88qzlqt6zc4h", - }, - }, - }, keptContractB) - downA, err = keeper.GetContract(ctx, downA.ContractAddr) - require.Nil(t, err) - require.Equal(t, int64(2), downA.NumIncomingDependencies) - downB, err = keeper.GetContract(ctx, downB.ContractAddr) - require.Nil(t, err) - require.Equal(t, int64(0), downB.NumIncomingDependencies) -} - -func TestGetContractWithoutGasCharge(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - _ = keeper.SetContract(ctx, &types.ContractInfoV2{ - Creator: keepertest.TestAccount, - ContractAddr: keepertest.TestContract, - CodeId: 1, - RentBalance: 1000000, - }) - // regular gas meter case - ctx = ctx.WithGasMeter(sdk.NewGasMeterWithMultiplier(ctx, 10000)) - contract, err := keeper.GetContractWithoutGasCharge(ctx, keepertest.TestContract) - require.Nil(t, err) - require.Equal(t, keepertest.TestContract, contract.ContractAddr) - require.Equal(t, uint64(0), ctx.GasMeter().GasConsumed()) - require.Equal(t, uint64(10000), ctx.GasMeter().Limit()) - - // regular gas meter out of gas case - ctx = ctx.WithGasMeter(sdk.NewGasMeterWithMultiplier(ctx, 1)) - contract, err = keeper.GetContractWithoutGasCharge(ctx, keepertest.TestContract) - require.Nil(t, err) - require.Equal(t, keepertest.TestContract, contract.ContractAddr) - require.Equal(t, uint64(0), ctx.GasMeter().GasConsumed()) - require.Equal(t, uint64(1), ctx.GasMeter().Limit()) - - // infinite gas meter case - ctx = ctx.WithGasMeter(sdk.NewInfiniteGasMeterWithMultiplier(ctx)) - contract, err = keeper.GetContractWithoutGasCharge(ctx, keepertest.TestContract) - require.Nil(t, err) - require.Equal(t, keepertest.TestContract, contract.ContractAddr) - require.Equal(t, uint64(0), ctx.GasMeter().GasConsumed()) - require.Equal(t, uint64(0), ctx.GasMeter().Limit()) -} - -func TestGetAllProcessableContractInfo(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - require.Greater(t, keeper.GetMinProcessableRent(ctx), uint64(0)) - - goodContract := types.ContractInfoV2{ - ContractAddr: "sei1avny5w9rcj7lmqmse8kukg2edvq4adqk8vlf58", - NeedOrderMatching: true, - RentBalance: keeper.GetMinProcessableRent(ctx) + 1, - } - noMatchingContract := types.ContractInfoV2{ - ContractAddr: "sei1fww2a30qc4sh25crhugcclaq2supxkpxeyz9lr", - NeedOrderMatching: false, - RentBalance: keeper.GetMinProcessableRent(ctx) + 1, - } - suspendedContract := types.ContractInfoV2{ - ContractAddr: "sei1hh95z3a5vk560khjnnkd3en8r0hu063mw64jzd", - NeedOrderMatching: true, - RentBalance: keeper.GetMinProcessableRent(ctx) + 1, - Suspended: true, - } - outOfRentContract := types.ContractInfoV2{ - ContractAddr: "sei1v2ye9tnmzwx5983emm00j0c7tyxqu855ktxw5l", - NeedOrderMatching: true, - RentBalance: keeper.GetMinProcessableRent(ctx) - 1, - } - require.NoError(t, keeper.SetContract(ctx, &goodContract)) - require.NoError(t, keeper.SetContract(ctx, &noMatchingContract)) - require.NoError(t, keeper.SetContract(ctx, &suspendedContract)) - require.NoError(t, keeper.SetContract(ctx, &outOfRentContract)) - - processableContracts := keeper.GetAllProcessableContractInfo(ctx) - require.Equal(t, 1, len(processableContracts)) - require.Equal(t, "sei1avny5w9rcj7lmqmse8kukg2edvq4adqk8vlf58", processableContracts[0].ContractAddr) -} diff --git a/x/dex/keeper/epoch.go b/x/dex/keeper/epoch.go deleted file mode 100644 index 33f8012af..000000000 --- a/x/dex/keeper/epoch.go +++ /dev/null @@ -1,26 +0,0 @@ -package keeper - -import ( - "encoding/binary" - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - -const EpochKey = "epoch" - -func (k Keeper) SetEpoch(ctx sdk.Context, epoch uint64) { - store := ctx.KVStore(k.storeKey) - bz := make([]byte, 8) - binary.BigEndian.PutUint64(bz, epoch) - store.Set([]byte(EpochKey), bz) - ctx.Logger().Info(fmt.Sprintf("Current epoch %d", epoch)) -} - -func (k Keeper) IsNewEpoch(ctx sdk.Context) (bool, uint64) { - store := ctx.KVStore(k.storeKey) - b := store.Get([]byte(EpochKey)) - lastEpoch := binary.BigEndian.Uint64(b) - currentEpoch := k.EpochKeeper.GetEpoch(ctx).CurrentEpoch - return currentEpoch > lastEpoch, currentEpoch -} diff --git a/x/dex/keeper/keeper.go b/x/dex/keeper/keeper.go deleted file mode 100644 index f89bf7ded..000000000 --- a/x/dex/keeper/keeper.go +++ /dev/null @@ -1,78 +0,0 @@ -package keeper - -import ( - "fmt" - - "github.com/tendermint/tendermint/libs/log" - - "github.com/CosmWasm/wasmd/x/wasm" - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" - paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - dexcache "github.com/sei-protocol/sei-chain/x/dex/cache" - "github.com/sei-protocol/sei-chain/x/dex/types" - epochkeeper "github.com/sei-protocol/sei-chain/x/epoch/keeper" -) - -type ( - Keeper struct { - Cdc codec.BinaryCodec - storeKey sdk.StoreKey - memKey sdk.StoreKey - Paramstore paramtypes.Subspace - AccountKeeper authkeeper.AccountKeeper - EpochKeeper epochkeeper.Keeper - BankKeeper bankkeeper.Keeper - WasmKeeper wasm.Keeper - MemState *dexcache.MemState - } -) - -func NewKeeper( - cdc codec.BinaryCodec, - storeKey, - memKey sdk.StoreKey, - ps paramtypes.Subspace, - epochKeeper epochkeeper.Keeper, - bankKeeper bankkeeper.Keeper, - accountKeeper authkeeper.AccountKeeper, -) *Keeper { - // set KeyTable if it has not already been set - if !ps.HasKeyTable() { - ps = ps.WithKeyTable(types.ParamKeyTable()) - } - return &Keeper{ - Cdc: cdc, - storeKey: storeKey, - memKey: memKey, - Paramstore: ps, - EpochKeeper: epochKeeper, - BankKeeper: bankKeeper, - AccountKeeper: accountKeeper, - MemState: dexcache.NewMemState(memKey), - } -} - -func (k Keeper) Logger(ctx sdk.Context) log.Logger { - return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) -} - -func (k Keeper) GetStoreKey() sdk.StoreKey { - return k.storeKey -} - -func (k Keeper) GetMemStoreKey() sdk.StoreKey { - return k.memKey -} - -func (k *Keeper) SetWasmKeeper(wasmKeeper *wasm.Keeper) { - k.WasmKeeper = *wasmKeeper -} - -func (k Keeper) CreateModuleAccount(ctx sdk.Context) { - moduleAcc := authtypes.NewEmptyModuleAccount(types.ModuleName, authtypes.Burner) - k.AccountKeeper.SetModuleAccount(ctx, moduleAcc) -} diff --git a/x/dex/keeper/long_book.go b/x/dex/keeper/long_book.go deleted file mode 100644 index d8f7e8c2f..000000000 --- a/x/dex/keeper/long_book.go +++ /dev/null @@ -1,184 +0,0 @@ -package keeper - -import ( - "github.com/cosmos/cosmos-sdk/store/prefix" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/query" - "github.com/sei-protocol/sei-chain/x/dex/types" - dexutils "github.com/sei-protocol/sei-chain/x/dex/utils" -) - -// SetLongBook set a specific longBook in the store -func (k Keeper) SetLongBook(ctx sdk.Context, contractAddr string, longBook types.LongBook) { - store := prefix.NewStore( - ctx.KVStore(k.storeKey), - types.OrderBookPrefix( - true, contractAddr, longBook.Entry.PriceDenom, longBook.Entry.AssetDenom, - ), - ) - b := k.Cdc.MustMarshal(&longBook) - store.Set(GetKeyForLongBook(longBook), b) -} - -func (k Keeper) SetLongOrderBookEntry(ctx sdk.Context, contractAddr string, longBook types.OrderBookEntry) { - k.SetLongBook(ctx, contractAddr, *longBook.(*types.LongBook)) -} - -func (k Keeper) GetLongBookByPrice(ctx sdk.Context, contractAddr string, price sdk.Dec, priceDenom string, assetDenom string) (val types.LongBook, found bool) { - store := prefix.NewStore( - ctx.KVStore(k.storeKey), - types.OrderBookPrefix( - true, contractAddr, priceDenom, assetDenom, - ), - ) - b := store.Get(GetKeyForPrice(price)) - if b == nil { - return val, false - } - k.Cdc.MustUnmarshal(b, &val) - return val, true -} - -func (k Keeper) GetLongOrderBookEntryByPrice(ctx sdk.Context, contractAddr string, price sdk.Dec, priceDenom string, assetDenom string) (types.OrderBookEntry, bool) { - entry, found := k.GetLongBookByPrice(ctx, contractAddr, price, priceDenom, assetDenom) - return &entry, found -} - -func (k Keeper) RemoveLongBookByPrice(ctx sdk.Context, contractAddr string, price sdk.Dec, priceDenom string, assetDenom string) { - store := prefix.NewStore( - ctx.KVStore(k.storeKey), - types.OrderBookPrefix( - true, contractAddr, priceDenom, assetDenom, - ), - ) - store.Delete(GetKeyForPrice(price)) -} - -// GetAllLongBook returns all longBook -func (k Keeper) GetAllLongBook(ctx sdk.Context, contractAddr string) (list []types.LongBook) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.ContractKeyPrefix(types.LongBookKey, contractAddr)) - iterator := sdk.KVStorePrefixIterator(store, []byte{}) - - defer iterator.Close() - - for ; iterator.Valid(); iterator.Next() { - var val types.LongBook - k.Cdc.MustUnmarshal(iterator.Value(), &val) - list = append(list, val) - } - - return -} - -func (k Keeper) GetAllLongBookForPair(ctx sdk.Context, contractAddr string, priceDenom string, assetDenom string) (list []types.OrderBookEntry) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.OrderBookPrefix(true, contractAddr, priceDenom, assetDenom)) - iterator := sdk.KVStorePrefixIterator(store, []byte{}) - - defer iterator.Close() - - for ; iterator.Valid(); iterator.Next() { - var val types.LongBook - k.Cdc.MustUnmarshal(iterator.Value(), &val) - list = append(list, &val) - } - - return -} - -func (k Keeper) GetTopNLongBooksForPair(ctx sdk.Context, contractAddr string, priceDenom string, assetDenom string, n int) (list []types.OrderBookEntry) { - if n == 0 { - return - } - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.OrderBookPrefix(true, contractAddr, priceDenom, assetDenom)) - iterator := sdk.KVStoreReversePrefixIterator(store, []byte{}) - - defer iterator.Close() - - for ; iterator.Valid(); iterator.Next() { - var val types.LongBook - k.Cdc.MustUnmarshal(iterator.Value(), &val) - list = append(list, &val) - if len(list) == n { - break - } - } - - return -} - -// Load the first (up to) N long book entries whose price are smaller than the specified limit -// in reverse sorted order. -// Parameters: -// -// n: the largest number of entries to load -// startExclusive: the price limit -func (k Keeper) GetTopNLongBooksForPairStarting(ctx sdk.Context, contractAddr string, priceDenom string, assetDenom string, n int, startExclusive sdk.Dec) (list []types.OrderBookEntry) { - if n == 0 { - return - } - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.OrderBookPrefix(true, contractAddr, priceDenom, assetDenom)) - iterator := sdk.KVStoreReversePrefixIterator(store, []byte{}) - - defer iterator.Close() - - // Fast-forward - // TODO: add iterator interface that allows starting at a certain subkey under prefix - for ; iterator.Valid(); iterator.Next() { - key := dexutils.BytesToDec(iterator.Key()) - if key.LT(startExclusive) { - break - } - } - - for ; iterator.Valid(); iterator.Next() { - var val types.LongBook - k.Cdc.MustUnmarshal(iterator.Value(), &val) - list = append(list, &val) - if len(list) == n { - break - } - } - - return -} - -func (k Keeper) GetAllLongBookForPairPaginated(ctx sdk.Context, contractAddr string, priceDenom string, assetDenom string, page *query.PageRequest) (list []types.LongBook, pageRes *query.PageResponse, err error) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.OrderBookPrefix(true, contractAddr, priceDenom, assetDenom)) - - pageRes, err = query.Paginate(store, page, func(key []byte, value []byte) error { - var longBook types.LongBook - if err := k.Cdc.Unmarshal(value, &longBook); err != nil { - return err - } - - list = append(list, longBook) - return nil - }) - - return -} - -func (k Keeper) GetLongAllocationForOrderID(ctx sdk.Context, contractAddr string, priceDenom string, assetDenom string, price sdk.Dec, orderID uint64) (*types.Allocation, bool) { - orderBook, found := k.GetLongBookByPrice(ctx, contractAddr, price, priceDenom, assetDenom) - if !found { - return nil, false - } - for _, allocation := range orderBook.Entry.Allocations { - if allocation.OrderId == orderID { - return allocation, true - } - } - return nil, false -} - -func (k Keeper) RemoveAllLongBooksForContract(ctx sdk.Context, contractAddr string) { - k.removeAllForPrefix(ctx, types.OrderBookContractPrefix(true, contractAddr)) -} - -func GetKeyForLongBook(longBook types.LongBook) []byte { - return GetKeyForPrice(longBook.Entry.Price) -} - -func GetKeyForPrice(price sdk.Dec) []byte { - return dexutils.DecToBigEndian(price) -} diff --git a/x/dex/keeper/long_book_test.go b/x/dex/keeper/long_book_test.go deleted file mode 100644 index a515cf0b4..000000000 --- a/x/dex/keeper/long_book_test.go +++ /dev/null @@ -1,92 +0,0 @@ -package keeper_test - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/testutil/nullify" - "github.com/sei-protocol/sei-chain/utils" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestLongBookGet(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - items := keepertest.CreateNLongBook(keeper, ctx, 10) - for i, item := range items { - got, found := keeper.GetLongBookByPrice(ctx, keepertest.TestContract, sdk.NewDec(int64(i)), keepertest.TestPriceDenom, keepertest.TestAssetDenom) - require.True(t, found) - require.Equal(t, - nullify.Fill(&item), - nullify.Fill(&got), - ) - } -} - -func TestLongBookRemove(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - items := keepertest.CreateNLongBook(keeper, ctx, 10) - for i := range items { - keeper.RemoveLongBookByPrice(ctx, keepertest.TestContract, sdk.NewDec(int64(i)), keepertest.TestPriceDenom, keepertest.TestAssetDenom) - _, found := keeper.GetLongBookByPrice(ctx, keepertest.TestContract, sdk.NewDec(int64(i)), keepertest.TestPriceDenom, keepertest.TestAssetDenom) - require.False(t, found) - } -} - -func TestLongBookGetAll(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - items := keepertest.CreateNLongBook(keeper, ctx, 10) - require.ElementsMatch(t, - nullify.Fill(items), - nullify.Fill(keeper.GetAllLongBook(ctx, keepertest.TestContract)), - ) -} - -func TestGetTopNLongBooksForPair(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - prices := []string{"9.99", "0.001", "90.0", "10", "10.01", "9.9", "9.0", "1"} - for _, price := range prices { - keeper.SetLongBook(ctx, keepertest.TestContract, types.LongBook{ - Price: sdk.MustNewDecFromStr(price), - Entry: &types.OrderEntry{ - Price: sdk.MustNewDecFromStr(price), - PriceDenom: keepertest.TestPriceDenom, - AssetDenom: keepertest.TestAssetDenom, - }, - }) - } - expected := []sdk.Dec{ - sdk.MustNewDecFromStr("90.0"), - sdk.MustNewDecFromStr("10.01"), - sdk.MustNewDecFromStr("10"), - sdk.MustNewDecFromStr("9.99"), - sdk.MustNewDecFromStr("9.9"), - sdk.MustNewDecFromStr("9.0"), - sdk.MustNewDecFromStr("1"), - sdk.MustNewDecFromStr("0.001"), - } - loaded := keeper.GetTopNLongBooksForPair(ctx, keepertest.TestContract, keepertest.TestPriceDenom, keepertest.TestAssetDenom, 10) - require.Equal(t, expected, utils.Map(loaded, func(b types.OrderBookEntry) sdk.Dec { return b.GetPrice() })) -} - -func TestGetTopNLongBooksForPairStarting(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - prices := []string{"9.99", "0.001", "90.0", "10", "10.01", "9.9", "9.0", "1"} - for _, price := range prices { - keeper.SetLongBook(ctx, keepertest.TestContract, types.LongBook{ - Price: sdk.MustNewDecFromStr(price), - Entry: &types.OrderEntry{ - Price: sdk.MustNewDecFromStr(price), - PriceDenom: keepertest.TestPriceDenom, - AssetDenom: keepertest.TestAssetDenom, - }, - }) - } - expected := []sdk.Dec{ - sdk.MustNewDecFromStr("9.99"), - sdk.MustNewDecFromStr("9.9"), - } - loaded := keeper.GetTopNLongBooksForPairStarting(ctx, keepertest.TestContract, keepertest.TestPriceDenom, keepertest.TestAssetDenom, 2, sdk.MustNewDecFromStr("9.999")) - require.Equal(t, expected, utils.Map(loaded, func(b types.OrderBookEntry) sdk.Dec { return b.GetPrice() })) -} diff --git a/x/dex/keeper/match_result.go b/x/dex/keeper/match_result.go deleted file mode 100644 index 09424196c..000000000 --- a/x/dex/keeper/match_result.go +++ /dev/null @@ -1,45 +0,0 @@ -package keeper - -import ( - "github.com/cosmos/cosmos-sdk/store/prefix" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -const MatchResultKey = "match-result" - -func (k Keeper) SetMatchResult(ctx sdk.Context, contractAddr string, result *types.MatchResult) { - store := prefix.NewStore( - ctx.KVStore(k.storeKey), - types.MatchResultPrefix(contractAddr), - ) - height := ctx.BlockHeight() - result.Height = height - result.ContractAddr = contractAddr - bz, err := result.Marshal() - if err != nil { - panic(err) - } - store.Set([]byte(MatchResultKey), bz) -} - -func (k Keeper) GetMatchResultState(ctx sdk.Context, contractAddr string) (*types.MatchResult, bool) { - store := prefix.NewStore( - ctx.KVStore(k.storeKey), - types.MatchResultPrefix(contractAddr), - ) - bz := store.Get([]byte(MatchResultKey)) - result := types.MatchResult{} - if err := result.Unmarshal(bz); err != nil { - panic(err) - } - return &result, true -} - -func (k Keeper) DeleteMatchResultState(ctx sdk.Context, contractAddr string) { - store := prefix.NewStore( - ctx.KVStore(k.storeKey), - types.MatchResultPrefix(contractAddr), - ) - store.Delete([]byte(MatchResultKey)) -} diff --git a/x/dex/keeper/msgserver/msg_server.go b/x/dex/keeper/msgserver/msg_server.go deleted file mode 100644 index 8d459eeb0..000000000 --- a/x/dex/keeper/msgserver/msg_server.go +++ /dev/null @@ -1,18 +0,0 @@ -package msgserver - -import ( - "github.com/sei-protocol/sei-chain/x/dex/keeper" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -type msgServer struct { - keeper.Keeper -} - -// NewMsgServerImpl returns an implementation of the MsgServer interface -// for the provided Keeper. -func NewMsgServerImpl(keeper keeper.Keeper) types.MsgServer { - return &msgServer{Keeper: keeper} -} - -var _ types.MsgServer = msgServer{} diff --git a/x/dex/keeper/msgserver/msg_server_cancel_orders.go b/x/dex/keeper/msgserver/msg_server_cancel_orders.go deleted file mode 100644 index 8ca3a4a1d..000000000 --- a/x/dex/keeper/msgserver/msg_server_cancel_orders.go +++ /dev/null @@ -1,12 +0,0 @@ -package msgserver - -import ( - "context" - - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -func (k msgServer) CancelOrders(goCtx context.Context, msg *types.MsgCancelOrders) (*types.MsgCancelOrdersResponse, error) { - return nil, sdkerrors.Wrapf(sdkerrors.ErrNotSupported, "deprecated") -} diff --git a/x/dex/keeper/msgserver/msg_server_cancel_orders_test.go b/x/dex/keeper/msgserver/msg_server_cancel_orders_test.go deleted file mode 100644 index 88f88473c..000000000 --- a/x/dex/keeper/msgserver/msg_server_cancel_orders_test.go +++ /dev/null @@ -1,36 +0,0 @@ -package msgserver_test - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex/keeper/msgserver" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestCancelOrder(t *testing.T) { - // store a long limit order to the orderbook - keeper, ctx := keepertest.DexKeeper(t) - - // cancel order - msg := &types.MsgCancelOrders{ - Creator: keepertest.TestAccount, - ContractAddr: keepertest.TestContract, - Cancellations: []*types.Cancellation{ - { - Price: sdk.OneDec(), - PositionDirection: types.PositionDirection_LONG, - PriceDenom: keepertest.TestPriceDenom, - AssetDenom: keepertest.TestAssetDenom, - Id: 1, - }, - }, - } - wctx := sdk.WrapSDKContext(ctx) - server := msgserver.NewMsgServerImpl(*keeper) - _, err := server.CancelOrders(wctx, msg) - require.EqualError(t, err, sdkerrors.Wrapf(sdkerrors.ErrNotSupported, "deprecated").Error()) -} diff --git a/x/dex/keeper/msgserver/msg_server_contract_deposit_rent.go b/x/dex/keeper/msgserver/msg_server_contract_deposit_rent.go deleted file mode 100644 index d1a4cf329..000000000 --- a/x/dex/keeper/msgserver/msg_server_contract_deposit_rent.go +++ /dev/null @@ -1,12 +0,0 @@ -package msgserver - -import ( - "context" - - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -func (k msgServer) ContractDepositRent(goCtx context.Context, msg *types.MsgContractDepositRent) (*types.MsgContractDepositRentResponse, error) { - return nil, sdkerrors.Wrapf(sdkerrors.ErrNotSupported, "deprecated") -} diff --git a/x/dex/keeper/msgserver/msg_server_contract_deposit_rent_test.go b/x/dex/keeper/msgserver/msg_server_contract_deposit_rent_test.go deleted file mode 100644 index 894ba170e..000000000 --- a/x/dex/keeper/msgserver/msg_server_contract_deposit_rent_test.go +++ /dev/null @@ -1,34 +0,0 @@ -package msgserver_test - -import ( - "context" - "testing" - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex" - dexcache "github.com/sei-protocol/sei-chain/x/dex/cache" - "github.com/sei-protocol/sei-chain/x/dex/types" - dexutils "github.com/sei-protocol/sei-chain/x/dex/utils" - "github.com/stretchr/testify/require" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" -) - -func TestDepositRent(t *testing.T) { - testApp := keepertest.TestApp() - ctx := testApp.BaseApp.NewContext(false, tmproto.Header{Time: time.Now()}) - ctx = ctx.WithContext(context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(testApp.GetMemKey(types.MemStoreKey)))) - dexkeeper := testApp.DexKeeper - - depositAccount, _ := sdk.AccAddressFromBech32("sei1yezq49upxhunjjhudql2fnj5dgvcwjj87pn2wx") - - handler := dex.NewHandler(dexkeeper) - _, err := handler(ctx, &types.MsgContractDepositRent{ - Sender: depositAccount.String(), - ContractAddr: TestContractA, - Amount: types.DefaultParams().MinRentDeposit, - }) - require.EqualError(t, err, sdkerrors.Wrapf(sdkerrors.ErrNotSupported, "deprecated").Error()) -} diff --git a/x/dex/keeper/msgserver/msg_server_place_orders.go b/x/dex/keeper/msgserver/msg_server_place_orders.go deleted file mode 100644 index ae7a70700..000000000 --- a/x/dex/keeper/msgserver/msg_server_place_orders.go +++ /dev/null @@ -1,12 +0,0 @@ -package msgserver - -import ( - "context" - - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -func (k msgServer) PlaceOrders(goCtx context.Context, msg *types.MsgPlaceOrders) (*types.MsgPlaceOrdersResponse, error) { - return nil, sdkerrors.Wrapf(sdkerrors.ErrNotSupported, "deprecated") -} diff --git a/x/dex/keeper/msgserver/msg_server_place_orders_fuzz_test.go b/x/dex/keeper/msgserver/msg_server_place_orders_fuzz_test.go deleted file mode 100644 index ec88e75db..000000000 --- a/x/dex/keeper/msgserver/msg_server_place_orders_fuzz_test.go +++ /dev/null @@ -1,65 +0,0 @@ -package msgserver_test - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - fuzzutils "github.com/sei-protocol/sei-chain/testutil/fuzzing" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex/keeper/msgserver" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func FuzzPlaceOrders(f *testing.F) { - f.Add(uint64(0), int32(0), 2, 2, int64(10), false, int64(2), false, keepertest.TestPriceDenom, keepertest.TestAssetDenom, int32(0), int32(0), "", "", false, int64(20)) - f.Fuzz(fuzzTargetPlaceOrders) -} - -func fuzzTargetPlaceOrders( - t *testing.T, - id uint64, - status int32, - accountIdx int, - contractIdx int, - priceI int64, - priceIsNil bool, - quantityI int64, - quantityIsNil bool, - priceDenom string, - assetDenom string, - orderType int32, - positionDirection int32, - data string, - statusDescription string, - fundIsNil bool, - fundAmount int64, -) { - keeper, ctx := keepertest.DexKeeper(t) - contract := fuzzutils.GetContract(contractIdx) - keeper.AddRegisteredPair(ctx, contract, keepertest.TestPair) - keeper.SetPriceTickSizeForPair(ctx, TestContract, keepertest.TestPair, *keepertest.TestPair.PriceTicksize) - keeper.SetQuantityTickSizeForPair(ctx, TestContract, keepertest.TestPair, *keepertest.TestPair.QuantityTicksize) - wctx := sdk.WrapSDKContext(ctx) - msg := &types.MsgPlaceOrders{ - Creator: fuzzutils.GetAccount(accountIdx), - ContractAddr: contract, - Orders: []*types.Order{ - { - Id: id, - Status: types.OrderStatus(status), - Price: fuzzutils.FuzzDec(priceI, priceIsNil), - Quantity: fuzzutils.FuzzDec(quantityI, quantityIsNil), - Data: data, - StatusDescription: statusDescription, - PositionDirection: types.PositionDirection(positionDirection), - OrderType: types.OrderType(orderType), - PriceDenom: priceDenom, - AssetDenom: assetDenom, - }, - }, - Funds: []sdk.Coin{fuzzutils.FuzzCoin(priceDenom, fundIsNil, fundAmount)}, - } - server := msgserver.NewMsgServerImpl(*keeper) - require.NotPanics(t, func() { server.PlaceOrders(wctx, msg) }) -} diff --git a/x/dex/keeper/msgserver/msg_server_place_orders_test.go b/x/dex/keeper/msgserver/msg_server_place_orders_test.go deleted file mode 100644 index d14e3e532..000000000 --- a/x/dex/keeper/msgserver/msg_server_place_orders_test.go +++ /dev/null @@ -1,49 +0,0 @@ -package msgserver_test - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex/keeper/msgserver" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -const ( - TestCreator = "sei1ewxvf5a9wq9zk5nurtl6m9yfxpnhyp7s7uk5sl" - TestContract = "sei14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sh9m79m" -) - -func TestPlaceOrder(t *testing.T) { - msg := &types.MsgPlaceOrders{ - Creator: TestCreator, - ContractAddr: TestContract, - Orders: []*types.Order{ - { - Price: sdk.MustNewDecFromStr("10"), - Quantity: sdk.MustNewDecFromStr("10"), - Data: "", - PositionDirection: types.PositionDirection_LONG, - OrderType: types.OrderType_LIMIT, - PriceDenom: keepertest.TestPriceDenom, - AssetDenom: keepertest.TestAssetDenom, - }, - { - Price: sdk.MustNewDecFromStr("20"), - Quantity: sdk.MustNewDecFromStr("5"), - Data: "", - PositionDirection: types.PositionDirection_SHORT, - OrderType: types.OrderType_MARKET, - PriceDenom: keepertest.TestPriceDenom, - AssetDenom: keepertest.TestAssetDenom, - }, - }, - } - keeper, ctx := keepertest.DexKeeper(t) - wctx := sdk.WrapSDKContext(ctx) - server := msgserver.NewMsgServerImpl(*keeper) - _, err := server.PlaceOrders(wctx, msg) - require.EqualError(t, err, sdkerrors.Wrapf(sdkerrors.ErrNotSupported, "deprecated").Error()) -} diff --git a/x/dex/keeper/msgserver/msg_server_register_contract.go b/x/dex/keeper/msgserver/msg_server_register_contract.go deleted file mode 100644 index 77bec2bd4..000000000 --- a/x/dex/keeper/msgserver/msg_server_register_contract.go +++ /dev/null @@ -1,12 +0,0 @@ -package msgserver - -import ( - "context" - - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -func (k msgServer) RegisterContract(goCtx context.Context, msg *types.MsgRegisterContract) (*types.MsgRegisterContractResponse, error) { - return nil, sdkerrors.Wrapf(sdkerrors.ErrNotSupported, "deprecated") -} diff --git a/x/dex/keeper/msgserver/msg_server_register_contract_test.go b/x/dex/keeper/msgserver/msg_server_register_contract_test.go deleted file mode 100644 index c4bcc6e1c..000000000 --- a/x/dex/keeper/msgserver/msg_server_register_contract_test.go +++ /dev/null @@ -1,34 +0,0 @@ -package msgserver_test - -import ( - "context" - "testing" - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - dexcache "github.com/sei-protocol/sei-chain/x/dex/cache" - "github.com/sei-protocol/sei-chain/x/dex/keeper/msgserver" - "github.com/sei-protocol/sei-chain/x/dex/types" - dexutils "github.com/sei-protocol/sei-chain/x/dex/utils" - "github.com/stretchr/testify/require" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" -) - -const ( - TestContractA = "sei1hrpna9v7vs3stzyd4z3xf00676kf78zpe2u5ksvljswn2vnjp3yslucc3n" -) - -func TestRegisterContract(t *testing.T) { - // Instantiate and get contract address - testApp := keepertest.TestApp() - ctx := testApp.BaseApp.NewContext(false, tmproto.Header{Time: time.Now()}) - ctx = ctx.WithContext(context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(testApp.GetMemKey(types.MemStoreKey)))) - wctx := sdk.WrapSDKContext(ctx) - keeper := testApp.DexKeeper - - server := msgserver.NewMsgServerImpl(keeper) - _, err := server.RegisterContract(wctx, &types.MsgRegisterContract{}) - require.EqualError(t, err, sdkerrors.Wrapf(sdkerrors.ErrNotSupported, "deprecated").Error()) -} diff --git a/x/dex/keeper/msgserver/msg_server_register_pairs.go b/x/dex/keeper/msgserver/msg_server_register_pairs.go deleted file mode 100644 index 582521dd5..000000000 --- a/x/dex/keeper/msgserver/msg_server_register_pairs.go +++ /dev/null @@ -1,12 +0,0 @@ -package msgserver - -import ( - "context" - - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -func (k msgServer) RegisterPairs(goCtx context.Context, msg *types.MsgRegisterPairs) (*types.MsgRegisterPairsResponse, error) { - return nil, sdkerrors.Wrapf(sdkerrors.ErrNotSupported, "deprecated") -} diff --git a/x/dex/keeper/msgserver/msg_server_register_pairs_test.go b/x/dex/keeper/msgserver/msg_server_register_pairs_test.go deleted file mode 100644 index bc4dc9198..000000000 --- a/x/dex/keeper/msgserver/msg_server_register_pairs_test.go +++ /dev/null @@ -1,38 +0,0 @@ -package msgserver_test - -import ( - "context" - "testing" - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - dexcache "github.com/sei-protocol/sei-chain/x/dex/cache" - "github.com/sei-protocol/sei-chain/x/dex/keeper/msgserver" - "github.com/sei-protocol/sei-chain/x/dex/types" - dexutils "github.com/sei-protocol/sei-chain/x/dex/utils" - "github.com/stretchr/testify/require" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" -) - -func TestRegisterPairs(t *testing.T) { - testApp := keepertest.TestApp() - ctx := testApp.BaseApp.NewContext(false, tmproto.Header{Time: time.Now()}) - ctx = ctx.WithContext(context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(testApp.GetMemKey(types.MemStoreKey)))) - wctx := sdk.WrapSDKContext(ctx) - keeper := testApp.DexKeeper - - server := msgserver.NewMsgServerImpl(keeper) - - batchContractPairs := []types.BatchContractPair{} - batchContractPairs = append(batchContractPairs, types.BatchContractPair{ - ContractAddr: TestContractA, - Pairs: []*types.Pair{&keepertest.TestPair}, - }) - _, err := server.RegisterPairs(wctx, &types.MsgRegisterPairs{ - Creator: keepertest.TestAccount, - Batchcontractpair: batchContractPairs, - }) - require.EqualError(t, err, sdkerrors.Wrapf(sdkerrors.ErrNotSupported, "deprecated").Error()) -} diff --git a/x/dex/keeper/msgserver/msg_server_unregister_contract.go b/x/dex/keeper/msgserver/msg_server_unregister_contract.go deleted file mode 100644 index c12650b85..000000000 --- a/x/dex/keeper/msgserver/msg_server_unregister_contract.go +++ /dev/null @@ -1,12 +0,0 @@ -package msgserver - -import ( - "context" - - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -func (k msgServer) UnregisterContract(goCtx context.Context, msg *types.MsgUnregisterContract) (*types.MsgUnregisterContractResponse, error) { - return nil, sdkerrors.Wrapf(sdkerrors.ErrNotSupported, "deprecated") -} diff --git a/x/dex/keeper/msgserver/msg_server_unregister_contract_test.go b/x/dex/keeper/msgserver/msg_server_unregister_contract_test.go deleted file mode 100644 index 2d91979a7..000000000 --- a/x/dex/keeper/msgserver/msg_server_unregister_contract_test.go +++ /dev/null @@ -1,34 +0,0 @@ -package msgserver_test - -import ( - "context" - "testing" - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex" - dexcache "github.com/sei-protocol/sei-chain/x/dex/cache" - "github.com/sei-protocol/sei-chain/x/dex/types" - dexutils "github.com/sei-protocol/sei-chain/x/dex/utils" - "github.com/stretchr/testify/require" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" -) - -func TestUnregisterContractSetSiblings(t *testing.T) { - testApp := keepertest.TestApp() - ctx := testApp.BaseApp.NewContext(false, tmproto.Header{Time: time.Now()}) - ctx = ctx.WithContext(context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(testApp.GetMemKey(types.MemStoreKey)))) - keeper := testApp.DexKeeper - - testAccount, _ := sdk.AccAddressFromBech32("sei1yezq49upxhunjjhudql2fnj5dgvcwjj87pn2wx") - - handler := dex.NewHandler(keeper) - - _, err := handler(ctx, &types.MsgUnregisterContract{ - Creator: testAccount.String(), - ContractAddr: TestContractA, - }) - require.EqualError(t, err, sdkerrors.Wrapf(sdkerrors.ErrNotSupported, "deprecated").Error()) -} diff --git a/x/dex/keeper/msgserver/msg_server_unsuspend_contract.go b/x/dex/keeper/msgserver/msg_server_unsuspend_contract.go deleted file mode 100644 index d1da8c2c5..000000000 --- a/x/dex/keeper/msgserver/msg_server_unsuspend_contract.go +++ /dev/null @@ -1,12 +0,0 @@ -package msgserver - -import ( - "context" - - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -func (k msgServer) UnsuspendContract(goCtx context.Context, msg *types.MsgUnsuspendContract) (*types.MsgUnsuspendContractResponse, error) { - return nil, sdkerrors.Wrapf(sdkerrors.ErrNotSupported, "deprecated") -} diff --git a/x/dex/keeper/msgserver/msg_server_unsuspend_contract_test.go b/x/dex/keeper/msgserver/msg_server_unsuspend_contract_test.go deleted file mode 100644 index a2ac0f3ac..000000000 --- a/x/dex/keeper/msgserver/msg_server_unsuspend_contract_test.go +++ /dev/null @@ -1,23 +0,0 @@ -package msgserver_test - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex/keeper/msgserver" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestUnsuspendContract(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - wctx := sdk.WrapSDKContext(ctx) - server := msgserver.NewMsgServerImpl(*keeper) - _, err := server.UnsuspendContract(wctx, &types.MsgUnsuspendContract{ - Creator: keepertest.TestAccount, - ContractAddr: keepertest.TestContract, - }) - require.EqualError(t, err, sdkerrors.Wrapf(sdkerrors.ErrNotSupported, "deprecated").Error()) -} diff --git a/x/dex/keeper/msgserver/msg_server_update_price_tick_size.go b/x/dex/keeper/msgserver/msg_server_update_price_tick_size.go deleted file mode 100644 index 6a09e1dc7..000000000 --- a/x/dex/keeper/msgserver/msg_server_update_price_tick_size.go +++ /dev/null @@ -1,12 +0,0 @@ -package msgserver - -import ( - "context" - - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -func (k msgServer) UpdatePriceTickSize(goCtx context.Context, msg *types.MsgUpdatePriceTickSize) (*types.MsgUpdateTickSizeResponse, error) { - return nil, sdkerrors.Wrapf(sdkerrors.ErrNotSupported, "deprecated") -} diff --git a/x/dex/keeper/msgserver/msg_server_update_price_tick_size_test.go b/x/dex/keeper/msgserver/msg_server_update_price_tick_size_test.go deleted file mode 100644 index 77ab54fae..000000000 --- a/x/dex/keeper/msgserver/msg_server_update_price_tick_size_test.go +++ /dev/null @@ -1,40 +0,0 @@ -package msgserver_test - -import ( - "context" - "testing" - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - dexcache "github.com/sei-protocol/sei-chain/x/dex/cache" - "github.com/sei-protocol/sei-chain/x/dex/keeper/msgserver" - "github.com/sei-protocol/sei-chain/x/dex/types" - dexutils "github.com/sei-protocol/sei-chain/x/dex/utils" - "github.com/stretchr/testify/require" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" -) - -func TestUpdatePriceTickSize(t *testing.T) { - // Instantiate and get contract address - testApp := keepertest.TestApp() - ctx := testApp.BaseApp.NewContext(false, tmproto.Header{Time: time.Now()}) - ctx = ctx.WithContext(context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(testApp.GetMemKey(types.MemStoreKey)))) - wctx := sdk.WrapSDKContext(ctx) - keeper := testApp.DexKeeper - server := msgserver.NewMsgServerImpl(keeper) - - // Test updated tick size - tickUpdates := []types.TickSize{} - tickUpdates = append(tickUpdates, types.TickSize{ - ContractAddr: TestContractA, - Pair: &keepertest.TestPair, - Ticksize: sdk.MustNewDecFromStr("0.1"), - }) - _, err := server.UpdatePriceTickSize(wctx, &types.MsgUpdatePriceTickSize{ - Creator: keepertest.TestAccount, - TickSizeList: tickUpdates, - }) - require.EqualError(t, err, sdkerrors.Wrapf(sdkerrors.ErrNotSupported, "deprecated").Error()) -} diff --git a/x/dex/keeper/msgserver/msg_server_update_quantity_tick_size.go b/x/dex/keeper/msgserver/msg_server_update_quantity_tick_size.go deleted file mode 100644 index f4e948a54..000000000 --- a/x/dex/keeper/msgserver/msg_server_update_quantity_tick_size.go +++ /dev/null @@ -1,12 +0,0 @@ -package msgserver - -import ( - "context" - - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -func (k msgServer) UpdateQuantityTickSize(goCtx context.Context, msg *types.MsgUpdateQuantityTickSize) (*types.MsgUpdateTickSizeResponse, error) { - return nil, sdkerrors.Wrapf(sdkerrors.ErrNotSupported, "deprecated") -} diff --git a/x/dex/keeper/msgserver/msg_server_update_quantity_tick_size_test.go b/x/dex/keeper/msgserver/msg_server_update_quantity_tick_size_test.go deleted file mode 100644 index eccbf9e45..000000000 --- a/x/dex/keeper/msgserver/msg_server_update_quantity_tick_size_test.go +++ /dev/null @@ -1,41 +0,0 @@ -package msgserver_test - -import ( - "context" - "testing" - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - dexcache "github.com/sei-protocol/sei-chain/x/dex/cache" - "github.com/sei-protocol/sei-chain/x/dex/keeper/msgserver" - "github.com/sei-protocol/sei-chain/x/dex/types" - dexutils "github.com/sei-protocol/sei-chain/x/dex/utils" - "github.com/stretchr/testify/require" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" -) - -func TestUpdateQuantityTickSize(t *testing.T) { - // Instantiate and get contract address - testApp := keepertest.TestApp() - ctx := testApp.BaseApp.NewContext(false, tmproto.Header{Time: time.Now()}) - ctx = ctx.WithContext(context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(testApp.GetMemKey(types.MemStoreKey)))) - wctx := sdk.WrapSDKContext(ctx) - keeper := testApp.DexKeeper - - server := msgserver.NewMsgServerImpl(keeper) - - // Test updated tick size - tickUpdates := []types.TickSize{} - tickUpdates = append(tickUpdates, types.TickSize{ - ContractAddr: TestContractA, - Pair: &keepertest.TestPair, - Ticksize: sdk.MustNewDecFromStr("0.1"), - }) - _, err := server.UpdateQuantityTickSize(wctx, &types.MsgUpdateQuantityTickSize{ - Creator: keepertest.TestAccount, - TickSizeList: tickUpdates, - }) - require.EqualError(t, err, sdkerrors.Wrapf(sdkerrors.ErrNotSupported, "deprecated").Error()) -} diff --git a/x/dex/keeper/msgserver/testdata/hackatom.wasm b/x/dex/keeper/msgserver/testdata/hackatom.wasm deleted file mode 100644 index 183eef304c9de413a24884ec6611ee0d13434fae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 208805 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

}GU#h*Z)$o|;7eU!8k$7&m@*^f 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 D^F!=F diff --git a/x/dex/keeper/msgserver/validations.go b/x/dex/keeper/msgserver/validations.go deleted file mode 100644 index cdbbb0647..000000000 --- a/x/dex/keeper/msgserver/validations.go +++ /dev/null @@ -1,40 +0,0 @@ -package msgserver - -import ( - "fmt" - "math" - - wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -// Since cosmwasm would amplify gas limit by a multiplier for its internal gas metering, -// we want to make sure the amplified result doesn't exceed uint64 limit. -func (k msgServer) ValidateRentBalance(ctx sdk.Context, rentBalance uint64) error { - maxAllowedRent := k.maxAllowedRentBalance() - minAllowedRent := k.minAllowedRentBalance(ctx) - if rentBalance > maxAllowedRent || rentBalance < minAllowedRent { - return fmt.Errorf("rent balance %d is either bigger than the maximum allowed rent balance %d, or smaller than the minimal allowed balance %d", - rentBalance, maxAllowedRent, minAllowedRent) - } - return nil -} - -func (k msgServer) ValidateSuspension(ctx sdk.Context, contractAddress string) error { - contract, err := k.GetContract(ctx, contractAddress) - if err == nil && contract.Suspended { - return types.ErrContractSuspended - } - return nil -} - -func (k msgServer) maxAllowedRentBalance() uint64 { - // TODO: replace with a wasm keeper query once its gas registry is made public - return uint64(math.MaxUint64) / wasmkeeper.DefaultGasMultiplier -} - -func (k msgServer) minAllowedRentBalance(ctx sdk.Context) uint64 { - params := k.GetParams(ctx) - return params.MinRentDeposit -} diff --git a/x/dex/keeper/order_count.go b/x/dex/keeper/order_count.go deleted file mode 100644 index 5b72366cb..000000000 --- a/x/dex/keeper/order_count.go +++ /dev/null @@ -1,56 +0,0 @@ -package keeper - -import ( - "encoding/binary" - "fmt" - - "github.com/cosmos/cosmos-sdk/store/prefix" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -func (k Keeper) SetOrderCount(ctx sdk.Context, contractAddr string, priceDenom string, assetDenom string, direction types.PositionDirection, price sdk.Dec, count uint64) error { - store := prefix.NewStore( - ctx.KVStore(k.storeKey), - types.OrderCountPrefix(contractAddr, priceDenom, assetDenom, direction == types.PositionDirection_LONG), - ) - key, err := price.Marshal() - if err != nil { - return err - } - value := make([]byte, 8) - binary.BigEndian.PutUint64(value, count) - store.Set(key, value) - return nil -} - -func (k Keeper) GetOrderCountState(ctx sdk.Context, contractAddr string, priceDenom string, assetDenom string, direction types.PositionDirection, price sdk.Dec) uint64 { - store := prefix.NewStore( - ctx.KVStore(k.storeKey), - types.OrderCountPrefix(contractAddr, priceDenom, assetDenom, direction == types.PositionDirection_LONG), - ) - key, err := price.Marshal() - if err != nil { - ctx.Logger().Error(fmt.Sprintf("error marshal provided price %s due to %s", price.String(), err)) - return 0 - } - value := store.Get(key) - if value == nil { - return 0 - } - return binary.BigEndian.Uint64(value) -} - -func (k Keeper) DecreaseOrderCount(ctx sdk.Context, contractAddr string, priceDenom string, assetDenom string, direction types.PositionDirection, price sdk.Dec, count uint64) error { - oldCount := k.GetOrderCountState(ctx, contractAddr, priceDenom, assetDenom, direction, price) - newCount := uint64(0) - if oldCount > count { - newCount = oldCount - count - } - return k.SetOrderCount(ctx, contractAddr, priceDenom, assetDenom, direction, price, newCount) -} - -func (k Keeper) IncreaseOrderCount(ctx sdk.Context, contractAddr string, priceDenom string, assetDenom string, direction types.PositionDirection, price sdk.Dec, count uint64) error { - oldCount := k.GetOrderCountState(ctx, contractAddr, priceDenom, assetDenom, direction, price) - return k.SetOrderCount(ctx, contractAddr, priceDenom, assetDenom, direction, price, oldCount+count) -} diff --git a/x/dex/keeper/order_count_test.go b/x/dex/keeper/order_count_test.go deleted file mode 100644 index 1fe604933..000000000 --- a/x/dex/keeper/order_count_test.go +++ /dev/null @@ -1,35 +0,0 @@ -package keeper_test - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestGetSetOrderCount(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - for _, direction := range []types.PositionDirection{ - types.PositionDirection_LONG, - types.PositionDirection_SHORT, - } { - require.Equal(t, uint64(0), keeper.GetOrderCountState(ctx, keepertest.TestContract, keepertest.TestPair.PriceDenom, keepertest.TestPair.AssetDenom, direction, sdk.NewDec(1))) - require.Nil(t, keeper.SetOrderCount(ctx, keepertest.TestContract, keepertest.TestPair.PriceDenom, keepertest.TestPair.AssetDenom, direction, sdk.NewDec(1), 5)) - require.Equal(t, uint64(5), keeper.GetOrderCountState(ctx, keepertest.TestContract, keepertest.TestPair.PriceDenom, keepertest.TestPair.AssetDenom, direction, sdk.NewDec(1))) - } -} - -func TestIncreaseOrderCount(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - keeper.IncreaseOrderCount(ctx, keepertest.TestContract, keepertest.TestPair.PriceDenom, keepertest.TestPair.AssetDenom, types.PositionDirection_LONG, sdk.NewDec(1), 10) - require.Equal(t, uint64(10), keeper.GetOrderCountState(ctx, keepertest.TestContract, keepertest.TestPair.PriceDenom, keepertest.TestPair.AssetDenom, types.PositionDirection_LONG, sdk.NewDec(1))) -} - -func TestDecreaseOrderCount(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - require.Nil(t, keeper.SetOrderCount(ctx, keepertest.TestContract, keepertest.TestPair.PriceDenom, keepertest.TestPair.AssetDenom, types.PositionDirection_LONG, sdk.NewDec(1), 10)) - keeper.DecreaseOrderCount(ctx, keepertest.TestContract, keepertest.TestPair.PriceDenom, keepertest.TestPair.AssetDenom, types.PositionDirection_LONG, sdk.NewDec(1), 5) - require.Equal(t, uint64(5), keeper.GetOrderCountState(ctx, keepertest.TestContract, keepertest.TestPair.PriceDenom, keepertest.TestPair.AssetDenom, types.PositionDirection_LONG, sdk.NewDec(1))) -} diff --git a/x/dex/keeper/order_placement.go b/x/dex/keeper/order_placement.go deleted file mode 100644 index b6d5fcec6..000000000 --- a/x/dex/keeper/order_placement.go +++ /dev/null @@ -1,33 +0,0 @@ -package keeper - -import ( - "encoding/binary" - - "github.com/cosmos/cosmos-sdk/store/prefix" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -func (k Keeper) GetNextOrderID(ctx sdk.Context, contractAddr string) uint64 { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.NextOrderIDPrefix(contractAddr)) - byteKey := types.KeyPrefix(types.NextOrderIDKey) - bz := store.Get(byteKey) - if bz == nil { - return 0 - } - return binary.BigEndian.Uint64(bz) -} - -func (k Keeper) SetNextOrderID(ctx sdk.Context, contractAddr string, nextID uint64) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.NextOrderIDPrefix(contractAddr)) - byteKey := types.KeyPrefix(types.NextOrderIDKey) - bz := make([]byte, 8) - binary.BigEndian.PutUint64(bz, nextID) - store.Set(byteKey, bz) -} - -func (k Keeper) DeleteNextOrderID(ctx sdk.Context, contractAddr string) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.NextOrderIDPrefix(contractAddr)) - byteKey := types.KeyPrefix(types.NextOrderIDKey) - store.Delete(byteKey) -} diff --git a/x/dex/keeper/pair.go b/x/dex/keeper/pair.go deleted file mode 100644 index 914131cc9..000000000 --- a/x/dex/keeper/pair.go +++ /dev/null @@ -1,56 +0,0 @@ -package keeper - -import ( - "github.com/cosmos/cosmos-sdk/store/prefix" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -func (k Keeper) AddRegisteredPair(ctx sdk.Context, contractAddr string, pair types.Pair) bool { - // only add pairs that haven't been added before - if k.HasRegisteredPair(ctx, contractAddr, pair.PriceDenom, pair.AssetDenom) { - return false - } - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.RegisteredPairPrefix(contractAddr)) - store.Set(types.PairPrefix(pair.PriceDenom, pair.AssetDenom), k.Cdc.MustMarshal(&pair)) - return true -} - -func (k Keeper) HasRegisteredPair(ctx sdk.Context, contractAddr string, priceDenom string, assetDenom string) bool { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.RegisteredPairPrefix(contractAddr)) - return store.Has(types.PairPrefix(priceDenom, assetDenom)) -} - -func (k Keeper) GetRegisteredPair(ctx sdk.Context, contractAddr string, priceDenom string, assetDenom string) (types.Pair, bool) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.RegisteredPairPrefix(contractAddr)) - b := store.Get(types.PairPrefix(priceDenom, assetDenom)) - res := types.Pair{} - if b == nil { - return res, false - } - err := res.Unmarshal(b) - if err != nil { - panic(err) - } - return res, true -} - -func (k Keeper) GetAllRegisteredPairs(ctx sdk.Context, contractAddr string) []types.Pair { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.RegisteredPairPrefix(contractAddr)) - iterator := sdk.KVStorePrefixIterator(store, []byte{}) - - list := []types.Pair{} - defer iterator.Close() - - for ; iterator.Valid(); iterator.Next() { - var val types.Pair - k.Cdc.MustUnmarshal(iterator.Value(), &val) - list = append(list, val) - } - - return list -} - -func (k Keeper) DeleteAllRegisteredPairsForContract(ctx sdk.Context, contractAddr string) { - k.removeAllForPrefix(ctx, types.RegisteredPairPrefix(contractAddr)) -} diff --git a/x/dex/keeper/pair_test.go b/x/dex/keeper/pair_test.go deleted file mode 100644 index 8dcbe65d2..000000000 --- a/x/dex/keeper/pair_test.go +++ /dev/null @@ -1,41 +0,0 @@ -package keeper_test - -import ( - "testing" - - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/testutil/nullify" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestAddGetPair(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - keeper.AddRegisteredPair(ctx, keepertest.TestContract, types.Pair{ - PriceDenom: keepertest.TestPriceDenom, - AssetDenom: keepertest.TestAssetDenom, - PriceTicksize: &keepertest.TestTicksize, - QuantityTicksize: &keepertest.TestTicksize, - }) - require.ElementsMatch(t, - nullify.Fill([]types.Pair{{ - PriceDenom: keepertest.TestPriceDenom, - AssetDenom: keepertest.TestAssetDenom, - PriceTicksize: &keepertest.TestTicksize, - QuantityTicksize: &keepertest.TestTicksize, - }}), - nullify.Fill(keeper.GetAllRegisteredPairs(ctx, keepertest.TestContract)), - ) - - pair, found := keeper.GetRegisteredPair(ctx, keepertest.TestContract, keepertest.TestPriceDenom, keepertest.TestAssetDenom) - require.True(t, found) - require.Equal(t, types.Pair{ - PriceDenom: keepertest.TestPriceDenom, - AssetDenom: keepertest.TestAssetDenom, - PriceTicksize: &keepertest.TestTicksize, - QuantityTicksize: &keepertest.TestTicksize, - }, pair) - hasPair := keeper.HasRegisteredPair(ctx, keepertest.TestContract, keepertest.TestPriceDenom, keepertest.TestAssetDenom) - require.True(t, hasPair) - -} diff --git a/x/dex/keeper/params.go b/x/dex/keeper/params.go deleted file mode 100644 index 2e4c77c02..000000000 --- a/x/dex/keeper/params.go +++ /dev/null @@ -1,42 +0,0 @@ -package keeper - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -// GetParams get all parameters as types.Params -func (k Keeper) GetParams(ctx sdk.Context) types.Params { - params := types.Params{} - k.Paramstore.GetParamSet(ctx, ¶ms) - return params -} - -func (k Keeper) GetSettlementGasAllowance(ctx sdk.Context, numSettlements int) uint64 { - return k.GetParams(ctx).GasAllowancePerSettlement * uint64(numSettlements) -} - -func (k Keeper) GetMinProcessableRent(ctx sdk.Context) uint64 { - return k.GetParams(ctx).MinProcessableRent -} - -func (k Keeper) GetOrderBookEntriesPerLoad(ctx sdk.Context) uint64 { - return k.GetParams(ctx).OrderBookEntriesPerLoad -} - -func (k Keeper) GetContractUnsuspendCost(ctx sdk.Context) uint64 { - return k.GetParams(ctx).ContractUnsuspendCost -} - -func (k Keeper) GetMaxOrderPerPrice(ctx sdk.Context) uint64 { - return k.GetParams(ctx).MaxOrderPerPrice -} - -func (k Keeper) GetMaxPairsPerContract(ctx sdk.Context) uint64 { - return k.GetParams(ctx).MaxPairsPerContract -} - -// SetParams set the params -func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { - k.Paramstore.SetParamSet(ctx, ¶ms) -} diff --git a/x/dex/keeper/params_test.go b/x/dex/keeper/params_test.go deleted file mode 100644 index 1bbab914e..000000000 --- a/x/dex/keeper/params_test.go +++ /dev/null @@ -1,24 +0,0 @@ -package keeper_test - -import ( - "testing" - - testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestGetParams(t *testing.T) { - k, ctx := testkeeper.DexKeeper(t) - params := types.DefaultParams() - - k.SetParams(ctx, params) - - require.EqualValues(t, params, k.GetParams(ctx)) -} - -func TestGetSettlementGasAllowance(t *testing.T) { - k, ctx := testkeeper.DexKeeper(t) - gasAllowance := k.GetSettlementGasAllowance(ctx, 10) - require.Equal(t, uint64(10)*types.DefaultGasAllowancePerSettlement, gasAllowance) -} diff --git a/x/dex/keeper/price.go b/x/dex/keeper/price.go deleted file mode 100644 index d18cc1ce0..000000000 --- a/x/dex/keeper/price.go +++ /dev/null @@ -1,98 +0,0 @@ -package keeper - -import ( - "encoding/binary" - - "github.com/cosmos/cosmos-sdk/store/prefix" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -func (k Keeper) SetPriceState(ctx sdk.Context, price types.Price, contractAddr string) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.PricePrefix(contractAddr, price.Pair.PriceDenom, price.Pair.AssetDenom)) - b := k.Cdc.MustMarshal(&price) - store.Set(GetKeyForTs(price.SnapshotTimestampInSeconds), b) -} - -func (k Keeper) DeletePriceStateBefore(ctx sdk.Context, contractAddr string, timestamp uint64, pair types.Pair) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.PricePrefix(contractAddr, pair.PriceDenom, pair.AssetDenom)) - for _, key := range k.GetPriceKeysToDelete(store, timestamp) { - store.Delete(key) - } -} - -func (k Keeper) GetPriceKeysToDelete(store sdk.KVStore, timestamp uint64) [][]byte { - keys := [][]byte{} - iterator := sdk.KVStorePrefixIterator(store, []byte{}) - defer iterator.Close() - - // Since timestamp is encoded in big endian, the first price being iterated has the smallest timestamp. - for ; iterator.Valid(); iterator.Next() { - priceKey := iterator.Key() - priceTs := binary.BigEndian.Uint64(priceKey) - if priceTs < timestamp { - keys = append(keys, priceKey) - } else { - break - } - } - return keys -} - -func (k Keeper) GetPriceState(ctx sdk.Context, contractAddr string, timestamp uint64, pair types.Pair) (types.Price, bool) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.PricePrefix(contractAddr, pair.PriceDenom, pair.AssetDenom)) - res := types.Price{} - key := GetKeyForTs(timestamp) - if !store.Has(key) { - res.Pair = &pair - return res, false - } - b := store.Get(key) - k.Cdc.MustUnmarshal(b, &res) - return res, true -} - -func (k Keeper) GetAllPrices(ctx sdk.Context, contractAddr string, pair types.Pair) (list []*types.Price) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.PricePrefix(contractAddr, pair.PriceDenom, pair.AssetDenom)) - iterator := sdk.KVStorePrefixIterator(store, []byte{}) - - defer iterator.Close() - - for ; iterator.Valid(); iterator.Next() { - var val types.Price - k.Cdc.MustUnmarshal(iterator.Value(), &val) - list = append(list, &val) - } - - return -} - -func (k Keeper) GetPricesForTwap(ctx sdk.Context, contractAddr string, pair types.Pair, lookback uint64) (list []*types.Price) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.PricePrefix(contractAddr, pair.PriceDenom, pair.AssetDenom)) - iterator := sdk.KVStoreReversePrefixIterator(store, []byte{}) - - defer iterator.Close() - - cutoff := uint64(ctx.BlockTime().Unix()) - lookback - for ; iterator.Valid(); iterator.Next() { - var val types.Price - k.Cdc.MustUnmarshal(iterator.Value(), &val) - // add to list before breaking since we want to include one older price if there is any - list = append(list, &val) - if val.SnapshotTimestampInSeconds < cutoff { - break - } - } - - return -} - -func (k Keeper) RemoveAllPricesForContract(ctx sdk.Context, contractAddr string) { - k.removeAllForPrefix(ctx, types.PriceContractPrefix(contractAddr)) -} - -func GetKeyForTs(ts uint64) []byte { - tsKey := make([]byte, 8) - binary.BigEndian.PutUint64(tsKey, ts) - return tsKey -} diff --git a/x/dex/keeper/price_test.go b/x/dex/keeper/price_test.go deleted file mode 100644 index fa519d47c..000000000 --- a/x/dex/keeper/price_test.go +++ /dev/null @@ -1,20 +0,0 @@ -package keeper_test - -import ( - "testing" - - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/stretchr/testify/require" -) - -func TestDeletePriceStateBefore(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - keepertest.SeedPriceSnapshot(ctx, keeper, "100", 1) - keepertest.SeedPriceSnapshot(ctx, keeper, "101", 2) - keepertest.SeedPriceSnapshot(ctx, keeper, "99", 3) - keeper.DeletePriceStateBefore(ctx, keepertest.TestContract, 2, keepertest.TestPair) - prices := keeper.GetAllPrices(ctx, keepertest.TestContract, keepertest.TestPair) - require.Equal(t, 2, len(prices)) - require.Equal(t, uint64(2), prices[0].SnapshotTimestampInSeconds) - require.Equal(t, uint64(3), prices[1].SnapshotTimestampInSeconds) -} diff --git a/x/dex/keeper/query/grpc_query.go b/x/dex/keeper/query/grpc_query.go deleted file mode 100644 index 2cc5e787e..000000000 --- a/x/dex/keeper/query/grpc_query.go +++ /dev/null @@ -1,7 +0,0 @@ -package query - -import ( - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -var _ types.QueryServer = KeeperWrapper{} diff --git a/x/dex/keeper/query/grpc_query_asset_list.go b/x/dex/keeper/query/grpc_query_asset_list.go deleted file mode 100644 index fc7748be9..000000000 --- a/x/dex/keeper/query/grpc_query_asset_list.go +++ /dev/null @@ -1,36 +0,0 @@ -package query - -import ( - "context" - - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/sei-protocol/sei-chain/x/dex/types" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" -) - -func (k KeeperWrapper) AssetList(c context.Context, req *types.QueryAssetListRequest) (*types.QueryAssetListResponse, error) { - if req == nil { - return nil, status.Error(codes.InvalidArgument, "invalid request") - } - ctx := sdk.UnwrapSDKContext(c) - - allAssetMetadata := k.GetAllAssetMetadata(ctx) - - return &types.QueryAssetListResponse{AssetList: allAssetMetadata}, nil -} - -func (k KeeperWrapper) AssetMetadata(c context.Context, req *types.QueryAssetMetadataRequest) (*types.QueryAssetMetadataResponse, error) { - if req == nil { - return nil, status.Error(codes.InvalidArgument, "invalid request") - } - ctx := sdk.UnwrapSDKContext(c) - - assetMetadata, found := k.GetAssetMetadataByDenom(ctx, req.Denom) - if !found { - return nil, sdkerrors.ErrKeyNotFound - } - - return &types.QueryAssetMetadataResponse{Metadata: &assetMetadata}, nil -} diff --git a/x/dex/keeper/query/grpc_query_asset_list_test.go b/x/dex/keeper/query/grpc_query_asset_list_test.go deleted file mode 100644 index b2bd8a4a9..000000000 --- a/x/dex/keeper/query/grpc_query_asset_list_test.go +++ /dev/null @@ -1,50 +0,0 @@ -package query_test - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex/keeper/query" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestAssetListQuery(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - wctx := sdk.WrapSDKContext(ctx) - item := keepertest.CreateAssetMetadata(keeper, ctx) - - var expectedAssetList []types.AssetMetadata - expectedAssetList = append(expectedAssetList, item) - - request := types.QueryAssetListRequest{} - expectedResponse := types.QueryAssetListResponse{ - AssetList: expectedAssetList, - } - wrapper := query.KeeperWrapper{Keeper: keeper} - t.Run("Asset list query", func(t *testing.T) { - response, err := wrapper.AssetList(wctx, &request) - require.NoError(t, err) - require.Equal(t, expectedResponse, *response) - }) -} - -func TestAssetMetadataQuery(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - wctx := sdk.WrapSDKContext(ctx) - expectedMetadata := keepertest.CreateAssetMetadata(keeper, ctx) - - request := types.QueryAssetMetadataRequest{ - Denom: "axlusdc", - } - expectedResponse := types.QueryAssetMetadataResponse{ - Metadata: &expectedMetadata, - } - wrapper := query.KeeperWrapper{Keeper: keeper} - t.Run("Asset metadata query", func(t *testing.T) { - response, err := wrapper.AssetMetadata(wctx, &request) - require.NoError(t, err) - require.Equal(t, expectedResponse, *response) - }) -} diff --git a/x/dex/keeper/query/grpc_query_get_historical_prices.go b/x/dex/keeper/query/grpc_query_get_historical_prices.go deleted file mode 100644 index 9e6dc434f..000000000 --- a/x/dex/keeper/query/grpc_query_get_historical_prices.go +++ /dev/null @@ -1,119 +0,0 @@ -package query - -import ( - "context" - "sort" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/types" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" -) - -var ZeroPrice = sdk.ZeroDec() - -func (k KeeperWrapper) GetHistoricalPrices(goCtx context.Context, req *types.QueryGetHistoricalPricesRequest) (*types.QueryGetHistoricalPricesResponse, error) { - if req == nil { - return nil, status.Error(codes.InvalidArgument, "invalid request") - } - - ctx := sdk.UnwrapSDKContext(goCtx) - - prices := k.GetAllPrices(ctx, req.ContractAddr, types.Pair{PriceDenom: req.PriceDenom, AssetDenom: req.AssetDenom}) - currentTimeStamp := uint64(ctx.BlockTime().Unix()) - beginTimestamp := currentTimeStamp - req.NumOfPeriods*req.PeriodLengthInSeconds - // sort descending - sort.Slice(prices, func(i, j int) bool { - return prices[i].SnapshotTimestampInSeconds > prices[j].SnapshotTimestampInSeconds - }) - validPrices := []*types.Price{} - for _, price := range prices { - // append early so that we include the latest price before beginTimestamp, since - // we need it to set the open price of the first period. - if price.SnapshotTimestampInSeconds < currentTimeStamp { - validPrices = append(validPrices, price) - } - if price.SnapshotTimestampInSeconds < beginTimestamp { - break - } - } - - candlesticks := make([]*types.PriceCandlestick, req.NumOfPeriods) - - // set timestamp - for i := range candlesticks { - candlesticks[i] = &types.PriceCandlestick{} - candlesticks[i].EndTimestamp = currentTimeStamp - uint64(i)*req.PeriodLengthInSeconds - candlesticks[i].BeginTimestamp = candlesticks[i].EndTimestamp - req.PeriodLengthInSeconds - } - - // set open - pricePtr := 0 - for i := range candlesticks { - for pricePtr < len(validPrices) && validPrices[pricePtr].SnapshotTimestampInSeconds > candlesticks[i].BeginTimestamp { - pricePtr++ - } - if pricePtr < len(validPrices) { - candlesticks[i].Open = &validPrices[pricePtr].Price - } else { - // this would happen if the earliest price point available is after the begin timestamp - candlesticks[i].Open = &ZeroPrice - } - } - - // set close - pricePtr = 0 - for i := range candlesticks { - for pricePtr < len(validPrices) && validPrices[pricePtr].SnapshotTimestampInSeconds >= candlesticks[i].EndTimestamp { - pricePtr++ - } - if pricePtr < len(validPrices) { - candlesticks[i].Close = &validPrices[pricePtr].Price - } else { - // this would happen if the earliest price point available is after the first end timestamp - candlesticks[i].Close = &ZeroPrice - } - } - - // set high - pricePtr = 0 - for i := range candlesticks { - // initialize to the open price - candlesticks[i].High = candlesticks[i].Open - set := false - for pricePtr < len(validPrices) { - price := validPrices[pricePtr] - if price.SnapshotTimestampInSeconds < candlesticks[i].BeginTimestamp || price.SnapshotTimestampInSeconds >= candlesticks[i].EndTimestamp { - break - } - if !set || price.Price.GT(*candlesticks[i].High) { - set = true - candlesticks[i].High = &price.Price - } - pricePtr++ - } - } - - // set low - pricePtr = 0 - for i := range candlesticks { - // initialize to the open price - candlesticks[i].Low = candlesticks[i].Open - set := false - for pricePtr < len(validPrices) { - price := validPrices[pricePtr] - if price.SnapshotTimestampInSeconds < candlesticks[i].BeginTimestamp || price.SnapshotTimestampInSeconds >= candlesticks[i].EndTimestamp { - break - } - if !set || price.Price.LT(*candlesticks[i].Low) { - set = true - candlesticks[i].Low = &price.Price - } - pricePtr++ - } - } - - return &types.QueryGetHistoricalPricesResponse{ - Prices: candlesticks, - }, nil -} diff --git a/x/dex/keeper/query/grpc_query_get_historical_prices_test.go b/x/dex/keeper/query/grpc_query_get_historical_prices_test.go deleted file mode 100644 index 29b62f942..000000000 --- a/x/dex/keeper/query/grpc_query_get_historical_prices_test.go +++ /dev/null @@ -1,185 +0,0 @@ -package query_test - -import ( - "testing" - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex/keeper/query" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestEachPeriodOneDataPoint(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - keepertest.SeedPriceSnapshot(ctx, keeper, "100", 1) - keepertest.SeedPriceSnapshot(ctx, keeper, "101", 2) - keepertest.SeedPriceSnapshot(ctx, keeper, "99", 3) // should not be included since end is exclusive - - ctx = ctx.WithBlockTime(time.Unix(3, 0)) - wctx := sdk.WrapSDKContext(ctx) - wrapper := query.KeeperWrapper{Keeper: keeper} - resp, err := wrapper.GetHistoricalPrices(wctx, &types.QueryGetHistoricalPricesRequest{ - ContractAddr: keepertest.TestContract, - PriceDenom: keepertest.TestPair.PriceDenom, - AssetDenom: keepertest.TestPair.AssetDenom, - PeriodLengthInSeconds: 1, - NumOfPeriods: 2, - }) - require.Nil(t, err) - require.Equal(t, 2, len(resp.Prices)) - require.Equal(t, uint64(2), resp.Prices[0].BeginTimestamp) - require.Equal(t, uint64(3), resp.Prices[0].EndTimestamp) - require.Equal(t, sdk.MustNewDecFromStr("101"), *resp.Prices[0].Open) - require.Equal(t, sdk.MustNewDecFromStr("101"), *resp.Prices[0].High) - require.Equal(t, sdk.MustNewDecFromStr("101"), *resp.Prices[0].Low) - require.Equal(t, sdk.MustNewDecFromStr("101"), *resp.Prices[0].Close) - require.Equal(t, uint64(1), resp.Prices[1].BeginTimestamp) - require.Equal(t, uint64(2), resp.Prices[1].EndTimestamp) - require.Equal(t, sdk.MustNewDecFromStr("100"), *resp.Prices[1].Open) - require.Equal(t, sdk.MustNewDecFromStr("100"), *resp.Prices[1].High) - require.Equal(t, sdk.MustNewDecFromStr("100"), *resp.Prices[1].Low) - require.Equal(t, sdk.MustNewDecFromStr("100"), *resp.Prices[1].Close) -} - -func TestEachPeriodMultipleDataPoints(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - keepertest.SeedPriceSnapshot(ctx, keeper, "100", 1) - keepertest.SeedPriceSnapshot(ctx, keeper, "101", 2) - keepertest.SeedPriceSnapshot(ctx, keeper, "102", 3) - keepertest.SeedPriceSnapshot(ctx, keeper, "99", 4) - keepertest.SeedPriceSnapshot(ctx, keeper, "98", 5) // should not be included since end is exclusive - - ctx = ctx.WithBlockTime(time.Unix(5, 0)) - wctx := sdk.WrapSDKContext(ctx) - wrapper := query.KeeperWrapper{Keeper: keeper} - resp, err := wrapper.GetHistoricalPrices(wctx, &types.QueryGetHistoricalPricesRequest{ - ContractAddr: keepertest.TestContract, - PriceDenom: keepertest.TestPair.PriceDenom, - AssetDenom: keepertest.TestPair.AssetDenom, - PeriodLengthInSeconds: 2, - NumOfPeriods: 2, - }) - require.Nil(t, err) - require.Equal(t, 2, len(resp.Prices)) - require.Equal(t, uint64(3), resp.Prices[0].BeginTimestamp) - require.Equal(t, uint64(5), resp.Prices[0].EndTimestamp) - require.Equal(t, sdk.MustNewDecFromStr("102"), *resp.Prices[0].Open) - require.Equal(t, sdk.MustNewDecFromStr("102"), *resp.Prices[0].High) - require.Equal(t, sdk.MustNewDecFromStr("99"), *resp.Prices[0].Low) - require.Equal(t, sdk.MustNewDecFromStr("99"), *resp.Prices[0].Close) - require.Equal(t, uint64(1), resp.Prices[1].BeginTimestamp) - require.Equal(t, uint64(3), resp.Prices[1].EndTimestamp) - require.Equal(t, sdk.MustNewDecFromStr("100"), *resp.Prices[1].Open) - require.Equal(t, sdk.MustNewDecFromStr("101"), *resp.Prices[1].High) - require.Equal(t, sdk.MustNewDecFromStr("100"), *resp.Prices[1].Low) - require.Equal(t, sdk.MustNewDecFromStr("101"), *resp.Prices[1].Close) -} - -func TestMissingDataPoints(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - keepertest.SeedPriceSnapshot(ctx, keeper, "100", 1) - keepertest.SeedPriceSnapshot(ctx, keeper, "102", 3) - keepertest.SeedPriceSnapshot(ctx, keeper, "98", 5) // should not be included since end is exclusive - - ctx = ctx.WithBlockTime(time.Unix(5, 0)) - wctx := sdk.WrapSDKContext(ctx) - wrapper := query.KeeperWrapper{Keeper: keeper} - resp, err := wrapper.GetHistoricalPrices(wctx, &types.QueryGetHistoricalPricesRequest{ - ContractAddr: keepertest.TestContract, - PriceDenom: keepertest.TestPair.PriceDenom, - AssetDenom: keepertest.TestPair.AssetDenom, - PeriodLengthInSeconds: 1, - NumOfPeriods: 4, - }) - require.Nil(t, err) - require.Equal(t, 4, len(resp.Prices)) - require.Equal(t, uint64(4), resp.Prices[0].BeginTimestamp) - require.Equal(t, uint64(5), resp.Prices[0].EndTimestamp) - require.Equal(t, sdk.MustNewDecFromStr("102"), *resp.Prices[0].Open) - require.Equal(t, sdk.MustNewDecFromStr("102"), *resp.Prices[0].High) - require.Equal(t, sdk.MustNewDecFromStr("102"), *resp.Prices[0].Low) - require.Equal(t, sdk.MustNewDecFromStr("102"), *resp.Prices[0].Close) - require.Equal(t, uint64(3), resp.Prices[1].BeginTimestamp) - require.Equal(t, uint64(4), resp.Prices[1].EndTimestamp) - require.Equal(t, sdk.MustNewDecFromStr("102"), *resp.Prices[1].Open) - require.Equal(t, sdk.MustNewDecFromStr("102"), *resp.Prices[1].High) - require.Equal(t, sdk.MustNewDecFromStr("102"), *resp.Prices[1].Low) - require.Equal(t, sdk.MustNewDecFromStr("102"), *resp.Prices[1].Close) - require.Equal(t, uint64(2), resp.Prices[2].BeginTimestamp) - require.Equal(t, uint64(3), resp.Prices[2].EndTimestamp) - require.Equal(t, sdk.MustNewDecFromStr("100"), *resp.Prices[2].Open) - require.Equal(t, sdk.MustNewDecFromStr("100"), *resp.Prices[2].High) - require.Equal(t, sdk.MustNewDecFromStr("100"), *resp.Prices[2].Low) - require.Equal(t, sdk.MustNewDecFromStr("100"), *resp.Prices[2].Close) - require.Equal(t, uint64(1), resp.Prices[3].BeginTimestamp) - require.Equal(t, uint64(2), resp.Prices[3].EndTimestamp) - require.Equal(t, sdk.MustNewDecFromStr("100"), *resp.Prices[3].Open) - require.Equal(t, sdk.MustNewDecFromStr("100"), *resp.Prices[3].High) - require.Equal(t, sdk.MustNewDecFromStr("100"), *resp.Prices[3].Low) - require.Equal(t, sdk.MustNewDecFromStr("100"), *resp.Prices[3].Close) -} - -func TestDataPointsNotEarlyEnoughFullBar(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - keepertest.SeedPriceSnapshot(ctx, keeper, "100", 2) - keepertest.SeedPriceSnapshot(ctx, keeper, "102", 3) // should not be included since end is exclusive - - ctx = ctx.WithBlockTime(time.Unix(3, 0)) - wctx := sdk.WrapSDKContext(ctx) - wrapper := query.KeeperWrapper{Keeper: keeper} - resp, err := wrapper.GetHistoricalPrices(wctx, &types.QueryGetHistoricalPricesRequest{ - ContractAddr: keepertest.TestContract, - PriceDenom: keepertest.TestPair.PriceDenom, - AssetDenom: keepertest.TestPair.AssetDenom, - PeriodLengthInSeconds: 1, - NumOfPeriods: 2, - }) - require.Nil(t, err) - require.Equal(t, 2, len(resp.Prices)) - require.Equal(t, uint64(2), resp.Prices[0].BeginTimestamp) - require.Equal(t, uint64(3), resp.Prices[0].EndTimestamp) - require.Equal(t, sdk.MustNewDecFromStr("100"), *resp.Prices[0].Open) - require.Equal(t, sdk.MustNewDecFromStr("100"), *resp.Prices[0].High) - require.Equal(t, sdk.MustNewDecFromStr("100"), *resp.Prices[0].Low) - require.Equal(t, sdk.MustNewDecFromStr("100"), *resp.Prices[0].Close) - require.Equal(t, uint64(1), resp.Prices[1].BeginTimestamp) - require.Equal(t, uint64(2), resp.Prices[1].EndTimestamp) - require.Equal(t, sdk.MustNewDecFromStr("0"), *resp.Prices[1].Open) - require.Equal(t, sdk.MustNewDecFromStr("0"), *resp.Prices[1].High) - require.Equal(t, sdk.MustNewDecFromStr("0"), *resp.Prices[1].Low) - require.Equal(t, sdk.MustNewDecFromStr("0"), *resp.Prices[1].Close) -} - -func TestDataPointsNotEarlyEnoughPartialBar(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - keepertest.SeedPriceSnapshot(ctx, keeper, "100", 2) - keepertest.SeedPriceSnapshot(ctx, keeper, "102", 3) - keepertest.SeedPriceSnapshot(ctx, keeper, "98", 5) // should not be included since end is exclusive - - ctx = ctx.WithBlockTime(time.Unix(5, 0)) - wctx := sdk.WrapSDKContext(ctx) - wrapper := query.KeeperWrapper{Keeper: keeper} - resp, err := wrapper.GetHistoricalPrices(wctx, &types.QueryGetHistoricalPricesRequest{ - ContractAddr: keepertest.TestContract, - PriceDenom: keepertest.TestPair.PriceDenom, - AssetDenom: keepertest.TestPair.AssetDenom, - PeriodLengthInSeconds: 2, - NumOfPeriods: 2, - }) - require.Nil(t, err) - require.Equal(t, 2, len(resp.Prices)) - require.Equal(t, uint64(3), resp.Prices[0].BeginTimestamp) - require.Equal(t, uint64(5), resp.Prices[0].EndTimestamp) - require.Equal(t, sdk.MustNewDecFromStr("102"), *resp.Prices[0].Open) - require.Equal(t, sdk.MustNewDecFromStr("102"), *resp.Prices[0].High) - require.Equal(t, sdk.MustNewDecFromStr("102"), *resp.Prices[0].Low) - require.Equal(t, sdk.MustNewDecFromStr("102"), *resp.Prices[0].Close) - require.Equal(t, uint64(1), resp.Prices[1].BeginTimestamp) - require.Equal(t, uint64(3), resp.Prices[1].EndTimestamp) - require.Equal(t, sdk.MustNewDecFromStr("0"), *resp.Prices[1].Open) - require.Equal(t, sdk.MustNewDecFromStr("100"), *resp.Prices[1].High) - require.Equal(t, sdk.MustNewDecFromStr("100"), *resp.Prices[1].Low) - require.Equal(t, sdk.MustNewDecFromStr("100"), *resp.Prices[1].Close) -} diff --git a/x/dex/keeper/query/grpc_query_get_latest_price.go b/x/dex/keeper/query/grpc_query_get_latest_price.go deleted file mode 100644 index 18fa7b5c1..000000000 --- a/x/dex/keeper/query/grpc_query_get_latest_price.go +++ /dev/null @@ -1,37 +0,0 @@ -package query - -import ( - "context" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/types" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" -) - -func (k KeeperWrapper) GetLatestPrice(goCtx context.Context, req *types.QueryGetLatestPriceRequest) (*types.QueryGetLatestPriceResponse, error) { - if req == nil { - return nil, status.Error(codes.InvalidArgument, "invalid request") - } - - ctx := sdk.UnwrapSDKContext(goCtx) - prices := k.GetAllPrices(ctx, req.ContractAddr, types.Pair{PriceDenom: req.PriceDenom, AssetDenom: req.AssetDenom}) - - if len(prices) == 0 { - return &types.QueryGetLatestPriceResponse{ - Price: &types.Price{}, - }, nil - } - - latestPrice := prices[0] - - for _, price := range prices { - if price.SnapshotTimestampInSeconds > latestPrice.SnapshotTimestampInSeconds { - latestPrice = price - } - } - - return &types.QueryGetLatestPriceResponse{ - Price: latestPrice, - }, nil -} diff --git a/x/dex/keeper/query/grpc_query_get_latest_price_test.go b/x/dex/keeper/query/grpc_query_get_latest_price_test.go deleted file mode 100644 index 731ca6354..000000000 --- a/x/dex/keeper/query/grpc_query_get_latest_price_test.go +++ /dev/null @@ -1,30 +0,0 @@ -package query_test - -import ( - "testing" - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex/keeper/query" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestGetLatestPrice(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - keepertest.SeedPriceSnapshot(ctx, keeper, "100", 1) - keepertest.SeedPriceSnapshot(ctx, keeper, "101", 2) - keepertest.SeedPriceSnapshot(ctx, keeper, "99", 3) - - ctx = ctx.WithBlockTime(time.Unix(4, 0)) - wctx := sdk.WrapSDKContext(ctx) - wrapper := query.KeeperWrapper{Keeper: keeper} - resp, err := wrapper.GetLatestPrice(wctx, &types.QueryGetLatestPriceRequest{ - ContractAddr: keepertest.TestContract, - PriceDenom: keepertest.TestPair.PriceDenom, - AssetDenom: keepertest.TestPair.AssetDenom, - }) - require.Nil(t, err) - require.Equal(t, sdk.MustNewDecFromStr("99"), resp.Price.Price) -} diff --git a/x/dex/keeper/query/grpc_query_get_market_summary.go b/x/dex/keeper/query/grpc_query_get_market_summary.go deleted file mode 100644 index 9d869207f..000000000 --- a/x/dex/keeper/query/grpc_query_get_market_summary.go +++ /dev/null @@ -1,49 +0,0 @@ -package query - -import ( - "context" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/types" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" -) - -func (k KeeperWrapper) GetMarketSummary(goCtx context.Context, req *types.QueryGetMarketSummaryRequest) (*types.QueryGetMarketSummaryResponse, error) { - if req == nil { - return nil, status.Error(codes.InvalidArgument, "invalid request") - } - - ctx := sdk.UnwrapSDKContext(goCtx) - - prices := k.GetAllPrices(ctx, req.ContractAddr, types.Pair{PriceDenom: req.PriceDenom, AssetDenom: req.AssetDenom}) - cutoff := ctx.BlockTime().Unix() - int64(req.LookbackInSeconds) - maxPrice := sdk.ZeroDec() - minPrice := sdk.ZeroDec() - latestTimestamp := 0 - lastPrice := sdk.ZeroDec() - for _, price := range prices { - if price.SnapshotTimestampInSeconds < uint64(cutoff) { - continue - } - if maxPrice.IsZero() || price.Price.GT(maxPrice) { - maxPrice = price.Price - } - if minPrice.IsZero() || price.Price.LT(minPrice) { - minPrice = price.Price - } - if price.SnapshotTimestampInSeconds > uint64(latestTimestamp) { - latestTimestamp = int(price.SnapshotTimestampInSeconds) - lastPrice = price.Price - } - } - - zero := sdk.ZeroDec() - return &types.QueryGetMarketSummaryResponse{ - TotalVolume: &zero, // TODO: replace once we start tracking volume - TotalVolumeNotional: &zero, // TODO: replace once we start tracking volume - HighPrice: &maxPrice, - LowPrice: &minPrice, - LastPrice: &lastPrice, - }, nil -} diff --git a/x/dex/keeper/query/grpc_query_get_market_summary_test.go b/x/dex/keeper/query/grpc_query_get_market_summary_test.go deleted file mode 100644 index e5f77b40a..000000000 --- a/x/dex/keeper/query/grpc_query_get_market_summary_test.go +++ /dev/null @@ -1,33 +0,0 @@ -package query_test - -import ( - "testing" - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex/keeper/query" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestGetMarketSummary(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - keepertest.SeedPriceSnapshot(ctx, keeper, "100", 1) - keepertest.SeedPriceSnapshot(ctx, keeper, "101", 2) - keepertest.SeedPriceSnapshot(ctx, keeper, "99", 3) - - ctx = ctx.WithBlockTime(time.Unix(4, 0)) - wctx := sdk.WrapSDKContext(ctx) - wrapper := query.KeeperWrapper{Keeper: keeper} - resp, err := wrapper.GetMarketSummary(wctx, &types.QueryGetMarketSummaryRequest{ - ContractAddr: keepertest.TestContract, - PriceDenom: keepertest.TestPair.PriceDenom, - AssetDenom: keepertest.TestPair.AssetDenom, - LookbackInSeconds: 4, - }) - require.Nil(t, err) - require.Equal(t, sdk.MustNewDecFromStr("99"), *resp.LowPrice) - require.Equal(t, sdk.MustNewDecFromStr("99"), *resp.LastPrice) - require.Equal(t, sdk.MustNewDecFromStr("101"), *resp.HighPrice) -} diff --git a/x/dex/keeper/query/grpc_query_get_order_count.go b/x/dex/keeper/query/grpc_query_get_order_count.go deleted file mode 100644 index 3a70cb0fe..000000000 --- a/x/dex/keeper/query/grpc_query_get_order_count.go +++ /dev/null @@ -1,19 +0,0 @@ -package query - -import ( - "context" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/types" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" -) - -func (k KeeperWrapper) GetOrderCount(c context.Context, req *types.QueryGetOrderCountRequest) (*types.QueryGetOrderCountResponse, error) { - if req == nil { - return nil, status.Error(codes.InvalidArgument, "invalid request") - } - ctx := sdk.UnwrapSDKContext(c) - - return &types.QueryGetOrderCountResponse{Count: k.GetOrderCountState(ctx, req.ContractAddr, req.PriceDenom, req.AssetDenom, req.PositionDirection, *req.Price)}, nil -} diff --git a/x/dex/keeper/query/grpc_query_get_order_count_test.go b/x/dex/keeper/query/grpc_query_get_order_count_test.go deleted file mode 100644 index 30fa1baf7..000000000 --- a/x/dex/keeper/query/grpc_query_get_order_count_test.go +++ /dev/null @@ -1,29 +0,0 @@ -package query_test - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex/keeper/query" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestGetOrderCount(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - wrapper := query.KeeperWrapper{Keeper: keeper} - wctx := sdk.WrapSDKContext(ctx) - keeper.SetOrderCount(ctx, keepertest.TestContract, keepertest.TestPair.PriceDenom, keepertest.TestPair.AssetDenom, types.PositionDirection_LONG, sdk.NewDec(1), 5) - price := sdk.NewDec(1) - query := types.QueryGetOrderCountRequest{ - ContractAddr: keepertest.TestContract, - PriceDenom: keepertest.TestPriceDenom, - AssetDenom: keepertest.TestAssetDenom, - PositionDirection: types.PositionDirection_LONG, - Price: &price, - } - resp, err := wrapper.GetOrderCount(wctx, &query) - require.Nil(t, err) - require.Equal(t, uint64(5), resp.Count) -} diff --git a/x/dex/keeper/query/grpc_query_get_price.go b/x/dex/keeper/query/grpc_query_get_price.go deleted file mode 100644 index f58d38645..000000000 --- a/x/dex/keeper/query/grpc_query_get_price.go +++ /dev/null @@ -1,25 +0,0 @@ -package query - -import ( - "context" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/types" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" -) - -func (k KeeperWrapper) GetPrice(goCtx context.Context, req *types.QueryGetPriceRequest) (*types.QueryGetPriceResponse, error) { - if req == nil { - return nil, status.Error(codes.InvalidArgument, "invalid request") - } - - ctx := sdk.UnwrapSDKContext(goCtx) - - price, found := k.GetPriceState(ctx, req.ContractAddr, req.Timestamp, types.Pair{PriceDenom: req.PriceDenom, AssetDenom: req.AssetDenom}) - - return &types.QueryGetPriceResponse{ - Price: &price, - Found: found, - }, nil -} diff --git a/x/dex/keeper/query/grpc_query_get_price_test.go b/x/dex/keeper/query/grpc_query_get_price_test.go deleted file mode 100644 index c46d15f7e..000000000 --- a/x/dex/keeper/query/grpc_query_get_price_test.go +++ /dev/null @@ -1,32 +0,0 @@ -package query_test - -import ( - "testing" - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex/keeper/query" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestGetPrice(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - keepertest.SeedPriceSnapshot(ctx, keeper, "100", 1) - keepertest.SeedPriceSnapshot(ctx, keeper, "101", 2) - keepertest.SeedPriceSnapshot(ctx, keeper, "99", 3) - - ctx = ctx.WithBlockTime(time.Unix(4, 0)) - wctx := sdk.WrapSDKContext(ctx) - wrapper := query.KeeperWrapper{Keeper: keeper} - resp, err := wrapper.GetPrice(wctx, &types.QueryGetPriceRequest{ - ContractAddr: keepertest.TestContract, - PriceDenom: keepertest.TestPair.PriceDenom, - AssetDenom: keepertest.TestPair.AssetDenom, - Timestamp: 2, - }) - require.Nil(t, err) - require.Equal(t, true, resp.Found) - require.Equal(t, sdk.MustNewDecFromStr("101"), resp.Price.Price) -} diff --git a/x/dex/keeper/query/grpc_query_get_prices.go b/x/dex/keeper/query/grpc_query_get_prices.go deleted file mode 100644 index d4b8c619e..000000000 --- a/x/dex/keeper/query/grpc_query_get_prices.go +++ /dev/null @@ -1,24 +0,0 @@ -package query - -import ( - "context" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/types" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" -) - -func (k KeeperWrapper) GetPrices(goCtx context.Context, req *types.QueryGetPricesRequest) (*types.QueryGetPricesResponse, error) { - if req == nil { - return nil, status.Error(codes.InvalidArgument, "invalid request") - } - - ctx := sdk.UnwrapSDKContext(goCtx) - - prices := k.GetAllPrices(ctx, req.ContractAddr, types.Pair{PriceDenom: req.PriceDenom, AssetDenom: req.AssetDenom}) - - return &types.QueryGetPricesResponse{ - Prices: prices, - }, nil -} diff --git a/x/dex/keeper/query/grpc_query_get_twaps.go b/x/dex/keeper/query/grpc_query_get_twaps.go deleted file mode 100644 index b16667285..000000000 --- a/x/dex/keeper/query/grpc_query_get_twaps.go +++ /dev/null @@ -1,57 +0,0 @@ -package query - -import ( - "context" - - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -func (k KeeperWrapper) GetTwaps(goCtx context.Context, req *types.QueryGetTwapsRequest) (*types.QueryGetTwapsResponse, error) { - if req == nil { - return nil, status.Error(codes.InvalidArgument, "invalid request") - } - ctx := sdk.UnwrapSDKContext(goCtx) - allRegisteredPairs := k.GetAllRegisteredPairs(ctx, req.ContractAddr) - twaps := []*types.Twap{} - for _, pair := range allRegisteredPairs { - prices := k.GetPricesForTwap(ctx, req.ContractAddr, pair, req.LookbackSeconds) - twaps = append(twaps, &types.Twap{ - Pair: &pair, //nolint:gosec,exportloopref // USING THE POINTER HERE COULD BE BAD, LET'S CHECK IT. - Twap: calculateTwap(ctx, prices, req.LookbackSeconds), - LookbackSeconds: req.LookbackSeconds, - }) - } - - return &types.QueryGetTwapsResponse{ - Twaps: twaps, - }, nil -} - -func calculateTwap(ctx sdk.Context, prices []*types.Price, lookback uint64) sdk.Dec { - if len(prices) == 0 { - return sdk.ZeroDec() - } - weightedPriceSum := sdk.ZeroDec() - lastTimestamp := ctx.BlockTime().Unix() - for _, price := range prices { - if uint64(ctx.BlockTime().Unix())-price.SnapshotTimestampInSeconds > lookback { - weight := lastTimestamp - ctx.BlockTime().Unix() + int64(lookback) - weightedPriceSum = weightedPriceSum.Add(price.Price.MulInt64(weight)) - break - } - weightedPriceSum = weightedPriceSum.Add( - price.Price.MulInt64(lastTimestamp - int64(price.SnapshotTimestampInSeconds)), - ) - lastTimestamp = int64(price.SnapshotTimestampInSeconds) - } - // not possible for division by 0 here since prices have unique timestamps - totalTimeSpan := ctx.BlockTime().Unix() - int64(prices[len(prices)-1].SnapshotTimestampInSeconds) - if totalTimeSpan > int64(lookback) { - totalTimeSpan = int64(lookback) - } - return weightedPriceSum.QuoInt64(totalTimeSpan) -} diff --git a/x/dex/keeper/query/grpc_query_get_twaps_test.go b/x/dex/keeper/query/grpc_query_get_twaps_test.go deleted file mode 100644 index a03944205..000000000 --- a/x/dex/keeper/query/grpc_query_get_twaps_test.go +++ /dev/null @@ -1,143 +0,0 @@ -package query_test - -import ( - "testing" - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex/keeper/query" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -const GENESIS_TIME uint64 = 3600 - -func TestGetTwapsNoPriceSnapshot(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - keeper.AddRegisteredPair(ctx, keepertest.TestContract, keepertest.TestPair) - wctx := sdk.WrapSDKContext(ctx) - var lookback uint64 = 10 - request := types.QueryGetTwapsRequest{ - ContractAddr: keepertest.TestContract, - LookbackSeconds: lookback, - } - expectedResponse := types.QueryGetTwapsResponse{ - Twaps: []*types.Twap{ - { - Pair: &keepertest.TestPair, - Twap: sdk.ZeroDec(), - LookbackSeconds: lookback, - }, - }, - } - wrapper := query.KeeperWrapper{Keeper: keeper} - t.Run("No snapshot", func(t *testing.T) { - response, err := wrapper.GetTwaps(wctx, &request) - require.NoError(t, err) - require.Equal(t, expectedResponse, *response) - }) -} - -func TestGetTwapsOnePriceSnapshot(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - keeper.AddRegisteredPair(ctx, keepertest.TestContract, keepertest.TestPair) - ctx = ctx.WithBlockTime(time.Unix(int64(GENESIS_TIME)+5, 0)) - wctx := sdk.WrapSDKContext(ctx) - - snapshotPrice := sdk.MustNewDecFromStr("100.00") - keeper.SetPriceState(ctx, types.Price{ - SnapshotTimestampInSeconds: GENESIS_TIME, - Price: snapshotPrice, - Pair: &keepertest.TestPair, - }, keepertest.TestContract) - - var lookback uint64 = 10 - request := types.QueryGetTwapsRequest{ - ContractAddr: keepertest.TestContract, - LookbackSeconds: lookback, - } - expectedResponse := types.QueryGetTwapsResponse{ - Twaps: []*types.Twap{ - { - Pair: &keepertest.TestPair, - Twap: snapshotPrice, - LookbackSeconds: lookback, - }, - }, - } - wrapper := query.KeeperWrapper{Keeper: keeper} - t.Run("One snapshot", func(t *testing.T) { - response, err := wrapper.GetTwaps(wctx, &request) - require.NoError(t, err) - require.Equal(t, expectedResponse, *response) - }) - - lookback = 4 - request = types.QueryGetTwapsRequest{ - ContractAddr: keepertest.TestContract, - LookbackSeconds: lookback, - } - expectedResponse = types.QueryGetTwapsResponse{ - Twaps: []*types.Twap{ - { - Pair: &keepertest.TestPair, - Twap: snapshotPrice, - LookbackSeconds: lookback, - }, - }, - } - t.Run("One old snapshot", func(t *testing.T) { - response, err := wrapper.GetTwaps(wctx, &request) - require.NoError(t, err) - require.Equal(t, expectedResponse, *response) - }) -} - -func TestGetTwapsMultipleSnapshots(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - keeper.AddRegisteredPair(ctx, keepertest.TestContract, keepertest.TestPair) - ctx = ctx.WithBlockTime(time.Unix(int64(GENESIS_TIME)+20, 0)) - wctx := sdk.WrapSDKContext(ctx) - - snapshotPrices := []sdk.Dec{ - sdk.MustNewDecFromStr("100.00"), - sdk.MustNewDecFromStr("98.50"), - sdk.MustNewDecFromStr("101.00"), - } - timestampDeltas := []uint64{0, 10, 15} - for i := range snapshotPrices { - keeper.SetPriceState(ctx, types.Price{ - SnapshotTimestampInSeconds: GENESIS_TIME + timestampDeltas[i], - Price: snapshotPrices[i], - Pair: &keepertest.TestPair, - }, keepertest.TestContract) - } - - var lookback uint64 = 20 - request := types.QueryGetTwapsRequest{ - ContractAddr: keepertest.TestContract, - LookbackSeconds: lookback, - } - expectedTwap := snapshotPrices[0].MulInt64(10).Add( - snapshotPrices[1].MulInt64(15 - 10), - ).Add( - snapshotPrices[2].MulInt64(20 - 15), - ).QuoInt64(20) - require.Equal(t, sdk.MustNewDecFromStr("99.875"), expectedTwap) - expectedResponse := types.QueryGetTwapsResponse{ - Twaps: []*types.Twap{ - { - Pair: &keepertest.TestPair, - Twap: expectedTwap, - LookbackSeconds: lookback, - }, - }, - } - wrapper := query.KeeperWrapper{Keeper: keeper} - t.Run("Multiple snapshots", func(t *testing.T) { - response, err := wrapper.GetTwaps(wctx, &request) - require.NoError(t, err) - require.Equal(t, expectedResponse, *response) - }) -} diff --git a/x/dex/keeper/query/grpc_query_long_book.go b/x/dex/keeper/query/grpc_query_long_book.go deleted file mode 100644 index d855059f2..000000000 --- a/x/dex/keeper/query/grpc_query_long_book.go +++ /dev/null @@ -1,50 +0,0 @@ -package query - -import ( - "context" - - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/sei-protocol/sei-chain/x/dex/types" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" -) - -func (k KeeperWrapper) LongBookAll(c context.Context, req *types.QueryAllLongBookRequest) (*types.QueryAllLongBookResponse, error) { - if req == nil { - return nil, status.Error(codes.InvalidArgument, "invalid request") - } - - ctx := sdk.UnwrapSDKContext(c) - - longBooks, pageRes, err := k.GetAllLongBookForPairPaginated( - ctx, - req.ContractAddr, - req.PriceDenom, - req.AssetDenom, - req.Pagination, - ) - if err != nil { - return nil, status.Error(codes.Internal, err.Error()) - } - - return &types.QueryAllLongBookResponse{LongBook: longBooks, Pagination: pageRes}, nil -} - -func (k KeeperWrapper) LongBook(c context.Context, req *types.QueryGetLongBookRequest) (*types.QueryGetLongBookResponse, error) { - if req == nil { - return nil, status.Error(codes.InvalidArgument, "invalid request") - } - - ctx := sdk.UnwrapSDKContext(c) - price, err := sdk.NewDecFromStr(req.Price) - if err != nil { - return nil, err - } - longBook, found := k.GetLongBookByPrice(ctx, req.ContractAddr, price, req.PriceDenom, req.AssetDenom) - if !found { - return nil, sdkerrors.ErrKeyNotFound - } - - return &types.QueryGetLongBookResponse{LongBook: longBook}, nil -} diff --git a/x/dex/keeper/query/grpc_query_long_book_test.go b/x/dex/keeper/query/grpc_query_long_book_test.go deleted file mode 100644 index ac29f3991..000000000 --- a/x/dex/keeper/query/grpc_query_long_book_test.go +++ /dev/null @@ -1,123 +0,0 @@ -package query_test - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/cosmos-sdk/types/query" - "github.com/stretchr/testify/require" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/testutil/nullify" - keeperquery "github.com/sei-protocol/sei-chain/x/dex/keeper/query" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -func TestLongBookQuerySingle(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - wrapper := keeperquery.KeeperWrapper{Keeper: keeper} - wctx := sdk.WrapSDKContext(ctx) - msgs := keepertest.CreateNLongBook(keeper, ctx, 2) - for _, tc := range []struct { - desc string - request *types.QueryGetLongBookRequest - response *types.QueryGetLongBookResponse - err error - }{ - { - desc: "First", - request: &types.QueryGetLongBookRequest{Price: msgs[0].Price.String(), ContractAddr: keepertest.TestContract, PriceDenom: keepertest.TestPriceDenom, AssetDenom: keepertest.TestAssetDenom}, - response: &types.QueryGetLongBookResponse{LongBook: msgs[0]}, - }, - { - desc: "Second", - request: &types.QueryGetLongBookRequest{Price: msgs[1].Price.String(), ContractAddr: keepertest.TestContract, PriceDenom: keepertest.TestPriceDenom, AssetDenom: keepertest.TestAssetDenom}, - response: &types.QueryGetLongBookResponse{LongBook: msgs[1]}, - }, - { - desc: "KeyNotFound", - request: &types.QueryGetLongBookRequest{Price: "100000", ContractAddr: keepertest.TestContract, PriceDenom: keepertest.TestPriceDenom, AssetDenom: keepertest.TestAssetDenom}, - err: sdkerrors.ErrKeyNotFound, - }, - { - desc: "InvalidRequest", - err: status.Error(codes.InvalidArgument, "invalid request"), - }, - } { - t.Run(tc.desc, func(t *testing.T) { - response, err := wrapper.LongBook(wctx, tc.request) - if tc.err != nil { - require.ErrorIs(t, err, tc.err) - } else { - require.NoError(t, err) - require.Equal(t, - nullify.Fill(tc.response), - nullify.Fill(response), - ) - } - }) - } -} - -func TestLongBookQueryPaginated(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - wrapper := keeperquery.KeeperWrapper{Keeper: keeper} - wctx := sdk.WrapSDKContext(ctx) - msgs := keepertest.CreateNLongBook(keeper, ctx, 5) - - request := func(next []byte, offset, limit uint64, total bool) *types.QueryAllLongBookRequest { - return &types.QueryAllLongBookRequest{ - Pagination: &query.PageRequest{ - Key: next, - Offset: offset, - Limit: limit, - CountTotal: total, - }, - ContractAddr: keepertest.TestContract, - PriceDenom: keepertest.TestPriceDenom, - AssetDenom: keepertest.TestAssetDenom, - } - } - t.Run("ByOffset", func(t *testing.T) { - step := 2 - for i := 0; i < len(msgs); i += step { - resp, err := wrapper.LongBookAll(wctx, request(nil, uint64(i), uint64(step), false)) - require.NoError(t, err) - require.LessOrEqual(t, len(resp.LongBook), step) - require.Subset(t, - nullify.Fill(msgs), - nullify.Fill(resp.LongBook), - ) - } - }) - t.Run("ByKey", func(t *testing.T) { - step := 2 - var next []byte - for i := 0; i < len(msgs); i += step { - resp, err := wrapper.LongBookAll(wctx, request(next, 0, uint64(step), false)) - require.NoError(t, err) - require.LessOrEqual(t, len(resp.LongBook), step) - require.Subset(t, - nullify.Fill(msgs), - nullify.Fill(resp.LongBook), - ) - next = resp.Pagination.NextKey - } - }) - t.Run("Total", func(t *testing.T) { - resp, err := wrapper.LongBookAll(wctx, request(nil, 0, 0, true)) - require.NoError(t, err) - require.Equal(t, len(msgs), int(resp.Pagination.Total)) - require.ElementsMatch(t, - nullify.Fill(msgs), - nullify.Fill(resp.LongBook), - ) - }) - t.Run("InvalidRequest", func(t *testing.T) { - _, err := wrapper.LongBookAll(wctx, nil) - require.ErrorIs(t, err, status.Error(codes.InvalidArgument, "invalid request")) - }) -} diff --git a/x/dex/keeper/query/grpc_query_match_result.go b/x/dex/keeper/query/grpc_query_match_result.go deleted file mode 100644 index 95226904e..000000000 --- a/x/dex/keeper/query/grpc_query_match_result.go +++ /dev/null @@ -1,24 +0,0 @@ -package query - -import ( - "context" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/types" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" -) - -func (k KeeperWrapper) GetMatchResult(c context.Context, req *types.QueryGetMatchResultRequest) (*types.QueryGetMatchResultResponse, error) { - if req == nil { - return nil, status.Error(codes.InvalidArgument, "invalid request") - } - ctx := sdk.UnwrapSDKContext(c) - - result, found := k.GetMatchResultState(ctx, req.ContractAddr) - if !found { - return nil, status.Error(codes.NotFound, "result not found") - } - - return &types.QueryGetMatchResultResponse{Result: result}, nil -} diff --git a/x/dex/keeper/query/grpc_query_order.go b/x/dex/keeper/query/grpc_query_order.go deleted file mode 100644 index 556c640a6..000000000 --- a/x/dex/keeper/query/grpc_query_order.go +++ /dev/null @@ -1,112 +0,0 @@ -package query - -import ( - "context" - - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -// To be deprecated once offchain query is built -func (k KeeperWrapper) GetOrder(c context.Context, req *types.QueryGetOrderByIDRequest) (*types.QueryGetOrderByIDResponse, error) { - if req == nil { - return nil, status.Error(codes.InvalidArgument, "invalid request") - } - ctx := sdk.UnwrapSDKContext(c) - longBooks := k.GetAllLongBook(ctx, req.ContractAddr) - for _, longBook := range longBooks { - for _, allocation := range longBook.Entry.Allocations { - if allocation.OrderId == req.Id { - return &types.QueryGetOrderByIDResponse{ - Order: &types.Order{ - Id: req.Id, - Price: longBook.Price, - Quantity: allocation.Quantity, - PriceDenom: longBook.Entry.PriceDenom, - AssetDenom: longBook.Entry.AssetDenom, - OrderType: types.OrderType_LIMIT, - Status: types.OrderStatus_PLACED, - ContractAddr: req.ContractAddr, - PositionDirection: types.PositionDirection_LONG, - Account: allocation.Account, - }, - }, nil - } - } - } - shortBooks := k.GetAllShortBook(ctx, req.ContractAddr) - for _, shortBook := range shortBooks { - for _, allocation := range shortBook.Entry.Allocations { - if allocation.OrderId == req.Id { - return &types.QueryGetOrderByIDResponse{ - Order: &types.Order{ - Id: req.Id, - Price: shortBook.Price, - Quantity: allocation.Quantity, - PriceDenom: shortBook.Entry.PriceDenom, - AssetDenom: shortBook.Entry.AssetDenom, - OrderType: types.OrderType_LIMIT, - Status: types.OrderStatus_PLACED, - ContractAddr: req.ContractAddr, - PositionDirection: types.PositionDirection_SHORT, - Account: allocation.Account, - }, - }, nil - } - } - } - - return &types.QueryGetOrderByIDResponse{}, types.ErrInvalidOrderID -} - -// To be deprecated once offchain query is built -func (k KeeperWrapper) GetOrders(c context.Context, req *types.QueryGetOrdersRequest) (*types.QueryGetOrdersResponse, error) { - if req == nil { - return nil, status.Error(codes.InvalidArgument, "invalid request") - } - ctx := sdk.UnwrapSDKContext(c) - orders := []*types.Order{} - longBooks := k.GetAllLongBook(ctx, req.ContractAddr) - for _, longBook := range longBooks { - for _, allocation := range longBook.Entry.Allocations { - if allocation.Account == req.Account { - orders = append(orders, &types.Order{ - Id: allocation.OrderId, - Price: longBook.Price, - Quantity: allocation.Quantity, - PriceDenom: longBook.Entry.PriceDenom, - AssetDenom: longBook.Entry.AssetDenom, - OrderType: types.OrderType_LIMIT, - Status: types.OrderStatus_PLACED, - ContractAddr: req.ContractAddr, - PositionDirection: types.PositionDirection_LONG, - Account: allocation.Account, - }) - } - } - } - shortBooks := k.GetAllShortBook(ctx, req.ContractAddr) - for _, shortBook := range shortBooks { - for _, allocation := range shortBook.Entry.Allocations { - if allocation.Account == req.Account { - orders = append(orders, &types.Order{ - Id: allocation.OrderId, - Price: shortBook.Price, - Quantity: allocation.Quantity, - PriceDenom: shortBook.Entry.PriceDenom, - AssetDenom: shortBook.Entry.AssetDenom, - OrderType: types.OrderType_LIMIT, - Status: types.OrderStatus_PLACED, - ContractAddr: req.ContractAddr, - PositionDirection: types.PositionDirection_SHORT, - Account: allocation.Account, - }) - } - } - } - - return &types.QueryGetOrdersResponse{Orders: orders}, nil -} diff --git a/x/dex/keeper/query/grpc_query_order_simulation.go b/x/dex/keeper/query/grpc_query_order_simulation.go deleted file mode 100644 index e16308c95..000000000 --- a/x/dex/keeper/query/grpc_query_order_simulation.go +++ /dev/null @@ -1,120 +0,0 @@ -package query - -import ( - "context" - "sort" - - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/types" - dexutils "github.com/sei-protocol/sei-chain/x/dex/utils" -) - -type priceQuantity struct { - price sdk.Dec - quantity sdk.Dec -} - -// Note that this simulation is only accurate if it's called as part of the main Sei process (e.g. in Begin/EndBlock, transaction handler -// or contract querier), because it needs to access dex's in-memory state. -func (k KeeperWrapper) GetOrderSimulation(c context.Context, req *types.QueryOrderSimulationRequest) (*types.QueryOrderSimulationResponse, error) { - if req == nil { - return nil, status.Error(codes.InvalidArgument, "invalid request") - } - ctx := sdk.UnwrapSDKContext(c) - matchedPriceQuantities := k.getMatchedPriceQuantities(ctx, req) - executedQuantity := sdk.ZeroDec() - for _, pq := range matchedPriceQuantities { - if executedQuantity.Add(pq.quantity).GTE(req.Order.Quantity) { - executedQuantity = req.Order.Quantity - break - } - executedQuantity = executedQuantity.Add(pq.quantity) - } - return &types.QueryOrderSimulationResponse{ - ExecutedQuantity: &executedQuantity, - }, nil -} - -func (k KeeperWrapper) getMatchedPriceQuantities(ctx sdk.Context, req *types.QueryOrderSimulationRequest) []priceQuantity { - orderDirection := req.Order.PositionDirection - // get existing liquidity - eligibleOrderBookPriceToQuantity := map[string]sdk.Dec{} - if orderDirection == types.PositionDirection_SHORT { - for _, lb := range k.GetAllLongBookForPair(ctx, req.ContractAddr, req.Order.PriceDenom, req.Order.AssetDenom) { - if req.Order.Price.IsZero() || req.Order.Price.LTE(lb.GetPrice()) { - eligibleOrderBookPriceToQuantity[lb.GetPrice().String()] = lb.GetOrderEntry().Quantity - } - } - } else { - for _, sb := range k.GetAllShortBookForPair(ctx, req.ContractAddr, req.Order.PriceDenom, req.Order.AssetDenom) { - if req.Order.Price.IsZero() || req.Order.Price.GTE(sb.GetPrice()) { - eligibleOrderBookPriceToQuantity[sb.GetPrice().String()] = sb.GetOrderEntry().Quantity - } - } - } - - // exclude liquidity to be cancelled - pair := types.Pair{PriceDenom: req.Order.PriceDenom, AssetDenom: req.Order.AssetDenom} - for _, cancel := range dexutils.GetMemState(ctx.Context()).GetBlockCancels(ctx, types.ContractAddress(req.ContractAddr), pair).Get() { - var cancelledAllocation *types.Allocation - var found bool - if cancel.PositionDirection == types.PositionDirection_LONG { - cancelledAllocation, found = k.GetLongAllocationForOrderID(ctx, req.ContractAddr, cancel.PriceDenom, cancel.AssetDenom, cancel.Price, cancel.Id) - } else { - cancelledAllocation, found = k.GetShortAllocationForOrderID(ctx, req.ContractAddr, cancel.PriceDenom, cancel.AssetDenom, cancel.Price, cancel.Id) - } - if !found { - continue - } - if q, ok := eligibleOrderBookPriceToQuantity[cancel.Price.String()]; ok { - eligibleOrderBookPriceToQuantity[cancel.Price.String()] = q.Sub(cancelledAllocation.Quantity) - } - } - - priceQuantities := []priceQuantity{} - for price, quantity := range eligibleOrderBookPriceToQuantity { - if quantity.IsPositive() { - priceQuantities = append(priceQuantities, priceQuantity{price: sdk.MustNewDecFromStr(price), quantity: quantity}) - } - } - sort.Slice(priceQuantities, func(i int, j int) bool { - if orderDirection == types.PositionDirection_SHORT { - // short order corresponds to long book which needs to be in descending order - return priceQuantities[i].price.GT(priceQuantities[j].price) - } - // long order corresponds to long book which needs to be in ascending order - return priceQuantities[i].price.LT(priceQuantities[j].price) - }) - - // exclude liquidity to be taken - ptr := 0 - for _, order := range dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, types.ContractAddress(req.ContractAddr), pair).GetSortedMarketOrders(orderDirection) { - // If existing market order has price zero, it means it doesn't specify a worst price and will always have precedence over the simulated - // order - if !order.Price.IsZero() { - // If the simulated order doesn't specify a worst price, no existing order with a worst price will take liquidity from it - if req.Order.Price.IsZero() { - break - } - if orderDirection == types.PositionDirection_LONG && order.Price.LT(req.Order.Price) { - break - } - if orderDirection == types.PositionDirection_SHORT && order.Price.GT(req.Order.Price) { - break - } - } - remainingQuantity := order.Quantity - for ptr < len(priceQuantities) { - if remainingQuantity.LTE(priceQuantities[ptr].quantity) { - priceQuantities[ptr].quantity = priceQuantities[ptr].quantity.Sub(remainingQuantity) - break - } - remainingQuantity = remainingQuantity.Sub(priceQuantities[ptr].quantity) - ptr++ - } - } - return priceQuantities[ptr:] -} diff --git a/x/dex/keeper/query/grpc_query_order_simulation_test.go b/x/dex/keeper/query/grpc_query_order_simulation_test.go deleted file mode 100644 index 07bfb2ccb..000000000 --- a/x/dex/keeper/query/grpc_query_order_simulation_test.go +++ /dev/null @@ -1,101 +0,0 @@ -package query_test - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex/keeper/query" - "github.com/sei-protocol/sei-chain/x/dex/types" - dexutils "github.com/sei-protocol/sei-chain/x/dex/utils" - "github.com/stretchr/testify/require" -) - -func TestGetOrderSimulation(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - wrapper := query.KeeperWrapper{Keeper: keeper} - wctx := sdk.WrapSDKContext(ctx) - - testOrder := types.Order{ - Account: keepertest.TestAccount, - ContractAddr: keepertest.TestContract, - PriceDenom: keepertest.TestPriceDenom, - AssetDenom: keepertest.TestAssetDenom, - Price: sdk.MustNewDecFromStr("10"), - Quantity: sdk.MustNewDecFromStr("5"), - PositionDirection: types.PositionDirection_LONG, - } - - // no liquidity - res, err := wrapper.GetOrderSimulation(wctx, &types.QueryOrderSimulationRequest{Order: &testOrder, ContractAddr: keepertest.TestContract}) - require.Nil(t, err) - require.Equal(t, sdk.ZeroDec(), *res.ExecutedQuantity) - - // partial liquidity on orderbook - keeper.SetShortBook(ctx, keepertest.TestContract, types.ShortBook{ - Price: sdk.MustNewDecFromStr("9"), - Entry: &types.OrderEntry{ - Price: sdk.MustNewDecFromStr("9"), - Quantity: sdk.MustNewDecFromStr("2"), - PriceDenom: keepertest.TestPriceDenom, - AssetDenom: keepertest.TestAssetDenom, - }, - }) - res, err = wrapper.GetOrderSimulation(wctx, &types.QueryOrderSimulationRequest{Order: &testOrder, ContractAddr: keepertest.TestContract}) - require.Nil(t, err) - require.Equal(t, sdk.MustNewDecFromStr("2"), *res.ExecutedQuantity) - - // full liquidity on orderbook - keeper.SetShortBook(ctx, keepertest.TestContract, types.ShortBook{ - Price: sdk.MustNewDecFromStr("8"), - Entry: &types.OrderEntry{ - Price: sdk.MustNewDecFromStr("8"), - Quantity: sdk.MustNewDecFromStr("1"), - PriceDenom: keepertest.TestPriceDenom, - AssetDenom: keepertest.TestAssetDenom, - }, - }) - res, err = wrapper.GetOrderSimulation(wctx, &types.QueryOrderSimulationRequest{Order: &testOrder, ContractAddr: keepertest.TestContract}) - require.Nil(t, err) - require.Equal(t, sdk.MustNewDecFromStr("3"), *res.ExecutedQuantity) - - // liquidity taken by cancel - keeper.SetShortBook(ctx, keepertest.TestContract, types.ShortBook{ - Price: sdk.MustNewDecFromStr("9"), - Entry: &types.OrderEntry{ - Price: sdk.MustNewDecFromStr("9"), - Quantity: sdk.MustNewDecFromStr("2"), - PriceDenom: keepertest.TestPriceDenom, - AssetDenom: keepertest.TestAssetDenom, - Allocations: []*types.Allocation{ - { - Account: keepertest.TestAccount, - Quantity: sdk.MustNewDecFromStr("2"), - OrderId: 1, - }, - }, - }, - }) - dexutils.GetMemState(ctx.Context()).GetBlockCancels(ctx, types.ContractAddress(keepertest.TestContract), keepertest.TestPair).Add( - &types.Cancellation{Id: 1, Price: sdk.MustNewDecFromStr("9"), PositionDirection: types.PositionDirection_SHORT, PriceDenom: keepertest.TestPriceDenom, AssetDenom: keepertest.TestAssetDenom}, - ) - res, err = wrapper.GetOrderSimulation(wctx, &types.QueryOrderSimulationRequest{Order: &testOrder, ContractAddr: keepertest.TestContract}) - require.Nil(t, err) - require.Equal(t, sdk.OneDec(), *res.ExecutedQuantity) - - // liquidity taken by earlier market orders - dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, types.ContractAddress(keepertest.TestContract), keepertest.TestPair).Add( - &types.Order{ - Account: keepertest.TestAccount, - PriceDenom: keepertest.TestPriceDenom, - AssetDenom: keepertest.TestAssetDenom, - Price: sdk.MustNewDecFromStr("11"), - Quantity: sdk.MustNewDecFromStr("2"), - PositionDirection: types.PositionDirection_LONG, - OrderType: types.OrderType_MARKET, - }, - ) - res, err = wrapper.GetOrderSimulation(wctx, &types.QueryOrderSimulationRequest{Order: &testOrder, ContractAddr: keepertest.TestContract}) - require.Nil(t, err) - require.Equal(t, sdk.ZeroDec(), *res.ExecutedQuantity) -} diff --git a/x/dex/keeper/query/grpc_query_order_test.go b/x/dex/keeper/query/grpc_query_order_test.go deleted file mode 100644 index 32025934a..000000000 --- a/x/dex/keeper/query/grpc_query_order_test.go +++ /dev/null @@ -1,75 +0,0 @@ -package query_test - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex/keeper/query" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestGetOrderById(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - wrapper := query.KeeperWrapper{Keeper: keeper} - wctx := sdk.WrapSDKContext(ctx) - // active order - keeper.SetLongBook(ctx, keepertest.TestContract, types.LongBook{ - Price: sdk.OneDec(), - Entry: &types.OrderEntry{ - Price: sdk.OneDec(), - Quantity: sdk.MustNewDecFromStr("2"), - PriceDenom: keepertest.TestPriceDenom, - AssetDenom: keepertest.TestAssetDenom, - Allocations: []*types.Allocation{ - { - Account: keepertest.TestAccount, - OrderId: 1, - Quantity: sdk.MustNewDecFromStr("2"), - }, - }, - }, - }) - query := types.QueryGetOrderByIDRequest{ - ContractAddr: keepertest.TestContract, - PriceDenom: keepertest.TestPriceDenom, - AssetDenom: keepertest.TestAssetDenom, - Id: 1, - } - resp, err := wrapper.GetOrder(wctx, &query) - require.Nil(t, err) - require.Equal(t, uint64(1), resp.Order.Id) - require.Equal(t, types.OrderStatus_PLACED, resp.Order.Status) -} - -func TestGetOrders(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - wrapper := query.KeeperWrapper{Keeper: keeper} - wctx := sdk.WrapSDKContext(ctx) - // active order - keeper.SetLongBook(ctx, keepertest.TestContract, types.LongBook{ - Price: sdk.OneDec(), - Entry: &types.OrderEntry{ - Price: sdk.OneDec(), - Quantity: sdk.MustNewDecFromStr("2"), - PriceDenom: keepertest.TestPriceDenom, - AssetDenom: keepertest.TestAssetDenom, - Allocations: []*types.Allocation{ - { - Account: keepertest.TestAccount, - OrderId: 1, - Quantity: sdk.MustNewDecFromStr("2"), - }, - }, - }, - }) - - query := types.QueryGetOrdersRequest{ - ContractAddr: keepertest.TestContract, - Account: keepertest.TestAccount, - } - resp, err := wrapper.GetOrders(wctx, &query) - require.Nil(t, err) - require.Equal(t, 1, len(resp.Orders)) -} diff --git a/x/dex/keeper/query/grpc_query_params.go b/x/dex/keeper/query/grpc_query_params.go deleted file mode 100644 index 2b7772ef2..000000000 --- a/x/dex/keeper/query/grpc_query_params.go +++ /dev/null @@ -1,19 +0,0 @@ -package query - -import ( - "context" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/types" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" -) - -func (k KeeperWrapper) Params(c context.Context, req *types.QueryParamsRequest) (*types.QueryParamsResponse, error) { - if req == nil { - return nil, status.Error(codes.InvalidArgument, "invalid request") - } - ctx := sdk.UnwrapSDKContext(c) - - return &types.QueryParamsResponse{Params: k.GetParams(ctx)}, nil -} diff --git a/x/dex/keeper/query/grpc_query_params_test.go b/x/dex/keeper/query/grpc_query_params_test.go deleted file mode 100644 index ff1eecdbe..000000000 --- a/x/dex/keeper/query/grpc_query_params_test.go +++ /dev/null @@ -1,23 +0,0 @@ -package query_test - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex/keeper/query" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestParamsQuery(t *testing.T) { - keeper, ctx := testkeeper.DexKeeper(t) - wrapper := query.KeeperWrapper{Keeper: keeper} - wctx := sdk.WrapSDKContext(ctx) - params := types.DefaultParams() - keeper.SetParams(ctx, params) - - response, err := wrapper.Params(wctx, &types.QueryParamsRequest{}) - require.NoError(t, err) - require.Equal(t, &types.QueryParamsResponse{Params: params}, response) -} diff --git a/x/dex/keeper/query/grpc_query_registered_contract.go b/x/dex/keeper/query/grpc_query_registered_contract.go deleted file mode 100644 index 63e870e86..000000000 --- a/x/dex/keeper/query/grpc_query_registered_contract.go +++ /dev/null @@ -1,24 +0,0 @@ -package query - -import ( - "context" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/types" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" -) - -func (k KeeperWrapper) GetRegisteredContract(c context.Context, req *types.QueryRegisteredContractRequest) (*types.QueryRegisteredContractResponse, error) { - if req == nil { - return nil, status.Error(codes.InvalidArgument, "invalid request") - } - ctx := sdk.UnwrapSDKContext(c) - - contractInfo, err := k.GetContract(ctx, req.ContractAddr) - if err != nil { - return nil, err - } - - return &types.QueryRegisteredContractResponse{ContractInfo: &contractInfo}, nil -} diff --git a/x/dex/keeper/query/grpc_query_registered_contract_test.go b/x/dex/keeper/query/grpc_query_registered_contract_test.go deleted file mode 100644 index 15a6f751a..000000000 --- a/x/dex/keeper/query/grpc_query_registered_contract_test.go +++ /dev/null @@ -1,42 +0,0 @@ -package query_test - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex/keeper/query" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestRegisteredContractQuery(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - wrapper := query.KeeperWrapper{Keeper: keeper} - wctx := sdk.WrapSDKContext(ctx) - expectedContractInfo := types.ContractInfoV2{ - Creator: keepertest.TestAccount, - ContractAddr: keepertest.TestContract, - CodeId: 1, - RentBalance: 1000000, - } - err := keeper.SetContract(ctx, &types.ContractInfoV2{ - Creator: keepertest.TestAccount, - ContractAddr: keepertest.TestContract, - CodeId: 1, - RentBalance: 1000000, - }) - require.NoError(t, err) - - request := types.QueryRegisteredContractRequest{ - ContractAddr: keepertest.TestContract, - } - expectedResponse := types.QueryRegisteredContractResponse{ - ContractInfo: &expectedContractInfo, - } - t.Run("Registered Contract query", func(t *testing.T) { - response, err := wrapper.GetRegisteredContract(wctx, &request) - require.NoError(t, err) - require.Equal(t, expectedResponse, *response) - }) -} diff --git a/x/dex/keeper/query/grpc_query_registered_pairs.go b/x/dex/keeper/query/grpc_query_registered_pairs.go deleted file mode 100644 index e32f68163..000000000 --- a/x/dex/keeper/query/grpc_query_registered_pairs.go +++ /dev/null @@ -1,21 +0,0 @@ -package query - -import ( - "context" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/types" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" -) - -func (k KeeperWrapper) GetRegisteredPairs(c context.Context, req *types.QueryRegisteredPairsRequest) (*types.QueryRegisteredPairsResponse, error) { - if req == nil { - return nil, status.Error(codes.InvalidArgument, "invalid request") - } - ctx := sdk.UnwrapSDKContext(c) - - registeredPairs := k.GetAllRegisteredPairs(ctx, req.ContractAddr) - - return &types.QueryRegisteredPairsResponse{Pairs: registeredPairs}, nil -} diff --git a/x/dex/keeper/query/grpc_query_registered_pairs_test.go b/x/dex/keeper/query/grpc_query_registered_pairs_test.go deleted file mode 100644 index 2b6007a4a..000000000 --- a/x/dex/keeper/query/grpc_query_registered_pairs_test.go +++ /dev/null @@ -1,39 +0,0 @@ -package query_test - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex/keeper/query" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestRegisteredPairsQuery(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - wrapper := query.KeeperWrapper{Keeper: keeper} - wctx := sdk.WrapSDKContext(ctx) - expectedPair := types.Pair{ - PriceDenom: keepertest.TestPriceDenom, - AssetDenom: keepertest.TestAssetDenom, - PriceTicksize: &keepertest.TestTicksize, - QuantityTicksize: &keepertest.TestTicksize, - } - keeper.AddRegisteredPair(ctx, keepertest.TestContract, expectedPair) - - var expectedRegisteredPairs []types.Pair - expectedRegisteredPairs = append(expectedRegisteredPairs, expectedPair) - - request := types.QueryRegisteredPairsRequest{ - ContractAddr: keepertest.TestContract, - } - expectedResponse := types.QueryRegisteredPairsResponse{ - Pairs: expectedRegisteredPairs, - } - t.Run("Registered Pairs query", func(t *testing.T) { - response, err := wrapper.GetRegisteredPairs(wctx, &request) - require.NoError(t, err) - require.Equal(t, expectedResponse, *response) - }) -} diff --git a/x/dex/keeper/query/grpc_query_short_book.go b/x/dex/keeper/query/grpc_query_short_book.go deleted file mode 100644 index 21855a20b..000000000 --- a/x/dex/keeper/query/grpc_query_short_book.go +++ /dev/null @@ -1,46 +0,0 @@ -package query - -import ( - "context" - - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/sei-protocol/sei-chain/x/dex/types" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" -) - -func (k KeeperWrapper) ShortBookAll(c context.Context, req *types.QueryAllShortBookRequest) (*types.QueryAllShortBookResponse, error) { - if req == nil { - return nil, status.Error(codes.InvalidArgument, "invalid request") - } - - ctx := sdk.UnwrapSDKContext(c) - - shortBooks, pageRes, err := k.GetAllShortBookForPairPaginated( - ctx, req.ContractAddr, req.PriceDenom, req.AssetDenom, req.Pagination, - ) - if err != nil { - return nil, status.Error(codes.Internal, err.Error()) - } - - return &types.QueryAllShortBookResponse{ShortBook: shortBooks, Pagination: pageRes}, nil -} - -func (k KeeperWrapper) ShortBook(c context.Context, req *types.QueryGetShortBookRequest) (*types.QueryGetShortBookResponse, error) { - if req == nil { - return nil, status.Error(codes.InvalidArgument, "invalid request") - } - - ctx := sdk.UnwrapSDKContext(c) - price, err := sdk.NewDecFromStr(req.Price) - if err != nil { - return nil, err - } - shortBook, found := k.GetShortBookByPrice(ctx, req.ContractAddr, price, req.PriceDenom, req.AssetDenom) - if !found { - return nil, sdkerrors.ErrKeyNotFound - } - - return &types.QueryGetShortBookResponse{ShortBook: shortBook}, nil -} diff --git a/x/dex/keeper/query/grpc_query_short_book_test.go b/x/dex/keeper/query/grpc_query_short_book_test.go deleted file mode 100644 index df919d7fc..000000000 --- a/x/dex/keeper/query/grpc_query_short_book_test.go +++ /dev/null @@ -1,123 +0,0 @@ -package query_test - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/cosmos-sdk/types/query" - "github.com/stretchr/testify/require" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/testutil/nullify" - keeperquery "github.com/sei-protocol/sei-chain/x/dex/keeper/query" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -func TestShortBookQuerySingle(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - wrapper := keeperquery.KeeperWrapper{Keeper: keeper} - wctx := sdk.WrapSDKContext(ctx) - msgs := keepertest.CreateNShortBook(keeper, ctx, 2) - for _, tc := range []struct { - desc string - request *types.QueryGetShortBookRequest - response *types.QueryGetShortBookResponse - err error - }{ - { - desc: "First", - request: &types.QueryGetShortBookRequest{Price: msgs[0].Price.String(), ContractAddr: keepertest.TestContract, PriceDenom: keepertest.TestPriceDenom, AssetDenom: keepertest.TestAssetDenom}, - response: &types.QueryGetShortBookResponse{ShortBook: msgs[0]}, - }, - { - desc: "Second", - request: &types.QueryGetShortBookRequest{Price: msgs[1].Price.String(), ContractAddr: keepertest.TestContract, PriceDenom: keepertest.TestPriceDenom, AssetDenom: keepertest.TestAssetDenom}, - response: &types.QueryGetShortBookResponse{ShortBook: msgs[1]}, - }, - { - desc: "KeyNotFound", - request: &types.QueryGetShortBookRequest{Price: "10000", ContractAddr: keepertest.TestContract, PriceDenom: keepertest.TestPriceDenom, AssetDenom: keepertest.TestAssetDenom}, - err: sdkerrors.ErrKeyNotFound, - }, - { - desc: "InvalidRequest", - err: status.Error(codes.InvalidArgument, "invalid request"), - }, - } { - t.Run(tc.desc, func(t *testing.T) { - response, err := wrapper.ShortBook(wctx, tc.request) - if tc.err != nil { - require.ErrorIs(t, err, tc.err) - } else { - require.NoError(t, err) - require.Equal(t, - nullify.Fill(tc.response), - nullify.Fill(response), - ) - } - }) - } -} - -func TestShortBookQueryPaginated(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - wrapper := keeperquery.KeeperWrapper{Keeper: keeper} - wctx := sdk.WrapSDKContext(ctx) - msgs := keepertest.CreateNShortBook(keeper, ctx, 5) - - request := func(next []byte, offset, limit uint64, total bool) *types.QueryAllShortBookRequest { - return &types.QueryAllShortBookRequest{ - Pagination: &query.PageRequest{ - Key: next, - Offset: offset, - Limit: limit, - CountTotal: total, - }, - ContractAddr: keepertest.TestContract, - PriceDenom: keepertest.TestPriceDenom, - AssetDenom: keepertest.TestAssetDenom, - } - } - t.Run("ByOffset", func(t *testing.T) { - step := 2 - for i := 0; i < len(msgs); i += step { - resp, err := wrapper.ShortBookAll(wctx, request(nil, uint64(i), uint64(step), false)) - require.NoError(t, err) - require.LessOrEqual(t, len(resp.ShortBook), step) - require.Subset(t, - nullify.Fill(msgs), - nullify.Fill(resp.ShortBook), - ) - } - }) - t.Run("ByKey", func(t *testing.T) { - step := 2 - var next []byte - for i := 0; i < len(msgs); i += step { - resp, err := wrapper.ShortBookAll(wctx, request(next, 0, uint64(step), false)) - require.NoError(t, err) - require.LessOrEqual(t, len(resp.ShortBook), step) - require.Subset(t, - nullify.Fill(msgs), - nullify.Fill(resp.ShortBook), - ) - next = resp.Pagination.NextKey - } - }) - t.Run("Total", func(t *testing.T) { - resp, err := wrapper.ShortBookAll(wctx, request(nil, 0, 0, true)) - require.NoError(t, err) - require.Equal(t, len(msgs), int(resp.Pagination.Total)) - require.ElementsMatch(t, - nullify.Fill(msgs), - nullify.Fill(resp.ShortBook), - ) - }) - t.Run("InvalidRequest", func(t *testing.T) { - _, err := wrapper.ShortBookAll(wctx, nil) - require.ErrorIs(t, err, status.Error(codes.InvalidArgument, "invalid request")) - }) -} diff --git a/x/dex/keeper/query/keeper_wrapper.go b/x/dex/keeper/query/keeper_wrapper.go deleted file mode 100644 index e1fcfdd04..000000000 --- a/x/dex/keeper/query/keeper_wrapper.go +++ /dev/null @@ -1,9 +0,0 @@ -package query - -import ( - "github.com/sei-protocol/sei-chain/x/dex/keeper" -) - -type KeeperWrapper struct { - *keeper.Keeper -} diff --git a/x/dex/keeper/short_book.go b/x/dex/keeper/short_book.go deleted file mode 100644 index 3e5763401..000000000 --- a/x/dex/keeper/short_book.go +++ /dev/null @@ -1,165 +0,0 @@ -package keeper - -import ( - "github.com/cosmos/cosmos-sdk/store/prefix" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/query" - "github.com/sei-protocol/sei-chain/x/dex/types" - dexutils "github.com/sei-protocol/sei-chain/x/dex/utils" -) - -// SetShortBook set a specific shortBook in the store -func (k Keeper) SetShortBook(ctx sdk.Context, contractAddr string, shortBook types.ShortBook) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.OrderBookPrefix(false, contractAddr, shortBook.Entry.PriceDenom, shortBook.Entry.AssetDenom)) - b := k.Cdc.MustMarshal(&shortBook) - store.Set(GetKeyForShortBook(shortBook), b) -} - -func (k Keeper) SetShortOrderBookEntry(ctx sdk.Context, contractAddr string, shortBook types.OrderBookEntry) { - k.SetShortBook(ctx, contractAddr, *shortBook.(*types.ShortBook)) -} - -func (k Keeper) GetShortBookByPrice(ctx sdk.Context, contractAddr string, price sdk.Dec, priceDenom string, assetDenom string) (val types.ShortBook, found bool) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.OrderBookPrefix(false, contractAddr, priceDenom, assetDenom)) - b := store.Get(GetKeyForPrice(price)) - if b == nil { - return val, false - } - k.Cdc.MustUnmarshal(b, &val) - return val, true -} - -func (k Keeper) GetShortOrderBookEntryByPrice(ctx sdk.Context, contractAddr string, price sdk.Dec, priceDenom string, assetDenom string) (types.OrderBookEntry, bool) { - entry, found := k.GetShortBookByPrice(ctx, contractAddr, price, priceDenom, assetDenom) - return &entry, found -} - -func (k Keeper) RemoveShortBookByPrice(ctx sdk.Context, contractAddr string, price sdk.Dec, priceDenom string, assetDenom string) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.OrderBookPrefix(false, contractAddr, priceDenom, assetDenom)) - store.Delete(GetKeyForPrice(price)) -} - -// GetAllShortBook returns all shortBook -func (k Keeper) GetAllShortBook(ctx sdk.Context, contractAddr string) (list []types.ShortBook) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.ContractKeyPrefix(types.ShortBookKey, contractAddr)) - iterator := sdk.KVStorePrefixIterator(store, []byte{}) - - defer iterator.Close() - - for ; iterator.Valid(); iterator.Next() { - var val types.ShortBook - k.Cdc.MustUnmarshal(iterator.Value(), &val) - list = append(list, val) - } - - return -} - -func (k Keeper) GetAllShortBookForPair(ctx sdk.Context, contractAddr string, priceDenom string, assetDenom string) (list []types.OrderBookEntry) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.OrderBookPrefix(false, contractAddr, priceDenom, assetDenom)) - iterator := sdk.KVStorePrefixIterator(store, []byte{}) - - defer iterator.Close() - - for ; iterator.Valid(); iterator.Next() { - var val types.ShortBook - k.Cdc.MustUnmarshal(iterator.Value(), &val) - list = append(list, &val) - } - - return -} - -func (k Keeper) GetTopNShortBooksForPair(ctx sdk.Context, contractAddr string, priceDenom string, assetDenom string, n int) (list []types.OrderBookEntry) { - if n == 0 { - return - } - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.OrderBookPrefix(false, contractAddr, priceDenom, assetDenom)) - iterator := sdk.KVStorePrefixIterator(store, []byte{}) - - defer iterator.Close() - - for ; iterator.Valid(); iterator.Next() { - var val types.ShortBook - k.Cdc.MustUnmarshal(iterator.Value(), &val) - list = append(list, &val) - if len(list) == n { - break - } - } - - return -} - -// Load the first (up to) N short book entries whose price are larger than the specified limit -// in sorted order. -// Parameters: -// -// n: the largest number of entries to load -// startExclusive: the price limit -func (k Keeper) GetTopNShortBooksForPairStarting(ctx sdk.Context, contractAddr string, priceDenom string, assetDenom string, n int, startExclusive sdk.Dec) (list []types.OrderBookEntry) { - if n == 0 { - return - } - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.OrderBookPrefix(false, contractAddr, priceDenom, assetDenom)) - iterator := sdk.KVStorePrefixIterator(store, []byte{}) - - defer iterator.Close() - - // Fast-forward - // TODO: add iterator interface that allows starting at a certain subkey under prefix - for ; iterator.Valid(); iterator.Next() { - key := dexutils.BytesToDec(iterator.Key()) - if key.GT(startExclusive) { - break - } - } - - for ; iterator.Valid(); iterator.Next() { - var val types.ShortBook - k.Cdc.MustUnmarshal(iterator.Value(), &val) - list = append(list, &val) - if len(list) == n { - break - } - } - - return -} - -func (k Keeper) GetAllShortBookForPairPaginated(ctx sdk.Context, contractAddr string, priceDenom string, assetDenom string, page *query.PageRequest) (list []types.ShortBook, pageRes *query.PageResponse, err error) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.OrderBookPrefix(false, contractAddr, priceDenom, assetDenom)) - - pageRes, err = query.Paginate(store, page, func(key []byte, value []byte) error { - var shortBook types.ShortBook - if err := k.Cdc.Unmarshal(value, &shortBook); err != nil { - return err - } - - list = append(list, shortBook) - return nil - }) - - return -} - -func (k Keeper) GetShortAllocationForOrderID(ctx sdk.Context, contractAddr string, priceDenom string, assetDenom string, price sdk.Dec, orderID uint64) (*types.Allocation, bool) { - orderBook, found := k.GetShortBookByPrice(ctx, contractAddr, price, priceDenom, assetDenom) - if !found { - return nil, false - } - for _, allocation := range orderBook.Entry.Allocations { - if allocation.OrderId == orderID { - return allocation, true - } - } - return nil, false -} - -func (k Keeper) RemoveAllShortBooksForContract(ctx sdk.Context, contractAddr string) { - k.removeAllForPrefix(ctx, types.OrderBookContractPrefix(false, contractAddr)) -} - -func GetKeyForShortBook(shortBook types.ShortBook) []byte { - return GetKeyForPrice(shortBook.Entry.Price) -} diff --git a/x/dex/keeper/short_book_test.go b/x/dex/keeper/short_book_test.go deleted file mode 100644 index 62e709dfd..000000000 --- a/x/dex/keeper/short_book_test.go +++ /dev/null @@ -1,92 +0,0 @@ -package keeper_test - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/testutil/nullify" - "github.com/sei-protocol/sei-chain/utils" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestShortBookGet(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - items := keepertest.CreateNShortBook(keeper, ctx, 10) - for i, item := range items { - got, found := keeper.GetShortBookByPrice(ctx, keepertest.TestContract, sdk.NewDec(int64(i)), keepertest.TestPriceDenom, keepertest.TestAssetDenom) - require.True(t, found) - require.Equal(t, - nullify.Fill(&item), - nullify.Fill(&got), - ) - } -} - -func TestShortBookRemove(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - items := keepertest.CreateNShortBook(keeper, ctx, 10) - for i := range items { - keeper.RemoveShortBookByPrice(ctx, keepertest.TestContract, sdk.NewDec(int64(i)), keepertest.TestPriceDenom, keepertest.TestAssetDenom) - _, found := keeper.GetShortBookByPrice(ctx, keepertest.TestContract, sdk.NewDec(int64(i)), keepertest.TestPriceDenom, keepertest.TestAssetDenom) - require.False(t, found) - } -} - -func TestShortBookGetAll(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - items := keepertest.CreateNShortBook(keeper, ctx, 10) - require.ElementsMatch(t, - nullify.Fill(items), - nullify.Fill(keeper.GetAllShortBook(ctx, keepertest.TestContract)), - ) -} - -func TestGetTopNShortBooksForPair(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - prices := []string{"9.99", "0.001", "90.0", "10", "10.01", "9.9", "9.0", "1"} - for _, price := range prices { - keeper.SetShortBook(ctx, keepertest.TestContract, types.ShortBook{ - Price: sdk.MustNewDecFromStr(price), - Entry: &types.OrderEntry{ - Price: sdk.MustNewDecFromStr(price), - PriceDenom: keepertest.TestPriceDenom, - AssetDenom: keepertest.TestAssetDenom, - }, - }) - } - expected := []sdk.Dec{ - sdk.MustNewDecFromStr("0.001"), - sdk.MustNewDecFromStr("1"), - sdk.MustNewDecFromStr("9.0"), - sdk.MustNewDecFromStr("9.9"), - sdk.MustNewDecFromStr("9.99"), - sdk.MustNewDecFromStr("10"), - sdk.MustNewDecFromStr("10.01"), - sdk.MustNewDecFromStr("90.0"), - } - loaded := keeper.GetTopNShortBooksForPair(ctx, keepertest.TestContract, keepertest.TestPriceDenom, keepertest.TestAssetDenom, 10) - require.Equal(t, expected, utils.Map(loaded, func(b types.OrderBookEntry) sdk.Dec { return b.GetPrice() })) -} - -func TestGetTopNShortBooksForPairStarting(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - prices := []string{"9.99", "0.001", "90.0", "10", "10.01", "9.9", "9.0", "1"} - for _, price := range prices { - keeper.SetShortBook(ctx, keepertest.TestContract, types.ShortBook{ - Price: sdk.MustNewDecFromStr(price), - Entry: &types.OrderEntry{ - Price: sdk.MustNewDecFromStr(price), - PriceDenom: keepertest.TestPriceDenom, - AssetDenom: keepertest.TestAssetDenom, - }, - }) - } - expected := []sdk.Dec{ - sdk.MustNewDecFromStr("9.0"), - sdk.MustNewDecFromStr("9.9"), - } - loaded := keeper.GetTopNShortBooksForPairStarting(ctx, keepertest.TestContract, keepertest.TestPriceDenom, keepertest.TestAssetDenom, 2, sdk.MustNewDecFromStr("1")) - require.Equal(t, expected, utils.Map(loaded, func(b types.OrderBookEntry) sdk.Dec { return b.GetPrice() })) -} diff --git a/x/dex/keeper/tick.go b/x/dex/keeper/tick.go deleted file mode 100644 index d89295266..000000000 --- a/x/dex/keeper/tick.go +++ /dev/null @@ -1,60 +0,0 @@ -package keeper - -import ( - "github.com/cosmos/cosmos-sdk/store/prefix" - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -// contract_addr, pair -> tick size -func (k Keeper) SetPriceTickSizeForPair(ctx sdk.Context, contractAddr string, pair types.Pair, ticksize sdk.Dec) error { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.RegisteredPairPrefix(contractAddr)) - - pair, found := k.GetRegisteredPair(ctx, contractAddr, pair.PriceDenom, pair.AssetDenom) - if !found { - return types.ErrPairNotRegistered - } - pair.PriceTicksize = &ticksize - store.Set(types.PairPrefix(pair.PriceDenom, pair.AssetDenom), k.Cdc.MustMarshal(&pair)) - - ctx.EventManager().EmitEvent(sdk.NewEvent( - types.EventTypeSetPriceTickSize, - sdk.NewAttribute(types.AttributeKeyContractAddress, contractAddr), - )) - return nil -} - -func (k Keeper) GetPriceTickSizeForPair(ctx sdk.Context, contractAddr string, pair types.Pair) (sdk.Dec, bool) { - pair, found := k.GetRegisteredPair(ctx, contractAddr, pair.PriceDenom, pair.AssetDenom) - if !found { - return sdk.ZeroDec(), false - } - return *pair.PriceTicksize, true -} - -// contract_addr, pair -> tick size -func (k Keeper) SetQuantityTickSizeForPair(ctx sdk.Context, contractAddr string, pair types.Pair, ticksize sdk.Dec) error { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.RegisteredPairPrefix(contractAddr)) - - pair, found := k.GetRegisteredPair(ctx, contractAddr, pair.PriceDenom, pair.AssetDenom) - if !found { - return types.ErrPairNotRegistered - } - pair.QuantityTicksize = &ticksize - store.Set(types.PairPrefix(pair.PriceDenom, pair.AssetDenom), k.Cdc.MustMarshal(&pair)) - - ctx.EventManager().EmitEvent(sdk.NewEvent( - types.EventTypeSetQuantityTickSize, - sdk.NewAttribute(types.AttributeKeyContractAddress, contractAddr), - )) - return nil -} - -func (k Keeper) GetQuantityTickSizeForPair(ctx sdk.Context, contractAddr string, pair types.Pair) (sdk.Dec, bool) { - pair, found := k.GetRegisteredPair(ctx, contractAddr, pair.PriceDenom, pair.AssetDenom) - if !found { - return sdk.ZeroDec(), false - } - return *pair.QuantityTicksize, true -} diff --git a/x/dex/keeper/tick_test.go b/x/dex/keeper/tick_test.go deleted file mode 100644 index 80abe43e9..000000000 --- a/x/dex/keeper/tick_test.go +++ /dev/null @@ -1,42 +0,0 @@ -package keeper_test - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestPriceTickSizeGet(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - // TEST_PAIR = atom/usdc pair - contractAddr := "sei14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sh9m79m" - ticksize, found := keeper.GetPriceTickSizeForPair(ctx, contractAddr, keepertest.TestPair) - assert.Equal(t, ticksize, sdk.ZeroDec()) - assert.False(t, found) - - keeper.AddRegisteredPair(ctx, contractAddr, keepertest.TestPair) - err := keeper.SetPriceTickSizeForPair(ctx, contractAddr, keepertest.TestPair, sdk.NewDec(2)) - require.NoError(t, err) - ticksize, found = keeper.GetPriceTickSizeForPair(ctx, contractAddr, keepertest.TestPair) - assert.Equal(t, ticksize, sdk.NewDec(2)) - assert.True(t, found) -} - -func TestQuantityTickSizeGet(t *testing.T) { - keeper, ctx := keepertest.DexKeeper(t) - // TEST_PAIR = atom/usdc pair - contractAddr := "sei14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sh9m79m" - ticksize, found := keeper.GetQuantityTickSizeForPair(ctx, contractAddr, keepertest.TestPair) - assert.Equal(t, ticksize, sdk.ZeroDec()) - assert.False(t, found) - - keeper.AddRegisteredPair(ctx, contractAddr, keepertest.TestPair) - err := keeper.SetQuantityTickSizeForPair(ctx, contractAddr, keepertest.TestPair, sdk.NewDec(2)) - require.NoError(t, err) - ticksize, found = keeper.GetQuantityTickSizeForPair(ctx, contractAddr, keepertest.TestPair) - assert.Equal(t, ticksize, sdk.NewDec(2)) - assert.True(t, found) -} diff --git a/x/dex/keeper/utils/order_book.go b/x/dex/keeper/utils/order_book.go deleted file mode 100644 index c232ac27f..000000000 --- a/x/dex/keeper/utils/order_book.go +++ /dev/null @@ -1,89 +0,0 @@ -package utils - -import ( - "fmt" - "sync" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/utils/datastructures" - "github.com/sei-protocol/sei-chain/x/dex/keeper" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -func PopulateOrderbook( - ctx sdk.Context, - keeper *keeper.Keeper, - contractAddr types.ContractAddress, - pair types.Pair, -) *types.OrderBook { - // TODO update to param - loadCnt := int(keeper.GetOrderBookEntriesPerLoad(ctx)) - longLoader := func(lctx sdk.Context, startExclusive sdk.Dec, withLimit bool) []types.OrderBookEntry { - if !withLimit { - return keeper.GetTopNLongBooksForPair(lctx, string(contractAddr), pair.PriceDenom, pair.AssetDenom, loadCnt) - } - return keeper.GetTopNLongBooksForPairStarting(lctx, string(contractAddr), pair.PriceDenom, pair.AssetDenom, loadCnt, startExclusive) - } - shortLoader := func(lctx sdk.Context, startExclusive sdk.Dec, withLimit bool) []types.OrderBookEntry { - if !withLimit { - return keeper.GetTopNShortBooksForPair(lctx, string(contractAddr), pair.PriceDenom, pair.AssetDenom, loadCnt) - } - return keeper.GetTopNShortBooksForPairStarting(lctx, string(contractAddr), pair.PriceDenom, pair.AssetDenom, loadCnt, startExclusive) - } - longSetter := func(lctx sdk.Context, o types.OrderBookEntry) { - keeper.SetLongOrderBookEntry(lctx, string(contractAddr), o) - err := keeper.SetOrderCount(lctx, string(contractAddr), pair.PriceDenom, pair.AssetDenom, types.PositionDirection_LONG, o.GetPrice(), uint64(len(o.GetOrderEntry().GetAllocations()))) - if err != nil { - ctx.Logger().Error(fmt.Sprintf("error setting order count: %s", err)) - } - } - shortSetter := func(lctx sdk.Context, o types.OrderBookEntry) { - keeper.SetShortOrderBookEntry(lctx, string(contractAddr), o) - err := keeper.SetOrderCount(lctx, string(contractAddr), pair.PriceDenom, pair.AssetDenom, types.PositionDirection_SHORT, o.GetPrice(), uint64(len(o.GetOrderEntry().GetAllocations()))) - if err != nil { - ctx.Logger().Error(fmt.Sprintf("error setting order count: %s", err)) - } - } - longDeleter := func(lctx sdk.Context, o types.OrderBookEntry) { - keeper.RemoveLongBookByPrice(lctx, string(contractAddr), o.GetPrice(), pair.PriceDenom, pair.AssetDenom) - err := keeper.SetOrderCount(lctx, string(contractAddr), pair.PriceDenom, pair.AssetDenom, types.PositionDirection_LONG, o.GetPrice(), 0) - if err != nil { - ctx.Logger().Error(fmt.Sprintf("error setting order count: %s", err)) - } - } - shortDeleter := func(lctx sdk.Context, o types.OrderBookEntry) { - keeper.RemoveShortBookByPrice(lctx, string(contractAddr), o.GetPrice(), pair.PriceDenom, pair.AssetDenom) - err := keeper.SetOrderCount(lctx, string(contractAddr), pair.PriceDenom, pair.AssetDenom, types.PositionDirection_SHORT, o.GetPrice(), 0) - if err != nil { - ctx.Logger().Error(fmt.Sprintf("error setting order count: %s", err)) - } - } - return &types.OrderBook{ - Contract: contractAddr, - Pair: pair, - Longs: types.NewCachedSortedOrderBookEntries(longLoader, longSetter, longDeleter), - Shorts: types.NewCachedSortedOrderBookEntries(shortLoader, shortSetter, shortDeleter), - } -} - -func PopulateAllOrderbooks( - ctx sdk.Context, - keeper *keeper.Keeper, - contractsAndPairs map[string][]types.Pair, -) *datastructures.TypedNestedSyncMap[string, types.PairString, *types.OrderBook] { - var orderBooks = datastructures.NewTypedNestedSyncMap[string, types.PairString, *types.OrderBook]() - wg := sync.WaitGroup{} - for contractAddr, pairs := range contractsAndPairs { - orderBooks.Store(contractAddr, datastructures.NewTypedSyncMap[types.PairString, *types.OrderBook]()) - for _, pair := range pairs { - wg.Add(1) - go func(contractAddr string, pair types.Pair) { - defer wg.Done() - orderBook := PopulateOrderbook(ctx, keeper, types.ContractAddress(contractAddr), pair) - orderBooks.StoreNested(contractAddr, types.GetPairString(&pair), orderBook) - }(contractAddr, pair) - } - } - wg.Wait() - return orderBooks -} diff --git a/x/dex/keeper/utils/price.go b/x/dex/keeper/utils/price.go deleted file mode 100644 index 9552c2fb7..000000000 --- a/x/dex/keeper/utils/price.go +++ /dev/null @@ -1,28 +0,0 @@ -package utils - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/exchange" - "github.com/sei-protocol/sei-chain/x/dex/keeper" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -func SetPriceStateFromExecutionOutcome( - ctx sdk.Context, - keeper *keeper.Keeper, - contractAddr types.ContractAddress, - pair types.Pair, - outcome exchange.ExecutionOutcome, -) { - if outcome.TotalQuantity.IsZero() { - return - } - - avgPrice := outcome.TotalNotional.Quo(outcome.TotalQuantity) - priceState := types.Price{ - Pair: &pair, - Price: avgPrice, - SnapshotTimestampInSeconds: uint64(ctx.BlockTime().Unix()), - } - keeper.SetPriceState(ctx, priceState, string(contractAddr)) -} diff --git a/x/dex/keeper/utils/wasm.go b/x/dex/keeper/utils/wasm.go deleted file mode 100644 index 8cc335455..000000000 --- a/x/dex/keeper/utils/wasm.go +++ /dev/null @@ -1,116 +0,0 @@ -package utils - -import ( - "encoding/json" - "fmt" - "strings" - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/utils" - "github.com/sei-protocol/sei-chain/utils/logging" - "github.com/sei-protocol/sei-chain/utils/metrics" - "github.com/sei-protocol/sei-chain/x/dex/keeper" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -const ErrWasmModuleInstCPUFeatureLiteral = "Error instantiating module: CpuFeature" -const SudoGasEventKey = "sudo-gas" -const LogAfter = 5 * time.Second - -func getMsgType(msg interface{}) string { - switch msg.(type) { - case types.SudoSettlementMsg: - return "settlement" - case types.SudoOrderPlacementMsg: - return "bulk_order_placements" - case types.SudoOrderCancellationMsg: - return "bulk_order_cancellations" - default: - return "unknown" - } -} - -func sudo(sdkCtx sdk.Context, k *keeper.Keeper, contractAddress sdk.AccAddress, wasmMsg []byte, msgType string) ([]byte, uint64, error) { - defer utils.PanicHandler(func(err any) { - utils.MetricsPanicCallback(err, sdkCtx, fmt.Sprintf("%s|%s", contractAddress, msgType)) - })() - - // Measure the time it takes to execute the contract in WASM - defer metrics.MeasureSudoExecutionDuration(time.Now(), msgType) - // set up a tmp context to prevent race condition in reading gas consumed - // Note that the limit will effectively serve as a soft limit since it's - // possible for the actual computation to go above the specified limit, but - // the associated contract would be charged corresponding rent. - gasLimit, err := k.GetContractGasLimit(sdkCtx, contractAddress) - if err != nil { - return nil, 0, err - } - tmpCtx := sdkCtx.WithGasMeter(sdk.NewGasMeterWithMultiplier(sdkCtx, gasLimit)) - data, err := sudoWithoutOutOfGasPanic(tmpCtx, k, contractAddress, wasmMsg, msgType) - gasConsumed := tmpCtx.GasMeter().GasConsumed() - sdkCtx.EventManager().EmitEvent( - sdk.NewEvent( - SudoGasEventKey, - sdk.NewAttribute("consumed", fmt.Sprintf("%d", gasConsumed)), - sdk.NewAttribute("type", msgType), - sdk.NewAttribute("contract", contractAddress.String()), - sdk.NewAttribute("height", fmt.Sprintf("%d", sdkCtx.BlockHeight())), - ), - ) - if gasConsumed > 0 { - sdkCtx.GasMeter().ConsumeGas(gasConsumed, "sudo") - } - if hasErrInstantiatingWasmModuleDueToCPUFeature(err) { - panic(utils.DecorateHardFailError(err)) - } - return data, gasConsumed, err -} - -func sudoWithoutOutOfGasPanic(ctx sdk.Context, k *keeper.Keeper, contractAddress []byte, wasmMsg []byte, logName string) ([]byte, error) { - defer func() { - if err := recover(); err != nil { - // only propagate panic if the error is NOT out of gas - if _, ok := err.(sdk.ErrorOutOfGas); !ok { - panic(err) - } - ctx.Logger().Error(fmt.Sprintf("%s %s is out of gas", sdk.AccAddress(contractAddress).String(), logName)) - } - }() - return logging.LogIfNotDoneAfter(ctx.Logger(), func() ([]byte, error) { - return k.WasmKeeper.Sudo(ctx, contractAddress, wasmMsg) - }, LogAfter, fmt.Sprintf("wasm_sudo_%s", logName)) -} - -func hasErrInstantiatingWasmModuleDueToCPUFeature(err error) bool { - if err == nil { - return false - } - return strings.Contains(err.Error(), ErrWasmModuleInstCPUFeatureLiteral) -} - -func CallContractSudo(sdkCtx sdk.Context, k *keeper.Keeper, contractAddr string, msg interface{}, gasAllowance uint64) ([]byte, error) { - contractAddress, err := sdk.AccAddressFromBech32(contractAddr) - if err != nil { - sdkCtx.Logger().Error(err.Error()) - return []byte{}, err - } - wasmMsg, err := json.Marshal(msg) - if err != nil { - sdkCtx.Logger().Error(err.Error()) - return []byte{}, err - } - msgType := getMsgType(msg) - data, gasUsed, suderr := sudo(sdkCtx, k, contractAddress, wasmMsg, msgType) - if err := k.ChargeRentForGas(sdkCtx, contractAddr, gasUsed, gasAllowance); err != nil { - metrics.IncrementSudoFailCount(msgType) - sdkCtx.Logger().Error(err.Error()) - return []byte{}, err - } - if suderr != nil { - metrics.IncrementSudoFailCount(msgType) - sdkCtx.Logger().Error(suderr.Error()) - return []byte{}, suderr - } - return data, nil -} diff --git a/x/dex/migrations/v10_to_v11.go b/x/dex/migrations/v10_to_v11.go deleted file mode 100644 index 4f35a5e68..000000000 --- a/x/dex/migrations/v10_to_v11.go +++ /dev/null @@ -1,45 +0,0 @@ -package migrations - -import ( - "github.com/cosmos/cosmos-sdk/store/prefix" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/keeper" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -var DexPrefixes = []string{ - types.LongBookKey, - types.ShortBookKey, - "TriggerBook-value-", - types.OrderKey, - types.TwapKey, - types.RegisteredPairKey, - types.OrderKey, - types.CancelKey, - types.AccountActiveOrdersKey, - types.NextOrderIDKey, - types.MatchResultKey, - types.MemOrderKey, - types.MemCancelKey, - types.MemDepositKey, - types.PriceKey, - "SettlementEntry-", - "NextSettlementID-", -} - -func V10ToV11(ctx sdk.Context, dexkeeper keeper.Keeper) error { - dexkeeper.CreateModuleAccount(ctx) - - // this will nuke all old prefixes data in the store - for _, prefixKey := range DexPrefixes { - store := prefix.NewStore(ctx.KVStore(dexkeeper.GetStoreKey()), []byte(prefixKey)) - iterator := sdk.KVStorePrefixIterator(store, []byte{}) - - defer iterator.Close() - for ; iterator.Valid(); iterator.Next() { - store.Delete(iterator.Key()) - } - } - - return nil -} diff --git a/x/dex/migrations/v10_to_v11_test.go b/x/dex/migrations/v10_to_v11_test.go deleted file mode 100644 index 775c20928..000000000 --- a/x/dex/migrations/v10_to_v11_test.go +++ /dev/null @@ -1,60 +0,0 @@ -package migrations_test - -import ( - "testing" - - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex/migrations" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestMigrate10to11(t *testing.T) { - dexkeeper, ctx := keepertest.DexKeeper(t) - // write old contract - store := ctx.KVStore(dexkeeper.GetStoreKey()) - value := []byte("test_value") - store.Set(types.ContractKeyPrefix(types.LongBookKey, keepertest.TestContract), value) - store.Set(types.OrderBookPrefix(false, keepertest.TestContract, "USDC", "ATOM"), value) - store.Set(TriggerOrderBookPrefix(keepertest.TestContract, "USDC", "ATOM"), value) - store.Set(types.PricePrefix(keepertest.TestContract, "USDC", "ATOM"), value) - store.Set(migrations.SettlementEntryPrefix(keepertest.TestContract, "USDC", "ATOM"), value) - store.Set(types.RegisteredPairPrefix(keepertest.TestContract), value) - store.Set(types.OrderPrefix(keepertest.TestContract), value) - store.Set(types.NextOrderIDPrefix(keepertest.TestContract), value) - store.Set(migrations.NextSettlementIDPrefix(keepertest.TestContract, "USDC", "ATOM"), value) - store.Set(types.MatchResultPrefix(keepertest.TestContract), value) - store.Set(types.MemOrderPrefixForPair(keepertest.TestContract, "USDC", "ATOM"), value) - store.Set(types.MemCancelPrefixForPair(keepertest.TestContract, "USDC", "ATOM"), value) - store.Set(types.MemOrderPrefix(keepertest.TestContract), value) - store.Set(types.MemCancelPrefix(keepertest.TestContract), value) - store.Set(types.MemDepositPrefix(keepertest.TestContract), value) - - err := migrations.V10ToV11(ctx, *dexkeeper) - require.NoError(t, err) - - require.False(t, store.Has(types.ContractKeyPrefix(types.LongBookKey, keepertest.TestContract))) - require.False(t, store.Has(types.OrderBookPrefix(false, keepertest.TestContract, "USDC", "ATOM"))) - require.False(t, store.Has(TriggerOrderBookPrefix(keepertest.TestContract, "USDC", "ATOM"))) - require.False(t, store.Has(types.PricePrefix(keepertest.TestContract, "USDC", "ATOM"))) - require.False(t, store.Has(migrations.SettlementEntryPrefix(keepertest.TestContract, "USDC", "ATOM"))) - require.False(t, store.Has(types.RegisteredPairPrefix(keepertest.TestContract))) - require.False(t, store.Has(types.OrderPrefix(keepertest.TestContract))) - require.False(t, store.Has(types.NextOrderIDPrefix(keepertest.TestContract))) - require.False(t, store.Has(migrations.NextSettlementIDPrefix(keepertest.TestContract, "USDC", "ATOM"))) - require.False(t, store.Has(types.MatchResultPrefix(keepertest.TestContract))) - require.False(t, store.Has(types.MemOrderPrefixForPair(keepertest.TestContract, "USDC", "ATOM"))) - require.False(t, store.Has(types.MemCancelPrefixForPair(keepertest.TestContract, "USDC", "ATOM"))) - require.False(t, store.Has(types.MemOrderPrefix(keepertest.TestContract))) - require.False(t, store.Has(types.MemCancelPrefix(keepertest.TestContract))) - require.False(t, store.Has(types.MemDepositPrefix(keepertest.TestContract))) -} - -func TriggerOrderBookPrefix(contractAddr string, priceDenom string, assetDenom string) []byte { - prefix := types.KeyPrefix("TriggerBook-value-") - - return append( - append(prefix, types.AddressKeyPrefix(contractAddr)...), - types.PairPrefix(priceDenom, assetDenom)..., - ) -} diff --git a/x/dex/migrations/v11_to_v12.go b/x/dex/migrations/v11_to_v12.go deleted file mode 100644 index 66c68a44a..000000000 --- a/x/dex/migrations/v11_to_v12.go +++ /dev/null @@ -1,13 +0,0 @@ -package migrations - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/keeper" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -func V11ToV12(ctx sdk.Context, dexkeeper keeper.Keeper) error { - defaultParams := types.DefaultParams() - dexkeeper.SetParams(ctx, defaultParams) - return nil -} diff --git a/x/dex/migrations/v11_to_v12_test.go b/x/dex/migrations/v11_to_v12_test.go deleted file mode 100644 index bf0baf6ca..000000000 --- a/x/dex/migrations/v11_to_v12_test.go +++ /dev/null @@ -1,31 +0,0 @@ -package migrations_test - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex/migrations" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestMigrate11to12(t *testing.T) { - dexkeeper, ctx := keepertest.DexKeeper(t) - // write old params - defaultParams := types.Params{ - PriceSnapshotRetention: 1, - SudoCallGasPrice: sdk.OneDec(), - BeginBlockGasLimit: 1, - EndBlockGasLimit: 1, - DefaultGasPerOrder: 1, - DefaultGasPerCancel: 1, - } - dexkeeper.SetParams(ctx, defaultParams) - - // migrate to default params - err := migrations.V11ToV12(ctx, *dexkeeper) - require.NoError(t, err) - params := dexkeeper.GetParams(ctx) - require.Equal(t, params, types.DefaultParams()) -} diff --git a/x/dex/migrations/v12_to_v13.go b/x/dex/migrations/v12_to_v13.go deleted file mode 100644 index 9bd5891f7..000000000 --- a/x/dex/migrations/v12_to_v13.go +++ /dev/null @@ -1,15 +0,0 @@ -package migrations - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/keeper" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -func V12ToV13(ctx sdk.Context, dexkeeper keeper.Keeper) error { - // This isn't the cleanest migration since it could potentially revert any dex params we have changed - // but we haven't, so we'll just do this. - defaultParams := types.DefaultParams() - dexkeeper.SetParams(ctx, defaultParams) - return nil -} diff --git a/x/dex/migrations/v12_to_v13_test.go b/x/dex/migrations/v12_to_v13_test.go deleted file mode 100644 index fd70a50ce..000000000 --- a/x/dex/migrations/v12_to_v13_test.go +++ /dev/null @@ -1,32 +0,0 @@ -package migrations_test - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex/migrations" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestMigrate12to13(t *testing.T) { - dexkeeper, ctx := keepertest.DexKeeper(t) - // write old params - prevParams := types.Params{ - PriceSnapshotRetention: 1, - SudoCallGasPrice: sdk.OneDec(), - BeginBlockGasLimit: 1, - EndBlockGasLimit: 1, - DefaultGasPerOrder: 1, - DefaultGasPerCancel: 1, - } - dexkeeper.SetParams(ctx, prevParams) - - // migrate to default params - err := migrations.V12ToV13(ctx, *dexkeeper) - require.NoError(t, err) - params := dexkeeper.GetParams(ctx) - require.Equal(t, params.GasAllowancePerSettlement, uint64(types.DefaultGasAllowancePerSettlement)) - require.Equal(t, params.MinProcessableRent, uint64(types.DefaultMinProcessableRent)) -} diff --git a/x/dex/migrations/v13_to_v14.go b/x/dex/migrations/v13_to_v14.go deleted file mode 100644 index 062cc35c8..000000000 --- a/x/dex/migrations/v13_to_v14.go +++ /dev/null @@ -1,69 +0,0 @@ -package migrations - -import ( - "fmt" - - "github.com/cosmos/cosmos-sdk/store/prefix" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/utils" - "github.com/sei-protocol/sei-chain/x/dex/keeper" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -func V13ToV14(ctx sdk.Context, dexkeeper keeper.Keeper) error { - setDefaultParams(ctx, dexkeeper) - - for _, contractAddr := range getAllContractAddresses(ctx, dexkeeper) { - convertOrderBookEntryKeysForContract(ctx, dexkeeper, contractAddr) - } - return nil -} - -func setDefaultParams(ctx sdk.Context, dexkeeper keeper.Keeper) { - // This isn't the cleanest migration since it could potentially revert any dex params we have changed - // but we haven't, so we'll just do this. - defaultParams := types.DefaultParams() - dexkeeper.SetParams(ctx, defaultParams) -} - -func getAllContractAddresses(ctx sdk.Context, dexkeeper keeper.Keeper) []string { - contracts := dexkeeper.GetAllContractInfo(ctx) - return utils.Map(contracts, func(c types.ContractInfoV2) string { return c.ContractAddr }) -} - -func convertOrderBookEntryKeysForContract(ctx sdk.Context, dexkeeper keeper.Keeper, contractAddr string) { - ctx.Logger().Info(fmt.Sprintf("converting order book entry keys for contract %s", contractAddr)) - store := prefix.NewStore(ctx.KVStore(dexkeeper.GetStoreKey()), types.ContractKeyPrefix(types.LongBookKey, contractAddr)) - iterator := sdk.KVStorePrefixIterator(store, []byte{}) - - keyToVal := map[string][]byte{} - for ; iterator.Valid(); iterator.Next() { - keyToVal[string(iterator.Key())] = iterator.Value() - } - iterator.Close() - - for key, v := range keyToVal { - store.Delete([]byte(key)) - var val types.LongBook - dexkeeper.Cdc.MustUnmarshal(v, &val) - newKey := append(types.PairPrefix(val.Entry.PriceDenom, val.Entry.AssetDenom), keeper.GetKeyForPrice(val.Price)...) - store.Set(newKey, v) - } - - store = prefix.NewStore(ctx.KVStore(dexkeeper.GetStoreKey()), types.ContractKeyPrefix(types.ShortBookKey, contractAddr)) - iterator = sdk.KVStorePrefixIterator(store, []byte{}) - - keyToVal = map[string][]byte{} - for ; iterator.Valid(); iterator.Next() { - keyToVal[string(iterator.Key())] = iterator.Value() - } - iterator.Close() - - for key, v := range keyToVal { - store.Delete([]byte(key)) - var val types.ShortBook - dexkeeper.Cdc.MustUnmarshal(v, &val) - newKey := append(types.PairPrefix(val.Entry.PriceDenom, val.Entry.AssetDenom), keeper.GetKeyForPrice(val.Price)...) - store.Set(newKey, v) - } -} diff --git a/x/dex/migrations/v13_to_v14_test.go b/x/dex/migrations/v13_to_v14_test.go deleted file mode 100644 index b9937b3e3..000000000 --- a/x/dex/migrations/v13_to_v14_test.go +++ /dev/null @@ -1,79 +0,0 @@ -package migrations_test - -import ( - "testing" - - "github.com/cosmos/cosmos-sdk/store/prefix" - sdk "github.com/cosmos/cosmos-sdk/types" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex/migrations" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/sei-protocol/sei-chain/x/dex/utils" - "github.com/stretchr/testify/require" -) - -func TestMigrate13to14(t *testing.T) { - dexkeeper, ctx := keepertest.DexKeeper(t) - // write old params - prevParams := types.Params{ - PriceSnapshotRetention: 1, - SudoCallGasPrice: sdk.OneDec(), - BeginBlockGasLimit: 1, - EndBlockGasLimit: 1, - DefaultGasPerOrder: 1, - DefaultGasPerCancel: 1, - GasAllowancePerSettlement: 1, - MinProcessableRent: 1, - } - dexkeeper.SetParams(ctx, prevParams) - - dexkeeper.SetContract(ctx, &types.ContractInfoV2{ContractAddr: keepertest.TestContract}) - longStore := prefix.NewStore(ctx.KVStore(dexkeeper.GetStoreKey()), types.OrderBookPrefix( - true, keepertest.TestContract, keepertest.TestPair.PriceDenom, keepertest.TestPair.AssetDenom, - )) - longEntry := types.LongBook{ - Price: sdk.MustNewDecFromStr("10.123"), - Entry: &types.OrderEntry{ - Price: sdk.MustNewDecFromStr("10.123"), - Quantity: sdk.MustNewDecFromStr("5"), - PriceDenom: keepertest.TestPair.PriceDenom, - AssetDenom: keepertest.TestPair.AssetDenom, - }, - } - longEntryKey, err := longEntry.GetPrice().Marshal() - require.Nil(t, err) - longStore.Set(longEntryKey, dexkeeper.Cdc.MustMarshal(&longEntry)) - - shortStore := prefix.NewStore(ctx.KVStore(dexkeeper.GetStoreKey()), types.OrderBookPrefix( - false, keepertest.TestContract, keepertest.TestPair.PriceDenom, keepertest.TestPair.AssetDenom, - )) - shortEntry := types.ShortBook{ - Price: sdk.MustNewDecFromStr("12.456"), - Entry: &types.OrderEntry{ - Price: sdk.MustNewDecFromStr("12.456"), - Quantity: sdk.MustNewDecFromStr("4"), - PriceDenom: keepertest.TestPair.PriceDenom, - AssetDenom: keepertest.TestPair.AssetDenom, - }, - } - shortEntryKey, err := shortEntry.GetPrice().Marshal() - require.Nil(t, err) - shortStore.Set(shortEntryKey, dexkeeper.Cdc.MustMarshal(&shortEntry)) - - // migrate to default params - err = migrations.V13ToV14(ctx, *dexkeeper) - require.NoError(t, err) - params := dexkeeper.GetParams(ctx) - require.Equal(t, params.OrderBookEntriesPerLoad, uint64(types.DefaultOrderBookEntriesPerLoad)) - - require.Nil(t, longStore.Get(longEntryKey)) - require.Nil(t, shortStore.Get(shortEntryKey)) - var loadedLongEntry types.LongBook - dexkeeper.Cdc.MustUnmarshal(longStore.Get(utils.DecToBigEndian(longEntry.Price)), &loadedLongEntry) - require.Equal(t, longEntry.Price, loadedLongEntry.Price) - require.Equal(t, *longEntry.Entry, *loadedLongEntry.Entry) - var loadedShortEntry types.ShortBook - dexkeeper.Cdc.MustUnmarshal(shortStore.Get(utils.DecToBigEndian(shortEntry.Price)), &loadedShortEntry) - require.Equal(t, shortEntry.Price, loadedShortEntry.Price) - require.Equal(t, *shortEntry.Entry, *loadedShortEntry.Entry) -} diff --git a/x/dex/migrations/v14_to_v15.go b/x/dex/migrations/v14_to_v15.go deleted file mode 100644 index 158990fb1..000000000 --- a/x/dex/migrations/v14_to_v15.go +++ /dev/null @@ -1,15 +0,0 @@ -package migrations - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/keeper" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -func V14ToV15(ctx sdk.Context, dexkeeper keeper.Keeper) error { - // This isn't the cleanest migration since it could potentially revert any dex params we have changed - // but we haven't, so we'll just do this. - defaultParams := types.DefaultParams() - dexkeeper.SetParams(ctx, defaultParams) - return nil -} diff --git a/x/dex/migrations/v14_to_v15_test.go b/x/dex/migrations/v14_to_v15_test.go deleted file mode 100644 index f6d76f1c7..000000000 --- a/x/dex/migrations/v14_to_v15_test.go +++ /dev/null @@ -1,26 +0,0 @@ -package migrations_test - -import ( - "testing" - - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex/migrations" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestMigrate14to15(t *testing.T) { - dexkeeper, ctx := keepertest.DexKeeper(t) - // write old params - prevParams := types.DefaultParams() - prevParams.MaxOrderPerPrice = 0 - prevParams.MaxPairsPerContract = 0 - dexkeeper.SetParams(ctx, prevParams) - - // migrate to default params - err := migrations.V14ToV15(ctx, *dexkeeper) - require.NoError(t, err) - params := dexkeeper.GetParams(ctx) - require.Equal(t, params.MaxOrderPerPrice, uint64(types.DefaultMaxOrderPerPrice)) - require.Equal(t, params.MaxPairsPerContract, uint64(types.DefaultMaxPairsPerContract)) -} diff --git a/x/dex/migrations/v15_to_v16.go b/x/dex/migrations/v15_to_v16.go deleted file mode 100644 index 3e5f9eb39..000000000 --- a/x/dex/migrations/v15_to_v16.go +++ /dev/null @@ -1,15 +0,0 @@ -package migrations - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/keeper" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -func V15ToV16(ctx sdk.Context, dexkeeper keeper.Keeper) error { - // This isn't the cleanest migration since it could potentially revert any dex params we have changed - // but we haven't, so we'll just do this. - defaultParams := types.DefaultParams() - dexkeeper.SetParams(ctx, defaultParams) - return nil -} diff --git a/x/dex/migrations/v15_to_v16_test.go b/x/dex/migrations/v15_to_v16_test.go deleted file mode 100644 index 48fa655ff..000000000 --- a/x/dex/migrations/v15_to_v16_test.go +++ /dev/null @@ -1,24 +0,0 @@ -package migrations_test - -import ( - "testing" - - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex/migrations" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestMigrate15to16(t *testing.T) { - dexkeeper, ctx := keepertest.DexKeeper(t) - // write old params - prevParams := types.DefaultParams() - prevParams.DefaultGasPerOrderDataByte = 0 - dexkeeper.SetParams(ctx, prevParams) - - // migrate to default params - err := migrations.V15ToV16(ctx, *dexkeeper) - require.NoError(t, err) - params := dexkeeper.GetParams(ctx) - require.Equal(t, params.DefaultGasPerOrderDataByte, uint64(30)) -} diff --git a/x/dex/migrations/v16_to_v17.go b/x/dex/migrations/v16_to_v17.go deleted file mode 100644 index 7066db584..000000000 --- a/x/dex/migrations/v16_to_v17.go +++ /dev/null @@ -1,110 +0,0 @@ -package migrations - -import ( - "github.com/cosmos/cosmos-sdk/store/prefix" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/goutils" - "github.com/sei-protocol/sei-chain/x/dex/keeper" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -const OldPairSeparator = '|' - -func OldPairPrefix(priceDenom string, assetDenom string) []byte { - return goutils.ImmutableAppend(goutils.ImmutableAppend([]byte(priceDenom), OldPairSeparator), []byte(assetDenom)...) -} - -func V16ToV17(ctx sdk.Context, dexkeeper keeper.Keeper) error { - rootStore := ctx.KVStore(dexkeeper.GetStoreKey()) - - handler := func(oldPref []byte, newPref []byte) { - store := prefix.NewStore(rootStore, oldPref) - kv := map[string][]byte{} - iter := store.Iterator(nil, nil) - defer iter.Close() - for ; iter.Valid(); iter.Next() { - kv[string(iter.Key())] = iter.Value() - } - for k, v := range kv { - kbz := []byte(k) - store.Delete(kbz) - rootStore.Set(goutils.ImmutableAppend(newPref, kbz...), v) - } - } - - for _, c := range dexkeeper.GetAllContractInfo(ctx) { - for _, p := range dexkeeper.GetAllRegisteredPairs(ctx, c.ContractAddr) { - // long order book - handler( - goutils.ImmutableAppend( - types.OrderBookContractPrefix(true, c.ContractAddr), - OldPairPrefix(p.PriceDenom, p.AssetDenom)..., - ), - types.OrderBookPrefix(true, c.ContractAddr, p.PriceDenom, p.AssetDenom), - ) - - // short order book - handler( - goutils.ImmutableAppend( - types.OrderBookContractPrefix(false, c.ContractAddr), - OldPairPrefix(p.PriceDenom, p.AssetDenom)..., - ), - types.OrderBookPrefix(false, c.ContractAddr, p.PriceDenom, p.AssetDenom), - ) - - // price - handler( - goutils.ImmutableAppend( - types.PriceContractPrefix(c.ContractAddr), - OldPairPrefix(p.PriceDenom, p.AssetDenom)..., - ), - types.PricePrefix(c.ContractAddr, p.PriceDenom, p.AssetDenom), - ) - - // order count (long) - handler( - goutils.ImmutableAppend( - goutils.ImmutableAppend(types.KeyPrefix(types.LongOrderCountKey), types.AddressKeyPrefix(c.ContractAddr)...), - OldPairPrefix(p.PriceDenom, p.AssetDenom)..., - ), - types.OrderCountPrefix(c.ContractAddr, p.PriceDenom, p.AssetDenom, true), - ) - - // order count (short) - handler( - goutils.ImmutableAppend( - goutils.ImmutableAppend(types.KeyPrefix(types.ShortOrderCountKey), types.AddressKeyPrefix(c.ContractAddr)...), - OldPairPrefix(p.PriceDenom, p.AssetDenom)..., - ), - types.OrderCountPrefix(c.ContractAddr, p.PriceDenom, p.AssetDenom, false), - ) - - // registered pair - k := goutils.ImmutableAppend(types.RegisteredPairPrefix(c.ContractAddr), OldPairPrefix(p.PriceDenom, p.AssetDenom)...) - pair := rootStore.Get(k) - rootStore.Delete(k) - rootStore.Set( - goutils.ImmutableAppend(types.RegisteredPairPrefix(c.ContractAddr), types.PairPrefix(p.PriceDenom, p.AssetDenom)...), - pair, - ) - } - } - - // asset list - pref := types.KeyPrefix(types.AssetListKey) - store := prefix.NewStore(rootStore, pref) - kv := map[string][]byte{} - iter := store.Iterator(nil, nil) - for ; iter.Valid(); iter.Next() { - kv[string(iter.Key())] = iter.Value() - } - iter.Close() - for k, v := range kv { - kbz := []byte(k) - store.Delete(kbz) - denom := string(kbz) - newKbz := types.AssetListPrefix(denom) - rootStore.Set(newKbz, v) - } - return nil -} diff --git a/x/dex/migrations/v16_to_v17_test.go b/x/dex/migrations/v16_to_v17_test.go deleted file mode 100644 index ac6c7ad0d..000000000 --- a/x/dex/migrations/v16_to_v17_test.go +++ /dev/null @@ -1,89 +0,0 @@ -package migrations_test - -import ( - "testing" - - "github.com/sei-protocol/goutils" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex/migrations" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestMigrate16to17(t *testing.T) { - dexkeeper, ctx := keepertest.DexKeeper(t) - store := ctx.KVStore(dexkeeper.GetStoreKey()) - dexkeeper.SetContract(ctx, &types.ContractInfoV2{ContractAddr: keepertest.TestContract}) - // add registered pair using the old key - pair := types.Pair{PriceDenom: keepertest.TestPair.PriceDenom, AssetDenom: keepertest.TestPair.AssetDenom} - store.Set( - goutils.ImmutableAppend( - types.RegisteredPairPrefix(keepertest.TestContract), - migrations.OldPairPrefix(keepertest.TestPair.PriceDenom, keepertest.TestPair.AssetDenom)..., - ), - dexkeeper.Cdc.MustMarshal(&pair), - ) - - value := []byte("test_value") - store.Set(goutils.ImmutableAppend( - types.OrderBookContractPrefix(true, keepertest.TestContract), - migrations.OldPairPrefix(pair.PriceDenom, pair.AssetDenom)..., - ), value) - store.Set(goutils.ImmutableAppend( - types.OrderBookContractPrefix(false, keepertest.TestContract), - migrations.OldPairPrefix(pair.PriceDenom, pair.AssetDenom)..., - ), value) - store.Set(goutils.ImmutableAppend( - types.PriceContractPrefix(keepertest.TestContract), - migrations.OldPairPrefix(pair.PriceDenom, pair.AssetDenom)..., - ), value) - store.Set(goutils.ImmutableAppend( - goutils.ImmutableAppend(types.KeyPrefix(types.LongOrderCountKey), types.AddressKeyPrefix(keepertest.TestContract)...), - migrations.OldPairPrefix(pair.PriceDenom, pair.AssetDenom)..., - ), value) - store.Set(goutils.ImmutableAppend( - goutils.ImmutableAppend(types.KeyPrefix(types.ShortOrderCountKey), types.AddressKeyPrefix(keepertest.TestContract)...), - migrations.OldPairPrefix(pair.PriceDenom, pair.AssetDenom)..., - ), value) - store.Set(goutils.ImmutableAppend(types.KeyPrefix(types.AssetListKey), []byte(pair.PriceDenom)...), value) - - err := migrations.V16ToV17(ctx, *dexkeeper) - require.NoError(t, err) - - require.False(t, store.Has(goutils.ImmutableAppend( - types.OrderBookContractPrefix(true, keepertest.TestContract), - migrations.OldPairPrefix(pair.PriceDenom, pair.AssetDenom)..., - ))) - require.False(t, store.Has(goutils.ImmutableAppend( - types.OrderBookContractPrefix(false, keepertest.TestContract), - migrations.OldPairPrefix(pair.PriceDenom, pair.AssetDenom)..., - ))) - require.False(t, store.Has(goutils.ImmutableAppend( - types.PriceContractPrefix(keepertest.TestContract), - migrations.OldPairPrefix(pair.PriceDenom, pair.AssetDenom)..., - ))) - require.False(t, store.Has(goutils.ImmutableAppend( - goutils.ImmutableAppend(types.KeyPrefix(types.LongOrderCountKey), types.AddressKeyPrefix(keepertest.TestContract)...), - migrations.OldPairPrefix(pair.PriceDenom, pair.AssetDenom)..., - ))) - require.False(t, store.Has(goutils.ImmutableAppend( - goutils.ImmutableAppend(types.KeyPrefix(types.ShortOrderCountKey), types.AddressKeyPrefix(keepertest.TestContract)...), - migrations.OldPairPrefix(pair.PriceDenom, pair.AssetDenom)..., - ))) - require.False(t, store.Has(goutils.ImmutableAppend(types.KeyPrefix(types.AssetListKey), []byte(pair.PriceDenom)...))) - require.False(t, store.Has(goutils.ImmutableAppend( - types.RegisteredPairPrefix(keepertest.TestContract), - migrations.OldPairPrefix(keepertest.TestPair.PriceDenom, keepertest.TestPair.AssetDenom)..., - ))) - - require.True(t, store.Has(types.OrderBookPrefix(true, keepertest.TestContract, pair.PriceDenom, pair.AssetDenom))) - require.True(t, store.Has(types.OrderBookPrefix(false, keepertest.TestContract, pair.PriceDenom, pair.AssetDenom))) - require.True(t, store.Has(types.PricePrefix(keepertest.TestContract, pair.PriceDenom, pair.AssetDenom))) - require.True(t, store.Has(types.OrderCountPrefix(keepertest.TestContract, pair.PriceDenom, pair.AssetDenom, true))) - require.True(t, store.Has(types.OrderCountPrefix(keepertest.TestContract, pair.PriceDenom, pair.AssetDenom, false))) - require.True(t, store.Has(types.AssetListPrefix(pair.PriceDenom))) - require.True(t, store.Has(goutils.ImmutableAppend( - types.RegisteredPairPrefix(keepertest.TestContract), - types.PairPrefix(keepertest.TestPair.PriceDenom, keepertest.TestPair.AssetDenom)..., - ))) -} diff --git a/x/dex/migrations/v17_to_v18.go b/x/dex/migrations/v17_to_v18.go deleted file mode 100644 index 7e6448bac..000000000 --- a/x/dex/migrations/v17_to_v18.go +++ /dev/null @@ -1,33 +0,0 @@ -package migrations - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - "github.com/sei-protocol/sei-chain/x/dex/keeper" - dextypes "github.com/sei-protocol/sei-chain/x/dex/types" -) - -func V17ToV18(ctx sdk.Context, dexkeeper keeper.Keeper) error { - // iterate over all contracts and unregister them - for _, c := range dexkeeper.GetAllContractInfo(ctx) { - if err := dexkeeper.DoUnregisterContractWithRefund(ctx, c); err != nil { - return err - } - } - // get module address - dexAddr := dexkeeper.AccountKeeper.GetModuleAddress(dextypes.ModuleName) - // send usei to the feecollector - useiCoins := dexkeeper.BankKeeper.GetBalance(ctx, dexAddr, sdk.MustGetBaseDenom()) - if err := dexkeeper.BankKeeper.SendCoinsFromModuleToModule(ctx, dextypes.ModuleName, authtypes.FeeCollectorName, sdk.NewCoins(useiCoins)); err != nil { - return err - } - // get bank balances remaining for module - balances := dexkeeper.BankKeeper.GetAllBalances(ctx, dexAddr) - // update accountkeeper to give dex burner perms - dexkeeper.CreateModuleAccount(ctx) - // burn all remaining module balances - need burner perms - if err := dexkeeper.BankKeeper.BurnCoins(ctx, dextypes.ModuleName, balances); err != nil { - return err - } - return nil -} diff --git a/x/dex/migrations/v17_to_v18_test.go b/x/dex/migrations/v17_to_v18_test.go deleted file mode 100644 index cec6d67bb..000000000 --- a/x/dex/migrations/v17_to_v18_test.go +++ /dev/null @@ -1,62 +0,0 @@ -package migrations_test - -import ( - "testing" - "time" - - "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" - sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - "github.com/sei-protocol/sei-chain/app" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex/migrations" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestMigrate17to18(t *testing.T) { - tm := time.Now().UTC() - valPub := secp256k1.GenPrivKey().PubKey() - - testWrapper := app.NewTestWrapper(t, tm, valPub, false) - - testAddr := sdk.MustAccAddressFromBech32(keepertest.TestAccount) - - testWrapper.FundAcc(testAddr, sdk.NewCoins(sdk.NewCoin(sdk.MustGetBaseDenom(), sdk.NewInt(100000)))) - testWrapper.FundAcc(testAddr, sdk.NewCoins(sdk.NewCoin("ueth", sdk.NewInt(100)))) - - dexkeeper, ctx := testWrapper.App.DexKeeper, testWrapper.Ctx - bal := dexkeeper.BankKeeper.GetBalance(ctx, testAddr, sdk.MustGetBaseDenom()) - require.Equal(t, int64(100000), bal.Amount.Int64()) - // add contract rent - rentAmt := int64(10000) - err := dexkeeper.BankKeeper.SendCoins(ctx, testAddr, dexkeeper.AccountKeeper.GetModuleAddress(types.ModuleName), sdk.NewCoins(sdk.NewCoin(sdk.MustGetBaseDenom(), sdk.NewInt(rentAmt)))) - require.NoError(t, err) - - contract := &types.ContractInfoV2{ContractAddr: keepertest.TestContract, Creator: keepertest.TestAccount, RentBalance: uint64(rentAmt)} - err = dexkeeper.SetContract(ctx, contract) - require.NoError(t, err) - // add some balance to the module just bc - err = dexkeeper.BankKeeper.SendCoins(ctx, testAddr, dexkeeper.AccountKeeper.GetModuleAddress(types.ModuleName), sdk.NewCoins(sdk.NewCoin("ueth", sdk.NewInt(10)), sdk.NewCoin(sdk.MustGetBaseDenom(), sdk.NewInt(1000)))) - require.NoError(t, err) - - supplyUseiInitial := dexkeeper.BankKeeper.GetSupply(ctx, sdk.MustGetBaseDenom()) - - // do migration - err = migrations.V17ToV18(ctx, dexkeeper) - require.NoError(t, err) - - // user refunded rent now has 99000usei and 90ueth - bals := dexkeeper.BankKeeper.GetAllBalances(ctx, testAddr) - require.Equal(t, sdk.NewCoins(sdk.NewCoin("ueth", sdk.NewInt(90)), sdk.NewCoin(sdk.MustGetBaseDenom(), sdk.NewInt(99000))), bals) - // feecollector gets 1000usei - bals = dexkeeper.BankKeeper.GetAllBalances(ctx, dexkeeper.AccountKeeper.GetModuleAddress(authtypes.FeeCollectorName)) - require.Equal(t, sdk.NewCoins(sdk.NewCoin(sdk.MustGetBaseDenom(), sdk.NewInt(1000))), bals) - // ueth supply decreased due to burn - supply := dexkeeper.BankKeeper.GetSupply(ctx, "ueth") - require.Equal(t, sdk.NewInt(90), supply.Amount) - // usei supply unchanged - supplyUseiFinal := dexkeeper.BankKeeper.GetSupply(ctx, sdk.MustGetBaseDenom()) - require.Equal(t, supplyUseiInitial, supplyUseiFinal) - -} diff --git a/x/dex/migrations/v2_to_v3.go b/x/dex/migrations/v2_to_v3.go deleted file mode 100644 index de789df98..000000000 --- a/x/dex/migrations/v2_to_v3.go +++ /dev/null @@ -1,35 +0,0 @@ -package migrations - -import ( - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -/** - * No `dex` state exists in any public chain at the time this data type update happened. - * Any new chain (including local ones) should be based on a Sei version newer than this update - * and therefore doesn't need this migration - */ -func DataTypeUpdate(ctx sdk.Context, storeKey sdk.StoreKey, _ codec.BinaryCodec) error { - ClearStore(ctx, storeKey) - return nil -} - -/** - * CAUTION: this function clears up the entire `dex` module store, so it should only ever - * be used outside of a production setting. - */ -func ClearStore(ctx sdk.Context, storeKey sdk.StoreKey) { - for i := 0; i < 256; i++ { - clearStoreForByte(ctx, storeKey, byte(i)) - } -} - -func clearStoreForByte(ctx sdk.Context, storeKey sdk.StoreKey, b byte) { - store := ctx.KVStore(storeKey) - iterator := sdk.KVStorePrefixIterator(store, []byte{b}) - defer iterator.Close() - for ; iterator.Valid(); iterator.Next() { - store.Delete(iterator.Key()) - } -} diff --git a/x/dex/migrations/v3_to_v4.go b/x/dex/migrations/v3_to_v4.go deleted file mode 100644 index b7b9217fc..000000000 --- a/x/dex/migrations/v3_to_v4.go +++ /dev/null @@ -1,21 +0,0 @@ -package migrations - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -func PriceSnapshotUpdate(ctx sdk.Context, paramStore paramtypes.Subspace) error { - err := migratePriceSnapshotParam(ctx, paramStore) - return err -} - -func migratePriceSnapshotParam(ctx sdk.Context, paramStore paramtypes.Subspace) error { - defaultParams := types.Params{ - PriceSnapshotRetention: types.DefaultPriceSnapshotRetention, - SudoCallGasPrice: types.DefaultSudoCallGasPrice, - } - paramStore.SetParamSet(ctx, &defaultParams) - return nil -} diff --git a/x/dex/migrations/v3_to_v4_test.go b/x/dex/migrations/v3_to_v4_test.go deleted file mode 100644 index 18712ba89..000000000 --- a/x/dex/migrations/v3_to_v4_test.go +++ /dev/null @@ -1,48 +0,0 @@ -package migrations_test - -import ( - "testing" - - "github.com/cosmos/cosmos-sdk/codec" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/store" - storetypes "github.com/cosmos/cosmos-sdk/store/types" - sdk "github.com/cosmos/cosmos-sdk/types" - typesparams "github.com/cosmos/cosmos-sdk/x/params/types" - "github.com/sei-protocol/sei-chain/x/dex/migrations" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/libs/log" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - tmdb "github.com/tendermint/tm-db" -) - -func TestMigrate3to4(t *testing.T) { - storeKey := sdk.NewKVStoreKey(types.StoreKey) - memStoreKey := storetypes.NewMemoryStoreKey(types.MemStoreKey) - - db := tmdb.NewMemDB() - stateStore := store.NewCommitMultiStore(db) - stateStore.MountStoreWithDB(storeKey, sdk.StoreTypeIAVL, db) - stateStore.MountStoreWithDB(memStoreKey, sdk.StoreTypeMemory, nil) - require.NoError(t, stateStore.LoadLatestVersion()) - - registry := codectypes.NewInterfaceRegistry() - cdc := codec.NewProtoCodec(registry) - - paramsSubspace := typesparams.NewSubspace(cdc, - types.Amino, - storeKey, - memStoreKey, - "DexParams", - ) - ctx := sdk.NewContext(stateStore, tmproto.Header{}, false, log.NewNopLogger()) - if !paramsSubspace.HasKeyTable() { - paramsSubspace = paramsSubspace.WithKeyTable(types.ParamKeyTable()) - } - migrations.PriceSnapshotUpdate(ctx, paramsSubspace) - - params := types.Params{} - paramsSubspace.GetParamSet(ctx, ¶ms) - require.Equal(t, uint64(types.DefaultPriceSnapshotRetention), params.PriceSnapshotRetention) -} diff --git a/x/dex/migrations/v4_to_v5.go b/x/dex/migrations/v4_to_v5.go deleted file mode 100644 index 8e40d7da3..000000000 --- a/x/dex/migrations/v4_to_v5.go +++ /dev/null @@ -1,28 +0,0 @@ -package migrations - -import ( - "encoding/binary" - - sdk "github.com/cosmos/cosmos-sdk/types" - paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - "github.com/sei-protocol/sei-chain/x/dex/keeper" -) - -/** - * No `dex` state exists in any public chain at the time this data type update happened. - * Any new chain (including local ones) should be based on a Sei version newer than this update - * and therefore doesn't need this migration - */ -func V4ToV5(ctx sdk.Context, storeKey sdk.StoreKey, paramStore paramtypes.Subspace) error { - ClearStore(ctx, storeKey) - if err := migratePriceSnapshotParam(ctx, paramStore); err != nil { - return err - } - - // initialize epoch to 0 - store := ctx.KVStore(storeKey) - bz := make([]byte, 8) - binary.BigEndian.PutUint64(bz, 0) - store.Set([]byte(keeper.EpochKey), bz) - return nil -} diff --git a/x/dex/migrations/v4_to_v5_test.go b/x/dex/migrations/v4_to_v5_test.go deleted file mode 100644 index 78eaa9c0e..000000000 --- a/x/dex/migrations/v4_to_v5_test.go +++ /dev/null @@ -1,59 +0,0 @@ -package migrations_test - -import ( - "encoding/binary" - "testing" - - "github.com/cosmos/cosmos-sdk/codec" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/store" - storetypes "github.com/cosmos/cosmos-sdk/store/types" - sdk "github.com/cosmos/cosmos-sdk/types" - typesparams "github.com/cosmos/cosmos-sdk/x/params/types" - "github.com/sei-protocol/sei-chain/x/dex/keeper" - "github.com/sei-protocol/sei-chain/x/dex/migrations" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/libs/log" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - tmdb "github.com/tendermint/tm-db" -) - -func TestMigrate4to5(t *testing.T) { - storeKey := sdk.NewKVStoreKey(types.StoreKey) - memStoreKey := storetypes.NewMemoryStoreKey(types.MemStoreKey) - - db := tmdb.NewMemDB() - stateStore := store.NewCommitMultiStore(db) - stateStore.MountStoreWithDB(storeKey, sdk.StoreTypeIAVL, db) - stateStore.MountStoreWithDB(memStoreKey, sdk.StoreTypeMemory, nil) - require.NoError(t, stateStore.LoadLatestVersion()) - - registry := codectypes.NewInterfaceRegistry() - cdc := codec.NewProtoCodec(registry) - - paramsSubspace := typesparams.NewSubspace(cdc, - types.Amino, - storeKey, - memStoreKey, - "DexParams", - ) - ctx := sdk.NewContext(stateStore, tmproto.Header{}, false, log.NewNopLogger()) - if !paramsSubspace.HasKeyTable() { - paramsSubspace = paramsSubspace.WithKeyTable(types.ParamKeyTable()) - } - store := ctx.KVStore(storeKey) - store.Set([]byte("garbage key"), []byte("garbage value")) - require.True(t, store.Has([]byte("garbage key"))) - err := migrations.V4ToV5(ctx, storeKey, paramsSubspace) - require.Nil(t, err) - require.False(t, store.Has([]byte("garbage key"))) - - params := types.Params{} - paramsSubspace.GetParamSet(ctx, ¶ms) - require.Equal(t, uint64(types.DefaultPriceSnapshotRetention), params.PriceSnapshotRetention) - - epochBytes := store.Get([]byte(keeper.EpochKey)) - epoch := binary.BigEndian.Uint64(epochBytes) - require.Equal(t, uint64(0), epoch) -} diff --git a/x/dex/migrations/v5_to_v6.go b/x/dex/migrations/v5_to_v6.go deleted file mode 100644 index 870bc82e7..000000000 --- a/x/dex/migrations/v5_to_v6.go +++ /dev/null @@ -1,57 +0,0 @@ -package migrations - -import ( - "errors" - "fmt" - - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/store/prefix" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/keeper" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -// This migration updates contract info to match the new data format -func V5ToV6(ctx sdk.Context, storeKey sdk.StoreKey, _ codec.BinaryCodec) error { - for i := 0; i < 256; i++ { - if err := updateContractInfoForBytePrefix(ctx, storeKey, byte(i)); err != nil { - return err - } - } - return nil -} - -// assuming no dependency exists at the time of this migration -func updateContractInfoForBytePrefix(ctx sdk.Context, storeKey sdk.StoreKey, b byte) error { - store := prefix.NewStore( - ctx.KVStore(storeKey), - []byte(keeper.ContractPrefixKey), - ) - iterator := sdk.KVStorePrefixIterator(store, []byte{b}) - defer iterator.Close() - for ; iterator.Valid(); iterator.Next() { - oldContractInfoBytes := iterator.Value() - oldContractInfo := types.LegacyContractInfo{} - if err := oldContractInfo.Unmarshal(oldContractInfoBytes); err != nil { - ctx.Logger().Error(fmt.Sprintf("Failed to unmarshal contract info for %s", iterator.Key())) - return err - } - if oldContractInfo.DependentContractAddrs != nil { - ctx.Logger().Error(fmt.Sprintf("Contract info of %s has dependencies!", iterator.Key())) - return errors.New("contract has unexpected dependencies") - } - newContractInfo := types.ContractInfo{ - CodeId: oldContractInfo.CodeId, - ContractAddr: oldContractInfo.ContractAddr, - NeedHook: oldContractInfo.NeedHook, - NeedOrderMatching: oldContractInfo.NeedOrderMatching, - } - bz, err := newContractInfo.Marshal() - if err != nil { - ctx.Logger().Error(fmt.Sprintf("Failed to marshal contract info for %s", iterator.Key())) - return err - } - store.Set([]byte(newContractInfo.ContractAddr), bz) - } - return nil -} diff --git a/x/dex/migrations/v5_to_v6_test.go b/x/dex/migrations/v5_to_v6_test.go deleted file mode 100644 index 3035ec0c1..000000000 --- a/x/dex/migrations/v5_to_v6_test.go +++ /dev/null @@ -1,79 +0,0 @@ -package migrations_test - -import ( - "testing" - - "github.com/cosmos/cosmos-sdk/codec" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/store" - "github.com/cosmos/cosmos-sdk/store/prefix" - storetypes "github.com/cosmos/cosmos-sdk/store/types" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/keeper" - "github.com/sei-protocol/sei-chain/x/dex/migrations" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/libs/log" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - tmdb "github.com/tendermint/tm-db" -) - -func TestMigrate5to6(t *testing.T) { - storeKey := sdk.NewKVStoreKey(types.StoreKey) - memStoreKey := storetypes.NewMemoryStoreKey(types.MemStoreKey) - - db := tmdb.NewMemDB() - stateStore := store.NewCommitMultiStore(db) - stateStore.MountStoreWithDB(storeKey, sdk.StoreTypeIAVL, db) - stateStore.MountStoreWithDB(memStoreKey, sdk.StoreTypeMemory, nil) - require.NoError(t, stateStore.LoadLatestVersion()) - - registry := codectypes.NewInterfaceRegistry() - cdc := codec.NewProtoCodec(registry) - ctx := sdk.NewContext(stateStore, tmproto.Header{}, false, log.NewNopLogger()) - store := prefix.NewStore( - ctx.KVStore(storeKey), - []byte(keeper.ContractPrefixKey), - ) - - oldContractA := types.LegacyContractInfo{ - CodeId: 1, - ContractAddr: "abc", - NeedHook: true, - NeedOrderMatching: false, - } - oldContractB := types.LegacyContractInfo{ - CodeId: 2, - ContractAddr: "def", - NeedHook: false, - NeedOrderMatching: true, - } - bzA, _ := oldContractA.Marshal() - bzB, _ := oldContractB.Marshal() - store.Set([]byte("abc"), bzA) - store.Set([]byte("def"), bzB) - - err := migrations.V5ToV6(ctx, storeKey, cdc) - require.Nil(t, err) - - newBzA := store.Get([]byte("abc")) - newBzB := store.Get([]byte("def")) - newContractA := types.ContractInfo{} - newContractB := types.ContractInfo{} - err = newContractA.Unmarshal(newBzA) - require.Nil(t, err) - err = newContractB.Unmarshal(newBzB) - require.Nil(t, err) - require.Equal(t, types.ContractInfo{ - CodeId: 1, - ContractAddr: "abc", - NeedHook: true, - NeedOrderMatching: false, - }, newContractA) - require.Equal(t, types.ContractInfo{ - CodeId: 2, - ContractAddr: "def", - NeedHook: false, - NeedOrderMatching: true, - }, newContractB) -} diff --git a/x/dex/migrations/v6_to_v7.go b/x/dex/migrations/v6_to_v7.go deleted file mode 100644 index c7df17849..000000000 --- a/x/dex/migrations/v6_to_v7.go +++ /dev/null @@ -1,84 +0,0 @@ -package migrations - -import ( - "encoding/binary" - - "github.com/cosmos/cosmos-sdk/store/prefix" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/keeper" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -func V6ToV7(ctx sdk.Context, storeKey sdk.StoreKey) error { - backfillOrderIDPerContract(ctx, storeKey) - reformatPriceState(ctx, storeKey) - return nil -} - -// this function backfills contract order ID according to the old global order ID -func backfillOrderIDPerContract(ctx sdk.Context, storeKey sdk.StoreKey) { - oldStore := prefix.NewStore( - ctx.KVStore(storeKey), - []byte{}, - ) - oldKey := types.KeyPrefix(types.NextOrderIDKey) - oldIDBytes := oldStore.Get(oldKey) - if oldIDBytes == nil { - // nothing to backfill - return - } - oldID := binary.BigEndian.Uint64(oldIDBytes) - - contractStore := prefix.NewStore(ctx.KVStore(storeKey), []byte(keeper.ContractPrefixKey)) - iterator := sdk.KVStorePrefixIterator(contractStore, []byte{}) - - defer iterator.Close() - - for ; iterator.Valid(); iterator.Next() { - contract := types.ContractInfo{} - if err := contract.Unmarshal(iterator.Value()); err == nil { - if contract.NeedOrderMatching { - newIDStore := prefix.NewStore(ctx.KVStore(storeKey), types.NextOrderIDPrefix(contract.ContractAddr)) - byteKey := types.KeyPrefix(types.NextOrderIDKey) - bz := make([]byte, 8) - binary.BigEndian.PutUint64(bz, oldID) - newIDStore.Set(byteKey, bz) - } - } - } -} - -func reformatPriceState(ctx sdk.Context, storeKey sdk.StoreKey) { - contractStore := prefix.NewStore(ctx.KVStore(storeKey), []byte(keeper.ContractPrefixKey)) - iterator := sdk.KVStorePrefixIterator(contractStore, []byte{}) - - defer iterator.Close() - - for ; iterator.Valid(); iterator.Next() { - contract := types.ContractInfo{} - if err := contract.Unmarshal(iterator.Value()); err == nil { - pairStore := prefix.NewStore(ctx.KVStore(storeKey), types.RegisteredPairPrefix(contract.ContractAddr)) - pairIterator := sdk.KVStorePrefixIterator(pairStore, []byte{}) - for ; pairIterator.Valid(); pairIterator.Next() { - pair := types.Pair{} - if err := pair.Unmarshal(pairIterator.Value()); err == nil { - oldPriceStore := prefix.NewStore(ctx.KVStore(storeKey), append( - append( - append(types.KeyPrefix(types.PriceKey), types.KeyPrefix(contract.ContractAddr)...), - types.KeyPrefix(pair.PriceDenom)..., - ), - types.KeyPrefix(pair.AssetDenom)..., - )) - newPriceStore := prefix.NewStore(ctx.KVStore(storeKey), types.PricePrefix(contract.ContractAddr, pair.PriceDenom, pair.AssetDenom)) - oldPriceIterator := sdk.KVStorePrefixIterator(oldPriceStore, []byte{}) - for ; oldPriceIterator.Valid(); oldPriceIterator.Next() { - newPriceStore.Set(oldPriceIterator.Key(), oldPriceIterator.Value()) - } - oldPriceIterator.Close() - } - } - - pairIterator.Close() - } - } -} diff --git a/x/dex/migrations/v6_to_v7_test.go b/x/dex/migrations/v6_to_v7_test.go deleted file mode 100644 index e00f9adbc..000000000 --- a/x/dex/migrations/v6_to_v7_test.go +++ /dev/null @@ -1,89 +0,0 @@ -package migrations_test - -import ( - "encoding/binary" - "testing" - - "github.com/cosmos/cosmos-sdk/store" - "github.com/cosmos/cosmos-sdk/store/prefix" - storetypes "github.com/cosmos/cosmos-sdk/store/types" - sdk "github.com/cosmos/cosmos-sdk/types" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex/keeper" - "github.com/sei-protocol/sei-chain/x/dex/migrations" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/libs/log" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - tmdb "github.com/tendermint/tm-db" -) - -func TestMigrate6to7(t *testing.T) { - storeKey := sdk.NewKVStoreKey(types.StoreKey) - memStoreKey := storetypes.NewMemoryStoreKey(types.MemStoreKey) - - db := tmdb.NewMemDB() - stateStore := store.NewCommitMultiStore(db) - stateStore.MountStoreWithDB(storeKey, sdk.StoreTypeIAVL, db) - stateStore.MountStoreWithDB(memStoreKey, sdk.StoreTypeMemory, nil) - require.NoError(t, stateStore.LoadLatestVersion()) - - ctx := sdk.NewContext(stateStore, tmproto.Header{}, false, log.NewNopLogger()) - - // write old order ID - store := prefix.NewStore(ctx.KVStore(storeKey), []byte{}) - oldID := make([]byte, 8) - binary.BigEndian.PutUint64(oldID, 10) - store.Set(types.KeyPrefix(types.NextOrderIDKey), oldID) - - // write old price state - store = prefix.NewStore(ctx.KVStore(storeKey), append( - append( - append(types.KeyPrefix(types.PriceKey), types.KeyPrefix(keepertest.TestContract)...), - types.KeyPrefix(keepertest.TestPriceDenom)..., - ), - types.KeyPrefix(keepertest.TestAssetDenom)...), - ) - - price := types.Price{ - SnapshotTimestampInSeconds: 5, - Price: sdk.MustNewDecFromStr("123.4"), - Pair: &keepertest.TestPair, - } - priceBytes, _ := price.Marshal() - store.Set(keeper.GetKeyForTs(price.SnapshotTimestampInSeconds), priceBytes) - - // register contract / pair - store = prefix.NewStore( - ctx.KVStore(storeKey), - []byte(keeper.ContractPrefixKey), - ) - contract := types.ContractInfo{ - CodeId: 1, - ContractAddr: keepertest.TestContract, - NeedOrderMatching: true, - } - contractBytes, _ := contract.Marshal() - store.Set([]byte(contract.ContractAddr), contractBytes) - - store = prefix.NewStore(ctx.KVStore(storeKey), types.RegisteredPairPrefix(keepertest.TestContract)) - keyBytes := make([]byte, 8) - binary.BigEndian.PutUint64(keyBytes, 0) - pairBytes, _ := keepertest.TestPair.Marshal() - store.Set(keyBytes, pairBytes) - - err := migrations.V6ToV7(ctx, storeKey) - require.Nil(t, err) - - store = prefix.NewStore(ctx.KVStore(storeKey), types.NextOrderIDPrefix(keepertest.TestContract)) - byteKey := types.KeyPrefix(types.NextOrderIDKey) - bz := store.Get(byteKey) - require.Equal(t, uint64(10), binary.BigEndian.Uint64(bz)) - - store = prefix.NewStore(ctx.KVStore(storeKey), types.PricePrefix(keepertest.TestContract, keepertest.TestPriceDenom, keepertest.TestAssetDenom)) - key := keeper.GetKeyForTs(5) - priceRes := types.Price{} - b := store.Get(key) - _ = priceRes.Unmarshal(b) - require.Equal(t, price, priceRes) -} diff --git a/x/dex/migrations/v7_to_v8.go b/x/dex/migrations/v7_to_v8.go deleted file mode 100644 index 26914ff4d..000000000 --- a/x/dex/migrations/v7_to_v8.go +++ /dev/null @@ -1,101 +0,0 @@ -package migrations - -import ( - "encoding/binary" - - "github.com/cosmos/cosmos-sdk/store/prefix" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/keeper" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -func V7ToV8(ctx sdk.Context, storeKey sdk.StoreKey) error { - return flattenSettlements(ctx, storeKey) -} - -func flattenSettlements(ctx sdk.Context, storeKey sdk.StoreKey) error { - contractStore := prefix.NewStore(ctx.KVStore(storeKey), []byte(keeper.ContractPrefixKey)) - iterator := sdk.KVStorePrefixIterator(contractStore, []byte{}) - - defer iterator.Close() - for ; iterator.Valid(); iterator.Next() { - contract := types.ContractInfo{} - if err := contract.Unmarshal(iterator.Value()); err != nil { - return err - } - pairStore := prefix.NewStore(ctx.KVStore(storeKey), types.RegisteredPairPrefix(contract.ContractAddr)) - pairIterator := sdk.KVStorePrefixIterator(pairStore, []byte{}) - for ; pairIterator.Valid(); pairIterator.Next() { - pair := types.Pair{} - if err := pair.Unmarshal(pairIterator.Value()); err != nil { - pairIterator.Close() - return err - } - settlementStore := prefix.NewStore( - ctx.KVStore(storeKey), - SettlementEntryPrefix(contract.ContractAddr, pair.PriceDenom, pair.AssetDenom), - ) - settlementIterator := sdk.KVStorePrefixIterator(settlementStore, []byte{}) - - oldKeys := [][]byte{} - newKeys := [][]byte{} - newVals := [][]byte{} - for ; settlementIterator.Valid(); settlementIterator.Next() { - var val types.Settlements - if err := val.Unmarshal(settlementIterator.Value()); err != nil { - pairIterator.Close() - settlementIterator.Close() - return err - } - for i, settlementEntry := range val.Entries { - settlementBytes, err := settlementEntry.Marshal() - if err != nil { - pairIterator.Close() - settlementIterator.Close() - return err - } - newKeys = append(newKeys, types.GetSettlementKey(settlementEntry.OrderId, settlementEntry.Account, uint64(i))) - newVals = append(newVals, settlementBytes) - } - - if len(val.Entries) > 0 { - settlementIDStore := prefix.NewStore( - ctx.KVStore(storeKey), - NextSettlementIDPrefix(contract.ContractAddr, pair.PriceDenom, pair.AssetDenom), - ) - key := make([]byte, 8) - binary.BigEndian.PutUint64(key, val.Entries[0].OrderId) - value := make([]byte, 8) - binary.BigEndian.PutUint64(value, uint64(len(val.Entries))) - settlementIDStore.Set(key, value) - } - oldKeys = append(oldKeys, settlementIterator.Key()) - } - - settlementIterator.Close() - - for _, oldKey := range oldKeys { - settlementStore.Delete(oldKey) - } - for i, newKey := range newKeys { - settlementStore.Set(newKey, newVals[i]) - } - } - pairIterator.Close() - } - return nil -} - -func SettlementEntryPrefix(contractAddr string, priceDenom string, assetDenom string) []byte { - return append( - append(types.KeyPrefix("SettlementEntry-"), types.AddressKeyPrefix(contractAddr)...), - types.PairPrefix(priceDenom, assetDenom)..., - ) -} - -func NextSettlementIDPrefix(contractAddr string, priceDenom string, assetDenom string) []byte { - return append( - append(types.KeyPrefix("NextSettlementID-"), types.AddressKeyPrefix(contractAddr)...), - types.PairPrefix(priceDenom, assetDenom)..., - ) -} diff --git a/x/dex/migrations/v7_to_v8_test.go b/x/dex/migrations/v7_to_v8_test.go deleted file mode 100644 index 5960ff7e7..000000000 --- a/x/dex/migrations/v7_to_v8_test.go +++ /dev/null @@ -1,98 +0,0 @@ -package migrations_test - -import ( - "encoding/binary" - "testing" - - "github.com/cosmos/cosmos-sdk/store" - "github.com/cosmos/cosmos-sdk/store/prefix" - storetypes "github.com/cosmos/cosmos-sdk/store/types" - sdk "github.com/cosmos/cosmos-sdk/types" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex/keeper" - "github.com/sei-protocol/sei-chain/x/dex/migrations" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/libs/log" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - tmdb "github.com/tendermint/tm-db" -) - -func TestMigrate7to8(t *testing.T) { - storeKey := sdk.NewKVStoreKey(types.StoreKey) - memStoreKey := storetypes.NewMemoryStoreKey(types.MemStoreKey) - - db := tmdb.NewMemDB() - stateStore := store.NewCommitMultiStore(db) - stateStore.MountStoreWithDB(storeKey, sdk.StoreTypeIAVL, db) - stateStore.MountStoreWithDB(memStoreKey, sdk.StoreTypeMemory, nil) - require.NoError(t, stateStore.LoadLatestVersion()) - - ctx := sdk.NewContext(stateStore, tmproto.Header{}, false, log.NewNopLogger()) - - // write old settlements - store := prefix.NewStore( - ctx.KVStore(storeKey), - migrations.SettlementEntryPrefix(keepertest.TestContract, keepertest.TestPriceDenom, keepertest.TestAssetDenom), - ) - settlements := types.Settlements{ - Entries: []*types.SettlementEntry{ - { - Account: keepertest.TestAccount, - OrderId: 1, - Quantity: sdk.MustNewDecFromStr("0.3"), - }, - { - Account: keepertest.TestAccount, - OrderId: 1, - Quantity: sdk.MustNewDecFromStr("0.7"), - }, - }, - } - bz, _ := settlements.Marshal() - store.Set(types.GetSettlementOrderIDPrefix(1, keepertest.TestAccount), bz) - - // register contract / pair - store = prefix.NewStore( - ctx.KVStore(storeKey), - []byte(keeper.ContractPrefixKey), - ) - contract := types.ContractInfo{ - CodeId: 1, - ContractAddr: keepertest.TestContract, - NeedOrderMatching: true, - } - contractBytes, _ := contract.Marshal() - store.Set([]byte(contract.ContractAddr), contractBytes) - - store = prefix.NewStore(ctx.KVStore(storeKey), types.RegisteredPairPrefix(keepertest.TestContract)) - keyBytes := make([]byte, 8) - binary.BigEndian.PutUint64(keyBytes, 0) - pairBytes, _ := keepertest.TestPair.Marshal() - store.Set(keyBytes, pairBytes) - - err := migrations.V7ToV8(ctx, storeKey) - require.Nil(t, err) - - store = prefix.NewStore( - ctx.KVStore(storeKey), - migrations.SettlementEntryPrefix(keepertest.TestContract, keepertest.TestPriceDenom, keepertest.TestAssetDenom), - ) - settlementEntry1Key := types.GetSettlementKey(1, keepertest.TestAccount, 0) - settlementEntry1 := types.SettlementEntry{} - settlementEntry1Bytes := store.Get(settlementEntry1Key) - _ = settlementEntry1.Unmarshal(settlementEntry1Bytes) - require.Equal(t, sdk.MustNewDecFromStr("0.3"), settlementEntry1.Quantity) - settlementEntry2Key := types.GetSettlementKey(1, keepertest.TestAccount, 1) - settlementEntry2 := types.SettlementEntry{} - settlementEntry2Bytes := store.Get(settlementEntry2Key) - _ = settlementEntry2.Unmarshal(settlementEntry2Bytes) - require.Equal(t, sdk.MustNewDecFromStr("0.7"), settlementEntry2.Quantity) - - require.False(t, store.Has(types.GetSettlementOrderIDPrefix(1, keepertest.TestAccount))) - - store = prefix.NewStore(ctx.KVStore(storeKey), migrations.NextSettlementIDPrefix(keepertest.TestContract, keepertest.TestPriceDenom, keepertest.TestAssetDenom)) - key := make([]byte, 8) - binary.BigEndian.PutUint64(key, uint64(1)) - require.Equal(t, uint64(2), binary.BigEndian.Uint64(store.Get(key))) -} diff --git a/x/dex/migrations/v8_to_v9.go b/x/dex/migrations/v8_to_v9.go deleted file mode 100644 index cb0e6095d..000000000 --- a/x/dex/migrations/v8_to_v9.go +++ /dev/null @@ -1,38 +0,0 @@ -package migrations - -import ( - "github.com/cosmos/cosmos-sdk/store/prefix" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/keeper" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -func V8ToV9(ctx sdk.Context, dexkeeper keeper.Keeper) error { - dexkeeper.CreateModuleAccount(ctx) - - contractStore := prefix.NewStore(ctx.KVStore(dexkeeper.GetStoreKey()), []byte(keeper.ContractPrefixKey)) - iterator := sdk.KVStorePrefixIterator(contractStore, []byte{}) - - defer iterator.Close() - for ; iterator.Valid(); iterator.Next() { - contract := types.ContractInfo{} - if err := contract.Unmarshal(iterator.Value()); err != nil { - return err - } - contractV2 := types.ContractInfoV2{ - CodeId: contract.CodeId, - ContractAddr: contract.ContractAddr, - NeedHook: contract.NeedHook, - NeedOrderMatching: contract.NeedOrderMatching, - Dependencies: contract.Dependencies, - NumIncomingDependencies: contract.NumIncomingDependencies, - } - bz, err := contractV2.Marshal() - if err != nil { - return err - } - contractStore.Set(iterator.Key(), bz) - } - - return nil -} diff --git a/x/dex/migrations/v8_to_v9_test.go b/x/dex/migrations/v8_to_v9_test.go deleted file mode 100644 index c1b87b3d6..000000000 --- a/x/dex/migrations/v8_to_v9_test.go +++ /dev/null @@ -1,42 +0,0 @@ -package migrations_test - -import ( - "testing" - - "github.com/cosmos/cosmos-sdk/store/prefix" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex/keeper" - "github.com/sei-protocol/sei-chain/x/dex/migrations" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestMigrate8to9(t *testing.T) { - dexkeeper, ctx := keepertest.DexKeeper(t) - // write old contract - store := prefix.NewStore( - ctx.KVStore(dexkeeper.GetStoreKey()), - []byte(keeper.ContractPrefixKey), - ) - contract := types.ContractInfo{ - CodeId: 1, - ContractAddr: keepertest.TestContract, - NeedOrderMatching: true, - } - contractBytes, _ := contract.Marshal() - store.Set(types.ContractKey(contract.ContractAddr), contractBytes) - - err := migrations.V8ToV9(ctx, *dexkeeper) - require.NoError(t, err) - - contractV2, err := dexkeeper.GetContract(ctx, keepertest.TestContract) - require.NoError(t, err) - require.Equal(t, types.ContractInfoV2{ - CodeId: 1, - ContractAddr: keepertest.TestContract, - NeedOrderMatching: true, - }, contractV2) - - moduleAccount := dexkeeper.AccountKeeper.GetModuleAccount(ctx, types.ModuleName) - require.NotNil(t, moduleAccount) -} diff --git a/x/dex/migrations/v9_to_v10.go b/x/dex/migrations/v9_to_v10.go deleted file mode 100644 index c8484d9b1..000000000 --- a/x/dex/migrations/v9_to_v10.go +++ /dev/null @@ -1,91 +0,0 @@ -package migrations - -import ( - "github.com/cosmos/cosmos-sdk/store/prefix" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/keeper" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -const PriceTickSizeKey = "ticks" -const QuantityTickSizeKey = "quantityticks" -const RegisteredPairCount = "rpcnt" - -// This migration deprecates the tick size store keys and registered pair count store keys. -// It also refactors the registered pair store to use pair denoms for key construction -// instead of index based key construction. -func V9ToV10(ctx sdk.Context, dexkeeper keeper.Keeper) error { - dexkeeper.CreateModuleAccount(ctx) - store := ctx.KVStore(dexkeeper.GetStoreKey()) - - rpIterator := sdk.KVStorePrefixIterator(store, []byte(types.RegisteredPairKey)) - - rpcntByte := []byte(RegisteredPairCount) - defer rpIterator.Close() - for ; rpIterator.Valid(); rpIterator.Next() { - // need to skip anything that has rpcnt in the key prefix - if string(rpIterator.Key()[:len(rpcntByte)]) == RegisteredPairCount { - continue - } - var registeredPair types.Pair - b := rpIterator.Value() - err := registeredPair.Unmarshal(b) - if err != nil { - return err - } - // this key is the contractAddress + index - rpKey := rpIterator.Key() - // remove first 2 bytes for prefix and last 8 bytes since that is the index - rpContractKey := rpKey[2 : len(rpKey)-8] - // get pair prefix used for indexing - pairPrefix := types.PairPrefix(registeredPair.PriceDenom, registeredPair.AssetDenom) - - // set the price and quantity ticks from the appropriate store - priceTickStore := prefix.NewStore(store, append([]byte(PriceTickSizeKey), rpContractKey...)) - priceTickSize := sdk.Dec{} - b = priceTickStore.Get(pairPrefix) - err = priceTickSize.Unmarshal(b) - if err != nil { - return err - } - registeredPair.PriceTicksize = &priceTickSize - - quantityTickStore := prefix.NewStore(store, append([]byte(QuantityTickSizeKey), rpContractKey...)) - quantityTickSize := sdk.Dec{} - b = quantityTickStore.Get(pairPrefix) - err = quantityTickSize.Unmarshal(b) - if err != nil { - return err - } - registeredPair.QuantityTicksize = &quantityTickSize - - // delete the old store value - rpStore := prefix.NewStore(store, append([]byte(types.RegisteredPairKey), rpContractKey...)) - rpStore.Delete(rpKey) - // updated registered pair, now we need to set it to the correct store value - writeBytes := dexkeeper.Cdc.MustMarshal(®isteredPair) - rpStore.Set(pairPrefix, writeBytes) - } - - // delete rpcnt - rpcIterator := sdk.KVStorePrefixIterator(store, []byte(RegisteredPairCount)) - defer rpcIterator.Close() - for ; rpcIterator.Valid(); rpcIterator.Next() { - store.Delete(rpcIterator.Key()) - } - - // delete price Ticks - priceTickIterator := sdk.KVStorePrefixIterator(store, []byte(PriceTickSizeKey)) - defer priceTickIterator.Close() - for ; priceTickIterator.Valid(); priceTickIterator.Next() { - store.Delete(priceTickIterator.Key()) - } - - // delete quantityTicks - quantityTickIterator := sdk.KVStorePrefixIterator(store, []byte(QuantityTickSizeKey)) - defer quantityTickIterator.Close() - for ; quantityTickIterator.Valid(); quantityTickIterator.Next() { - store.Delete(quantityTickIterator.Key()) - } - return nil -} diff --git a/x/dex/migrations/v9_to_v10_test.go b/x/dex/migrations/v9_to_v10_test.go deleted file mode 100644 index 27f6406a8..000000000 --- a/x/dex/migrations/v9_to_v10_test.go +++ /dev/null @@ -1,94 +0,0 @@ -package migrations_test - -import ( - "encoding/binary" - "testing" - - "github.com/cosmos/cosmos-sdk/store/prefix" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkaddress "github.com/cosmos/cosmos-sdk/types/address" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex/migrations" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestMigrate9to10(t *testing.T) { - dexkeeper, ctx := keepertest.DexKeeper(t) - // write old contract - dexStore := ctx.KVStore(dexkeeper.GetStoreKey()) - rpStore := prefix.NewStore( - dexStore, - []byte(types.RegisteredPairKey), - ) - priceTickSize := sdk.MustNewDecFromStr("0.0001") - quantityTickSize := sdk.MustNewDecFromStr("0.0001") - pair := types.Pair{ - PriceDenom: keepertest.TestPair.PriceDenom, - AssetDenom: keepertest.TestPair.AssetDenom, - PriceTicksize: &priceTickSize, - QuantityTicksize: &quantityTickSize, - } - pairPrefix := types.PairPrefix(keepertest.TestPair.PriceDenom, keepertest.TestPair.AssetDenom) - - pairBytes := dexkeeper.Cdc.MustMarshal(&pair) - countBytes := make([]byte, 8) - binary.BigEndian.PutUint64(countBytes, 1) - // simulate legacy store where registered pairs are indexed by auto increment count - address, _ := sdk.AccAddressFromBech32(keepertest.TestContract) - address = sdkaddress.MustLengthPrefix(address) - rpStore.Set(append(address, countBytes...), pairBytes) - - bytes := rpStore.Get(append(address, countBytes...)) - require.Equal(t, pairBytes, bytes) - - // set count, ticksize, and quantity size - newCountBytes := make([]byte, 8) - binary.BigEndian.PutUint64(newCountBytes, 2) - dexStore.Set( - append([]byte(migrations.RegisteredPairCount), address...), - newCountBytes, - ) - - tickBytes, _ := sdk.MustNewDecFromStr("0.0002").Marshal() - dexStore.Set( - append(append([]byte(migrations.PriceTickSizeKey), address...), pairPrefix...), - tickBytes, - ) - - dexStore.Set( - append(append([]byte(migrations.QuantityTickSizeKey), address...), pairPrefix...), - tickBytes, - ) - - err := migrations.V9ToV10(ctx, *dexkeeper) - require.NoError(t, err) - - pair, found := dexkeeper.GetRegisteredPair(ctx, keepertest.TestContract, keepertest.TestPair.PriceDenom, keepertest.TestPair.AssetDenom) - require.True(t, found) - newTickSize := sdk.MustNewDecFromStr("0.0002") - require.Equal(t, types.Pair{ - PriceDenom: keepertest.TestPair.PriceDenom, - AssetDenom: keepertest.TestPair.AssetDenom, - PriceTicksize: &newTickSize, - QuantityTicksize: &newTickSize, - }, pair) - - // verify old/deprecated keeper store data is removed - require.False( - t, - dexStore.Has(append(address, countBytes...)), - ) - require.False( - t, - dexStore.Has(append([]byte(migrations.RegisteredPairCount), address...)), - ) - require.False( - t, - dexStore.Has(append(append([]byte(migrations.PriceTickSizeKey), address...), pairPrefix...)), - ) - require.False( - t, - dexStore.Has(append(append([]byte(migrations.QuantityTickSizeKey), address...), pairPrefix...)), - ) -} diff --git a/x/dex/module.go b/x/dex/module.go deleted file mode 100644 index 0a82142be..000000000 --- a/x/dex/module.go +++ /dev/null @@ -1,383 +0,0 @@ -package dex - -import ( - "context" - "encoding/json" - "fmt" - "sync" - "time" - - "github.com/CosmWasm/wasmd/x/wasm" - "github.com/cosmos/cosmos-sdk/store/prefix" - "github.com/cosmos/cosmos-sdk/telemetry" - "github.com/gorilla/mux" - "github.com/grpc-ecosystem/grpc-gateway/runtime" - "github.com/spf13/cobra" - abci "github.com/tendermint/tendermint/abci/types" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/codec" - cdctypes "github.com/cosmos/cosmos-sdk/codec/types" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/module" - "github.com/cosmos/cosmos-sdk/utils/tracing" - "github.com/sei-protocol/sei-chain/utils" - "github.com/sei-protocol/sei-chain/utils/datastructures" - "github.com/sei-protocol/sei-chain/x/dex/client/cli/query" - "github.com/sei-protocol/sei-chain/x/dex/client/cli/tx" - "github.com/sei-protocol/sei-chain/x/dex/contract" - "github.com/sei-protocol/sei-chain/x/dex/keeper" - dexkeeperabci "github.com/sei-protocol/sei-chain/x/dex/keeper/abci" - "github.com/sei-protocol/sei-chain/x/dex/keeper/msgserver" - dexkeeperquery "github.com/sei-protocol/sei-chain/x/dex/keeper/query" - "github.com/sei-protocol/sei-chain/x/dex/migrations" - "github.com/sei-protocol/sei-chain/x/dex/types" - dexutils "github.com/sei-protocol/sei-chain/x/dex/utils" - "github.com/sei-protocol/sei-chain/x/store" -) - -var ( - _ module.AppModule = AppModule{} - _ module.AppModuleBasic = AppModuleBasic{} -) - -// ---------------------------------------------------------------------------- -// AppModuleBasic -// ---------------------------------------------------------------------------- - -// AppModuleBasic implements the AppModuleBasic interface for the capability module. -type AppModuleBasic struct { - cdc codec.BinaryCodec -} - -func NewAppModuleBasic(cdc codec.BinaryCodec) AppModuleBasic { - return AppModuleBasic{cdc: cdc} -} - -// Name returns the capability module's name. -func (AppModuleBasic) Name() string { - return types.ModuleName -} - -func (AppModuleBasic) RegisterCodec(cdc *codec.LegacyAmino) { - types.RegisterCodec(cdc) -} - -func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { - types.RegisterCodec(cdc) -} - -// RegisterInterfaces registers the module's interface types -func (a AppModuleBasic) RegisterInterfaces(reg cdctypes.InterfaceRegistry) { - types.RegisterInterfaces(reg) -} - -// DefaultGenesis returns the capability module's default genesis state. -func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { - return cdc.MustMarshalJSON(types.DefaultGenesis()) -} - -// ValidateGenesis performs genesis state validation for the capability module. -func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, _ client.TxEncodingConfig, bz json.RawMessage) error { - var genState types.GenesisState - if err := cdc.UnmarshalJSON(bz, &genState); err != nil { - return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) - } - return genState.Validate() -} - -// ExportGenesisStream returns the tokenfactory module's exported genesis state as raw JSON bytes in a streaming fashion. -func (am AppModule) ExportGenesisStream(ctx sdk.Context, cdc codec.JSONCodec) <-chan json.RawMessage { - ch := make(chan json.RawMessage) - go func() { - ch <- am.ExportGenesis(ctx, cdc) - close(ch) - }() - return ch -} - -// ValidateGenesisStream performs genesis state validation for the x/tokenfactory module in a streaming fashion. -func (am AppModuleBasic) ValidateGenesisStream(cdc codec.JSONCodec, config client.TxEncodingConfig, genesisCh <-chan json.RawMessage) error { - for genesis := range genesisCh { - err := am.ValidateGenesis(cdc, config, genesis) - if err != nil { - return err - } - } - return nil -} - -// RegisterRESTRoutes registers the capability module's REST service handlers. -func (AppModuleBasic) RegisterRESTRoutes(_ client.Context, _ *mux.Router) { -} - -// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the module. -func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { - types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)) //nolint:errcheck // this is inside a module, and the method doesn't return error. Leave it alone. -} - -// GetTxCmd returns the capability module's root tx command. -func (a AppModuleBasic) GetTxCmd() *cobra.Command { - return tx.GetTxCmd() -} - -// GetQueryCmd returns the capability module's root query command. -func (AppModuleBasic) GetQueryCmd() *cobra.Command { - return query.GetQueryCmd() -} - -// ---------------------------------------------------------------------------- -// AppModule -// ---------------------------------------------------------------------------- - -// AppModule implements the AppModule interface for the capability module. -type AppModule struct { - AppModuleBasic - - keeper keeper.Keeper - accountKeeper types.AccountKeeper - bankKeeper types.BankKeeper - wasmKeeper wasm.Keeper - - abciWrapper dexkeeperabci.KeeperWrapper - - tracingInfo *tracing.Info -} - -func NewAppModule( - cdc codec.Codec, - keeper keeper.Keeper, - accountKeeper types.AccountKeeper, - bankKeeper types.BankKeeper, - wasmKeeper wasm.Keeper, - tracingInfo *tracing.Info, -) AppModule { - return AppModule{ - AppModuleBasic: NewAppModuleBasic(cdc), - keeper: keeper, - accountKeeper: accountKeeper, - bankKeeper: bankKeeper, - wasmKeeper: wasmKeeper, - abciWrapper: dexkeeperabci.KeeperWrapper{Keeper: &keeper}, - tracingInfo: tracingInfo, - } -} - -// Name returns the capability module's name. -func (am AppModule) Name() string { - return am.AppModuleBasic.Name() -} - -// Route returns the capability module's message routing key. -func (am AppModule) Route() sdk.Route { - return sdk.NewRoute(types.RouterKey, NewHandler(am.keeper)) -} - -// QuerierRoute returns the capability module's query routing key. -func (AppModule) QuerierRoute() string { return types.QuerierRoute } - -// LegacyQuerierHandler returns the capability module's Querier. -func (am AppModule) LegacyQuerierHandler(_ *codec.LegacyAmino) sdk.Querier { - return nil -} - -// RegisterServices registers a GRPC query service to respond to the -// module-specific GRPC queries. -func (am AppModule) RegisterServices(cfg module.Configurator) { - types.RegisterMsgServer(cfg.MsgServer(), msgserver.NewMsgServerImpl(am.keeper)) - types.RegisterQueryServer(cfg.QueryServer(), dexkeeperquery.KeeperWrapper{Keeper: &am.keeper}) - - _ = cfg.RegisterMigration(types.ModuleName, 1, func(ctx sdk.Context) error { return nil }) - _ = cfg.RegisterMigration(types.ModuleName, 2, func(ctx sdk.Context) error { - return migrations.DataTypeUpdate(ctx, am.keeper.GetStoreKey(), am.keeper.Cdc) - }) - _ = cfg.RegisterMigration(types.ModuleName, 3, func(ctx sdk.Context) error { - return migrations.PriceSnapshotUpdate(ctx, am.keeper.Paramstore) - }) - _ = cfg.RegisterMigration(types.ModuleName, 4, func(ctx sdk.Context) error { - return migrations.V4ToV5(ctx, am.keeper.GetStoreKey(), am.keeper.Paramstore) - }) - _ = cfg.RegisterMigration(types.ModuleName, 5, func(ctx sdk.Context) error { - return migrations.V5ToV6(ctx, am.keeper.GetStoreKey(), am.keeper.Cdc) - }) - _ = cfg.RegisterMigration(types.ModuleName, 6, func(ctx sdk.Context) error { - return migrations.V6ToV7(ctx, am.keeper.GetStoreKey()) - }) - _ = cfg.RegisterMigration(types.ModuleName, 7, func(ctx sdk.Context) error { - return migrations.V7ToV8(ctx, am.keeper.GetStoreKey()) - }) - _ = cfg.RegisterMigration(types.ModuleName, 8, func(ctx sdk.Context) error { - return migrations.V8ToV9(ctx, am.keeper) - }) - _ = cfg.RegisterMigration(types.ModuleName, 9, func(ctx sdk.Context) error { - return migrations.V9ToV10(ctx, am.keeper) - }) - _ = cfg.RegisterMigration(types.ModuleName, 10, func(ctx sdk.Context) error { - return migrations.V10ToV11(ctx, am.keeper) - }) - _ = cfg.RegisterMigration(types.ModuleName, 11, func(ctx sdk.Context) error { - return migrations.V11ToV12(ctx, am.keeper) - }) - _ = cfg.RegisterMigration(types.ModuleName, 12, func(ctx sdk.Context) error { - return migrations.V12ToV13(ctx, am.keeper) - }) - _ = cfg.RegisterMigration(types.ModuleName, 13, func(ctx sdk.Context) error { - return migrations.V13ToV14(ctx, am.keeper) - }) - _ = cfg.RegisterMigration(types.ModuleName, 14, func(ctx sdk.Context) error { - return migrations.V14ToV15(ctx, am.keeper) - }) - _ = cfg.RegisterMigration(types.ModuleName, 15, func(ctx sdk.Context) error { - return migrations.V15ToV16(ctx, am.keeper) - }) - _ = cfg.RegisterMigration(types.ModuleName, 16, func(ctx sdk.Context) error { - return nil - }) - _ = cfg.RegisterMigration(types.ModuleName, 17, func(ctx sdk.Context) error { - return migrations.V17ToV18(ctx, am.keeper) - }) -} - -// RegisterInvariants registers the capability module's invariants. -func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} - -// InitGenesis performs the capability module's genesis initialization It returns -// no validator updates. -func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, gs json.RawMessage) []abci.ValidatorUpdate { - var genState types.GenesisState - // Initialize global index to index in genesis state - cdc.MustUnmarshalJSON(gs, &genState) - - InitGenesis(ctx, am.keeper, genState) - - return []abci.ValidatorUpdate{} -} - -// ExportGenesis returns the capability module's exported genesis state as raw JSON bytes. -func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { - genState := ExportGenesis(ctx, am.keeper) - return cdc.MustMarshalJSON(genState) -} - -// ConsensusVersion implements ConsensusVersion. -func (AppModule) ConsensusVersion() uint64 { return 18 } - -// BeginBlock executes all ABCI BeginBlock logic respective to the capability module. -func (am AppModule) BeginBlock(ctx sdk.Context, _ abci.RequestBeginBlock) { - defer func() { - _, span := am.tracingInfo.Start("DexBeginBlockRollback") - defer span.End() - }() - - dexutils.GetMemState(ctx.Context()).Clear(ctx) - isNewEpoch, currentEpoch := am.keeper.IsNewEpoch(ctx) - if isNewEpoch { - am.keeper.SetEpoch(ctx, currentEpoch) - } - cachedCtx, cachedStore := store.GetCachedContext(ctx) - priceRetention := am.keeper.GetParams(ctx).PriceSnapshotRetention - cutOffTime := uint64(ctx.BlockTime().Unix()) - priceRetention - wg := sync.WaitGroup{} - mutex := sync.Mutex{} - allContracts := am.keeper.GetAllProcessableContractInfo(ctx) - allPricesToDelete := make(map[string][]*types.PriceStore, len(allContracts)) - - // Parallelize the logic to find all prices to delete - for _, contract := range allContracts { - wg.Add(1) - go func(contract types.ContractInfoV2) { - priceKeysToDelete := am.getPriceToDelete(cachedCtx, contract, cutOffTime) - mutex.Lock() - allPricesToDelete[contract.ContractAddr] = priceKeysToDelete - mutex.Unlock() - wg.Done() - }(contract) - } - wg.Wait() - - // Execute the deletion in order - for _, contract := range allContracts { - if priceStores, found := allPricesToDelete[contract.ContractAddr]; found { - for _, priceStore := range priceStores { - for _, key := range priceStore.PriceKeys { - priceStore.Store.Delete(key) - } - } - } - } - // only write if all contracts have been processed - cachedStore.Write() -} - -func (am AppModule) getPriceToDelete( - ctx sdk.Context, - contract types.ContractInfoV2, - timestamp uint64, -) []*types.PriceStore { - var result []*types.PriceStore - if contract.NeedOrderMatching { - for _, pair := range am.keeper.GetAllRegisteredPairs(ctx, contract.ContractAddr) { - store := prefix.NewStore(ctx.KVStore(am.keeper.GetStoreKey()), types.PricePrefix(contract.ContractAddr, pair.PriceDenom, pair.AssetDenom)) - keysToDelete := am.keeper.GetPriceKeysToDelete(store, timestamp) - result = append(result, &types.PriceStore{ - Store: store, - PriceKeys: keysToDelete, - }) - } - } - return result -} - -// EndBlock executes all ABCI EndBlock logic respective to the capability module. It -// returns no validator updates. -func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) (ret []abci.ValidatorUpdate) { - defer func() { - if err := recover(); err != nil { - telemetry.IncrCounter(1, "recovered_panics") - ctx.Logger().Error(fmt.Sprintf("panic in endblock recovered: %s", err)) - } - }() - _, span := am.tracingInfo.Start("DexEndBlock") - defer span.End() - defer dexutils.GetMemState(ctx.Context()).Clear(ctx) - - validContractsInfo := am.keeper.GetAllProcessableContractInfo(ctx) - // Each iteration is atomic. If an iteration finishes without any error, it will return, - // otherwise it will rollback any state change, filter out contracts that cause the error, - // and proceed to the next iteration. The loop is guaranteed to finish since - // `validContractAddresses` will always decrease in size every iteration. - iterCounter := len(validContractsInfo) - endBlockerStartTime := time.Now() - for len(validContractsInfo) > 0 { - newValidContractsInfo, newOutOfRentContractsInfo, failedContractToReasons, ctx, ok := contract.EndBlockerAtomic(ctx, &am.keeper, validContractsInfo, am.tracingInfo) - if ok { - break - } - telemetry.IncrCounter(float32(len(newOutOfRentContractsInfo)), am.Name(), "total_out_of_rent_contracts") - keptContractAddrs := datastructures.NewSyncSet(utils.Map(newValidContractsInfo, func(c types.ContractInfoV2) string { return c.ContractAddr })) - keptContractAddrs.AddAll(utils.Map(newOutOfRentContractsInfo, func(c types.ContractInfoV2) string { return c.ContractAddr })) - for failedContract, reason := range failedContractToReasons { - ctx.Logger().Info(fmt.Sprintf("Suspending invalid contract %s", failedContract)) - err := am.keeper.SuspendContract(ctx, failedContract, reason) - if err != nil { - ctx.Logger().Error(fmt.Sprintf("failed to suspend invalid contract %s: %s", failedContract, err)) - } - telemetry.IncrCounter(float32(1), am.Name(), "total_suspended_contracts") - } - validContractsInfo = am.keeper.GetAllProcessableContractInfo(ctx) // reload contract info to get updated dependencies due to unregister above - if len(failedContractToReasons) != 0 { - dexutils.GetMemState(ctx.Context()).ClearContractToDependencies(ctx) - } - // technically we don't really need this if `EndBlockerAtomic` guarantees that `validContractsInfo` size will - // always shrink if not `ok`, but just in case, we decided to have an explicit termination criteria here to - // prevent the chain from being stuck. - iterCounter-- - if iterCounter == 0 { - ctx.Logger().Error("All contracts failed in dex EndBlock. Doing nothing.") - break - } - } - telemetry.MeasureSince(endBlockerStartTime, am.Name(), "total_end_blocker_atomic") - - return []abci.ValidatorUpdate{} -} diff --git a/x/dex/module_simulation.go b/x/dex/module_simulation.go deleted file mode 100644 index c7b9f2942..000000000 --- a/x/dex/module_simulation.go +++ /dev/null @@ -1,91 +0,0 @@ -package dex - -import ( - "math/rand" - - "github.com/cosmos/cosmos-sdk/baseapp" - simappparams "github.com/cosmos/cosmos-sdk/simapp/params" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/module" - simtypes "github.com/cosmos/cosmos-sdk/types/simulation" - "github.com/cosmos/cosmos-sdk/x/simulation" - "github.com/sei-protocol/sei-chain/testutil/sample" - dexsimulation "github.com/sei-protocol/sei-chain/x/dex/simulation" - "github.com/sei-protocol/sei-chain/x/dex/types" -) - -// avoid unused import issue -var ( - _ = sample.AccAddress - _ = dexsimulation.FindAccount - _ = simappparams.StakePerAccount - _ = simulation.MsgEntryKind - _ = baseapp.Paramspace -) - -//nolint:deadcode,unused,gosec // Assume this will be used later, and gosec is nolint because there are no hard-coded credentials here. -const ( - opWeightMsgLimitBuy = "op_weight_msg_create_chain" - // TODO: Determine the simulation weight value - defaultWeightMsgLimitBuy int = 100 - - opWeightMsgLimitSell = "op_weight_msg_create_chain" - // TODO: Determine the simulation weight value - defaultWeightMsgLimitSell int = 100 - - opWeightMsgMarketBuy = "op_weight_msg_create_chain" - // TODO: Determine the simulation weight value - defaultWeightMsgMarketBuy int = 100 - - opWeightMsgMarketSell = "op_weight_msg_create_chain" - // TODO: Determine the simulation weight value - defaultWeightMsgMarketSell int = 100 - - opWeightMsgCancelBuy = "op_weight_msg_create_chain" - // TODO: Determine the simulation weight value - defaultWeightMsgCancelBuy int = 100 - - opWeightMsgCancelSell = "op_weight_msg_create_chain" - // TODO: Determine the simulation weight value - defaultWeightMsgCancelSell int = 100 - - opWeightMsgCancelAll = "op_weight_msg_create_chain" - // TODO: Determine the simulation weight value - defaultWeightMsgCancelAll int = 100 - - // this line is used by starport scaffolding # simapp/module/const -) - -// GenerateGenesisState creates a randomized GenState of the module -func (AppModule) GenerateGenesisState(simState *module.SimulationState) { - accs := make([]string, len(simState.Accounts)) - for i, acc := range simState.Accounts { - accs[i] = acc.Address.String() - } - dexGenesis := types.GenesisState{ - // this line is used by starport scaffolding # simapp/module/genesisState - } - simState.GenState[types.ModuleName] = simState.Cdc.MustMarshalJSON(&dexGenesis) -} - -// ProposalContents doesn't return any content functions for governance proposals -func (AppModule) ProposalContents(_ module.SimulationState) []simtypes.WeightedProposalContent { - return nil -} - -// RandomizedParams creates randomized param changes for the simulator -func (am AppModule) RandomizedParams(_ *rand.Rand) []simtypes.ParamChange { - return []simtypes.ParamChange{} -} - -// RegisterStoreDecoder registers a decoder -func (am AppModule) RegisterStoreDecoder(_ sdk.StoreDecoderRegistry) {} - -// WeightedOperations returns the all the gov module operations with their respective weights. -func (am AppModule) WeightedOperations(_ module.SimulationState) []simtypes.WeightedOperation { - operations := make([]simtypes.WeightedOperation, 0) - - // this line is used by starport scaffolding # simapp/module/operation - - return operations -} diff --git a/x/dex/module_test.go b/x/dex/module_test.go deleted file mode 100644 index cea426c10..000000000 --- a/x/dex/module_test.go +++ /dev/null @@ -1,835 +0,0 @@ -package dex_test - -import ( - "context" - "io/ioutil" - "testing" - "time" - - wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" - wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/utils/tracing" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - dexcache "github.com/sei-protocol/sei-chain/x/dex/cache" - "github.com/sei-protocol/sei-chain/x/dex/contract" - "github.com/sei-protocol/sei-chain/x/dex/types" - dexutils "github.com/sei-protocol/sei-chain/x/dex/utils" - minttypes "github.com/sei-protocol/sei-chain/x/mint/types" - "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - "go.opentelemetry.io/otel" - "go.opentelemetry.io/otel/trace" -) - -const ( - GOOD_CONTRACT_INSTANTIATE = `{"whitelist": ["sei1h9yjz89tl0dl6zu65dpxcqnxfhq60wxx8s5kag"], - "use_whitelist":false,"admin":"sei1h9yjz89tl0dl6zu65dpxcqnxfhq60wxx8s5kag", - "limit_order_fee":{"decimal":"0.0001","negative":false}, - "market_order_fee":{"decimal":"0.0001","negative":false}, - "liquidation_order_fee":{"decimal":"0.0001","negative":false}, - "margin_ratio":{"decimal":"0.0625","negative":false}, - "max_leverage":{"decimal":"4","negative":false}, - "default_base":"USDC", - "native_token":"USDC","denoms": ["SEI","ATOM","USDC","SOL","ETH","OSMO","AVAX","BTC"], - "full_denom_mapping": [["usei","SEI","0.000001"],["uatom","ATOM","0.000001"],["uusdc","USDC","0.000001"]], - "funding_payment_lookback":3600,"spot_market_contract":"sei1h9yjz89tl0dl6zu65dpxcqnxfhq60wxx8s5kag", - "supported_collateral_denoms": ["USDC"], - "supported_multicollateral_denoms": ["ATOM"], - "oracle_denom_mapping": [["usei","SEI","1"],["uatom","ATOM","1"],["uusdc","USDC","1"],["ueth","ETH","1"]], - "multicollateral_whitelist": ["sei1h9yjz89tl0dl6zu65dpxcqnxfhq60wxx8s5kag"], - "multicollateral_whitelist_enable": true, - "funding_payment_pairs": [["USDC","ETH"]], - "default_margin_ratios":{ - "initial":"0.3", - "partial":"0.25", - "maintenance":"0.06" - }}` -) - -func TestEndBlockMarketOrder(t *testing.T) { - testApp := keepertest.TestApp() - dexkeeper := testApp.DexKeeper - ctx := testApp.BaseApp.NewContext(false, tmproto.Header{Time: time.Now()}) - ctx = ctx.WithContext(context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(dexkeeper.GetMemStoreKey()))) - pair := types.Pair{PriceDenom: "SEI", AssetDenom: "ATOM"} - - testAccount, _ := sdk.AccAddressFromBech32("sei1yezq49upxhunjjhudql2fnj5dgvcwjj87pn2wx") - amounts := sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(10000000)), sdk.NewCoin("uusdc", sdk.NewInt(10000000))) - bankkeeper := testApp.BankKeeper - bankkeeper.MintCoins(ctx, minttypes.ModuleName, amounts) - bankkeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, testAccount, amounts) - dexAmounts := sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(5000000)), sdk.NewCoin("uusdc", sdk.NewInt(10000000))) - bankkeeper.SendCoinsFromAccountToModule(ctx, testAccount, types.ModuleName, dexAmounts) - wasm, err := ioutil.ReadFile("./testdata/mars.wasm") - if err != nil { - panic(err) - } - wasmKeeper := testApp.WasmKeeper - contractKeeper := wasmkeeper.NewDefaultPermissionKeeper(&wasmKeeper) - var perm *wasmtypes.AccessConfig - codeId, err := contractKeeper.Create(ctx, testAccount, wasm, perm) - if err != nil { - panic(err) - } - contractAddr, _, err := contractKeeper.Instantiate(ctx, codeId, testAccount, testAccount, []byte(GOOD_CONTRACT_INSTANTIATE), "test", - sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(100000)))) - if err != nil { - panic(err) - } - err = dexkeeper.SetContract(ctx, &types.ContractInfoV2{CodeId: 123, ContractAddr: contractAddr.String(), NeedHook: false, NeedOrderMatching: true, RentBalance: 100000000}) - if err != nil { - panic(err) - } - dexkeeper.AddRegisteredPair(ctx, contractAddr.String(), pair) - dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, types.ContractAddress(contractAddr.String()), pair).Add( - &types.Order{ - Id: 1, - Account: testAccount.String(), - ContractAddr: contractAddr.String(), - Price: sdk.MustNewDecFromStr("1"), - Quantity: sdk.MustNewDecFromStr("1"), - PriceDenom: pair.PriceDenom, - AssetDenom: pair.AssetDenom, - OrderType: types.OrderType_LIMIT, - PositionDirection: types.PositionDirection_LONG, - Data: "{\"position_effect\":\"Open\",\"leverage\":\"1\"}", - }, - ) - dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, types.ContractAddress(contractAddr.String()), pair).Add( - &types.Order{ - Id: 2, - Account: testAccount.String(), - ContractAddr: contractAddr.String(), - Price: sdk.MustNewDecFromStr("2"), - Quantity: sdk.MustNewDecFromStr("1"), - PriceDenom: pair.PriceDenom, - AssetDenom: pair.AssetDenom, - OrderType: types.OrderType_LIMIT, - PositionDirection: types.PositionDirection_LONG, - Data: "{\"position_effect\":\"Open\",\"leverage\":\"1\"}", - }, - ) - dexutils.GetMemState(ctx.Context()).GetDepositInfo(ctx, types.ContractAddress(contractAddr.String())).Add( - &types.DepositInfoEntry{ - Creator: testAccount.String(), - Denom: "uusdc", - Amount: sdk.MustNewDecFromStr("2000000"), - }, - ) - dexutils.GetMemState(ctx.Context()).SetDownstreamsToProcess(ctx, contractAddr.String(), dexkeeper.GetContractWithoutGasCharge) - - ctx = ctx.WithBlockHeight(1) - testApp.EndBlocker(ctx, abci.RequestEndBlock{}) - _, found := dexkeeper.GetLongBookByPrice(ctx, contractAddr.String(), sdk.MustNewDecFromStr("1"), pair.PriceDenom, pair.AssetDenom) - // Long book should be populated - require.True(t, found) - - dexutils.GetMemState(ctx.Context()).Clear(ctx) - dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, types.ContractAddress(contractAddr.String()), pair).Add( - &types.Order{ - Id: 3, - Account: testAccount.String(), - ContractAddr: contractAddr.String(), - Price: sdk.MustNewDecFromStr("1"), - Quantity: sdk.MustNewDecFromStr("1"), - PriceDenom: pair.PriceDenom, - AssetDenom: pair.AssetDenom, - OrderType: types.OrderType_MARKET, - PositionDirection: types.PositionDirection_SHORT, - Data: "{\"position_effect\":\"Open\",\"leverage\":\"1\"}", - }, - ) - dexutils.GetMemState(ctx.Context()).SetDownstreamsToProcess(ctx, contractAddr.String(), dexkeeper.GetContractWithoutGasCharge) - - ctx = ctx.WithBlockHeight(2) - testApp.EndBlocker(ctx, abci.RequestEndBlock{}) - - // Long book should be removed since it's executed - // No state change should've been persisted for bad contract - _, found = dexkeeper.GetLongBookByPrice(ctx, contractAddr.String(), sdk.MustNewDecFromStr("2"), pair.PriceDenom, pair.AssetDenom) - // Long book should be populated - require.False(t, found) - _, found = dexkeeper.GetLongBookByPrice(ctx, contractAddr.String(), sdk.MustNewDecFromStr("1"), pair.PriceDenom, pair.AssetDenom) - require.True(t, found) - - matchResults, _ := dexkeeper.GetMatchResultState(ctx, contractAddr.String()) - require.Equal(t, 1, len(matchResults.Orders)) - require.Equal(t, 2, len(matchResults.Settlements)) - - dexutils.GetMemState(ctx.Context()).Clear(ctx) - dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, types.ContractAddress(contractAddr.String()), pair).Add( - &types.Order{ - Id: 4, - Account: testAccount.String(), - ContractAddr: contractAddr.String(), - Price: sdk.MustNewDecFromStr("1000000"), - Quantity: sdk.MustNewDecFromStr("1"), - PriceDenom: pair.PriceDenom, - AssetDenom: pair.AssetDenom, - OrderType: types.OrderType_MARKET, - PositionDirection: types.PositionDirection_LONG, - Data: "{\"position_effect\":\"Open\",\"leverage\":\"1\"}", - }, - ) - dexutils.GetMemState(ctx.Context()).SetDownstreamsToProcess(ctx, contractAddr.String(), dexkeeper.GetContractWithoutGasCharge) - - ctx = ctx.WithBlockHeight(3) - testApp.EndBlocker(ctx, abci.RequestEndBlock{}) - - matchResults, _ = dexkeeper.GetMatchResultState(ctx, contractAddr.String()) - require.Equal(t, 1, len(matchResults.Orders)) - require.Equal(t, 0, len(matchResults.Settlements)) -} - -func TestEndBlockLimitOrder(t *testing.T) { - testApp := keepertest.TestApp() - ctx := testApp.BaseApp.NewContext(false, tmproto.Header{Time: time.Now()}) - ctx = ctx.WithContext(context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(testApp.GetMemKey(types.MemStoreKey)))) - dexkeeper := testApp.DexKeeper - pair := types.Pair{PriceDenom: "SEI", AssetDenom: "ATOM"} - - testAccount, _ := sdk.AccAddressFromBech32("sei1yezq49upxhunjjhudql2fnj5dgvcwjj87pn2wx") - amounts := sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(10000000)), sdk.NewCoin("uusdc", sdk.NewInt(10000000))) - bankkeeper := testApp.BankKeeper - bankkeeper.MintCoins(ctx, minttypes.ModuleName, amounts) - bankkeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, testAccount, amounts) - dexAmounts := sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(5000000)), sdk.NewCoin("uusdc", sdk.NewInt(10000000))) - bankkeeper.SendCoinsFromAccountToModule(ctx, testAccount, types.ModuleName, dexAmounts) - wasm, err := ioutil.ReadFile("./testdata/mars.wasm") - if err != nil { - panic(err) - } - wasmKeeper := testApp.WasmKeeper - contractKeeper := wasmkeeper.NewDefaultPermissionKeeper(&wasmKeeper) - var perm *wasmtypes.AccessConfig - codeId, err := contractKeeper.Create(ctx, testAccount, wasm, perm) - if err != nil { - panic(err) - } - contractAddr, _, err := contractKeeper.Instantiate(ctx, codeId, testAccount, testAccount, []byte(GOOD_CONTRACT_INSTANTIATE), "test", - sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(100000)))) - if err != nil { - panic(err) - } - - dexkeeper.SetContract(ctx, &types.ContractInfoV2{CodeId: 123, ContractAddr: contractAddr.String(), NeedHook: false, NeedOrderMatching: true, RentBalance: 100000000}) - dexkeeper.AddRegisteredPair(ctx, contractAddr.String(), pair) - dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, types.ContractAddress(contractAddr.String()), pair).Add( - &types.Order{ - Id: 1, - Account: testAccount.String(), - ContractAddr: contractAddr.String(), - Price: sdk.MustNewDecFromStr("1"), - Quantity: sdk.MustNewDecFromStr("1"), - PriceDenom: pair.PriceDenom, - AssetDenom: pair.AssetDenom, - OrderType: types.OrderType_LIMIT, - PositionDirection: types.PositionDirection_LONG, - Data: "{\"position_effect\":\"Open\",\"leverage\":\"1\"}", - }, - ) - dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, types.ContractAddress(contractAddr.String()), pair).Add( - &types.Order{ - Id: 2, - Account: testAccount.String(), - ContractAddr: contractAddr.String(), - Price: sdk.MustNewDecFromStr("2"), - Quantity: sdk.MustNewDecFromStr("1"), - PriceDenom: pair.PriceDenom, - AssetDenom: pair.AssetDenom, - OrderType: types.OrderType_LIMIT, - PositionDirection: types.PositionDirection_LONG, - Data: "{\"position_effect\":\"Open\",\"leverage\":\"1\"}", - }, - ) - dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, types.ContractAddress(contractAddr.String()), pair).Add( - &types.Order{ - Id: 3, - Account: testAccount.String(), - ContractAddr: contractAddr.String(), - Price: sdk.MustNewDecFromStr("3"), - Quantity: sdk.MustNewDecFromStr("1"), - PriceDenom: pair.PriceDenom, - AssetDenom: pair.AssetDenom, - OrderType: types.OrderType_LIMIT, - PositionDirection: types.PositionDirection_SHORT, - Data: "{\"position_effect\":\"Open\",\"leverage\":\"1\"}", - }, - ) - dexutils.GetMemState(ctx.Context()).GetDepositInfo(ctx, types.ContractAddress(contractAddr.String())).Add( - &types.DepositInfoEntry{ - Creator: testAccount.String(), - Denom: "uusdc", - Amount: sdk.MustNewDecFromStr("2000000"), - }, - ) - dexutils.GetMemState(ctx.Context()).SetDownstreamsToProcess(ctx, contractAddr.String(), dexkeeper.GetContractWithoutGasCharge) - - ctx = ctx.WithBlockHeight(1) - testApp.EndBlocker(ctx, abci.RequestEndBlock{}) - _, found := dexkeeper.GetLongBookByPrice(ctx, contractAddr.String(), sdk.MustNewDecFromStr("1"), pair.PriceDenom, pair.AssetDenom) - require.True(t, found) - _, found = dexkeeper.GetLongBookByPrice(ctx, contractAddr.String(), sdk.MustNewDecFromStr("2"), pair.PriceDenom, pair.AssetDenom) - require.True(t, found) - _, found = dexkeeper.GetShortBookByPrice(ctx, contractAddr.String(), sdk.MustNewDecFromStr("3"), pair.PriceDenom, pair.AssetDenom) - require.True(t, found) - - dexutils.GetMemState(ctx.Context()).Clear(ctx) - dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, types.ContractAddress(contractAddr.String()), pair).Add( - &types.Order{ - Id: 4, - Account: testAccount.String(), - ContractAddr: contractAddr.String(), - Price: sdk.MustNewDecFromStr("2"), - Quantity: sdk.MustNewDecFromStr("2"), - PriceDenom: pair.PriceDenom, - AssetDenom: pair.AssetDenom, - OrderType: types.OrderType_LIMIT, - PositionDirection: types.PositionDirection_SHORT, - Data: "{\"position_effect\":\"Open\",\"leverage\":\"1\"}", - }, - ) - dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, types.ContractAddress(contractAddr.String()), pair).Add( - &types.Order{ - Id: 5, - Account: testAccount.String(), - ContractAddr: contractAddr.String(), - Price: sdk.MustNewDecFromStr("3"), - Quantity: sdk.MustNewDecFromStr("1"), - PriceDenom: pair.PriceDenom, - AssetDenom: pair.AssetDenom, - OrderType: types.OrderType_LIMIT, - PositionDirection: types.PositionDirection_LONG, - Data: "{\"position_effect\":\"Open\",\"leverage\":\"1\"}", - }, - ) - dexutils.GetMemState(ctx.Context()).SetDownstreamsToProcess(ctx, contractAddr.String(), dexkeeper.GetContractWithoutGasCharge) - - ctx = ctx.WithBlockHeight(2) - testApp.EndBlocker(ctx, abci.RequestEndBlock{}) - - _, found = dexkeeper.GetLongBookByPrice(ctx, contractAddr.String(), sdk.MustNewDecFromStr("2"), pair.PriceDenom, pair.AssetDenom) - require.False(t, found) - _, found = dexkeeper.GetLongBookByPrice(ctx, contractAddr.String(), sdk.MustNewDecFromStr("1"), pair.PriceDenom, pair.AssetDenom) - require.True(t, found) - _, found = dexkeeper.GetShortBookByPrice(ctx, contractAddr.String(), sdk.MustNewDecFromStr("3"), pair.PriceDenom, pair.AssetDenom) - require.True(t, found) - _, found = dexkeeper.GetLongBookByPrice(ctx, contractAddr.String(), sdk.MustNewDecFromStr("3"), pair.PriceDenom, pair.AssetDenom) - require.False(t, found) - - matchResults, _ := dexkeeper.GetMatchResultState(ctx, contractAddr.String()) - require.Equal(t, 2, len(matchResults.Orders)) - require.Equal(t, 4, len(matchResults.Settlements)) - - dexutils.GetMemState(ctx.Context()).Clear(ctx) - dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, types.ContractAddress(contractAddr.String()), pair).Add( - &types.Order{ - Id: 6, - Account: testAccount.String(), - ContractAddr: contractAddr.String(), - Price: sdk.MustNewDecFromStr("1000000"), - Quantity: sdk.MustNewDecFromStr("1"), - PriceDenom: pair.PriceDenom, - AssetDenom: pair.AssetDenom, - OrderType: types.OrderType_LIMIT, - PositionDirection: types.PositionDirection_LONG, - Data: "{\"position_effect\":\"Open\",\"leverage\":\"1\"}", - }, - ) - dexutils.GetMemState(ctx.Context()).SetDownstreamsToProcess(ctx, contractAddr.String(), dexkeeper.GetContractWithoutGasCharge) - - ctx = ctx.WithBlockHeight(3) - testApp.EndBlocker(ctx, abci.RequestEndBlock{}) - - _, found = dexkeeper.GetLongBookByPrice(ctx, contractAddr.String(), sdk.MustNewDecFromStr("1"), pair.PriceDenom, pair.AssetDenom) - require.True(t, found) - _, found = dexkeeper.GetLongBookByPrice(ctx, contractAddr.String(), sdk.MustNewDecFromStr("1000000"), pair.PriceDenom, pair.AssetDenom) - require.False(t, found) - _, found = dexkeeper.GetShortBookByPrice(ctx, contractAddr.String(), sdk.MustNewDecFromStr("3"), pair.PriceDenom, pair.AssetDenom) - require.False(t, found) - - matchResults, _ = dexkeeper.GetMatchResultState(ctx, contractAddr.String()) - require.Equal(t, 1, len(matchResults.Orders)) - require.Equal(t, 2, len(matchResults.Settlements)) -} - -func TestEndBlockRollback(t *testing.T) { - testApp := keepertest.TestApp() - ctx := testApp.BaseApp.NewContext(false, tmproto.Header{}) - ctx = ctx.WithContext(context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(testApp.GetMemKey(types.MemStoreKey)))) - dexkeeper := testApp.DexKeeper - pair := TEST_PAIR() - // register contract and pair - dexkeeper.SetContract(ctx, &types.ContractInfoV2{CodeId: 123, ContractAddr: keepertest.TestContract, NeedHook: false, NeedOrderMatching: true, RentBalance: 100000000}) - dexkeeper.AddRegisteredPair(ctx, keepertest.TestContract, pair) - // place one order to a nonexistent contract - dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, types.ContractAddress(keepertest.TestContract), pair).Add( - &types.Order{ - Id: 1, - Account: keepertest.TestAccount, - ContractAddr: keepertest.TestContract, - Price: sdk.MustNewDecFromStr("1"), - Quantity: sdk.MustNewDecFromStr("1"), - PriceDenom: pair.PriceDenom, - AssetDenom: pair.AssetDenom, - OrderType: types.OrderType_LIMIT, - PositionDirection: types.PositionDirection_LONG, - }, - ) - dexutils.GetMemState(ctx.Context()).SetDownstreamsToProcess(ctx, keepertest.TestContract, dexkeeper.GetContractWithoutGasCharge) - ctx = ctx.WithBlockHeight(1) - testApp.EndBlocker(ctx, abci.RequestEndBlock{}) - // No state change should've been persisted - matchResult, _ := dexkeeper.GetMatchResultState(ctx, keepertest.TestContract) - require.Equal(t, &types.MatchResult{}, matchResult) - // contract should be suspended - contract, err := dexkeeper.GetContract(ctx, keepertest.TestContract) - require.Nil(t, err) - require.True(t, contract.Suspended) -} - -func TestEndBlockPartialRollback(t *testing.T) { - testApp := keepertest.TestApp() - ctx := testApp.BaseApp.NewContext(false, tmproto.Header{Time: time.Now()}) - ctx = ctx.WithContext(context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(testApp.GetMemKey(types.MemStoreKey)))) - // BAD CONTRACT - dexkeeper := testApp.DexKeeper - pair := TEST_PAIR() - // register contract and pair - dexkeeper.SetContract(ctx, &types.ContractInfoV2{CodeId: 123, ContractAddr: keepertest.TestContract, NeedHook: false, NeedOrderMatching: true, RentBalance: 100000000}) - dexkeeper.AddRegisteredPair(ctx, keepertest.TestContract, pair) - // place one order to a nonexistent contract - dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, types.ContractAddress(keepertest.TestContract), pair).Add( - &types.Order{ - Id: 1, - Account: keepertest.TestAccount, - ContractAddr: keepertest.TestContract, - Price: sdk.MustNewDecFromStr("1"), - Quantity: sdk.MustNewDecFromStr("1"), - PriceDenom: pair.PriceDenom, - AssetDenom: pair.AssetDenom, - OrderType: types.OrderType_LIMIT, - PositionDirection: types.PositionDirection_LONG, - }, - ) - dexutils.GetMemState(ctx.Context()).SetDownstreamsToProcess(ctx, keepertest.TestContract, dexkeeper.GetContractWithoutGasCharge) - // GOOD CONTRACT - testAccount, _ := sdk.AccAddressFromBech32("sei1yezq49upxhunjjhudql2fnj5dgvcwjj87pn2wx") - amounts := sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(1000000)), sdk.NewCoin("uusdc", sdk.NewInt(1000000))) - bankkeeper := testApp.BankKeeper - bankkeeper.MintCoins(ctx, minttypes.ModuleName, amounts) - bankkeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, testAccount, amounts) - dexAmounts := sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(500000)), sdk.NewCoin("uusdc", sdk.NewInt(1000000))) - bankkeeper.SendCoinsFromAccountToModule(ctx, testAccount, types.ModuleName, dexAmounts) - wasm, err := ioutil.ReadFile("./testdata/mars.wasm") - if err != nil { - panic(err) - } - wasmKeeper := testApp.WasmKeeper - contractKeeper := wasmkeeper.NewDefaultPermissionKeeper(&wasmKeeper) - var perm *wasmtypes.AccessConfig - codeId, err := contractKeeper.Create(ctx, testAccount, wasm, perm) - if err != nil { - panic(err) - } - contractAddr, _, err := contractKeeper.Instantiate(ctx, codeId, testAccount, testAccount, []byte(GOOD_CONTRACT_INSTANTIATE), "test", - sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(100000)))) - if err != nil { - panic(err) - } - dexkeeper.SetContract(ctx, &types.ContractInfoV2{CodeId: 123, ContractAddr: contractAddr.String(), NeedHook: false, NeedOrderMatching: true, RentBalance: 100000000}) - dexkeeper.AddRegisteredPair(ctx, contractAddr.String(), pair) - // place one order to the good contract - dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, types.ContractAddress(contractAddr.String()), pair).Add( - &types.Order{ - Id: 2, - Account: testAccount.String(), - ContractAddr: contractAddr.String(), - Price: sdk.MustNewDecFromStr("0.0001"), - Quantity: sdk.MustNewDecFromStr("0.0001"), - PriceDenom: pair.PriceDenom, - AssetDenom: pair.AssetDenom, - OrderType: types.OrderType_LIMIT, - PositionDirection: types.PositionDirection_LONG, - Data: "{\"position_effect\":\"Open\",\"leverage\":\"1\"}", - }, - ) - dexutils.GetMemState(ctx.Context()).GetDepositInfo(ctx, types.ContractAddress(contractAddr.String())).Add( - &types.DepositInfoEntry{ - Creator: testAccount.String(), - Denom: "uusdc", - Amount: sdk.MustNewDecFromStr("10000"), - }, - ) - dexutils.GetMemState(ctx.Context()).SetDownstreamsToProcess(ctx, contractAddr.String(), dexkeeper.GetContractWithoutGasCharge) - - ctx = ctx.WithBlockHeight(1) - testApp.EndBlocker(ctx, abci.RequestEndBlock{}) - // No state change should've been persisted for bad contract - matchResult, _ := dexkeeper.GetMatchResultState(ctx, keepertest.TestContract) - require.Equal(t, &types.MatchResult{}, matchResult) - // bad contract should be suspended - contract, err := dexkeeper.GetContract(ctx, keepertest.TestContract) - require.Nil(t, err) - require.True(t, contract.Suspended) - // state change should've been persisted for good contract - matchResult, _ = dexkeeper.GetMatchResultState(ctx, contractAddr.String()) - require.Equal(t, 1, len(matchResult.Orders)) - _, found := dexkeeper.GetLongBookByPrice(ctx, contractAddr.String(), sdk.MustNewDecFromStr("0.0001"), pair.PriceDenom, pair.AssetDenom) - require.True(t, found) -} - -func TestBeginBlock(t *testing.T) { - testApp := keepertest.TestApp() - ctx := testApp.BaseApp.NewContext(false, tmproto.Header{Time: time.Now()}) - ctx = ctx.WithContext(context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(testApp.GetMemKey(types.MemStoreKey)))) - dexkeeper := testApp.DexKeeper - - testAccount, _ := sdk.AccAddressFromBech32("sei1yezq49upxhunjjhudql2fnj5dgvcwjj87pn2wx") - amounts := sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(10000000))) - bankkeeper := testApp.BankKeeper - bankkeeper.MintCoins(ctx, minttypes.ModuleName, amounts) - bankkeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, testAccount, amounts) - wasm, err := ioutil.ReadFile("./testdata/mars.wasm") - if err != nil { - panic(err) - } - wasmKeeper := testApp.WasmKeeper - contractKeeper := wasmkeeper.NewDefaultPermissionKeeper(&wasmKeeper) - var perm *wasmtypes.AccessConfig - codeId, err := contractKeeper.Create(ctx, testAccount, wasm, perm) - if err != nil { - panic(err) - } - contractAddr, _, err := contractKeeper.Instantiate(ctx, codeId, testAccount, testAccount, []byte(GOOD_CONTRACT_INSTANTIATE), "test", - sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(100000)))) - if err != nil { - panic(err) - } - dexkeeper.SetContract(ctx, &types.ContractInfoV2{CodeId: 123, ContractAddr: contractAddr.String(), NeedHook: false, NeedOrderMatching: true, RentBalance: 100000000}) - - // right now just make sure it doesn't crash since it doesn't register any state to be checked against - testApp.BeginBlocker(ctx, abci.RequestBeginBlock{}) -} - -// Note that once the bug that causes EndBlock to panic is fixed, this test will need to be -// updated to trigger the next bug that causes panics, if any. -func TestEndBlockPanicHandling(t *testing.T) { - testApp := keepertest.TestApp() - ctx := testApp.BaseApp.NewContext(false, tmproto.Header{Time: time.Now()}) - ctx = ctx.WithContext(context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(testApp.GetMemKey(types.MemStoreKey)))) - dexkeeper := testApp.DexKeeper - pair := types.Pair{PriceDenom: "SEI", AssetDenom: "ATOM"} - - testAccount, _ := sdk.AccAddressFromBech32("sei1yezq49upxhunjjhudql2fnj5dgvcwjj87pn2wx") - amounts := sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(10000000))) - bankkeeper := testApp.BankKeeper - bankkeeper.MintCoins(ctx, minttypes.ModuleName, amounts) - bankkeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, testAccount, amounts) - dexAmounts := sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(5000000))) - bankkeeper.SendCoinsFromAccountToModule(ctx, testAccount, types.ModuleName, dexAmounts) - wasm, err := ioutil.ReadFile("./testdata/mars.wasm") - if err != nil { - panic(err) - } - wasmKeeper := testApp.WasmKeeper - contractKeeper := wasmkeeper.NewDefaultPermissionKeeper(&wasmKeeper) - var perm *wasmtypes.AccessConfig - codeId, err := contractKeeper.Create(ctx, testAccount, wasm, perm) - if err != nil { - panic(err) - } - contractAddr, _, err := contractKeeper.Instantiate(ctx, codeId, testAccount, testAccount, []byte(GOOD_CONTRACT_INSTANTIATE), "test", - sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(100000)))) - if err != nil { - panic(err) - } - dexkeeper.SetContract(ctx, &types.ContractInfoV2{CodeId: 123, ContractAddr: contractAddr.String(), NeedHook: false, NeedOrderMatching: true, RentBalance: 100000000}) - dexkeeper.AddRegisteredPair(ctx, contractAddr.String(), pair) - dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, types.ContractAddress(contractAddr.String()), pair).Add( - &types.Order{ - Id: 1, - Account: testAccount.String(), - ContractAddr: contractAddr.String(), - Price: sdk.Dec{}, - Quantity: sdk.Dec{}, - PriceDenom: pair.PriceDenom, - AssetDenom: pair.AssetDenom, - OrderType: types.OrderType_LIMIT, - PositionDirection: types.PositionDirection_LONG, - Data: "{\"position_effect\":\"Open\",\"leverage\":\"1\"}", - }, - ) - dexutils.GetMemState(ctx.Context()).GetDepositInfo(ctx, types.ContractAddress(contractAddr.String())).Add( - &types.DepositInfoEntry{ - Creator: testAccount.String(), - Denom: "usei", - Amount: sdk.MustNewDecFromStr("2000000"), - }, - ) - - require.NotPanics(t, func() { testApp.EndBlocker(ctx, abci.RequestEndBlock{}) }) - _, found := dexkeeper.GetLongBookByPrice(ctx, contractAddr.String(), sdk.MustNewDecFromStr("1"), pair.PriceDenom, pair.AssetDenom) - require.False(t, found) -} - -func TestEndBlockRollbackWithRentCharge(t *testing.T) { - testApp := keepertest.TestApp() - ctx := testApp.BaseApp.NewContext(false, tmproto.Header{Time: time.Now()}) - ctx = ctx.WithContext(context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(testApp.GetMemKey(types.MemStoreKey)))) - dexkeeper := testApp.DexKeeper - pair := TEST_PAIR() - // GOOD CONTRACT - testAccount, _ := sdk.AccAddressFromBech32("sei1yezq49upxhunjjhudql2fnj5dgvcwjj87pn2wx") - amounts := sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(1000000)), sdk.NewCoin("uusdc", sdk.NewInt(1000000))) - bankkeeper := testApp.BankKeeper - bankkeeper.MintCoins(ctx, minttypes.ModuleName, amounts) - bankkeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, testAccount, amounts) - dexAmounts := sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(500000)), sdk.NewCoin("uusdc", sdk.NewInt(1000000))) - bankkeeper.SendCoinsFromAccountToModule(ctx, testAccount, types.ModuleName, dexAmounts) - wasm, err := ioutil.ReadFile("./testdata/mars.wasm") - if err != nil { - panic(err) - } - wasmKeeper := testApp.WasmKeeper - contractKeeper := wasmkeeper.NewDefaultPermissionKeeper(&wasmKeeper) - var perm *wasmtypes.AccessConfig - codeId, err := contractKeeper.Create(ctx, testAccount, wasm, perm) - if err != nil { - panic(err) - } - contractAddr, _, err := contractKeeper.Instantiate(ctx, codeId, testAccount, testAccount, []byte(GOOD_CONTRACT_INSTANTIATE), "test", - sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(100000)))) - if err != nil { - panic(err) - } - dexkeeper.SetContract(ctx, &types.ContractInfoV2{CodeId: 123, ContractAddr: contractAddr.String(), NeedHook: false, NeedOrderMatching: true, RentBalance: 1}) - dexkeeper.AddRegisteredPair(ctx, contractAddr.String(), pair) - // place one order to a nonexistent contract - dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, types.ContractAddress(contractAddr.String()), pair).Add( - &types.Order{ - Id: 2, - Account: testAccount.String(), - ContractAddr: contractAddr.String(), - Price: sdk.MustNewDecFromStr("0.0001"), - Quantity: sdk.MustNewDecFromStr("0.0001"), - PriceDenom: pair.PriceDenom, - AssetDenom: pair.AssetDenom, - OrderType: types.OrderType_LIMIT, - PositionDirection: types.PositionDirection_LONG, - Data: "{\"position_effect\":\"Open\",\"leverage\":\"1\"}", - }, - ) - dexutils.GetMemState(ctx.Context()).GetDepositInfo(ctx, types.ContractAddress(contractAddr.String())).Add( - &types.DepositInfoEntry{ - Creator: testAccount.String(), - Denom: "uusdc", - Amount: sdk.MustNewDecFromStr("10000"), - }, - ) - dexutils.GetMemState(ctx.Context()).SetDownstreamsToProcess(ctx, contractAddr.String(), dexkeeper.GetContractWithoutGasCharge) - // overwrite params for testing - params := dexkeeper.GetParams(ctx) - params.MinProcessableRent = 0 - dexkeeper.SetParams(ctx, params) - - ctx = ctx.WithBlockHeight(1) - creatorBalanceBefore := bankkeeper.GetBalance(ctx, testAccount, "usei") - testApp.EndBlocker(ctx, abci.RequestEndBlock{}) - // no state change should've been persisted for good contract because it should've run out of gas - matchResult, _ := dexkeeper.GetMatchResultState(ctx, contractAddr.String()) - require.Equal(t, 0, len(matchResult.Orders)) - // rent should still be charged even if the contract failed - c, err := dexkeeper.GetContract(ctx, contractAddr.String()) - require.Nil(t, err) - require.True(t, c.Suspended) // bad contract is suspended not because of out-of-rent but because of execution error - require.Equal(t, uint64(0), c.RentBalance) // rent balance should be drained - require.Equal(t, int64(1), dexkeeper.BankKeeper.GetBalance( - ctx, - dexkeeper.AccountKeeper.GetModuleAddress(authtypes.FeeCollectorName), - "usei", - ).Amount.Int64()) // bad contract rent should be sent to fee collector - creatorBalanceAfter := bankkeeper.GetBalance(ctx, testAccount, "usei") - require.Equal(t, creatorBalanceBefore, creatorBalanceAfter) -} - -func TestEndBlockContractWithoutPair(t *testing.T) { - testApp := keepertest.TestApp() - ctx := testApp.BaseApp.NewContext(false, tmproto.Header{Time: time.Now()}) - ctx = ctx.WithContext(context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(testApp.GetMemKey(types.MemStoreKey)))) - dexkeeper := testApp.DexKeeper - - testAccount, _ := sdk.AccAddressFromBech32("sei1yezq49upxhunjjhudql2fnj5dgvcwjj87pn2wx") - amounts := sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(10000000)), sdk.NewCoin("uusdc", sdk.NewInt(10000000))) - bankkeeper := testApp.BankKeeper - bankkeeper.MintCoins(ctx, minttypes.ModuleName, amounts) - bankkeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, testAccount, amounts) - dexAmounts := sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(5000000)), sdk.NewCoin("uusdc", sdk.NewInt(10000000))) - bankkeeper.SendCoinsFromAccountToModule(ctx, testAccount, types.ModuleName, dexAmounts) - wasm, err := ioutil.ReadFile("./testdata/mars.wasm") - if err != nil { - panic(err) - } - wasmKeeper := testApp.WasmKeeper - contractKeeper := wasmkeeper.NewDefaultPermissionKeeper(&wasmKeeper) - var perm *wasmtypes.AccessConfig - codeId, err := contractKeeper.Create(ctx, testAccount, wasm, perm) - if err != nil { - panic(err) - } - contractAddr, _, err := contractKeeper.Instantiate(ctx, codeId, testAccount, testAccount, []byte(GOOD_CONTRACT_INSTANTIATE), "test", - sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(100000)))) - if err != nil { - panic(err) - } - - // no pair registered - contractInfo := types.ContractInfoV2{CodeId: 123, ContractAddr: contractAddr.String(), NeedHook: false, NeedOrderMatching: true, RentBalance: 100000000} - dexkeeper.SetContract(ctx, &contractInfo) - - tp := trace.NewNoopTracerProvider() - otel.SetTracerProvider(trace.NewNoopTracerProvider()) - tr := tp.Tracer("component-main") - ti := tracing.Info{ - Tracer: &tr, - } - _, _, _, _, success := contract.EndBlockerAtomic(ctx, &testApp.DexKeeper, []types.ContractInfoV2{contractInfo}, &ti) - require.True(t, success) - - contractInfo, err = dexkeeper.GetContract(ctx, contractInfo.ContractAddr) - require.Nil(t, err) - require.False(t, contractInfo.Suspended) -} - -func TestOrderCountUpdate(t *testing.T) { - testApp := keepertest.TestApp() - ctx := testApp.BaseApp.NewContext(false, tmproto.Header{Time: time.Now()}) - ctx = ctx.WithContext(context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(testApp.GetMemKey(types.MemStoreKey)))) - dexkeeper := testApp.DexKeeper - pair := types.Pair{PriceDenom: "SEI", AssetDenom: "ATOM"} - - testAccount, _ := sdk.AccAddressFromBech32("sei1yezq49upxhunjjhudql2fnj5dgvcwjj87pn2wx") - amounts := sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(10000000)), sdk.NewCoin("uusdc", sdk.NewInt(10000000))) - bankkeeper := testApp.BankKeeper - bankkeeper.MintCoins(ctx, minttypes.ModuleName, amounts) - bankkeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, testAccount, amounts) - dexAmounts := sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(5000000)), sdk.NewCoin("uusdc", sdk.NewInt(10000000))) - bankkeeper.SendCoinsFromAccountToModule(ctx, testAccount, types.ModuleName, dexAmounts) - wasm, err := ioutil.ReadFile("./testdata/mars.wasm") - if err != nil { - panic(err) - } - wasmKeeper := testApp.WasmKeeper - contractKeeper := wasmkeeper.NewDefaultPermissionKeeper(&wasmKeeper) - var perm *wasmtypes.AccessConfig - codeId, err := contractKeeper.Create(ctx, testAccount, wasm, perm) - if err != nil { - panic(err) - } - contractAddr, _, err := contractKeeper.Instantiate(ctx, codeId, testAccount, testAccount, []byte(GOOD_CONTRACT_INSTANTIATE), "test", - sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(100000)))) - if err != nil { - panic(err) - } - - dexkeeper.SetContract(ctx, &types.ContractInfoV2{CodeId: 123, ContractAddr: contractAddr.String(), NeedHook: false, NeedOrderMatching: true, RentBalance: 100000000}) - dexkeeper.AddRegisteredPair(ctx, contractAddr.String(), pair) - dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, types.ContractAddress(contractAddr.String()), pair).Add( - &types.Order{ - Id: 1, - Account: testAccount.String(), - ContractAddr: contractAddr.String(), - Price: sdk.MustNewDecFromStr("1"), - Quantity: sdk.MustNewDecFromStr("1"), - PriceDenom: pair.PriceDenom, - AssetDenom: pair.AssetDenom, - OrderType: types.OrderType_LIMIT, - PositionDirection: types.PositionDirection_LONG, - Data: "{\"position_effect\":\"Open\",\"leverage\":\"1\"}", - }, - ) - dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, types.ContractAddress(contractAddr.String()), pair).Add( - &types.Order{ - Id: 2, - Account: testAccount.String(), - ContractAddr: contractAddr.String(), - Price: sdk.MustNewDecFromStr("2"), - Quantity: sdk.MustNewDecFromStr("1"), - PriceDenom: pair.PriceDenom, - AssetDenom: pair.AssetDenom, - OrderType: types.OrderType_LIMIT, - PositionDirection: types.PositionDirection_LONG, - Data: "{\"position_effect\":\"Open\",\"leverage\":\"1\"}", - }, - ) - dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, types.ContractAddress(contractAddr.String()), pair).Add( - &types.Order{ - Id: 3, - Account: testAccount.String(), - ContractAddr: contractAddr.String(), - Price: sdk.MustNewDecFromStr("3"), - Quantity: sdk.MustNewDecFromStr("1"), - PriceDenom: pair.PriceDenom, - AssetDenom: pair.AssetDenom, - OrderType: types.OrderType_LIMIT, - PositionDirection: types.PositionDirection_SHORT, - Data: "{\"position_effect\":\"Open\",\"leverage\":\"1\"}", - }, - ) - dexutils.GetMemState(ctx.Context()).GetDepositInfo(ctx, types.ContractAddress(contractAddr.String())).Add( - &types.DepositInfoEntry{ - Creator: testAccount.String(), - Denom: "uusdc", - Amount: sdk.MustNewDecFromStr("2000000"), - }, - ) - dexutils.GetMemState(ctx.Context()).SetDownstreamsToProcess(ctx, contractAddr.String(), dexkeeper.GetContractWithoutGasCharge) - - ctx = ctx.WithBlockHeight(1) - testApp.EndBlocker(ctx, abci.RequestEndBlock{}) - require.Equal(t, uint64(1), dexkeeper.GetOrderCountState(ctx, contractAddr.String(), pair.PriceDenom, pair.AssetDenom, types.PositionDirection_LONG, sdk.NewDec(1))) - require.Equal(t, uint64(0), dexkeeper.GetOrderCountState(ctx, contractAddr.String(), pair.PriceDenom, pair.AssetDenom, types.PositionDirection_SHORT, sdk.NewDec(1))) - require.Equal(t, uint64(1), dexkeeper.GetOrderCountState(ctx, contractAddr.String(), pair.PriceDenom, pair.AssetDenom, types.PositionDirection_LONG, sdk.NewDec(2))) - require.Equal(t, uint64(0), dexkeeper.GetOrderCountState(ctx, contractAddr.String(), pair.PriceDenom, pair.AssetDenom, types.PositionDirection_SHORT, sdk.NewDec(2))) - require.Equal(t, uint64(0), dexkeeper.GetOrderCountState(ctx, contractAddr.String(), pair.PriceDenom, pair.AssetDenom, types.PositionDirection_LONG, sdk.NewDec(3))) - require.Equal(t, uint64(1), dexkeeper.GetOrderCountState(ctx, contractAddr.String(), pair.PriceDenom, pair.AssetDenom, types.PositionDirection_SHORT, sdk.NewDec(3))) - - dexutils.GetMemState(ctx.Context()).Clear(ctx) - dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, types.ContractAddress(contractAddr.String()), pair).Add( - &types.Order{ - Id: 4, - Account: testAccount.String(), - ContractAddr: contractAddr.String(), - Price: sdk.MustNewDecFromStr("1"), - Quantity: sdk.MustNewDecFromStr("1"), - PriceDenom: pair.PriceDenom, - AssetDenom: pair.AssetDenom, - OrderType: types.OrderType_LIMIT, - PositionDirection: types.PositionDirection_LONG, - Data: "{\"position_effect\":\"Open\",\"leverage\":\"1\"}", - }, - ) - dexutils.GetMemState(ctx.Context()).GetBlockCancels(ctx, types.ContractAddress(contractAddr.String()), pair).Add( - &types.Cancellation{ - Id: 2, - Creator: testAccount.String(), - ContractAddr: contractAddr.String(), - Price: sdk.MustNewDecFromStr("2"), - PriceDenom: pair.PriceDenom, - AssetDenom: pair.AssetDenom, - PositionDirection: types.PositionDirection_LONG, - }, - ) - dexutils.GetMemState(ctx.Context()).SetDownstreamsToProcess(ctx, contractAddr.String(), dexkeeper.GetContractWithoutGasCharge) - ctx = ctx.WithBlockHeight(2) - testApp.EndBlocker(ctx, abci.RequestEndBlock{}) - require.Equal(t, uint64(2), dexkeeper.GetOrderCountState(ctx, contractAddr.String(), pair.PriceDenom, pair.AssetDenom, types.PositionDirection_LONG, sdk.NewDec(1))) - require.Equal(t, uint64(0), dexkeeper.GetOrderCountState(ctx, contractAddr.String(), pair.PriceDenom, pair.AssetDenom, types.PositionDirection_SHORT, sdk.NewDec(1))) - require.Equal(t, uint64(0), dexkeeper.GetOrderCountState(ctx, contractAddr.String(), pair.PriceDenom, pair.AssetDenom, types.PositionDirection_LONG, sdk.NewDec(2))) - require.Equal(t, uint64(0), dexkeeper.GetOrderCountState(ctx, contractAddr.String(), pair.PriceDenom, pair.AssetDenom, types.PositionDirection_SHORT, sdk.NewDec(2))) - require.Equal(t, uint64(0), dexkeeper.GetOrderCountState(ctx, contractAddr.String(), pair.PriceDenom, pair.AssetDenom, types.PositionDirection_LONG, sdk.NewDec(3))) - require.Equal(t, uint64(1), dexkeeper.GetOrderCountState(ctx, contractAddr.String(), pair.PriceDenom, pair.AssetDenom, types.PositionDirection_SHORT, sdk.NewDec(3))) -} diff --git a/x/dex/simulation/simap.go b/x/dex/simulation/simap.go deleted file mode 100644 index 92c437c0d..000000000 --- a/x/dex/simulation/simap.go +++ /dev/null @@ -1,15 +0,0 @@ -package simulation - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - simtypes "github.com/cosmos/cosmos-sdk/types/simulation" -) - -// FindAccount find a specific address from an account list -func FindAccount(accs []simtypes.Account, address string) (simtypes.Account, bool) { - creator, err := sdk.AccAddressFromBech32(address) - if err != nil { - panic(err) - } - return simtypes.FindAccount(accs, creator) -} diff --git a/x/dex/spec/README.md b/x/dex/spec/README.md deleted file mode 100644 index 36f46e3bd..000000000 --- a/x/dex/spec/README.md +++ /dev/null @@ -1,56 +0,0 @@ -## Abstract -`dex` module is responsible for matching orders for registered contracts. - -## Concepts -### Frequent Batch Auction -The traditional implementation of exchange logic would look something like the following: -1. User A sends an order placement transaction -2. User B sends another order placement transaction -3. User A's transaction is processed by matching it against the order book state and settle accordingly -4. User B's transaction is processed similarly - -Sei's `dex` module takes a different approach: -1. User A sends an order placement transaction -2. User B sends another order placement transaction -3. User A's transaction is processed by simply adding the order to an in-memory queue, without matching -4. User B's transaction is processed similarly -5. At the end of the block that contains both transactions, the in-memory queue as a whole will be matched against the order book state - -Step 5 is where the majority of `dex`'s logic takes place. Specifically it consists of the follow stages for each market: -1. Cancel orders for transactions in the current block -2. Add new limit orders to the order book -3. Match market orders in the current block against the order book -4. Market limit orders in the current block against the order book - -### Contract Registration -Since `dex` only provides order matching logic, product logic specific to individual protocols still needs to be defined in CosmWasm contracts. As such, `dex` offers a way to inform the protocol contracts about order placement and matching results. `dex` achieves this by requiring contracts that want to leverage `dex`'s order matching logic to explicitly register via a special transaction type `MsgRegisterContract`. - -## State (KV Store) -The following prefixes are persisted in disk: -- "LongBook-value-": order book state on the long side where each entry represents a price level and can contain multiple orders at that same price. -- "ShortBook-value-": similar to the above but on the short side. -- "x-wasm-contract": contract registration information. -- "MatchResult-": match results of the most recent block. - -The following prefixes are only used intrablock and are cleared before committing the block, since they serve no purpose beyond the scope of its enclosing block and flushing them to disk would be computationally expensive: -- "MemOrder-": orders added by transactions in the current block and will be matched against the order book states at the end of the block. -- "MemCancel-": cancellations added by transactions in the current block and will update the order book states at the end of the block. - -## Hooks -A registered contract can define the following `sudo` hooks that will be called by the `dex` module at appropriate times: -- BulkOrderPlacements: informs the contract about order placements -- BulkOrderCancellations: informs the contract about order cancellations -- Settlement: informs the contract about matched orders and the settlement prices - -There are two more utility hooks that a contract can define for housekeeping purposes (e.g. recalculate TWAPs): -- NewBlock -- FinalizeBlock (note that this is distinct from ABCI++'s FinalizeBlock) - -## Transactions -- MsgPlaceOrders - place one or more orders against a registered contract -- MsgCancelOrders - cancel one or more orders against a registered contract -- MsgRegisterContract - register or reregister a CosmWasm contract with `dex` - - -## Spam Prevention -Conventionally, spamming to a blockchain is mainly mitigated through charging gas based on the resource a transaction consumes. With `dex`'s unique design though, the bulk of resource comsumption happens at the end of a block, which cannot be quantified precisely beforehand. Thus the `dex` module charges transaction messages of type MsgPlaceOrders and MsgCancelOrders based on a flat rate per order/cancel. This amount is guaranteed to well cover any `dex`-level computation, and any exceeded usage must have come from registered contract's logic being expensive and will be charged against the contract, which is required to post a rent sum upon registration. \ No newline at end of file diff --git a/x/dex/testdata/clearing_house.wasm b/x/dex/testdata/clearing_house.wasm deleted file mode 100644 index 358f884871f18c96d332d2a9ee1c3ccd333a57e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 833624 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
  • RaDe^~oBf~4&lKW1hHHFxa(4g166|5VR5eqyCKzm4Rw@gRC+R$3*EpONF|&7Z`| zqXvSdep7xJJy1d``4_`WS%UPXYUSO(&r2?cMncx_VX^xCZ|eOt@6nf4ea&H2|Gj#z z`^%8k`R76h@MT@#!zyq(1sHDCf{~2?Wi-S^<^P(=WsK;y&7;OwEo4d7v0U=ZR^Pj@ z4%o0Baeo;TuPT()ww|kfDTEWYhx_S-Ww5hPSVk)KM6hGZoT!ZN%*t+(sUwrPg@S`h z2{kvBDd}uc?l09n0hD=x${;mOi4ujbJ$N6#l}k~n7gHN2Z(M%*3pNi%cKOf7g?Z<+ z*N9BC?I+Ec_9N?OI7{1&)iWbBT`W^bP^3F>2Fm)NBAp`a*mf=uI64miH7E~zW`3?M z*Nkt`nKpr4WQ)Q^y`M{x)Wh&5*ab{c8-Z=?(y7@6-PFl{=xc+YKmI)U*+`F~)2|YK zh_`IwN8f+#-eVJb6n@-owH!YmZ`BLYOd{22mF5VPw+hRb#r~TC=76^;SAJ&o2ZjRkMf?wRuEqPy6_%b z#;j)xw9G$a`%3|UPfr3s1*1!0gw#p^)Exjo=s*KHx(9NC$U-HW@gy-c-mTT<(Fw~S zVoq2F5p%*a@a2ih$V25TIOa%7LIfpsU@JW*s6_q;Cn$P#g8GuFUC(x6BJjrUwL|6F z>L){>m;|mCUJ?_>e5qH8l|*7oo%S9`@ZLa67&$B)9V}661FUQe7D#olDmtgA)d_Si z4mtdO*tu2FIdW)B=O@vy=p6nzx?Nl8*!qU1MMhsS7VQQ3|`#JVI0X5mbhCUL|p2L}F;1Mqtfq^+md?JSNI~mN_`31Gvub^;oaD3)xhxzG1da_M3>0k(X_-ld;mw@D9 zke9mV>4alr=R08dU236oDq~aKr!fmBGqwsW8{2;uWO5%COZgkD$NZGr_yBD?fSvzgFq{f@RQK4}!Ive<9QIt|X<4VSj?C?3UM}ne;%h{*eCf$7skVeO zP9RA^6(NZk1-~qnXGtkzk&%l49N{MdgRJ__i?qtfyxrnB4UCR%z+7NOdr#SVp@6`= zZpqi{z%Z-Z=-Ui+-Nh`~42_Q)x>ainU4Z++E5!mOs_3o+ZUHv#y+3>T-u2C92( zHgMs!f~Y>3u~lH%EIlm@PqeTChRr*7A|WBaKh^ zSz}I^j#9RAAyqFNsJYF*lPo8ig-(vzfWcmcq9ir^c97!JlH%=RS|e2v_5tt<*ho!^ zw=Gvv91J7HW0&HpZtWJwX~3lTWCMnNZWSoIlH&BsM_rNP4xD#faQnb7??b$FO^RC? z@0}4cXZaZRAk0<7g!%Gjf-txDw%!~tFp$s%Q*_Q#mzz?L1pk&ajD?C5IK!p;@;&Ex z5W3Jf3&K%$UNmnf6WaK-t{%?f9qj5Pz**KDw{>*!^f~5jtBGga9DVT3Nc-xzCn{EI zgi4`j^hZr>j9pWp7p6$1bb=z~vUhTQC85hDq(;@8PM@$T(St6Ex#kVdi%Fp=HbJ*J zoF4J$;qxK|_1m5hrz`H0V>jVTz^+G%LG0|%Gxe{dgMw9CCt7y|!jYXocEMJZcDHR2 zq$2obF^a}ev-#{$kJyIj7vWTE0N;tv9?%r z+hGUwDF3CLuuP-LQ~40(%#>_KuLQl^^L4d_>QGEO|JK$#4Vm)<_o+K_v|noV*o|b{ zZ*o1(a@LMop6p0`$=@6bOMdGhI69<@#9}@p1OZzd~Wjo$}mvloaWjZ zZ4!=n=nk^dj?aXu#qv48bzpPQ7n+aVJ`;58m*C`>FS+bVK-y`(IZcpCR+tG#p0)`s zl8y|1T3&r*=q$f`MziczXl0-S-W1504D~9V)+rFo`A2dYLk}B=#0{V z&VV!&+FTK#eTR%=F^Ct$ahSv0TN=;dkPVRBZ*Rm1M*W-@8%d zfo}d`sx>wzC9&l(U+UE=vCEV(pvw9QA}+#s2}U7dRDfnu4?E4g|G~MZYi$Cp8t3b^ zPW#lat0_c}LU&}h3-MKH?E$Rh8#Q|}wz8EmljwLY{&&APh2LzC(1Rlr zuy+g+RD@+A!P5Kzmj`&KG!5>aKR#QT0ophWR$%VH^ z31GClu__cgx80K5&;Qj8HoC9nf~ z>0q~SDX(LI9u>uP)G`S=ij&}`-cEV9g%=N}sHo2#X^~?eP}O%pM{DxmN|PP_pRshc z+7TfU;zXH346k>6yJ~Bm;3#E~i$$Pg3Rcf00+;b<`wXGaUpogVPKEga&$iz#BdI_% zQ^FR&bv8K%fBN?@A=ncvKh5t;tpaE`2WnE?BT8P(b$v()os!FctEId9)bwfqRP2-i zafLo%2cVZJAcZNkeLVj9CZGTn1y!4b_PpHzHQ0F1%K)f=;gnGW&@0G!zyQ6B)Q14{ zwN`FU?VTiP_T{-iivFw#mCkh zL9O4y2>gq%)d0^99ek+y!J61bg$7MDgLzKf|40_I=h|3pPhus7S4Z6>b0Ehbt%UgezML?0i3jjDu!5^sDL=xlR z!XDiVaJCMOSp~s*5dj@`s-N_gbYZ9Z+oi6Lu*!@^iJFnTgSqUkOK`+BwuV zFwQKcj)H3~H5jaFg%-AXo!?`i&yUhwsFX!QNcr>x z4eG3^woevx%TX>XVZjCLf*C806-T5{K#hw=X?3Bv;bJu9xLhxA_#QI-t~cO>+Zw9~ z3_HDV!?916LzFpGmkV}X&lRL|USCc@%I@v~f%fUST&>#I=W>zm#v(_a@Hr_GRSPEW@%R_>TPzGALEd1bgL6%?u4j`#oYG(v z2~$5)P0P*t8F!49j`cG@XFwjFwI)!!0HbOQM|~B9$@We-6bGB=U4gQAH4;l;3a?X) zZOR=Q3`bf~#-U2_PUEQVBhZM6|F!!1s<*WeB$hDgf2}D!FIWUxpfdV^*e383UfK zMuix`CEW-sp+NM&ZiOVs0%n8BA`M?^bfJM!#_x}YQH|_?u0BGeIVp8XIVqv#L`qYp zTS%HKQ;N@Yq3%CZrfCD{cV1!JSuyVXgk zvw;pn3pE|iI~{UYxqA2eD~uzjPK@jZJ7&9>9iu~7+K@f#L^CgS%cpL9$+%5gm`_{S zTxY>BV}L#!{4Rj&rmYq}Dkb~N%cqx79!vBsKaTQ!HpPx$cKik^+82(*kV~G(4z&Jt zJ7+OtNv?XeDO!`iCB>k(`LapDwQ$&Oq3V~!_fhg1j(zbhUMH5!r!;!s5u4#i75ZJ3?%-K;dK(<2>7F}*h~ig0qIBf8+5 zN1cLJ?(<{UtHJnaPNKuOqEixH4sYN#Ar9RT$kKEO_V_7$VEpw{j}kuYP;5!}@kOD- z^2#W#AL<(pu*z6>p9W2L6!t#K`DLLq+LZrUG8`cd@S^MT)zNe@y63v#dUE{e#tilN zAn|DD`u#hfif-R|>uq=JKXCBSzWA2mX5kyoohjBYZNYbcX0iEoqcd3f7H5o${m|`= zAnV&lXPC{lNqV+R)iuQ#7F10O#q@RD&(*qd5ATYu1Tv)}U5H)qfknL$MWG0v;(P?s z=M3Vqi!-c66Afn;XYPz&Khc|FDc9q3l98(R`AUq!?N1ZC+Ps~{D-(LOEaaW03Cj5~ z*_TFOjnE{Sva4J=VeA@~X28;DBLHjQ%Ld5lBldt8T*f8~N{8JSx$*`)&#YWS@FzRe za+hKOBScVBe0u3D?TYC9%wFCNnD%COhCB*wjUsIgV6==j={g^#oJfG-H2<&jsmF%# zF8U+Xlx~0SVQMb|aN^>SN zjz(F`-czo>N!wnKHkaH|mt2vhW#Qv3_ue4dC!QawWk}VtnR0%8f%d=<)tGwKv+C1G z^^B2dZ}{X~vEc&Rz{RmnR-NQqz}s-GubZIP_&QA*wD=OgZA#m79Uyp-&Jz>^4nI0| zz*#yMIVje03$*v32G$ulisF(2p?Vz4$B*Grb^RAj`KIM4G~BS+g=s+il=V<3W;a0&ahYENjF_&m_Z^n1RX!q zh(Uf@#fTr1jq4g<>U!x(Fg3gDfK}8w@iycMz(OzwK+M5>`j{}yEq3~tFk3ca`o=je zn(Tth4bTBXx?+DAufGSeAP(;uHf_a&p6TqDleN}Ix1$lB`tp~)@YzrO^?RR+?$FUp z9GjYaHSD)yA5+5kp2h|t36cIF9iRh61E>{-lW`z{V!9Dxmr-Mzqo--|s%O|*8nb#X zP75iy12%JnZ+M0XWDPYXuvnPp!!w~c)2V7*SJYr0&hMn=j7P znZS8>^qFzHSpc2p6Oj6Cq?Te6 zA_3dwhhap84kWs1r^|$D%dWQQ_|Qx|ngdDL$C#QJcXRUaLx*#Wec7(SFc@&dH7+1akaK4=p1zA3p(qS36LFNj2*I7fMS22~X7Sgdd$F8~ z+cj5nawdi69@8z-yOXfDieV4kE!*#QMB%oPP%x~hQpV~-v0lqp<3_N#}YA_mTx{1fcpY{7!oWOVeAi%}Otw051a zA|PvqteQE@1Sg~Bj!v-#eDFa_ZGXyn2|K}Kr+rCz*V_+8j-()djWJ5wxvW-;AOmn3_ATFrCls#4|bxO z3KFZjs$i!+G2i>k*w%GsO{Z>(rgrdM$0+>Zds^DTcOCm?r7T9#!T0fQq#|F??zmmp z_uIh(ZiFQNbgWIj`5~?hez|EP-1WhlpRZH+(w{vg%`dJ3r8o$2muhl8tr{a((z+lkhZqk0)C)3n#KQWH&<}bgrk-HQR@O2ll*8H zn?c8BBDZu%00}DPD|V>}W~jy6SJxn?3ufSO{`ZYXJG z0me92jSGtEj!N^0FD$!MK`OG>xXlF|={A@7$iQKI0!|x)an$?VFLsjNE#IQ>%7bh@ z#)jI%2oXV`X+SQ-+LKEpN~&iFRPsJBmL0`ZBzyggdJi{UdVS!wYRj1&AqI(sm+~( z)4l#+W;UN&wR(Qd+I0)-H*AC^=NVaZBF(^QOyqn(G!_t_>XFc?kvA__6d5)0=CzYe zMvc6A7E;QnkvA_N5E(V{=Cw&iMvc6AWSlhBmGr0SG@9|*n-90>Q#ND-x822*h5T?2 zR+BU@h1J+jmh#YSfA$cqgT z?+8&oW6f5Yt|2(WuRbg_l5gxtd#So%Y55e>GGw6dO8JE=ls<$a;`Thdluv?y@Uktm z$4AH!p5^||QhCRZ93tDB&;K5gq986luFx6TS1J#5iq&BwpUeG_R;~PDIXx(Hf1*n~ zsEn<|%?3yrlOH_Z*+F`QkGfSrs@P%wC~yQNERh}Z2V;A1P`-Uo8G z_##)dU*11{ChP>aC_U^vzzvJ|GC?BUG3}t-rhR{a(WYHfRb8ybSG)2jT7yBEqd)0- ze`jc4pgzEy;XpH(OZgFqYUTBz#EadZpa#$uOT`A>=}Xr(US@m^H;9 z!!0qwRKm!-!3Q&`8D6W{5;yQ@rR;M+Ay!;GISvEuGN?luDYR^KM{_7IhqD^gDzyC@ zvw?pUG{HAwkZbIV$s^1f7;cXeyY9-E008aOj=c!*FuTw@A3zJEyI&N*fNO|E`S*cV zQLInf{eE_v93xtO_xnUHxaGq{esigz`;|4{QY1TXW4hRF5sJ+4XqEqPIMzuYhO~v| zbuQXW5C&)jY2DjK3_HaS(7mSqkY*RUGjTzrjXAzyZgPVg+*|;a0Lg#OT95AG?3>9h z%xSQ~6;eZGJZO9l#Y6wrojx3)4kkJOQEs(7Ohc*&E|Q0oCQq{>wm8JEvBd&DG-nOd zmoP#8UcEa2z+6Y~EQ@}&mLBAiXd~7~EnjezM?5Lm9?#^tZLpQN{$Xo~<|=>%(tbdB zkSfNZ;#8iEV-pPj^PcJsxnt%C5@rUN`aK}kEEhJiA!XT zL07@04#`;t>4O#09O~o&8U~(@$ePt;M(B0PPaAse>0sA}6XtD_k$(_v25yFFaO2{1I z^@Dm~Lm%FC;U;AxhHRA&A)U&<)SrI-%fggqTdTba7p(TAA(?BmMEP-*6i6Tx0{)eR zvj3#Knf%vSC?jM36E7dPi9S3z(T70aqaF9zD?-sYVT7W|aFp{C4Hxv&9YKX)W3-Vh zQbd<+AT?TTV!%R-R~PH@$KyiTLp~Thhi2d_$_YE6>$FtRGKB|UE#Pq%)AA%$f_<{u zQpE<{I)z`7wUt%Ld5{g7|6jKFEjDV@)DbFx!tDe-|9|YgeUKg3dFFSg@4cA8moy(7 zeDb631xOA^f`nudfGA2rV^@?aC6(Z{%HbcX3jR=~7*KyuE@fAhQtVL#JFpGQBQI79 zuOWG4W212lr{I|Dg?Aa(co*ehD~y7~SOwZ}mDw2OU`vdH&2nudVdVUt=RMuG?|cCm z03t|Dv54+I)3^KdIq!MT`#$e;-UAvCf618A`3#wJ%;DmYb*Tw65$C2=N*V9h&lr}SpB zW9g7;<$5p*QazCWT0Mw)@MS0s2}P|1q@pEtDvGbs5VxSINT~q%p$s;g$rPp3#I7}2 zhf&fE4SZJ!><5TJzj5|3|Jn|0+II|5;3xX4g6ZnR*V#vd(V8q3?)=(w{o?9>fzRCRE1294)d3!PG&=DITZpxvITUt~G8pMqTdpSo@BHLgK0A6Q<)H>?TVmDxdib7qX67qK*y zc9W{;WKJ26Pf&JneybMMF-L1aq7eVJpRqJ12cG*Jbf^$GXzSMMM%aE8)dN>03efUqS?W~U0Ji>rRTXkgMdcH6DHEO zDK(3s8-T_Zny9-i=g{hIrA*e9+;tfIxa*A)VJMFR$7a2~fH&zTrxc4KA`h}GGini6 zy1(?-qt}1)mnz+DUHjX;>voPiah7*h?)uBB0EL&ahUMAfxUk1J77Q>(ak1vEy%z-bp#Tlp1G}b*MTrF%(=+*a1Zb}*twBh!$n&um?Fq06 zJd|r70wfj2gC$n!it#EtIY;ch&Ss9M29I>Q95F~co$LS_2ksxH=qPoo)_qYEUhWZf zeGTV+ZTBI~6*Aa5jdF7uroRq1=rEY`SQ56{816D9n%kv@uuW@U?xDTeN%?dbe1K1k zvkgQ^ISh3kpc;Jrg(Ty%l5u3)d)MRL*2G~{;-G|Z{5kIk&ahLg!RwY0*Jor=^nYJv*M0r6MP*a6ApfV3wX zzikI33&Wi%-ncs!eg>pD7N-`tfus)lk7Xldj8jHDVUgl}5=NR+$wWD`n#yQGCacjP z`)v9Mq%m(q2=c?#lQSZgM{9q}|ST@rN#zlZi8|*4Mq4%u8->%Aw%Vg8w$$gd5^uMm{5Ee<)DG!qO0?fLiirggg_*6D zkMjM?`fY43!Cm&-=uz&r$li|MHd^=F#(I7m%!xkd#GQN4b~1yk1W(&SOfO@gRfs8| zK>HwrVzw0)W&w*&;eZf!!g2q$?!^lMP5yuT;8*bHwc0|qVi=GWr2;bnEKu`56bin& zt##{!fLH-Z!{Jj(KVwq3XXtp2h(fbi_lZbd-7YXK3Tzs|pZxKaWHz49*2@~x+nCGS z`KGEk$k3392 zYUU3QmNnhx@SscHg5j~@k@X>~fg!KjykKe`_zcEbq(VvKcm(% z0d3GSK5+v~EsJurixd8PiE^YFSNbc>qt?e)9mH``;-5kEuV(3q?Cfg^Cn|juj3B;}~v2pg)^AVm=52I=dFq zGa%4NF#}tn1_BYh6A07{5NMM?ppoJ%0PzA4s04%JDBA8!`w+b_Qk-mR+NdC*5tECm zEhpoZ1V4#q{d?(WnyE+Rf!Z|DY{7gzVn#w@s2Qv(up+W+IHJkp>R>)1J7R9I z7^zzj|L0dLi@~VVU)Ha|{{M>W-P#d>mueb62?lZSt5_COIAyF0^uuR{D8zA`=BQR9 z^f*#XE8g%;oQXee<6UQY*gF5$wp?g3=>xcEfHZUp`|I9wer|`7+S20p}LL& zyODr33d9&xqS{mJ0YDQKGdyiPyqhjJ+9r#}!>g1;%C3J2L%p|6qj|%-Q~Bk zN=7Q-qHY(fT)ysAUGSpmA%#rm^aSzx2FY;9?h4?y>Wi1${h|b_YT$IcnqMG-jHYP7 zCXm7af#Z|cs&T16ynY(-Whp>0y%vzAssq10i9=?2Lt2Vg7<>AybcWb*ERWMGuOU-9 zULVS#CT!@AE745|d~5i-)GTDgo0;nLlq{dLmYd5rBr~HSLA$b-+q5U83=jsS6jh*1 zs2nugs6W%hIU#cTo(*IHL4)8f(2fUD0%z2oul>p_62joZTG(sZ=ZtRv%%zNTK7B7W z=Zw$cU$lhs&$xOWmKkUOAru@LcC1sG7@>1J)HK$hmo0cPTJWKK=~g@Tx0h-)D(+TW zNrOe`29CnQ27{{yHQMf}BeQ}Yi(y1ifT&zh7G2S@v+d40nu5V5)gZ@*=IFI5UAmxE z&-JzHskLrNM5$_3x9~~I7i(1*B7Ln&EXb`oUTamRFSWW9VOJt|PThZbsMBdmyN%{Mw91f$ zIqQD5t8{DpzFG@7Z_)YSp^Xjy=;4HaXi^*hoTJw`$wPTZv+_fF4Mz?d=f26x3N!hqGKO6gOq4>ay-G@VkkBcnO z-Kh)KHm0O&o%?AY?w*iUXZd0=QhvX(f{oK|TZKUFIMRJssp=>|A#}GZMG)soCPshE zgQcJ#d2&=mm7#8@rj=IVEtTbNX=zmVk$fkfpk|Qq;cqhwlXZtK>*S9N|9RGZ1T*Rp zO4{5s@Hu`F#3>GrO|yLTbBK!q(hat0UY~EJ$*Hab*o)z0gZZda=A`Ysx91Ow_Dm;1OAg{|v#`v$%t9XBDh$e#=&Cq&pN zy32sC{6lL-exmy{MM*1;h!rRO_CLzJWx#kIK#RzD*V4CebxKbD%Z28&5WF-Z5WzmQ3`J{`|`IxeWZpkHj_535z^yMM$}qD^H!*h-dPI~sGP zJ7cD;d>ho6jw_$JsCT38?e}iXiAPsfp*)+za<-zuu8MI?<6JT07z2QbC>#EF_Ta7# zie}0m=M+vO(KzxIa5ovRpJ^OsFHMHvA;y}T1SiBTDWz^FLt|H3zw|+LMbb-;WR2B$ zl>7#92(HGg*FUSnSIWmeN*rg5Xy3cnZ`iti!xk-YA6k&Z1WibjDJI+H9plWD);qn~ zC@c#Z$I=?6NS7lq3aIsnY!r35?*O~C8B-N7Q0o>=j6*ljd}CyR%|-AMjt{a;aLa+e zh9ZH@12~OK2LJFNHN&Og-?opCCBnf!S;li7qnwfV$#~ab;Xoi}&F(^7V@MF}RbaD%-~KKBqG9uic`K_a#l``>d(3 z67IQ5QKRDoiw&$vH#nXrO@z5UKxoT2^GM2WDy5_tLC5>8j1;G8TsoGW_-|xFAWCrq zmLU-HCzydtmZ9csI++=Gv^MA74$H9Ji&oKHeK0e_FVJ41K3*AIen$@^hDj*o9aFhH z5v$HLL-a}yakj>eDBpsniMymunMhXBG(j`GgH2OH@a-N1kFd^f8$s~3mYD~i6R#Tn zlCx0y7#v}ZX(j3^2^i(^+sLC@+U`J_EpH`a_y;qS+q5yl_W4$4Tgjx7t$uCSH( zY58^_U(-JFam+`sr@ACVIzuz)2ZAz%JydX=U<$!?f9~mQx|!yGblIqF%OtQ;BRH^l_oaX!;Znep8JFXb|yWLv~kmgLbZP zJa|qw0C(`O%%^{!;|%k)%pRJ*YO1r8QO$bumW`#(7qWn+4bfBZ*4Ebfwv@RXRMe~D z!qof%>)MHOsZYgvP-qt`W!hGXBe_~CBJ)nDc@-q?iwJv%F#im@p}e!Q8(d&>Fxd?* zz>w&R2;RpGzZBEn|IS#t63nQ|B)#cSrI)wHV3{7Wtk^7gH3RatLAYrlh9l`Ln^ z)1=ExIP=`3y{4MT>ftz>aL4A?7l@ zLh#WC$byMiiz?lc0W(@#z97rnsu%`L7F;6@Ci=_|iyg52_<&?(MGyaX9z9pov)qNY zs&1PLRvSN1zi-rTtkwZC-)bTAMJDW!gWiOVW@dfWrivW}2Rs6ai7H;2oSJL+o5|=m zJ>6`=tk>{z{Yx^sp5l+(T!kuGOdVwO%@L~H*aQ*GXzzu>Y)kO=g!$gFp5}MPsy!KY zaZfx~?a9j0?z09l4N5a|h4$nqkI{p# zo=lh(B=s0KA;C#KE)GUg4{;Q*gh(edys!BMnKipI=DU}4CJw_0ncd@@r38Dk7cj$) zVPvw#`?K;In#Z0>FxQ~W;NGFrUyhqKxTn0aVJcM}0fbT-D)3-}iVpLYkt z0IO1A-qY;=P8?xhL#7m=u`~5+CY)4;M4J^S<#?=p2(*ZGox2*})_1l=mS7?OuEt+w`eLi;b9kx7GhJ^z#ZBmgqW*PKI&z4(=WrD|j(6(Gc8p$G~9 zP7V(zV_pcFG4znn#D^gH48jV#wV`D|8WY{Ex`@OqZSon!r^?G~I;#+Z;mULs3UPW5 z(P4t@s)QmQ9Sgu`cl)N&z&^5ang#vq=DN^LI`Vi*_UfkVKT#w)E;q9cTAu7WA z^&#!}EMt?S8q)lAS98n0#t2`?K;fB6^r{V)B1}Xp9c$xfZTzS+VsMKi;0~1utS1bv z=1;1A#>?LIz~(fkp$8aOiVQSqIkf^}l5(slO@vj57}ZiC`w) zKW|bTfeRrsv-$>$FPZB>MhVs^nQWq9uJJ z#rk?h4z6+(W^_3nrBD?DSI!FuaKfQ635@VfL?cSFl@L?KBKXv+iEyPUEVkv4*rQtm zkP6LXG`}f0YFe*D4^1kKiDwo*ns-awFa08V@Dd_jY)`36sJ+}Nw~oGJ)|x-Y58Wjq z`Vi~N(}?wYC^!r(MG#}2N|Kvde2LF?w=t5HMug^%@8ZbBE<~-{HnEHfoUd1XpZC=OU%23Y-5t+P*Ql9i|b_$ z?RpACxYgi7R9w@o@gC@fF@Bh8G-w$fUIl^p#F+K7ku*kMZORwcROsuQ1!KgjJot^# z03J(SWk@NTMQspjf3r%XWe_#A16F|AVKWut^$M?YDC?zRY#Rh53q`V+{gH1{KuoLw z>2BF_!NS+t5I$M+~vb-y*Yu zLPYbZ5S=y6DzgGGh*$>=Cd(Ir9o5V3`A)X-mjLJIepv;Nd zEaGbj%1M6J0$SZp!}MAq_O+Ye3MumQ4rzttuczd&P6Ad5M_N?cR35OZ@N#K{U3H=C zZe-_5l=c(@sB9oYV-+%`WJRGXLVfg*DHcQ|WGX{wl8Tf`QvO1UOd_X1NTf;7{&xJe zADPlq{D!4T^r|l*m|)TKxr4H8w*5%ZayOy1t$!vOE@-~ZeFto#MR4%O2 zG2oou)IN-*$*o=b)axwPztfHa>xd7|a}<=hPmbUmM>&F**T@>gHfPDPj0~2)NlwC1 zh%Az&jItQN=O|RQr|w#`FVa_}Et7j&xeR!66_dYdiUlu`ZFEvE!x&)QtFLD=r3`Bk z8FA(?88AdPh-H|Z9Q9+b5hiJt7{nW;kr#QT+P(MA#Oms}J4&N6OT0&%0zr|_58cenIXbVx*UWC=wqb+Ye`bGbM96ll$>bE!@+R#&sJPASUJ*q@9 zTwrabuU9BSe#qf4%9#Bz{xleUzKaZZb%O zGOLf+LwU6=sXyW~l$=jnd$x+$mQ*$ON4(^Z*h4?ZSMWLfiEj}tTvfs;B&YVLnSE_!sCuvKhH~T#Lem&oNk}g*9a!=A$p*=}!tzTAr zk!q*bhb%m=^$#s*{n~z|d~9#OQgx*E{?bC&*soMa9*551#@Me^pXEE!ex*0M1+CZr z-1R(ADkTvHq!w==pZuL3(tf3S5=$GXjFRVYXmwaK&>7_awfw(^5w+*V?j{D5cBvtU z1Rjd^F5QIGc&nsq(3#r&*`C7#>>^nVl)6?+;Bm&ZgDGd_4yF%i2U8MSXa`ffO!9g7 zJ3jy) z?4t$grL%zs_V}7_nd-@a(B7s0P=O61%#D1IY;&uI1KTZ--{`fO|#l+t1u)2b^;oSA8b}r?|httNT>AehXjYSlQ zeyVYOpSY%;l;Vf;UVgZIIZd!D`;2}m?Z{iGOH~Wr{qcCW>i_8Q-}k#e24bZ8EcwN} zSpZ3`g<_*r7C!Ts2ebpKzdwubk9;a_tp+(V8PfH(V3in7uslKk$%HWfLf#FWw@iO} zgs%r4;?oZya|0dMpx5!y?T)jiYCqf8Pw%6>RA*~2bPKg3!GBqo{K(T;<3qHNUu(xH zRSJRFtfeh2v9ULc;;X&D#1ZfflICk73nyq1@8A0tZVFY(i`bY+9oHH3K=9bmUWU36 z%xGMIBHK1;Vi0bYd`k6`K3>YLd;pJv+D)B(pI(sa96Pwuzv@R{Y)ZQqraMcuC`Pqf znwtda>d||I>Ws2Gij+|}E>uE#CMo{VN4^+3=r?$l;g)FMQlGN_?O~KP?(?;;GGd1()O*bg6hd;GBUwp2VFgs zJqLx@Z83DC4l>t@e|ZE|mP5>gxW-)2HIj8vcE?pr7)u%E3a9Bd-1#{;AbRFy{9yHg zO%%E7TRe5Df&Fksl6y70@?bla_=Wn7yQn>P1%44PaJu*szlhfdegReTC2f_FdVdSg zcJEUL2IC+5oBf+DO0lVL)?BXYT+@ykd57;4j;a*PNL^_?lAH+R&O-kwIIv2JqlQ@X zDawafJRwV2mY(wQVpMvM=}9&PH0ml`FPVCoz?V+jQjRUJ|5W$unK~p>D?%f$?6XV_ z4z4ayvDKI9QJv9b(1p>(3XIK2;IqXZ3HHagdx@N9Bjyf6;j%~A{R|qj<`C*VEL0tt z)wiybbu-an0-MO5k9q0SEV*kvogHRBJKNbi!p@fAMsHxR`Kb>S=YD@y3k7x{et_$q z;HZk_x?66%BqISO+x!^i*e%hzEsb@r8;Na7X$0Hs00p!NB|82=RE>x)lciQXxtd1 z6WOy0BT%rP0x6~)A({`wP)ZFzCG;RSpBq3rA$=p`C`?d|qhySZN~I3zv7eSgsNT1o zmv61T*?-cTWwC^Y2>BBQDl3j5sY$uVn9LNgp~%gt8sTNQAer7OVC00p)eNb6UxwSq z#QUzSnNdTzczQ%_r1!tbBb|}adv0hPq@BT^-YuoW%lrnBqOXZ7TMqS+YN%^bKvG1S z29kR4Q1^let=%ZDAh^ZO;@CeVigHGad3Y1kEtE73ZGV|AwshG)Ayr!rnV^M}0)BOHQ zSvuL$WL3^iiXACmRmLKW)F6gL+~#hd1lp9%4_3ZTGtEOWA82F&lvC8Es2bTs3MgU+ zv)<@uqc-=&bpnjgeKQ~mj;FHc_&#u4M)2tHUpnA9O-ducA}IYrEwtO7v6$;IjMaJA zA=Yt`8Lqlu{7MD8PLf2t^l5&oOqKDrGwE$Jej5QQ|4nZj)1U;Wp#Y31g{u7N)rY4i z0ws-eGpieI>JkZHQ`Ba06lxGc&51A18sO4I6s_YgIEnnJAX<<(a_uH2Ewzj~W`@w) zo17ahvr*t#)H7;I{eO9l_k*~;=19yW#*xygVrJShp^BN!=>i*ul$!4Bcyh$fPKm-j zoMLCJFrz2f1va&z*PK-?s)bb=MbW-a;NWg9OH_6B5%l7w;4S_ITO0nmBCkXb&mn56 zp`x!ksy0w5TgVc}`i>(lg%15UZN$#W1-ZVCs`dAX6MTbJxTi&;kRVI5^X4j>lk7wa zdg+}UaHWQ|J5cvLxmJLTc|M~5+;bOFa&DUzq%$rPXj8d!u}ogo%mBLAY}hEElczI; zY%-N`Bc4x@he(+Sp6p{3d4i02s~1k=oB0Y_F$Lq4tTAT0n4=s{qYYCS2@A3o({dH~ zVjfX4hCZ^*T-6!8``9F-x*jU1$MD-&`@0_=`qr|ECq zaRo~>)|QRQjeP=SxK)T2&Sv!7jpEW%RvwdUl`**+(88O=pV2@N4crAZ!GJW`_gsdU zM#95HjQWmCk=SyN1>MWtD21+=5h6x?o9_tOW@)n2;^>X#TCazY*!rpA|AA4dDTeti z!bxa{kNlLpXU5^1vC|=w-cVQIoikHnMQ}6y+i8QgYk>fl{1Fr)B3!aE1$-)A)k>=U zcMM8mXC$zpg7TDvBVsC zDO)UUP|Pr9hIKZ5cnNXBN}e*C{spfJL>9`X@wEiPBd=_lxT}BU-BQzNncE#5dF3)U zcC{(P;jC4j-!@w2R%;o5My$cNf}6mSIF<|Dde1oHzo%ya zNb5P6MIKqK9%3r%TmOLM&7=sOjknsk;!h_vuXV;8#wrI^Ep*JlLeJF(mh8TGftSY8 z+j>SCR98w{mclt(ts(hadcC{ThHcroAf*V@Jh8uNttzpfgXwTb`?mQv3*}e9 z4K2GiEoS6POR+~$Z20MKu>*bah0j$h8PmrkO1}Hkk%(Rk;CAt~m3*fra1zRQN)z~F z%2f$W^)<10J)9W`A+^HmW#O@ybwOQ_praD25RltZAgO_0T}*-8l91gs1+wfqS=ONT z*2$t;LxGf=X%u+NH>p6%wYKc_5(=bx#_F&wbdDiobao-A&I?4>F@^KJheI+J1V9U)l{i6f;n_ zBu#azjGq*hT&3xCfGy;|5ac`nnd6|8J&WeB&>N#o2K?HT-bp>dK(KD93iOjkudzVou`kZjezOY5$WU#(maR~(-fHw?%7+8M+-nDFoU|pIK0D#0}VE#j%;dbW^ z(Br{}V@<$FL~R!TSH}6_2xBOIYlOY4h^u@f`Fx7!Z1wd4uFi7xC|8PR6f;~*=zE12kiAP(q3+|lAaG;i&l9>3nh#js-K~oaTqu(Cq%JmcagvLt^jYIv zOve|BZgOtGn|r>8(~EKXUQR(AcQ+cHALA5AUZ-NyFdyr2?^5%g8tBk$EK?s)qzLr7 z`!omQUfkg?6_bF^gN3xWDgq4PBPrTf72$AGABy%@MMD3CBX-|k7I97dp!N z>I3?k2f4Vw#k0EjAQu;HGr-8AWhnoU%5yH}xcIOx)aV!xI_>HM&S%iLIKG-GlBA96 zI)#p}Wu1= zUYJtK-zfq|1nC<2Q~92Fm^z@S*%bycz&0@5Cu?eO~DF z*+{dtJAa>+#ypg_}wFX{-$bxud1mT4V#>_t*J=6l(X zhT{W!k!X(ZqSjfyH-9=c-#%JrPdPaEbK#(oM(X>yFs7yptuHXxnY0y=Rn}+_auY|% zd=~WtVH$G_=Li7(4YWLDE8YobvMC`3TV|?&`Eg#79u7U*uB4@IYraK24BwM1xXOQA~^l3a229 zGyH3`nsc%s@Kq)b)S?IVT(5+?E~YDVi*PWW#9ArbW=0j6N0RF0rgZAfFzALVhHya_ zXdzE}n%z;Ru8>#YO#Rv{OHvg@Xo*NOshgQ+Sqh<&>o^T%I_g&OZa#7N`|XVb#l~u_ zq85j>j}(80$LwmP<*IsSx@alKiE1q>3}0u$=X3OSt2jkfoGA`5BJ~N898Tb{M5egr z!C%q>Mp&IdaHXzcqSfN24Vdd@Y)<;wYVQajXeOR&R%9)=utoznICQ{NRIRJZg#0pH z)e1aWr5rN+gsxM~kU^5+PzTJ)DzwlD))6;&TXK$RTXN1`!YqOt!r2!k*ICFllq*Wu zSuuoLH45QIPcJ6iJ;7!WenN?djB+5;cU-WEs+NMCuq=(shO$VulEbN~->Zt;i_}0! zx)cLlz`xjGDl-~v-HL69$RS0R{?M5gK>sloowsb?gUySHh;G&)r*d(PJ~yux)^Ig7APH<_j53*R zH6fJRz)&7osT8Vve)z3}Dq8BpPYk3l*LPjWq*!F&*>>UVQYyJvmCVsH9@wuLT>{Qu z`r)gsdMmAJdmvg>WWvR}j8#SD3b64I(d`n?@z9Zor`JpnjCYadeg|44}z+w9jhO5r@@THyjqvY=zt>cf&F9be(LVoI7Q{dx3U&D~^l%T6AzGlKY?_ z=l zL+p)sy6)YtM)V}=YWF5l8QNL#J?@8_7nEN6hFS3)m&Loo<;;q2yNp`$>~J}=;*VXH z+)%rmvi_0_ip%*S-n%l7GYE0u2jwT43)1__eBnoKDZ!XxB9`%MpN}BbiOrLV-o_el z6MOi%%@rpT(Yh=|EOHt|!%68-Q1Q0uHaDa?OpYyG${8pH#^CTbO_6(nSj~1Bvds#_ zM0f(%)blylA4}9x`5k!#ZG12Z0?n9CWwB2pFqOsr66Xly3;Y0%psNs+pYI`G#e*`| zGa))=5bz=yz>qIJ3Qi6b>!>6dkG=VyzN|R zvPIt%jn`6EKU|KFi_63DuQS$^)US2$7ckAIZJJ}8m+nsUBqc(jv~o<<>#9LqH%n=) zeJ%dnbkXQV3=EovlFPLcgp?9I&YpNv8JpuD=MPdTq9pj|mE;FUuzWFeGpPm|CG7x6 zqjYG5HAjl$G)ig*a=-L0vb0p$jlw&;hix@bQOcbIu`ZTrl(J?B z8{ZIPCmMjppd?0Il+YNI)O3OxgOV7%>ASIh-6UV+4;T1zUz5CG1tMQ%S^|b+cao!I z+NueNuyXIDxJg6$i>-~_;@y=5iTgo-^VfRq18c5#k)_oBUbM*Dy9yomB*^ZaB?#}% z5){r|>)xnG$8*;*2>t8oH?S@pR74^q75NI%v-HH zgi8&Wk z)WTAW-if!?!qPWOwea|jTX_7FxZkBMc;{Pq>GTJlikwtZI@l)~N|6a-F*8wv(UKI# zqJ!NxdEX*?`X*CSwq-@(Sd=a`FUE$in__G&PzP=GhHNA6I8ZU6wZKZ?SJcc)tzYv1 z5Y?oNvFRzcX)^^mFdR3n8je=j=%-b~Q4==WE@BlwiiYEFymf}-d8X_lzmeg%p_=yb zgk(6r&d;>jyA8)Hi%k2sYB(Ne+Mm7Qw11Bpjya98YB(-qICfSIM_IY6hGQfXSv4H7 zLQ9Um*rYdOI7$bv8jj;XLMfs|Ei=v9@TFkO>5`M>cyNu3wWAEFD>$#c_IhM2HsP2@ z#>(+6Zi|eCyF8za^=Z5V$XKk*7M5^G{t8h&*|;2ut;%5tGS=xnG8QrJuGktpvY(9g zJR}D~c*=ppZ%xJm6Va(SM&#P)f<`-Kia`r45$}v=2NwTN;on0+!~!=fNi@Pqz+_D3 z+G)HX+33k<^oX*DS1gDqdbQh=B;`A|2ugAm8xjLRWS0@I{djiEUn~IA0tB@NC z;8Ilucp7F>RRspqp;A=^pgbk7t8AIc+Ml6ssnTN3LG9A%(rt=)}(m37oP!m)xd z=dRm@jO?>#%El^iI=nBrQhe&Ku&xNsn-(*zW3aEz`c%t^pv%li!X%{*UXy*R(7S}G z)9|pwl;eO`R!wx2x1>$e2ycUJnN$QF2_BDGPl%IQLgo!YEOMM%FW8~Ps3fr9#W~4@ zH9Yls?9{0N@;cAujo}74PYV1YmkE#qa#jRgA62~OQjHcx`@!G+sWdYsX&F{_2}CSl z?fzw0W(*y|Eq6~-t6m5|b-7L!IW~-70pF(h$j#;FUEu@#c?93wwhp!|=!eB0E#6M6 z_zUW-F;^CPh__55KUWQXd&MQlCjya1QAE_ zIMm{eq#hFNX|9n%kV5dtOhYAZ$TiyhNtQ#F7}K4nWNhnEGPW(?8lg=kBZ1vl0-1fP z`|hMoB_;%!Vt`NxOVJ4&JPNwmu;_{r*x*w`lhF2*!S_ie z+fJ?|!CnnbDDNW}xcG(AuM% zF0FjeGmYkcX}7C;^iK#jrvlh=LDE)=dX&?_Hs#TJJTbzO{qdq*lMIUhp0+Un-W~`FbQRk z(l%YEwAC4Gp6$=o7;L#(4(gQJl1Dg-iu6|nG$oUAP}*LmDHZvsbKn{kt?f)=&ZMP- z{OqtuMe2*lfEH122SkADnaDyNt&rZcRNlQ0Ei4c@5y(!AX5~wlsa2Oa5$7DoslsaUL z1v`(tSD{HT1EdXPCophIi()=AuU}L`saRMVI$tO*Ru{J?E~?DjU1I5t_u6@UUOO*E z6-&aO7(Yp^)=7BB7n1Of-jgJ}6?{BHXdr#L2G6;qI9{$Ocjr^dY*lg*O=5zqb6z{3 zx>(c;(bHf|u`!69@BH>(MprHM@hfb9PX*Eb=f{#13@|jv-JfjfdxN{Tj7;MK-H^NYkbQ>-_|h78uj9fLgH_AO?{nE(!spvk zEox*#i^v4OrCQWTQOW0t0;;1W6R(E|iIX>#^euM>DUT!u zLCTY-EyD*RzS|?4;ggf{D)Vx@9#;TL%PNoKM>=`83>orCm zMp<8yt3Gz#VG|G;Cs@wEV1|}IsW|_YS%UU=sgf{bdz3*oNlBJ=rX_;?{_;tEvq6~me94St6U6ID}BgItxnqAnA)vw9$ zJ6XTRpSa$Op^_G%ccJ7%2Y(OO;H+VxhB$O4)+yJF5_ZcS;P=Tf5bH*1iZZdtdMrsm z&tBg$zUNDx#*h5`b`T`p`^nj`U`OxEY48wH|9@3uWtOo*j?>|vU_lmsV-wAf6E+)T zOk>u5BUF4#6i+jqdvgpMJmL?so<|E^o)RYy``{*rhqjM;=bYPfgVkCSW2Zq6ee6p%WU|IRtM=+ zuHy_Zsa!`f=HxmuFx-4)+du%d`}nH9^zn$Tt4Wo*vT9Y(NIu46%9)kED+VX2iiZD7 zrq)C?149}9c@ZME=tzbk%b`g_S=#wtE8vXAsei+$H{nfSNiyoA2W8WLj2YM_{dk!3 zV`0u`+Db>ABn)PWQO;Xj8AMAdmWAP~vx_Qgiz#qp(Q~z|EppQJC-w&?8?Gv~06+u3 zO$+syEVVxk4u`Y0X!R3qf$7j#IR&oDg{3&#G829?A6sm~&msj)X~rhfl;(9Xl$h5S z-Me@mkqS>K5vdw{t{ixNjp5KJAHtB}Gx_u?Q9jO1O+5M%!9{ABb#yuduHNYg2*qg?wpQmv^$r|OJPm9e9Jpomd`xg{w zU~YdYP3_F)Ju`u}>S^+|{?1)3s$T)xyDk$`gcc^jZ1FwnFSxN%?bcWFu5iB_@F z7maE^@z0Y2{0i~9hCK$nsHsBim%%s%o3PiZqfK2xD z8&I;ql$II`c6wBMQ|(u3!TCQ^^X1X?`q=T|Um=8H*8a%wuk&4Mtd`Wi=)Bao)cVLt zP3s@y&PwZlfpdg5I>uaZJ$W=#{#6>S=!DAG9Ha!`HKnf^(TlZd*W%~D%DtMZr@65y zy|1khYj?*KF)g@wv^WuW`#uuEOIWa2)xI_X%+Q^y6_}xmC|7rwp-YEV1)}_x(JehA zL=^zCnts>>h4tQY1~d(^wcLgcs_&m!RFi#{R*Lkk9&tQp-s+KL>-DW3scb#Ej%vx) zdycoS(AFc)wD?Mx#RVhTvUFa}mR-BP*cGN;OCzCCn8qw1zW8;9;O<5vkbW$@zsq&9 z_yofjzg)k@Hv7-(*H~zOg*8y!|ChZBTX?^Pg*VlXuB4+_Xr!5MfrUpN%_Zx1f%nzx zH(P%{^*dL;=E-O4*VJ#Oem&j0xTX4;0gt}A#_x+KhJTfTzh{j98#w6tNYzsj z=7C)6mGE~c9{xLe3{a#Ixy0@ejq1MH`fE9}WjX$LX1g2H}iyo6I zEB>e6#foWFzk*{u{WhjmiEzGvR>i)Jw@a&9cNax?8LGlPM0FOv!*tun^3uF}J1nok zyV$BX!}5|5vJ}g!OmVju)5}E61#B;Cjgs+2(9w)9LXJ1h_)=q<@5P+8P>QWxZjbGC zH(7N{$BL}R0-RW!B~lK~~HH@QmtvR$hzY+>o%GVKd=r$_rT@u+Fykt5#k_^wz+ zt=?e<7-~c-agw#TC<6?XuqWNCq%XT{Z&T9Oj}nA83R)?%pS6^;P|cd!H8BF!tg=$p zH*$cJumI=S}2pT&E-NO+IMn*qG>b0t4yK(@_< zQzNEsPOD=0J8?q=v7lkNF_Fe7K!iNBssaS8i6d{%*FPch%${Ub0TM#3U@z^>KE(r( zI#)jZz7b(bZrRcu(`yjwqjXj90qW~UG^+ho z9k>X0ByIW97A~Jcn2&~K(PL9Y4Gp~r12)Ar616V;h!|Xo|B1!Jq2Vwfhmr6cu+a7r z_=9MwFyLZ}NR7NjA-(~Pyj~kR#Aim?f;M!B4@TJy*WR$Nt3rGwTyy8!aM=*wB8)N( za0fBNdXknH(>8g%{lcK${H^CUE^^;u+_Obfa?RtO*=qJiIT=A(4O2Rn!6$uTyG0Zk ziDpsdh*j!T{@Twy!zPT_-)ICWc?7Jj;FOP6oN|iFjdErkAsqP;iV%*3dC|HR^P*id zFEBM0nimV0?2DNh2+>_IGepR3A{`aeP4h68$qi>>8Avi<(7`Q*KUxv~V5B<-J{CnH zr^U*jn20siu(|M0NJh1b1ouo2fD|q|36Iq#;W6t)1Xf}4n1rEoCimr@wQ-p27UL@= z<3*DUS~T?Qk~SPX5H^!up^>4vSVl%kl>Xrx8UL4zjFFy^q1DQCqj)3upbLx)kqU3d z$PndtzLDYdtVq?Mp0 z{Ygf~4YQ6y>$_Kt48>M%WMm`;`^_2|?FB{#7A&n4#(L1!D??3x5^epSHZt0a(bg9+ z9)hwqj6MK^6^EKhJBsf-L3(1npPQW+T(^&1((GBU95`xdUr zOGKeqjcCQ0qNZA9b)T0v4fOUvx=)UFJ^;%zY2Evrr(%GauPT68$Q{*wNRhaH06VF= zLv!AM-WQttzI?!EN?ebRfl8{ask`igTHS&ftfg?^1gNGx)nnw<)-pldCv&`2uNn4u zEf0j(>pAs(S&b?MM9$N3Zb(5C)ci4ySbhdWnrX8?8|bKh28sr?JmN@=S((n^u~M`@)dG)~nPxEh2komnVlm3obsBJPpxSyLpu#UESI zp~^jxvZ~eTL$2wkc%6J5gf0_FbgCWx&I^mtg>E57KY4l@osp8OR6puj6Om5}Au|o5 zZ(lzqpR})^;&*cNt9|{DlHR_4h+S`AKTXAtQCnx0n&G0_*G~lTYF|IB>fXM7O#Qum z{gATWzJ7GHs!z)aB)}){XkR~o9-Y3IQ}70zYG1z#ajM3?XwJU&^()9H(tTRbP{J*; zjdb_wLYs%3jGRu|aBrIO{VG=ms2MKauM2G*1`$Q4Ij83$@zV#SQa;l$y8PKrS69bV z`ll0V$GuZo=UJ7XPCM?M$vQi9O}Z#{^xNI|gRJu*9+=PDQtlcVW9Uq6xaS?vNd4r@ zF|pFb$(UlP$(*_t`Ju~@^OWytLS}BO_!?pH`hI&~ahROpNS_1@)+&C^W!?@TP_S0< z0~39m?WUKY$ir6{*k8!6;)N?%yy(sLwp*gL*&cbB#^prUHrsoafe^NmskYJ@{afv+ zT_&i2%y4Q^1OIs1)A>GIJH=7HAnmkw9WB@9&T`Nw{TKz69wa2_f=UlE3|&y^L0Z-Y zl^$$~kTprWn=Ik=d#-3rhk0ynQB^$%<0~};%Zx(hhqm$$JkvO$j{===}> z2o}Q>L=_{!Pqp74Igw)BWVPSlhn{Kt?v3{FQ&J;uNBI6cS6l7RpNS?r#UDuF!z5Xp z;PhFY?u{HrH{8Py@XvXHSU%{yK$AK`rhb6~Imu4z^X}i9oz#(hM8|a`EzpGlFOp*T zNHgQ7{ul3a}`j*KiIS1+>h-VpLP zcbCXA%Wk|!`Ww&xe7Son&Ho}AszK^`hscQ%d54%&`0KGAH74=+NRv_y3I1Mk^3X9o zvW%xD?hB;VH>Fd9uDrDZU9Zz8LS31QO8^xGBqDH`rD8HjAUOHK& z$=Dwh8vgdzW5t`Z?L>~6XBVcZ0RUU9vp|E=!b=d{Pu$fMHOs^iNSpT*q9&RCb_R^3 z%q`uB^LksWwmQW!ie_IPtT+XfEINyyPo=^=E1l7GM48l}gw>_tl?H zU#-5JN~7#}HOfwTX2RZR~9``$t9CF zD<3eA?Dw-FDnJs%HjYHcTJ20%X_A+pO*+t?pDnLOPRxN= z@<6wQ@A*hoWK0AP)P8r|W!MBy)ZTX#8CjX7Xjk<^+`aB&JPxCyEaM8nOaA;JdXe|@ z8+qsZnmJdq{MGI`T`Vv@+;ioJ#uWt3K*4?N0QAdLUzpA@O7s?WiPt|>oE|e#F zhKu*AsaU@#CtauWobv6i5)03{UT=$9WOiB;^@_@Z}z<_?oP-&A7^Bc@1 zfdF#qlaHYO#4-w}Ui*P#jCG$;CFJg7h3Qnz{$Vo#z-S|>dUb?7y zoe%5yM%L--_DLFHeDamCFq2#{56z;oLAk^LW z$S{o9(Xgfa9vOxaIhFNg7)FFuR%I9lv(Ysk{C8xvAYv==;5%sWyz<~#bO4u5zR1?n zu~iP-eixn>FYKxmIQPf*Y*wwt|6ur@Kw4PI$s^Sx=r?~s2)YvRro7dB{DPOuk7i); z!EyT;?r~=8_vSxl*Qq#7iPH}4Oc|i%4_}Z;&Cooo@Kh_`_e?{Mja+lPwEX2z%65yd z{eMfBOj1c_kbF<1?R_dz_U z5;SWg-;?jv;mQ1I9iGVFr-PL*Id5C}#(m8>9oO5Lw(o6Uyt^04q?{DRb2{R5U(yk$ zdn(I!<&UL?ncxemogkI5y-IPcOzzdR^f(vQl;j4=*&GIQO~l ztng7CSG2;1cgQToh;lA#6DURn9BDr7K%uGDM&G>qz8>knTkiY4wARJ$J8NP}_kFH9 zy~&ip;0Y#9eeG1~!MEhWPs#BIyFNw~n{EeMs5Vv6@diRmy z@AH^Mo>K1>-{5*zqp=T(&I-LFUCdt@W0T@J^v;b_4*zYX73*Ic!o3}O{MqpjlTS;v3%p`z)Jno!MiBy%XsC^ z>W@}10`itF-&m@tkzBC)daByMnpWP_cXQ>&(oOAQw(QD{TF%tWHp+B;*~XcA69gD? zdd1Rq&!Hiw2WoK0o|g^4`G*@JGx&B8>wKE0V#D3QekSfbMg0bg_*R7J&^3o1V3f>bDK<|-G; zri!Y-mPA2S*i=y!DC*C#>*dm`n8=;PM8peQ#YDgjc2+Ljy^Dzm`FN6gc7%xt`KT}v z{J0(_f~$B-m`DObgo#WA-Cz|HaaM*^OhoSXy^4wS10et*%TqMYU6%(17o}K)eFL&3}R{s6?#>V=*UhuQ* z&a}Qem=7Kt_)ot~ytQwK;ia3}!)z53S;&sZY=D-qiiu4A%nBt7zIJOl0$sVwT5LJQ23__=6q{ zVvOW>>(_ec?PDarCf*1v5!T6<>{gcYtr(GcPvJt zVYiBrEaru-l<>gfQ7xJ#$iIB5k=3;|_{I~Yd}CDx#~UqKTIG?vQ+Xuoe}r<4D|rg* zl+unS$~tnkRVMK~d(#O<&T2QlzAT>Ow+o7p(Pe&ukx%1PkznNcSPFe85{!`l#7m;d z)5hZ0lwjoLrWSLh6^7ciu&d+*JhDH*$n&@#VurpESuRI7Wg)%R&?;Fa8|HOccNK{| z$%D|{tc&qTCbHDO%4D#*7jcXcVy&QIkKneAl? zxzNi5N}dpPg;FGtKSZZpPUm95&J$AJWcnmW%tZD|$`x`x>+II`t9`jboIB)6Ar}8C z>paCH$lK!VAFj8$a*hlq%m&3P425>FLGS8rbutO%8F?AuQL;rP1JrIN?EEw9(}`@T zOZhnomjsj)EIfb|{Cd|RZ5im|9a{b8g@i*n*=sh8kgA$0>Jy5a*FNz@iPFpcEX(R6%kS@b6Xf z*qu|wNa4ZmHWXBg_Wdih1ZiuW^H4cu_^j^s;S&yfR!q?uH?c!ks5aeAIpvU#W!A^ebXa>DF7iPZ=@gcMvM-mJ!O)2>FX}lgyMy9L%ug&*_8;B0x09V z;L@vwwnj3^?Wv2^Df6l!%bcW5WbsVj>@P^UMyHW*Ph!EvEXa0LOt(_5QRcm_8t^(t zXT6XPDP}$VogbzgP?TPyG&bEpV>##OrnJ$M?<|v+a9b_s=yjfc5FBE1mOj3!3k22E zrgWOsN2DzI%Tx5+24I$AZ9peX!rEzov?IUx^=d<>X7Ob%Drn@qwTu-Gbw(*XC+pk# zHq(Yq=#KNvPUMMrg-Uz3h3w$ZQ=h2;kw@6rLv6(l1WKqz&XG(xN5(>O^p{@B5wT5_ z_r%>#yQyVdK+1Q9cC8>+!NppE7s6hy3g{5ki`4#mIq*nNaeP2}WFw^=DM`SI_D=J#)G3XD|JT{?^TIVjBk1_}^U$)za%f^fB(gj^?ZxBtyEp zOujnJwNj|p60c%1B1b1_yciYZF-FpeY30naQVi0}2wNJnb7a{4?{zg0BYc_WU9(v8 zl7o2Z<{imzkl(hgt+a-C``u#cEVGpsNyAYNJEKhpG{k@4(U+8!_t%U4(@_HGWRa*#naTc4?TLKfN@g-a(C&h5i1ubr>&)~dhN==rj3|GUhME&bDZgfS zqQ2JMIi ze_@L2W^KlWWfRg5mJUB-O7OK6Q8<%fU>n-*1wG2S|)N=_`dbyed&Zm;us^nrSc{NJ5 zX+UXgX(TQ6nj&_-zU?-?;SN8ZTJB~WFEh0)_3?M4jR&HQ5x6Zwa=Z> z<)@+rJLB;;?~HfTnP8URv}Q|{31&-~31&-`35KFF6U^C`vg5APoMvMjM)f-|6Yl8z zOt{LADubey`?gcM4RS!bJHnL?B{RJMnqmu|dumOSa{1ze_Cr(ia^H?|&s1b_6)dtK z_w6>MbMZ}P0;rOUydd}O!&n62(b)k0RUjBr1KNME0sPHcfeql_suegl?(fzLoEi5I zY6Z@V`$x5c{}y*?C$-0kF71En)%Yr|yBJxKAa|Q9C8S}NHc>8Kr+UU$j@@t6`cn@*1!?h zsllK~io1tWTzMt9)!sMP<5YX!;3=z=w7Pw%a%BJuyePM4=F4`G$ha?6uGdusbfxYW z*5gfblx^lJ7yDERAuE7dI#t$OrONdtIq&BJ^da);l0?_3a=k4MsdCAq>r}b9j-<-% z>PV_wHoh_3^^lIF%EgKFJ|VKP0S~5i3<#@4voOzRD6OT+O#oJn-lN{a$hSdyFQm$q zi4rN!wb_kR<+2-QBi|O8U|Yt07N*Kw&{a#P%B_;gir$k@p~cg}_{9M_ISp;?<;q_j z7I+LdrOGv|_+5X~1je#TaQ)+QZEnPnY6iMLKE|d1l+Y6vb$S#hJ|R^ooq0Ro^q?o*Rzsn#qKPUL>as2ns*6%jG6f9QluM$H zgD(|3Z-MUfMtkGtlJ0|dqJ0mc`&{5LiSE+`-zjE$u$3{bbM@=9y^AW9t|S_WY+fqe z64iRSM77S)2np5d(S0gZi>V`0=^EC$hg0d&aJ5vr$*EhIO83^VtiikJ5-;O$RB2;m zcAYG-tF&r#%JK%nrKt~CU5bxh!p=k@k4YlI2?Nt=m#P+Yy9Dx?6)tg;plZao#G?Cg zEybx&AxzYLG#{E6nVRP}2Q<2v-+XgE-CLAGx1#yngmagbtL8Q>_gAPtF0v+63 z6Wnud?Hx!Lv)Zi1U>`q)akHXk^@yvb&>dS0EUUqSig+ThTPq~A9~LwcYAj!P_zht} z@cg$(Iw5c@_NCM&U_osw6tG~Iv)EvAi?EYG2;UOmT-pK&0S$%^JP$>dbSQXVc1U1KRb>sZR<0xV_hcCi%V61PP2Ip!c! zqWK&ZmR!+%i0Caz^N~+`OEjOcg#;hX^7E)YecSco1$G~_oh!&-8dRa$u9rZ5Z@XSW z83rr_Wq>yXU{OLD)porQ1$x`{3d(Sv7eN`I5xwntk8$zT1Q5X{{xTKlh29UUQ9>2~ zDLNHo0dkTc3qd71O&MOOckKCdJni{&V!-?JOaM&iX+Sn5SY&JnPpiAPDl&cqlc2k= zDk@1o-ThUOETv z{JSJ92{H3-L9y?yF&YD%LCC4L;H`)|kCdbxRmt6!I!#zvjVJ`@V3N>*#0=s?4%2%F z6QPDdeITeqoS8E8WUzLg2%64gVaiX0{l4tByoHEDU}+8ZQ}X^pA1Zen5<#fYAA(ne zXrrrOwU`2RL()z~`T>-g#U2rEXR;497N-Fs(BAy%^!59AM_vxr{ajQ`9>Inci{}|G zmSpgZd3zxux8bbwO3}Tl4Thu|HE`ydGIDTbU|xtW107D^1W|4=5)UyIk$5y3OyN<$ zPplP3iL0j2v!FPMH=Gde>qVi1;=|x!ITI&PB2?X3M34P0Ams3 zajIF50W(==z|fkK8Eyc7&{v+U733SATCL1`Nn} za%JbyUkny}Rsz(A6?|r4{P*UZxVH={fEr3Wd)J-o#v|!R>GT8_Tyt5pbqy}SltRSJ z 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

    *_{r(2hH|=zL)8(i(Y_Nl} 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˔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

    ox_qM>W2bHDgNrF3IV>(9I8@YBU&p) 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

      m==mJaZymj_IQpvn59|3X&q2lY2Y{Wr!mp{q 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 F{|`2uo0k9p diff --git a/x/dex/types/alias.go b/x/dex/types/alias.go deleted file mode 100644 index e50603631..000000000 --- a/x/dex/types/alias.go +++ /dev/null @@ -1,24 +0,0 @@ -package types - -import ( - "fmt" - "strings" -) - -type ( - ContractAddress string - PairString string -) - -const PairDelim = "|" - -func GetPairString(pair *Pair) PairString { - return PairString( - fmt.Sprintf("%s%s%s", pair.PriceDenom, PairDelim, pair.AssetDenom), - ) -} - -func GetPriceAssetString(pairString PairString) (string, string) { - output := strings.Split(string(pairString), "|") - return output[0], output[1] -} diff --git a/x/dex/types/alias_test.go b/x/dex/types/alias_test.go deleted file mode 100644 index 76736bb99..000000000 --- a/x/dex/types/alias_test.go +++ /dev/null @@ -1,20 +0,0 @@ -package types_test - -import ( - "testing" - - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestGetPairString(t *testing.T) { - pair := types.Pair{PriceDenom: "USDC", AssetDenom: "ATOM"} - expected := types.PairString("USDC|ATOM") - require.Equal(t, expected, types.GetPairString(&pair)) -} - -func TestGetPriceAssetString(t *testing.T) { - priceDenom, assetDenom := types.GetPriceAssetString(types.PairString("USDC|ATOM")) - require.Equal(t, "USDC", priceDenom) - require.Equal(t, "ATOM", assetDenom) -} diff --git a/x/dex/types/asset_list.pb.go b/x/dex/types/asset_list.pb.go deleted file mode 100644 index 4ae77c2d8..000000000 --- a/x/dex/types/asset_list.pb.go +++ /dev/null @@ -1,768 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: dex/asset_list.proto - -package types - -import ( - fmt "fmt" - types "github.com/cosmos/cosmos-sdk/x/bank/types" - _ "github.com/gogo/protobuf/gogoproto" - proto "github.com/gogo/protobuf/proto" - io "io" - math "math" - math_bits "math/bits" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package - -type AssetIBCInfo struct { - SourceChannel string `protobuf:"bytes,1,opt,name=sourceChannel,proto3" json:"source_channel"` - DstChannel string `protobuf:"bytes,2,opt,name=dstChannel,proto3" json:"dst_channel"` - SourceDenom string `protobuf:"bytes,3,opt,name=sourceDenom,proto3" json:"source_denom"` - SourceChainID string `protobuf:"bytes,4,opt,name=sourceChainID,proto3" json:"source_chain_id"` -} - -func (m *AssetIBCInfo) Reset() { *m = AssetIBCInfo{} } -func (m *AssetIBCInfo) String() string { return proto.CompactTextString(m) } -func (*AssetIBCInfo) ProtoMessage() {} -func (*AssetIBCInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_65992190d1b6a2ed, []int{0} -} -func (m *AssetIBCInfo) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *AssetIBCInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_AssetIBCInfo.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *AssetIBCInfo) XXX_Merge(src proto.Message) { - xxx_messageInfo_AssetIBCInfo.Merge(m, src) -} -func (m *AssetIBCInfo) XXX_Size() int { - return m.Size() -} -func (m *AssetIBCInfo) XXX_DiscardUnknown() { - xxx_messageInfo_AssetIBCInfo.DiscardUnknown(m) -} - -var xxx_messageInfo_AssetIBCInfo proto.InternalMessageInfo - -func (m *AssetIBCInfo) GetSourceChannel() string { - if m != nil { - return m.SourceChannel - } - return "" -} - -func (m *AssetIBCInfo) GetDstChannel() string { - if m != nil { - return m.DstChannel - } - return "" -} - -func (m *AssetIBCInfo) GetSourceDenom() string { - if m != nil { - return m.SourceDenom - } - return "" -} - -func (m *AssetIBCInfo) GetSourceChainID() string { - if m != nil { - return m.SourceChainID - } - return "" -} - -type AssetMetadata struct { - IbcInfo *AssetIBCInfo `protobuf:"bytes,1,opt,name=ibcInfo,proto3" json:"ibc_info"` - TypeAsset string `protobuf:"bytes,2,opt,name=type_asset,json=typeAsset,proto3" json:"type_asset"` - Metadata types.Metadata `protobuf:"bytes,3,opt,name=metadata,proto3" json:"metadata"` -} - -func (m *AssetMetadata) Reset() { *m = AssetMetadata{} } -func (m *AssetMetadata) String() string { return proto.CompactTextString(m) } -func (*AssetMetadata) ProtoMessage() {} -func (*AssetMetadata) Descriptor() ([]byte, []int) { - return fileDescriptor_65992190d1b6a2ed, []int{1} -} -func (m *AssetMetadata) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *AssetMetadata) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_AssetMetadata.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *AssetMetadata) XXX_Merge(src proto.Message) { - xxx_messageInfo_AssetMetadata.Merge(m, src) -} -func (m *AssetMetadata) XXX_Size() int { - return m.Size() -} -func (m *AssetMetadata) XXX_DiscardUnknown() { - xxx_messageInfo_AssetMetadata.DiscardUnknown(m) -} - -var xxx_messageInfo_AssetMetadata proto.InternalMessageInfo - -func (m *AssetMetadata) GetIbcInfo() *AssetIBCInfo { - if m != nil { - return m.IbcInfo - } - return nil -} - -func (m *AssetMetadata) GetTypeAsset() string { - if m != nil { - return m.TypeAsset - } - return "" -} - -func (m *AssetMetadata) GetMetadata() types.Metadata { - if m != nil { - return m.Metadata - } - return types.Metadata{} -} - -func init() { - proto.RegisterType((*AssetIBCInfo)(nil), "seiprotocol.seichain.dex.AssetIBCInfo") - proto.RegisterType((*AssetMetadata)(nil), "seiprotocol.seichain.dex.AssetMetadata") -} - -func init() { proto.RegisterFile("dex/asset_list.proto", fileDescriptor_65992190d1b6a2ed) } - -var fileDescriptor_65992190d1b6a2ed = []byte{ - // 404 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x52, 0x31, 0xcf, 0xd3, 0x30, - 0x10, 0x4d, 0x00, 0xc1, 0xf7, 0x39, 0xfd, 0xda, 0xca, 0x74, 0x88, 0x2a, 0x91, 0xa0, 0x0e, 0x88, - 0xa5, 0xb6, 0x5a, 0x16, 0x18, 0x49, 0x2b, 0xa1, 0x0a, 0xc1, 0x90, 0x91, 0x25, 0x72, 0x1c, 0xb7, - 0xb5, 0x68, 0xec, 0xaa, 0x76, 0x51, 0xf9, 0x17, 0xfc, 0xac, 0x8e, 0x1d, 0x91, 0x90, 0x22, 0xd4, - 0x2e, 0x28, 0xbf, 0x02, 0xd9, 0x49, 0x4a, 0x3a, 0xb0, 0x3d, 0xdf, 0xdd, 0xbb, 0x7b, 0xef, 0xce, - 0x60, 0x90, 0xb1, 0x03, 0x26, 0x4a, 0x31, 0x9d, 0x6c, 0xb8, 0xd2, 0x68, 0xbb, 0x93, 0x5a, 0x42, - 0x5f, 0x31, 0x6e, 0x11, 0x95, 0x1b, 0xa4, 0x18, 0xa7, 0x6b, 0xc2, 0x05, 0xca, 0xd8, 0x61, 0x18, - 0x50, 0xa9, 0x72, 0xa9, 0x70, 0x4a, 0xc4, 0x57, 0xfc, 0x6d, 0x92, 0x32, 0x4d, 0x26, 0xf6, 0x51, - 0x31, 0x87, 0x83, 0x95, 0x5c, 0x49, 0x0b, 0xb1, 0x41, 0x55, 0x74, 0xf4, 0xc7, 0x05, 0x9d, 0xf7, - 0x66, 0xc8, 0x22, 0x9a, 0x2d, 0xc4, 0x52, 0xc2, 0xb7, 0xe0, 0x41, 0xc9, 0xfd, 0x8e, 0xb2, 0xd9, - 0x9a, 0x08, 0xc1, 0x36, 0xbe, 0xfb, 0xd2, 0x7d, 0x7d, 0x1f, 0xc1, 0xb2, 0x08, 0xbb, 0x55, 0x22, - 0xa1, 0x55, 0x26, 0xbe, 0x2d, 0x84, 0x18, 0x80, 0x4c, 0xe9, 0x86, 0xf6, 0xc8, 0xd2, 0x7a, 0x65, - 0x11, 0x7a, 0x99, 0xd2, 0x57, 0x4e, 0xab, 0x04, 0x4e, 0x81, 0x57, 0x75, 0x98, 0x33, 0x21, 0x73, - 0xff, 0xb1, 0x65, 0xf4, 0xcb, 0x22, 0xec, 0xd4, 0x83, 0x32, 0x13, 0x8f, 0xdb, 0x45, 0xf0, 0x5d, - 0x4b, 0x1e, 0x17, 0x8b, 0xb9, 0xff, 0xc4, 0xb2, 0x9e, 0x97, 0x45, 0xd8, 0xfb, 0x27, 0x8f, 0x8b, - 0x84, 0x67, 0xf1, 0x6d, 0xe5, 0xe8, 0x97, 0x0b, 0x1e, 0xac, 0xd5, 0x4f, 0x4c, 0x93, 0x8c, 0x68, - 0x02, 0x3f, 0x83, 0x67, 0x3c, 0xa5, 0xc6, 0xb6, 0x75, 0xe9, 0x4d, 0x5f, 0xa1, 0xff, 0xad, 0x17, - 0xb5, 0x97, 0x14, 0x75, 0xca, 0x22, 0xbc, 0xe3, 0x29, 0x4d, 0xb8, 0x58, 0xca, 0xb8, 0x69, 0x02, - 0xc7, 0x00, 0xe8, 0xef, 0x5b, 0x96, 0xd8, 0xab, 0xd5, 0x1b, 0xe8, 0x96, 0x45, 0xd8, 0x8a, 0xc6, - 0xf7, 0x06, 0xdb, 0x66, 0xf0, 0x23, 0xb8, 0xcb, 0x6b, 0x29, 0xd6, 0xbc, 0x37, 0x7d, 0x81, 0xaa, - 0x23, 0x22, 0x7b, 0xb7, 0xfa, 0x88, 0xa8, 0xd1, 0x1b, 0xf5, 0x8f, 0x45, 0xe8, 0x98, 0xd1, 0x0d, - 0x2d, 0xbe, 0xa2, 0xe8, 0xc3, 0xf1, 0x1c, 0xb8, 0xa7, 0x73, 0xe0, 0xfe, 0x3e, 0x07, 0xee, 0x8f, - 0x4b, 0xe0, 0x9c, 0x2e, 0x81, 0xf3, 0xf3, 0x12, 0x38, 0x5f, 0xc6, 0x2b, 0xae, 0xd7, 0xfb, 0x14, - 0x51, 0x99, 0x63, 0xc5, 0xf8, 0xb8, 0xf1, 0x67, 0x1f, 0xd6, 0x20, 0x3e, 0x60, 0xf3, 0xd9, 0x8c, - 0x32, 0x95, 0x3e, 0xb5, 0xf9, 0x37, 0x7f, 0x03, 0x00, 0x00, 0xff, 0xff, 0xa7, 0xaa, 0x78, 0x83, - 0x80, 0x02, 0x00, 0x00, -} - -func (m *AssetIBCInfo) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *AssetIBCInfo) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *AssetIBCInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.SourceChainID) > 0 { - i -= len(m.SourceChainID) - copy(dAtA[i:], m.SourceChainID) - i = encodeVarintAssetList(dAtA, i, uint64(len(m.SourceChainID))) - i-- - dAtA[i] = 0x22 - } - if len(m.SourceDenom) > 0 { - i -= len(m.SourceDenom) - copy(dAtA[i:], m.SourceDenom) - i = encodeVarintAssetList(dAtA, i, uint64(len(m.SourceDenom))) - i-- - dAtA[i] = 0x1a - } - if len(m.DstChannel) > 0 { - i -= len(m.DstChannel) - copy(dAtA[i:], m.DstChannel) - i = encodeVarintAssetList(dAtA, i, uint64(len(m.DstChannel))) - i-- - dAtA[i] = 0x12 - } - if len(m.SourceChannel) > 0 { - i -= len(m.SourceChannel) - copy(dAtA[i:], m.SourceChannel) - i = encodeVarintAssetList(dAtA, i, uint64(len(m.SourceChannel))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *AssetMetadata) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *AssetMetadata) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *AssetMetadata) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - { - size, err := m.Metadata.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintAssetList(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x1a - if len(m.TypeAsset) > 0 { - i -= len(m.TypeAsset) - copy(dAtA[i:], m.TypeAsset) - i = encodeVarintAssetList(dAtA, i, uint64(len(m.TypeAsset))) - i-- - dAtA[i] = 0x12 - } - if m.IbcInfo != nil { - { - size, err := m.IbcInfo.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintAssetList(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func encodeVarintAssetList(dAtA []byte, offset int, v uint64) int { - offset -= sovAssetList(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *AssetIBCInfo) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.SourceChannel) - if l > 0 { - n += 1 + l + sovAssetList(uint64(l)) - } - l = len(m.DstChannel) - if l > 0 { - n += 1 + l + sovAssetList(uint64(l)) - } - l = len(m.SourceDenom) - if l > 0 { - n += 1 + l + sovAssetList(uint64(l)) - } - l = len(m.SourceChainID) - if l > 0 { - n += 1 + l + sovAssetList(uint64(l)) - } - return n -} - -func (m *AssetMetadata) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.IbcInfo != nil { - l = m.IbcInfo.Size() - n += 1 + l + sovAssetList(uint64(l)) - } - l = len(m.TypeAsset) - if l > 0 { - n += 1 + l + sovAssetList(uint64(l)) - } - l = m.Metadata.Size() - n += 1 + l + sovAssetList(uint64(l)) - return n -} - -func sovAssetList(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozAssetList(x uint64) (n int) { - return sovAssetList(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *AssetIBCInfo) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowAssetList - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: AssetIBCInfo: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: AssetIBCInfo: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field SourceChannel", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowAssetList - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthAssetList - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthAssetList - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.SourceChannel = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field DstChannel", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowAssetList - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthAssetList - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthAssetList - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.DstChannel = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field SourceDenom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowAssetList - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthAssetList - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthAssetList - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.SourceDenom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field SourceChainID", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowAssetList - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthAssetList - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthAssetList - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.SourceChainID = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipAssetList(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthAssetList - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *AssetMetadata) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowAssetList - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: AssetMetadata: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: AssetMetadata: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field IbcInfo", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowAssetList - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthAssetList - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthAssetList - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.IbcInfo == nil { - m.IbcInfo = &AssetIBCInfo{} - } - if err := m.IbcInfo.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field TypeAsset", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowAssetList - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthAssetList - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthAssetList - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.TypeAsset = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Metadata", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowAssetList - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthAssetList - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthAssetList - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.Metadata.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipAssetList(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthAssetList - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipAssetList(dAtA []byte) (n int, err error) { - l := len(dAtA) - iNdEx := 0 - depth := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowAssetList - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowAssetList - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - iNdEx++ - if dAtA[iNdEx-1] < 0x80 { - break - } - } - case 1: - iNdEx += 8 - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowAssetList - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if length < 0 { - return 0, ErrInvalidLengthAssetList - } - iNdEx += length - case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupAssetList - } - depth-- - case 5: - iNdEx += 4 - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - if iNdEx < 0 { - return 0, ErrInvalidLengthAssetList - } - if depth == 0 { - return iNdEx, nil - } - } - return 0, io.ErrUnexpectedEOF -} - -var ( - ErrInvalidLengthAssetList = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowAssetList = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupAssetList = fmt.Errorf("proto: unexpected end of group") -) diff --git a/x/dex/types/codec.go b/x/dex/types/codec.go deleted file mode 100644 index 1dcfae37c..000000000 --- a/x/dex/types/codec.go +++ /dev/null @@ -1,71 +0,0 @@ -package types - -import ( - "github.com/cosmos/cosmos-sdk/codec" - cdctypes "github.com/cosmos/cosmos-sdk/codec/types" - cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/msgservice" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" -) - -func RegisterCodec(cdc *codec.LegacyAmino) { - cdc.RegisterConcrete(&MsgPlaceOrders{}, "dex/MsgPlaceOrders", nil) - cdc.RegisterConcrete(&MsgCancelOrders{}, "dex/MsgCancelOrders", nil) - cdc.RegisterConcrete(&MsgRegisterContract{}, "dex/MsgRegisterContract", nil) - cdc.RegisterConcrete(&MsgRegisterPairs{}, "dex/MsgRegisterPairs", nil) - cdc.RegisterConcrete(&MsgUpdatePriceTickSize{}, "dex/MsgUpdatePriceTickSize", nil) - cdc.RegisterConcrete(&MsgUpdateQuantityTickSize{}, "dex/MsgUpdateQuantityTickSize", nil) - cdc.RegisterConcrete(&AddAssetMetadataProposal{}, "dex/AddAssetMetadataProposal", nil) - cdc.RegisterConcrete(&MsgUnregisterContract{}, "dex/MsgUnregisterContract", nil) - cdc.RegisterConcrete(&MsgContractDepositRent{}, "dex/MsgContractDepositRent", nil) - cdc.RegisterConcrete(&MsgUnsuspendContract{}, "dex/MsgUnsuspendContract", nil) - // this line is used by starport scaffolding # 2 -} - -func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { - registry.RegisterImplementations((*sdk.Msg)(nil), - &MsgPlaceOrders{}, - ) - registry.RegisterImplementations((*sdk.Msg)(nil), - &MsgCancelOrders{}, - ) - registry.RegisterImplementations((*sdk.Msg)(nil), - &MsgRegisterContract{}, - ) - registry.RegisterImplementations((*sdk.Msg)(nil), - &MsgRegisterPairs{}, - ) - registry.RegisterImplementations((*sdk.Msg)(nil), - &MsgUpdatePriceTickSize{}, - ) - registry.RegisterImplementations((*sdk.Msg)(nil), - &MsgUpdateQuantityTickSize{}, - ) - registry.RegisterImplementations((*govtypes.Content)(nil), - &AddAssetMetadataProposal{}, - ) - registry.RegisterImplementations((*sdk.Msg)(nil), - &MsgUnregisterContract{}, - ) - registry.RegisterImplementations((*sdk.Msg)(nil), - &MsgContractDepositRent{}, - ) - registry.RegisterImplementations((*sdk.Msg)(nil), - &MsgUnsuspendContract{}, - ) - // this line is used by starport scaffolding # 3 - - msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) -} - -var ( - Amino = codec.NewLegacyAmino() - ModuleCdc = codec.NewProtoCodec(cdctypes.NewInterfaceRegistry()) -) - -func init() { - RegisterCodec(Amino) - cryptocodec.RegisterCrypto(Amino) - Amino.Seal() -} diff --git a/x/dex/types/contract.pb.go b/x/dex/types/contract.pb.go deleted file mode 100644 index 701429157..000000000 --- a/x/dex/types/contract.pb.go +++ /dev/null @@ -1,1902 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: dex/contract.proto - -package types - -import ( - fmt "fmt" - proto "github.com/gogo/protobuf/proto" - io "io" - math "math" - math_bits "math/bits" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package - -type ContractInfo struct { - CodeId uint64 `protobuf:"varint,1,opt,name=codeId,proto3" json:"codeId,omitempty"` - ContractAddr string `protobuf:"bytes,2,opt,name=contractAddr,proto3" json:"contractAddr,omitempty"` - NeedHook bool `protobuf:"varint,3,opt,name=needHook,proto3" json:"needHook,omitempty"` - NeedOrderMatching bool `protobuf:"varint,4,opt,name=needOrderMatching,proto3" json:"needOrderMatching,omitempty"` - Dependencies []*ContractDependencyInfo `protobuf:"bytes,5,rep,name=dependencies,proto3" json:"dependencies,omitempty"` - NumIncomingDependencies int64 `protobuf:"varint,6,opt,name=numIncomingDependencies,proto3" json:"numIncomingDependencies,omitempty"` -} - -func (m *ContractInfo) Reset() { *m = ContractInfo{} } -func (m *ContractInfo) String() string { return proto.CompactTextString(m) } -func (*ContractInfo) ProtoMessage() {} -func (*ContractInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_ee35557664974a8a, []int{0} -} -func (m *ContractInfo) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *ContractInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_ContractInfo.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *ContractInfo) XXX_Merge(src proto.Message) { - xxx_messageInfo_ContractInfo.Merge(m, src) -} -func (m *ContractInfo) XXX_Size() int { - return m.Size() -} -func (m *ContractInfo) XXX_DiscardUnknown() { - xxx_messageInfo_ContractInfo.DiscardUnknown(m) -} - -var xxx_messageInfo_ContractInfo proto.InternalMessageInfo - -func (m *ContractInfo) GetCodeId() uint64 { - if m != nil { - return m.CodeId - } - return 0 -} - -func (m *ContractInfo) GetContractAddr() string { - if m != nil { - return m.ContractAddr - } - return "" -} - -func (m *ContractInfo) GetNeedHook() bool { - if m != nil { - return m.NeedHook - } - return false -} - -func (m *ContractInfo) GetNeedOrderMatching() bool { - if m != nil { - return m.NeedOrderMatching - } - return false -} - -func (m *ContractInfo) GetDependencies() []*ContractDependencyInfo { - if m != nil { - return m.Dependencies - } - return nil -} - -func (m *ContractInfo) GetNumIncomingDependencies() int64 { - if m != nil { - return m.NumIncomingDependencies - } - return 0 -} - -type ContractInfoV2 struct { - CodeId uint64 `protobuf:"varint,1,opt,name=codeId,proto3" json:"codeId,omitempty"` - ContractAddr string `protobuf:"bytes,2,opt,name=contractAddr,proto3" json:"contractAddr,omitempty"` - NeedHook bool `protobuf:"varint,3,opt,name=needHook,proto3" json:"needHook,omitempty"` - NeedOrderMatching bool `protobuf:"varint,4,opt,name=needOrderMatching,proto3" json:"needOrderMatching,omitempty"` - Dependencies []*ContractDependencyInfo `protobuf:"bytes,5,rep,name=dependencies,proto3" json:"dependencies,omitempty"` - NumIncomingDependencies int64 `protobuf:"varint,6,opt,name=numIncomingDependencies,proto3" json:"numIncomingDependencies,omitempty"` - Creator string `protobuf:"bytes,7,opt,name=creator,proto3" json:"creator,omitempty"` - RentBalance uint64 `protobuf:"varint,8,opt,name=rentBalance,proto3" json:"rentBalance,omitempty"` - Suspended bool `protobuf:"varint,9,opt,name=suspended,proto3" json:"suspended,omitempty"` - SuspensionReason string `protobuf:"bytes,10,opt,name=suspensionReason,proto3" json:"suspensionReason,omitempty"` -} - -func (m *ContractInfoV2) Reset() { *m = ContractInfoV2{} } -func (m *ContractInfoV2) String() string { return proto.CompactTextString(m) } -func (*ContractInfoV2) ProtoMessage() {} -func (*ContractInfoV2) Descriptor() ([]byte, []int) { - return fileDescriptor_ee35557664974a8a, []int{1} -} -func (m *ContractInfoV2) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *ContractInfoV2) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_ContractInfoV2.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *ContractInfoV2) XXX_Merge(src proto.Message) { - xxx_messageInfo_ContractInfoV2.Merge(m, src) -} -func (m *ContractInfoV2) XXX_Size() int { - return m.Size() -} -func (m *ContractInfoV2) XXX_DiscardUnknown() { - xxx_messageInfo_ContractInfoV2.DiscardUnknown(m) -} - -var xxx_messageInfo_ContractInfoV2 proto.InternalMessageInfo - -func (m *ContractInfoV2) GetCodeId() uint64 { - if m != nil { - return m.CodeId - } - return 0 -} - -func (m *ContractInfoV2) GetContractAddr() string { - if m != nil { - return m.ContractAddr - } - return "" -} - -func (m *ContractInfoV2) GetNeedHook() bool { - if m != nil { - return m.NeedHook - } - return false -} - -func (m *ContractInfoV2) GetNeedOrderMatching() bool { - if m != nil { - return m.NeedOrderMatching - } - return false -} - -func (m *ContractInfoV2) GetDependencies() []*ContractDependencyInfo { - if m != nil { - return m.Dependencies - } - return nil -} - -func (m *ContractInfoV2) GetNumIncomingDependencies() int64 { - if m != nil { - return m.NumIncomingDependencies - } - return 0 -} - -func (m *ContractInfoV2) GetCreator() string { - if m != nil { - return m.Creator - } - return "" -} - -func (m *ContractInfoV2) GetRentBalance() uint64 { - if m != nil { - return m.RentBalance - } - return 0 -} - -func (m *ContractInfoV2) GetSuspended() bool { - if m != nil { - return m.Suspended - } - return false -} - -func (m *ContractInfoV2) GetSuspensionReason() string { - if m != nil { - return m.SuspensionReason - } - return "" -} - -// suppose A is first registered and depends on X, then B is added and depends on X, -// and then C is added and depends on X, then A is the elder sibling to B and B is -// the younger sibling to A, and B is the elder sibling to C and C is the younger to B -type ContractDependencyInfo struct { - Dependency string `protobuf:"bytes,1,opt,name=dependency,proto3" json:"dependency,omitempty"` - ImmediateElderSibling string `protobuf:"bytes,2,opt,name=immediateElderSibling,proto3" json:"immediateElderSibling,omitempty"` - ImmediateYoungerSibling string `protobuf:"bytes,3,opt,name=immediateYoungerSibling,proto3" json:"immediateYoungerSibling,omitempty"` -} - -func (m *ContractDependencyInfo) Reset() { *m = ContractDependencyInfo{} } -func (m *ContractDependencyInfo) String() string { return proto.CompactTextString(m) } -func (*ContractDependencyInfo) ProtoMessage() {} -func (*ContractDependencyInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_ee35557664974a8a, []int{2} -} -func (m *ContractDependencyInfo) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *ContractDependencyInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_ContractDependencyInfo.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *ContractDependencyInfo) XXX_Merge(src proto.Message) { - xxx_messageInfo_ContractDependencyInfo.Merge(m, src) -} -func (m *ContractDependencyInfo) XXX_Size() int { - return m.Size() -} -func (m *ContractDependencyInfo) XXX_DiscardUnknown() { - xxx_messageInfo_ContractDependencyInfo.DiscardUnknown(m) -} - -var xxx_messageInfo_ContractDependencyInfo proto.InternalMessageInfo - -func (m *ContractDependencyInfo) GetDependency() string { - if m != nil { - return m.Dependency - } - return "" -} - -func (m *ContractDependencyInfo) GetImmediateElderSibling() string { - if m != nil { - return m.ImmediateElderSibling - } - return "" -} - -func (m *ContractDependencyInfo) GetImmediateYoungerSibling() string { - if m != nil { - return m.ImmediateYoungerSibling - } - return "" -} - -type LegacyContractInfo struct { - CodeId uint64 `protobuf:"varint,1,opt,name=codeId,proto3" json:"codeId,omitempty"` - ContractAddr string `protobuf:"bytes,2,opt,name=contractAddr,proto3" json:"contractAddr,omitempty"` - NeedHook bool `protobuf:"varint,3,opt,name=needHook,proto3" json:"needHook,omitempty"` - NeedOrderMatching bool `protobuf:"varint,4,opt,name=needOrderMatching,proto3" json:"needOrderMatching,omitempty"` - DependentContractAddrs []string `protobuf:"bytes,5,rep,name=dependentContractAddrs,proto3" json:"dependentContractAddrs,omitempty"` -} - -func (m *LegacyContractInfo) Reset() { *m = LegacyContractInfo{} } -func (m *LegacyContractInfo) String() string { return proto.CompactTextString(m) } -func (*LegacyContractInfo) ProtoMessage() {} -func (*LegacyContractInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_ee35557664974a8a, []int{3} -} -func (m *LegacyContractInfo) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *LegacyContractInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_LegacyContractInfo.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *LegacyContractInfo) XXX_Merge(src proto.Message) { - xxx_messageInfo_LegacyContractInfo.Merge(m, src) -} -func (m *LegacyContractInfo) XXX_Size() int { - return m.Size() -} -func (m *LegacyContractInfo) XXX_DiscardUnknown() { - xxx_messageInfo_LegacyContractInfo.DiscardUnknown(m) -} - -var xxx_messageInfo_LegacyContractInfo proto.InternalMessageInfo - -func (m *LegacyContractInfo) GetCodeId() uint64 { - if m != nil { - return m.CodeId - } - return 0 -} - -func (m *LegacyContractInfo) GetContractAddr() string { - if m != nil { - return m.ContractAddr - } - return "" -} - -func (m *LegacyContractInfo) GetNeedHook() bool { - if m != nil { - return m.NeedHook - } - return false -} - -func (m *LegacyContractInfo) GetNeedOrderMatching() bool { - if m != nil { - return m.NeedOrderMatching - } - return false -} - -func (m *LegacyContractInfo) GetDependentContractAddrs() []string { - if m != nil { - return m.DependentContractAddrs - } - return nil -} - -type DownsteamContracts struct { - ContractAddrs []string `protobuf:"bytes,1,rep,name=contractAddrs,proto3" json:"contractAddrs,omitempty"` -} - -func (m *DownsteamContracts) Reset() { *m = DownsteamContracts{} } -func (m *DownsteamContracts) String() string { return proto.CompactTextString(m) } -func (*DownsteamContracts) ProtoMessage() {} -func (*DownsteamContracts) Descriptor() ([]byte, []int) { - return fileDescriptor_ee35557664974a8a, []int{4} -} -func (m *DownsteamContracts) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *DownsteamContracts) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_DownsteamContracts.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *DownsteamContracts) XXX_Merge(src proto.Message) { - xxx_messageInfo_DownsteamContracts.Merge(m, src) -} -func (m *DownsteamContracts) XXX_Size() int { - return m.Size() -} -func (m *DownsteamContracts) XXX_DiscardUnknown() { - xxx_messageInfo_DownsteamContracts.DiscardUnknown(m) -} - -var xxx_messageInfo_DownsteamContracts proto.InternalMessageInfo - -func (m *DownsteamContracts) GetContractAddrs() []string { - if m != nil { - return m.ContractAddrs - } - return nil -} - -func init() { - proto.RegisterType((*ContractInfo)(nil), "seiprotocol.seichain.dex.ContractInfo") - proto.RegisterType((*ContractInfoV2)(nil), "seiprotocol.seichain.dex.ContractInfoV2") - proto.RegisterType((*ContractDependencyInfo)(nil), "seiprotocol.seichain.dex.ContractDependencyInfo") - proto.RegisterType((*LegacyContractInfo)(nil), "seiprotocol.seichain.dex.LegacyContractInfo") - proto.RegisterType((*DownsteamContracts)(nil), "seiprotocol.seichain.dex.DownsteamContracts") -} - -func init() { proto.RegisterFile("dex/contract.proto", fileDescriptor_ee35557664974a8a) } - -var fileDescriptor_ee35557664974a8a = []byte{ - // 481 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x54, 0x41, 0x8b, 0x13, 0x31, - 0x14, 0x6e, 0xb6, 0x6b, 0xb7, 0x7d, 0x5b, 0x45, 0x03, 0xd6, 0x20, 0x32, 0x0c, 0x83, 0x87, 0x22, - 0xee, 0x54, 0x56, 0x11, 0xf1, 0xe6, 0x6e, 0x45, 0x0b, 0x8a, 0x30, 0x8a, 0xa0, 0xb7, 0x34, 0x79, - 0x4e, 0x83, 0x9d, 0xa4, 0x4c, 0x52, 0x6c, 0xff, 0x85, 0x3f, 0xc2, 0x83, 0x07, 0x7f, 0x88, 0xc7, - 0xc5, 0x93, 0x47, 0x69, 0xff, 0x88, 0x4c, 0xba, 0xd3, 0x9d, 0xb2, 0xed, 0xdd, 0x83, 0xb7, 0xbc, - 0xef, 0x4b, 0xbe, 0xc7, 0xf7, 0xbd, 0x37, 0x03, 0x54, 0xe2, 0xac, 0x27, 0x8c, 0x76, 0x39, 0x17, - 0x2e, 0x9e, 0xe4, 0xc6, 0x19, 0xca, 0x2c, 0x2a, 0x7f, 0x12, 0x66, 0x1c, 0x5b, 0x54, 0x62, 0xc4, - 0x95, 0x8e, 0x25, 0xce, 0xa2, 0x6f, 0x7b, 0xd0, 0x3e, 0x3d, 0xbf, 0x3c, 0xd0, 0x9f, 0x0c, 0xed, - 0x40, 0x43, 0x18, 0x89, 0x03, 0xc9, 0x48, 0x48, 0xba, 0xfb, 0xc9, 0x79, 0x45, 0x23, 0x68, 0x97, - 0xa2, 0xcf, 0xa4, 0xcc, 0xd9, 0x5e, 0x48, 0xba, 0xad, 0x64, 0x03, 0xa3, 0xb7, 0xa1, 0xa9, 0x11, - 0xe5, 0x4b, 0x63, 0x3e, 0xb3, 0x7a, 0x48, 0xba, 0xcd, 0x64, 0x5d, 0xd3, 0xfb, 0x70, 0xa3, 0x38, - 0xbf, 0xc9, 0x25, 0xe6, 0xaf, 0xb9, 0x13, 0x23, 0xa5, 0x53, 0xb6, 0xef, 0x2f, 0x5d, 0x26, 0xe8, - 0x3b, 0x68, 0x4b, 0x9c, 0xa0, 0x96, 0xa8, 0x85, 0x42, 0xcb, 0xae, 0x84, 0xf5, 0xee, 0xe1, 0xf1, - 0x83, 0x78, 0x97, 0x8f, 0xb8, 0xf4, 0xd0, 0x2f, 0x5f, 0xcd, 0x0b, 0x37, 0xc9, 0x86, 0x0a, 0x7d, - 0x02, 0xb7, 0xf4, 0x34, 0x1b, 0x68, 0x61, 0x32, 0xa5, 0xd3, 0x7e, 0xb5, 0x41, 0x23, 0x24, 0xdd, - 0x7a, 0xb2, 0x8b, 0x8e, 0x7e, 0xd4, 0xe1, 0x5a, 0x35, 0xa6, 0xf7, 0xc7, 0xff, 0x83, 0xda, 0x46, - 0x53, 0x06, 0x07, 0x22, 0x47, 0xee, 0x4c, 0xce, 0x0e, 0xbc, 0xf1, 0xb2, 0xa4, 0x21, 0x1c, 0xe6, - 0xa8, 0xdd, 0x09, 0x1f, 0x73, 0x2d, 0x90, 0x35, 0x7d, 0x68, 0x55, 0x88, 0xde, 0x81, 0x96, 0x9d, - 0x5a, 0x2f, 0x26, 0x59, 0xcb, 0x3b, 0xbe, 0x00, 0xe8, 0x3d, 0xb8, 0xbe, 0x2a, 0xac, 0x32, 0x3a, - 0x41, 0x6e, 0x8d, 0x66, 0xe0, 0x5b, 0x5c, 0xc2, 0xa3, 0xef, 0x04, 0x3a, 0xdb, 0x8d, 0xd2, 0x00, - 0x60, 0x6d, 0x75, 0xee, 0x47, 0xd7, 0x4a, 0x2a, 0x08, 0x7d, 0x04, 0x37, 0x55, 0x96, 0xa1, 0x54, - 0xdc, 0xe1, 0xf3, 0xb1, 0xc4, 0xfc, 0xad, 0x1a, 0x8e, 0x8b, 0x11, 0xac, 0xe6, 0xb8, 0x9d, 0x2c, - 0x02, 0x5b, 0x13, 0x1f, 0xcc, 0x54, 0xa7, 0x17, 0xef, 0xea, 0xfe, 0xdd, 0x2e, 0x3a, 0xfa, 0x45, - 0x80, 0xbe, 0xc2, 0x94, 0x8b, 0xf9, 0x3f, 0xf8, 0x19, 0x3e, 0x86, 0x4e, 0x19, 0x8d, 0x3b, 0xad, - 0xb4, 0x58, 0xed, 0x59, 0x2b, 0xd9, 0xc1, 0x46, 0x4f, 0x81, 0xf6, 0xcd, 0x17, 0x6d, 0x1d, 0xf2, - 0xac, 0x64, 0x2c, 0xbd, 0x0b, 0x57, 0xc5, 0x86, 0x08, 0xf1, 0x22, 0x9b, 0xe0, 0xc9, 0x8b, 0x9f, - 0x8b, 0x80, 0x9c, 0x2d, 0x02, 0xf2, 0x67, 0x11, 0x90, 0xaf, 0xcb, 0xa0, 0x76, 0xb6, 0x0c, 0x6a, - 0xbf, 0x97, 0x41, 0xed, 0xe3, 0x51, 0xaa, 0xdc, 0x68, 0x3a, 0x8c, 0x85, 0xc9, 0x7a, 0x16, 0xd5, - 0x51, 0xb9, 0xe0, 0xbe, 0xf0, 0x1b, 0xde, 0x9b, 0xf5, 0x8a, 0xbf, 0x9f, 0x9b, 0x4f, 0xd0, 0x0e, - 0x1b, 0x9e, 0x7f, 0xf8, 0x37, 0x00, 0x00, 0xff, 0xff, 0x37, 0xae, 0xf3, 0x6f, 0x11, 0x05, 0x00, - 0x00, -} - -func (m *ContractInfo) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *ContractInfo) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *ContractInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.NumIncomingDependencies != 0 { - i = encodeVarintContract(dAtA, i, uint64(m.NumIncomingDependencies)) - i-- - dAtA[i] = 0x30 - } - if len(m.Dependencies) > 0 { - for iNdEx := len(m.Dependencies) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Dependencies[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintContract(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x2a - } - } - if m.NeedOrderMatching { - i-- - if m.NeedOrderMatching { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i-- - dAtA[i] = 0x20 - } - if m.NeedHook { - i-- - if m.NeedHook { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i-- - dAtA[i] = 0x18 - } - if len(m.ContractAddr) > 0 { - i -= len(m.ContractAddr) - copy(dAtA[i:], m.ContractAddr) - i = encodeVarintContract(dAtA, i, uint64(len(m.ContractAddr))) - i-- - dAtA[i] = 0x12 - } - if m.CodeId != 0 { - i = encodeVarintContract(dAtA, i, uint64(m.CodeId)) - i-- - dAtA[i] = 0x8 - } - return len(dAtA) - i, nil -} - -func (m *ContractInfoV2) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *ContractInfoV2) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *ContractInfoV2) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.SuspensionReason) > 0 { - i -= len(m.SuspensionReason) - copy(dAtA[i:], m.SuspensionReason) - i = encodeVarintContract(dAtA, i, uint64(len(m.SuspensionReason))) - i-- - dAtA[i] = 0x52 - } - if m.Suspended { - i-- - if m.Suspended { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i-- - dAtA[i] = 0x48 - } - if m.RentBalance != 0 { - i = encodeVarintContract(dAtA, i, uint64(m.RentBalance)) - i-- - dAtA[i] = 0x40 - } - if len(m.Creator) > 0 { - i -= len(m.Creator) - copy(dAtA[i:], m.Creator) - i = encodeVarintContract(dAtA, i, uint64(len(m.Creator))) - i-- - dAtA[i] = 0x3a - } - if m.NumIncomingDependencies != 0 { - i = encodeVarintContract(dAtA, i, uint64(m.NumIncomingDependencies)) - i-- - dAtA[i] = 0x30 - } - if len(m.Dependencies) > 0 { - for iNdEx := len(m.Dependencies) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Dependencies[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintContract(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x2a - } - } - if m.NeedOrderMatching { - i-- - if m.NeedOrderMatching { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i-- - dAtA[i] = 0x20 - } - if m.NeedHook { - i-- - if m.NeedHook { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i-- - dAtA[i] = 0x18 - } - if len(m.ContractAddr) > 0 { - i -= len(m.ContractAddr) - copy(dAtA[i:], m.ContractAddr) - i = encodeVarintContract(dAtA, i, uint64(len(m.ContractAddr))) - i-- - dAtA[i] = 0x12 - } - if m.CodeId != 0 { - i = encodeVarintContract(dAtA, i, uint64(m.CodeId)) - i-- - dAtA[i] = 0x8 - } - return len(dAtA) - i, nil -} - -func (m *ContractDependencyInfo) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *ContractDependencyInfo) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *ContractDependencyInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.ImmediateYoungerSibling) > 0 { - i -= len(m.ImmediateYoungerSibling) - copy(dAtA[i:], m.ImmediateYoungerSibling) - i = encodeVarintContract(dAtA, i, uint64(len(m.ImmediateYoungerSibling))) - i-- - dAtA[i] = 0x1a - } - if len(m.ImmediateElderSibling) > 0 { - i -= len(m.ImmediateElderSibling) - copy(dAtA[i:], m.ImmediateElderSibling) - i = encodeVarintContract(dAtA, i, uint64(len(m.ImmediateElderSibling))) - i-- - dAtA[i] = 0x12 - } - if len(m.Dependency) > 0 { - i -= len(m.Dependency) - copy(dAtA[i:], m.Dependency) - i = encodeVarintContract(dAtA, i, uint64(len(m.Dependency))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *LegacyContractInfo) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *LegacyContractInfo) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *LegacyContractInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.DependentContractAddrs) > 0 { - for iNdEx := len(m.DependentContractAddrs) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.DependentContractAddrs[iNdEx]) - copy(dAtA[i:], m.DependentContractAddrs[iNdEx]) - i = encodeVarintContract(dAtA, i, uint64(len(m.DependentContractAddrs[iNdEx]))) - i-- - dAtA[i] = 0x2a - } - } - if m.NeedOrderMatching { - i-- - if m.NeedOrderMatching { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i-- - dAtA[i] = 0x20 - } - if m.NeedHook { - i-- - if m.NeedHook { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i-- - dAtA[i] = 0x18 - } - if len(m.ContractAddr) > 0 { - i -= len(m.ContractAddr) - copy(dAtA[i:], m.ContractAddr) - i = encodeVarintContract(dAtA, i, uint64(len(m.ContractAddr))) - i-- - dAtA[i] = 0x12 - } - if m.CodeId != 0 { - i = encodeVarintContract(dAtA, i, uint64(m.CodeId)) - i-- - dAtA[i] = 0x8 - } - return len(dAtA) - i, nil -} - -func (m *DownsteamContracts) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *DownsteamContracts) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *DownsteamContracts) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.ContractAddrs) > 0 { - for iNdEx := len(m.ContractAddrs) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.ContractAddrs[iNdEx]) - copy(dAtA[i:], m.ContractAddrs[iNdEx]) - i = encodeVarintContract(dAtA, i, uint64(len(m.ContractAddrs[iNdEx]))) - i-- - dAtA[i] = 0xa - } - } - return len(dAtA) - i, nil -} - -func encodeVarintContract(dAtA []byte, offset int, v uint64) int { - offset -= sovContract(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *ContractInfo) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.CodeId != 0 { - n += 1 + sovContract(uint64(m.CodeId)) - } - l = len(m.ContractAddr) - if l > 0 { - n += 1 + l + sovContract(uint64(l)) - } - if m.NeedHook { - n += 2 - } - if m.NeedOrderMatching { - n += 2 - } - if len(m.Dependencies) > 0 { - for _, e := range m.Dependencies { - l = e.Size() - n += 1 + l + sovContract(uint64(l)) - } - } - if m.NumIncomingDependencies != 0 { - n += 1 + sovContract(uint64(m.NumIncomingDependencies)) - } - return n -} - -func (m *ContractInfoV2) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.CodeId != 0 { - n += 1 + sovContract(uint64(m.CodeId)) - } - l = len(m.ContractAddr) - if l > 0 { - n += 1 + l + sovContract(uint64(l)) - } - if m.NeedHook { - n += 2 - } - if m.NeedOrderMatching { - n += 2 - } - if len(m.Dependencies) > 0 { - for _, e := range m.Dependencies { - l = e.Size() - n += 1 + l + sovContract(uint64(l)) - } - } - if m.NumIncomingDependencies != 0 { - n += 1 + sovContract(uint64(m.NumIncomingDependencies)) - } - l = len(m.Creator) - if l > 0 { - n += 1 + l + sovContract(uint64(l)) - } - if m.RentBalance != 0 { - n += 1 + sovContract(uint64(m.RentBalance)) - } - if m.Suspended { - n += 2 - } - l = len(m.SuspensionReason) - if l > 0 { - n += 1 + l + sovContract(uint64(l)) - } - return n -} - -func (m *ContractDependencyInfo) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Dependency) - if l > 0 { - n += 1 + l + sovContract(uint64(l)) - } - l = len(m.ImmediateElderSibling) - if l > 0 { - n += 1 + l + sovContract(uint64(l)) - } - l = len(m.ImmediateYoungerSibling) - if l > 0 { - n += 1 + l + sovContract(uint64(l)) - } - return n -} - -func (m *LegacyContractInfo) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.CodeId != 0 { - n += 1 + sovContract(uint64(m.CodeId)) - } - l = len(m.ContractAddr) - if l > 0 { - n += 1 + l + sovContract(uint64(l)) - } - if m.NeedHook { - n += 2 - } - if m.NeedOrderMatching { - n += 2 - } - if len(m.DependentContractAddrs) > 0 { - for _, s := range m.DependentContractAddrs { - l = len(s) - n += 1 + l + sovContract(uint64(l)) - } - } - return n -} - -func (m *DownsteamContracts) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if len(m.ContractAddrs) > 0 { - for _, s := range m.ContractAddrs { - l = len(s) - n += 1 + l + sovContract(uint64(l)) - } - } - return n -} - -func sovContract(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozContract(x uint64) (n int) { - return sovContract(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *ContractInfo) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowContract - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: ContractInfo: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: ContractInfo: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field CodeId", wireType) - } - m.CodeId = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowContract - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.CodeId |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractAddr", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowContract - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthContract - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthContract - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ContractAddr = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field NeedHook", wireType) - } - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowContract - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.NeedHook = bool(v != 0) - case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field NeedOrderMatching", wireType) - } - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowContract - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.NeedOrderMatching = bool(v != 0) - case 5: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Dependencies", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowContract - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthContract - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthContract - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Dependencies = append(m.Dependencies, &ContractDependencyInfo{}) - if err := m.Dependencies[len(m.Dependencies)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 6: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field NumIncomingDependencies", wireType) - } - m.NumIncomingDependencies = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowContract - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.NumIncomingDependencies |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipContract(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthContract - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *ContractInfoV2) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowContract - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: ContractInfoV2: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: ContractInfoV2: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field CodeId", wireType) - } - m.CodeId = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowContract - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.CodeId |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractAddr", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowContract - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthContract - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthContract - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ContractAddr = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field NeedHook", wireType) - } - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowContract - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.NeedHook = bool(v != 0) - case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field NeedOrderMatching", wireType) - } - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowContract - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.NeedOrderMatching = bool(v != 0) - case 5: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Dependencies", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowContract - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthContract - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthContract - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Dependencies = append(m.Dependencies, &ContractDependencyInfo{}) - if err := m.Dependencies[len(m.Dependencies)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 6: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field NumIncomingDependencies", wireType) - } - m.NumIncomingDependencies = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowContract - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.NumIncomingDependencies |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 7: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowContract - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthContract - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthContract - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Creator = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 8: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field RentBalance", wireType) - } - m.RentBalance = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowContract - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.RentBalance |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 9: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Suspended", wireType) - } - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowContract - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.Suspended = bool(v != 0) - case 10: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field SuspensionReason", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowContract - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthContract - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthContract - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.SuspensionReason = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipContract(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthContract - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *ContractDependencyInfo) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowContract - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: ContractDependencyInfo: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: ContractDependencyInfo: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Dependency", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowContract - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthContract - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthContract - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Dependency = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ImmediateElderSibling", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowContract - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthContract - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthContract - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ImmediateElderSibling = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ImmediateYoungerSibling", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowContract - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthContract - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthContract - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ImmediateYoungerSibling = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipContract(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthContract - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *LegacyContractInfo) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowContract - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: LegacyContractInfo: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: LegacyContractInfo: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field CodeId", wireType) - } - m.CodeId = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowContract - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.CodeId |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractAddr", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowContract - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthContract - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthContract - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ContractAddr = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field NeedHook", wireType) - } - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowContract - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.NeedHook = bool(v != 0) - case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field NeedOrderMatching", wireType) - } - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowContract - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.NeedOrderMatching = bool(v != 0) - case 5: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field DependentContractAddrs", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowContract - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthContract - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthContract - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.DependentContractAddrs = append(m.DependentContractAddrs, string(dAtA[iNdEx:postIndex])) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipContract(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthContract - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *DownsteamContracts) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowContract - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: DownsteamContracts: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: DownsteamContracts: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractAddrs", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowContract - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthContract - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthContract - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ContractAddrs = append(m.ContractAddrs, string(dAtA[iNdEx:postIndex])) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipContract(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthContract - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipContract(dAtA []byte) (n int, err error) { - l := len(dAtA) - iNdEx := 0 - depth := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowContract - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowContract - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - iNdEx++ - if dAtA[iNdEx-1] < 0x80 { - break - } - } - case 1: - iNdEx += 8 - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowContract - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if length < 0 { - return 0, ErrInvalidLengthContract - } - iNdEx += length - case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupContract - } - depth-- - case 5: - iNdEx += 4 - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - if iNdEx < 0 { - return 0, ErrInvalidLengthContract - } - if depth == 0 { - return iNdEx, nil - } - } - return 0, io.ErrUnexpectedEOF -} - -var ( - ErrInvalidLengthContract = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowContract = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupContract = fmt.Errorf("proto: unexpected end of group") -) diff --git a/x/dex/types/deposit.go b/x/dex/types/deposit.go deleted file mode 100644 index 3479571ad..000000000 --- a/x/dex/types/deposit.go +++ /dev/null @@ -1,19 +0,0 @@ -package types - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" -) - -type ContractDepositInfo struct { - Account string `json:"account"` - Denom string `json:"denom"` - Amount sdk.Dec `json:"amount"` -} - -func (d *DepositInfoEntry) ToContractDepositInfo() ContractDepositInfo { - return ContractDepositInfo{ - Account: d.Creator, - Denom: d.Denom, - Amount: d.Amount, - } -} diff --git a/x/dex/types/deposit.pb.go b/x/dex/types/deposit.pb.go deleted file mode 100644 index fbdaff23c..000000000 --- a/x/dex/types/deposit.pb.go +++ /dev/null @@ -1,422 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: dex/deposit.proto - -package types - -import ( - fmt "fmt" - github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" - _ "github.com/gogo/protobuf/gogoproto" - proto "github.com/gogo/protobuf/proto" - io "io" - math "math" - math_bits "math/bits" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package - -type DepositInfoEntry struct { - Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator"` - Denom string `protobuf:"bytes,2,opt,name=denom,proto3" json:"denom"` - Amount github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,3,opt,name=amount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"amount" yaml:"amount"` -} - -func (m *DepositInfoEntry) Reset() { *m = DepositInfoEntry{} } -func (m *DepositInfoEntry) String() string { return proto.CompactTextString(m) } -func (*DepositInfoEntry) ProtoMessage() {} -func (*DepositInfoEntry) Descriptor() ([]byte, []int) { - return fileDescriptor_93caea15661b640e, []int{0} -} -func (m *DepositInfoEntry) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *DepositInfoEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_DepositInfoEntry.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *DepositInfoEntry) XXX_Merge(src proto.Message) { - xxx_messageInfo_DepositInfoEntry.Merge(m, src) -} -func (m *DepositInfoEntry) XXX_Size() int { - return m.Size() -} -func (m *DepositInfoEntry) XXX_DiscardUnknown() { - xxx_messageInfo_DepositInfoEntry.DiscardUnknown(m) -} - -var xxx_messageInfo_DepositInfoEntry proto.InternalMessageInfo - -func (m *DepositInfoEntry) GetCreator() string { - if m != nil { - return m.Creator - } - return "" -} - -func (m *DepositInfoEntry) GetDenom() string { - if m != nil { - return m.Denom - } - return "" -} - -func init() { - proto.RegisterType((*DepositInfoEntry)(nil), "seiprotocol.seichain.dex.DepositInfoEntry") -} - -func init() { proto.RegisterFile("dex/deposit.proto", fileDescriptor_93caea15661b640e) } - -var fileDescriptor_93caea15661b640e = []byte{ - // 273 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x4c, 0x50, 0x3f, 0x4b, 0xfb, 0x40, - 0x18, 0xce, 0xfd, 0x7e, 0x58, 0x69, 0x44, 0xd0, 0xe0, 0x10, 0x1c, 0xee, 0x24, 0xa0, 0xb8, 0x24, - 0x19, 0xdc, 0x1c, 0x4b, 0x45, 0xba, 0x66, 0x74, 0x4b, 0x2f, 0xaf, 0xe9, 0x61, 0x93, 0x37, 0xe4, - 0xae, 0x90, 0x7c, 0x0b, 0xbf, 0x90, 0x7b, 0xc7, 0x8e, 0xe2, 0x70, 0x48, 0xb2, 0x65, 0xf4, 0x13, - 0x48, 0xef, 0x12, 0x70, 0x7a, 0x9f, 0x7f, 0x77, 0x0f, 0x3c, 0xee, 0x65, 0x06, 0x4d, 0x9c, 0x41, - 0x85, 0x52, 0xa8, 0xa8, 0xaa, 0x51, 0xa1, 0xe7, 0x4b, 0x10, 0x06, 0x71, 0xdc, 0x46, 0x12, 0x04, - 0xdf, 0xa4, 0xa2, 0x8c, 0x32, 0x68, 0xae, 0xaf, 0x72, 0xcc, 0xd1, 0x58, 0xf1, 0x11, 0xd9, 0x7c, - 0xf0, 0x41, 0xdc, 0x8b, 0xa5, 0xfd, 0x61, 0x55, 0xbe, 0xe2, 0x53, 0xa9, 0xea, 0xd6, 0xbb, 0x75, - 0x4f, 0x79, 0x0d, 0xa9, 0xc2, 0xda, 0x27, 0x37, 0xe4, 0x7e, 0xbe, 0x38, 0x1b, 0x34, 0x9b, 0xa4, - 0x64, 0x02, 0x1e, 0x73, 0x4f, 0x32, 0x28, 0xb1, 0xf0, 0xff, 0x99, 0xd0, 0x7c, 0xd0, 0xcc, 0x0a, - 0x89, 0x3d, 0x5e, 0xea, 0xce, 0xd2, 0x02, 0x77, 0xa5, 0xf2, 0xff, 0x9b, 0xc4, 0x6a, 0xaf, 0x99, - 0xf3, 0xa5, 0xd9, 0x5d, 0x2e, 0xd4, 0x66, 0xb7, 0x8e, 0x38, 0x16, 0x31, 0x47, 0x59, 0xa0, 0x1c, - 0x4f, 0x28, 0xb3, 0xb7, 0x58, 0xb5, 0x15, 0xc8, 0x68, 0x09, 0x7c, 0xd0, 0x6c, 0x7c, 0xff, 0xa3, - 0xd9, 0x79, 0x9b, 0x16, 0xdb, 0xc7, 0xc0, 0xf2, 0x20, 0x19, 0x8d, 0xc5, 0xf3, 0xbe, 0xa3, 0xe4, - 0xd0, 0x51, 0xf2, 0xdd, 0x51, 0xf2, 0xde, 0x53, 0xe7, 0xd0, 0x53, 0xe7, 0xb3, 0xa7, 0xce, 0x4b, - 0xf8, 0xa7, 0x44, 0x82, 0x08, 0xa7, 0x55, 0x0c, 0x31, 0xb3, 0xc4, 0xc7, 0xf1, 0x1a, 0xdb, 0xb7, - 0x9e, 0x19, 0xff, 0xe1, 0x37, 0x00, 0x00, 0xff, 0xff, 0x06, 0xf6, 0x98, 0x0a, 0x54, 0x01, 0x00, - 0x00, -} - -func (m *DepositInfoEntry) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *DepositInfoEntry) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *DepositInfoEntry) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - { - size := m.Amount.Size() - i -= size - if _, err := m.Amount.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintDeposit(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x1a - if len(m.Denom) > 0 { - i -= len(m.Denom) - copy(dAtA[i:], m.Denom) - i = encodeVarintDeposit(dAtA, i, uint64(len(m.Denom))) - i-- - dAtA[i] = 0x12 - } - if len(m.Creator) > 0 { - i -= len(m.Creator) - copy(dAtA[i:], m.Creator) - i = encodeVarintDeposit(dAtA, i, uint64(len(m.Creator))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func encodeVarintDeposit(dAtA []byte, offset int, v uint64) int { - offset -= sovDeposit(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *DepositInfoEntry) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Creator) - if l > 0 { - n += 1 + l + sovDeposit(uint64(l)) - } - l = len(m.Denom) - if l > 0 { - n += 1 + l + sovDeposit(uint64(l)) - } - l = m.Amount.Size() - n += 1 + l + sovDeposit(uint64(l)) - return n -} - -func sovDeposit(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozDeposit(x uint64) (n int) { - return sovDeposit(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *DepositInfoEntry) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowDeposit - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: DepositInfoEntry: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: DepositInfoEntry: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowDeposit - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthDeposit - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthDeposit - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Creator = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowDeposit - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthDeposit - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthDeposit - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Denom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowDeposit - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthDeposit - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthDeposit - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipDeposit(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthDeposit - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipDeposit(dAtA []byte) (n int, err error) { - l := len(dAtA) - iNdEx := 0 - depth := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowDeposit - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowDeposit - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - iNdEx++ - if dAtA[iNdEx-1] < 0x80 { - break - } - } - case 1: - iNdEx += 8 - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowDeposit - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if length < 0 { - return 0, ErrInvalidLengthDeposit - } - iNdEx += length - case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupDeposit - } - depth-- - case 5: - iNdEx += 4 - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - if iNdEx < 0 { - return 0, ErrInvalidLengthDeposit - } - if depth == 0 { - return iNdEx, nil - } - } - return 0, io.ErrUnexpectedEOF -} - -var ( - ErrInvalidLengthDeposit = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowDeposit = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupDeposit = fmt.Errorf("proto: unexpected end of group") -) diff --git a/x/dex/types/enums.go b/x/dex/types/enums.go deleted file mode 100644 index 0ac28ea0e..000000000 --- a/x/dex/types/enums.go +++ /dev/null @@ -1,29 +0,0 @@ -package types - -import ( - "fmt" - "strings" -) - -func GetPositionEffectFromStr(str string) (PositionEffect, error) { - val, err := getEnumFromStr(str, PositionEffect_value) - return PositionEffect(val), err -} - -func GetPositionDirectionFromStr(str string) (PositionDirection, error) { - val, err := getEnumFromStr(str, PositionDirection_value) - return PositionDirection(val), err -} - -func GetOrderTypeFromStr(str string) (OrderType, error) { - val, err := getEnumFromStr(str, OrderType_value) - return OrderType(val), err -} - -func getEnumFromStr(str string, enumMap map[string]int32) (int32, error) { - upperStr := strings.ToUpper(str) - if val, ok := enumMap[upperStr]; ok { - return val, nil - } - return 0, fmt.Errorf("unknown enum literal: %s", str) -} diff --git a/x/dex/types/enums.pb.go b/x/dex/types/enums.pb.go deleted file mode 100644 index 97464194a..000000000 --- a/x/dex/types/enums.pb.go +++ /dev/null @@ -1,235 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: dex/enums.proto - -package types - -import ( - fmt "fmt" - proto "github.com/gogo/protobuf/proto" - math "math" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package - -type PositionDirection int32 - -const ( - PositionDirection_LONG PositionDirection = 0 - PositionDirection_SHORT PositionDirection = 1 -) - -var PositionDirection_name = map[int32]string{ - 0: "LONG", - 1: "SHORT", -} - -var PositionDirection_value = map[string]int32{ - "LONG": 0, - "SHORT": 1, -} - -func (x PositionDirection) String() string { - return proto.EnumName(PositionDirection_name, int32(x)) -} - -func (PositionDirection) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_b8c5bb23c6eb0b88, []int{0} -} - -type PositionEffect int32 - -const ( - PositionEffect_OPEN PositionEffect = 0 - PositionEffect_CLOSE PositionEffect = 1 -) - -var PositionEffect_name = map[int32]string{ - 0: "OPEN", - 1: "CLOSE", -} - -var PositionEffect_value = map[string]int32{ - "OPEN": 0, - "CLOSE": 1, -} - -func (x PositionEffect) String() string { - return proto.EnumName(PositionEffect_name, int32(x)) -} - -func (PositionEffect) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_b8c5bb23c6eb0b88, []int{1} -} - -type OrderType int32 - -const ( - OrderType_LIMIT OrderType = 0 - OrderType_MARKET OrderType = 1 - OrderType_FOKMARKET OrderType = 3 - OrderType_FOKMARKETBYVALUE OrderType = 4 - OrderType_STOPLOSS OrderType = 5 - OrderType_STOPLIMIT OrderType = 6 -) - -var OrderType_name = map[int32]string{ - 0: "LIMIT", - 1: "MARKET", - 3: "FOKMARKET", - 4: "FOKMARKETBYVALUE", - 5: "STOPLOSS", - 6: "STOPLIMIT", -} - -var OrderType_value = map[string]int32{ - "LIMIT": 0, - "MARKET": 1, - "FOKMARKET": 3, - "FOKMARKETBYVALUE": 4, - "STOPLOSS": 5, - "STOPLIMIT": 6, -} - -func (x OrderType) String() string { - return proto.EnumName(OrderType_name, int32(x)) -} - -func (OrderType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_b8c5bb23c6eb0b88, []int{2} -} - -type Unit int32 - -const ( - Unit_STANDARD Unit = 0 - Unit_MILLI Unit = 1 - Unit_MICRO Unit = 2 - Unit_NANO Unit = 3 -) - -var Unit_name = map[int32]string{ - 0: "STANDARD", - 1: "MILLI", - 2: "MICRO", - 3: "NANO", -} - -var Unit_value = map[string]int32{ - "STANDARD": 0, - "MILLI": 1, - "MICRO": 2, - "NANO": 3, -} - -func (x Unit) String() string { - return proto.EnumName(Unit_name, int32(x)) -} - -func (Unit) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_b8c5bb23c6eb0b88, []int{3} -} - -type OrderStatus int32 - -const ( - OrderStatus_PLACED OrderStatus = 0 - OrderStatus_FAILED_TO_PLACE OrderStatus = 1 - OrderStatus_CANCELLED OrderStatus = 2 - OrderStatus_FULFILLED OrderStatus = 3 -) - -var OrderStatus_name = map[int32]string{ - 0: "PLACED", - 1: "FAILED_TO_PLACE", - 2: "CANCELLED", - 3: "FULFILLED", -} - -var OrderStatus_value = map[string]int32{ - "PLACED": 0, - "FAILED_TO_PLACE": 1, - "CANCELLED": 2, - "FULFILLED": 3, -} - -func (x OrderStatus) String() string { - return proto.EnumName(OrderStatus_name, int32(x)) -} - -func (OrderStatus) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_b8c5bb23c6eb0b88, []int{4} -} - -type CancellationInitiator int32 - -const ( - CancellationInitiator_USER CancellationInitiator = 0 - CancellationInitiator_LIQUIDATED CancellationInitiator = 1 -) - -var CancellationInitiator_name = map[int32]string{ - 0: "USER", - 1: "LIQUIDATED", -} - -var CancellationInitiator_value = map[string]int32{ - "USER": 0, - "LIQUIDATED": 1, -} - -func (x CancellationInitiator) String() string { - return proto.EnumName(CancellationInitiator_name, int32(x)) -} - -func (CancellationInitiator) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_b8c5bb23c6eb0b88, []int{5} -} - -func init() { - proto.RegisterEnum("seiprotocol.seichain.dex.PositionDirection", PositionDirection_name, PositionDirection_value) - proto.RegisterEnum("seiprotocol.seichain.dex.PositionEffect", PositionEffect_name, PositionEffect_value) - proto.RegisterEnum("seiprotocol.seichain.dex.OrderType", OrderType_name, OrderType_value) - proto.RegisterEnum("seiprotocol.seichain.dex.Unit", Unit_name, Unit_value) - proto.RegisterEnum("seiprotocol.seichain.dex.OrderStatus", OrderStatus_name, OrderStatus_value) - proto.RegisterEnum("seiprotocol.seichain.dex.CancellationInitiator", CancellationInitiator_name, CancellationInitiator_value) -} - -func init() { proto.RegisterFile("dex/enums.proto", fileDescriptor_b8c5bb23c6eb0b88) } - -var fileDescriptor_b8c5bb23c6eb0b88 = []byte{ - // 394 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x3c, 0x91, 0xdf, 0x6e, 0xd3, 0x30, - 0x18, 0xc5, 0xe3, 0xb5, 0xab, 0xd6, 0x0f, 0xd8, 0x8c, 0x01, 0x89, 0xab, 0xdc, 0x21, 0xa1, 0x48, - 0x6b, 0x84, 0xe0, 0x05, 0xbc, 0xc4, 0x1d, 0xd6, 0xdc, 0x38, 0xe4, 0x0f, 0x12, 0xdc, 0x4c, 0x59, - 0xe2, 0x31, 0x4b, 0x5d, 0x52, 0x25, 0xae, 0xd4, 0xbd, 0x05, 0x8f, 0xc5, 0xe5, 0x2e, 0xb9, 0x44, - 0xed, 0x8b, 0x20, 0x3b, 0x8c, 0xbb, 0x73, 0x3e, 0x9f, 0xcf, 0xfe, 0xc9, 0x07, 0xce, 0x1a, 0xb5, - 0x0b, 0x55, 0xbb, 0xbd, 0x1f, 0x16, 0x9b, 0xbe, 0x33, 0x1d, 0x79, 0x3b, 0x28, 0xed, 0x54, 0xdd, - 0xad, 0x17, 0x83, 0xd2, 0xf5, 0x5d, 0xa5, 0xdb, 0x45, 0xa3, 0x76, 0xc1, 0x7b, 0x78, 0x99, 0x76, - 0x83, 0x36, 0xba, 0x6b, 0x63, 0xdd, 0xab, 0xda, 0x0a, 0x72, 0x02, 0x53, 0x21, 0x93, 0x4b, 0xec, - 0x91, 0x39, 0x1c, 0xe7, 0x9f, 0x65, 0x56, 0x60, 0x14, 0xbc, 0x83, 0xd3, 0xa7, 0x24, 0xbb, 0xbd, - 0x55, 0xb5, 0xb1, 0x31, 0x99, 0xb2, 0x64, 0x8c, 0x45, 0x42, 0xe6, 0x0c, 0xa3, 0xa0, 0x81, 0xb9, - 0xec, 0x1b, 0xd5, 0x17, 0x0f, 0x1b, 0x65, 0xe7, 0x82, 0xaf, 0x78, 0x81, 0x3d, 0x02, 0x30, 0x5b, - 0xd1, 0xec, 0x8a, 0x15, 0x18, 0x91, 0x17, 0x30, 0x5f, 0xca, 0xab, 0x7f, 0x76, 0x42, 0x5e, 0x03, - 0xfe, 0x6f, 0x2f, 0xbe, 0x7d, 0xa5, 0xa2, 0x64, 0x78, 0x4a, 0x9e, 0xc3, 0x49, 0x5e, 0xc8, 0x54, - 0xc8, 0x3c, 0xc7, 0xc7, 0x76, 0xc5, 0x39, 0x77, 0xdb, 0x2c, 0xf8, 0x04, 0xd3, 0xb2, 0xd5, 0x66, - 0x0c, 0xd1, 0x24, 0xa6, 0x59, 0x3c, 0x62, 0xac, 0xb8, 0x10, 0x1c, 0xa3, 0x51, 0x46, 0x99, 0xc4, - 0x47, 0x16, 0x33, 0xa1, 0x89, 0xc4, 0x93, 0x40, 0xc0, 0x33, 0xc7, 0x96, 0x9b, 0xca, 0x6c, 0x07, - 0x8b, 0x94, 0x0a, 0x1a, 0x31, 0xbb, 0xfa, 0x0a, 0xce, 0x96, 0x94, 0x0b, 0x16, 0x5f, 0x17, 0xf2, - 0xda, 0x4d, 0x47, 0xce, 0x88, 0x26, 0x11, 0x13, 0x82, 0xc5, 0xf8, 0xc8, 0x61, 0x97, 0x62, 0xc9, - 0x9d, 0x9d, 0x04, 0x1f, 0xe0, 0x4d, 0x54, 0xb5, 0xb5, 0x5a, 0xaf, 0x2b, 0xfb, 0x29, 0xbc, 0xd5, - 0x46, 0x57, 0xa6, 0xeb, 0xed, 0x83, 0x65, 0xce, 0x32, 0xec, 0x91, 0x53, 0x00, 0xc1, 0xbf, 0x94, - 0x3c, 0xa6, 0x05, 0x8b, 0x31, 0xba, 0xb8, 0xfc, 0xb5, 0xf7, 0xd1, 0xe3, 0xde, 0x47, 0x7f, 0xf6, - 0x3e, 0xfa, 0x79, 0xf0, 0xbd, 0xc7, 0x83, 0xef, 0xfd, 0x3e, 0xf8, 0xde, 0xf7, 0xf3, 0x1f, 0xda, - 0xdc, 0x6d, 0x6f, 0x16, 0x75, 0x77, 0x1f, 0x0e, 0x4a, 0x9f, 0x3f, 0xb5, 0xe5, 0x8c, 0xab, 0x2b, - 0xdc, 0x85, 0xb6, 0x56, 0xf3, 0xb0, 0x51, 0xc3, 0xcd, 0xcc, 0x9d, 0x7f, 0xfc, 0x1b, 0x00, 0x00, - 0xff, 0xff, 0x40, 0x7d, 0x48, 0x4c, 0xea, 0x01, 0x00, 0x00, -} diff --git a/x/dex/types/enums_test.go b/x/dex/types/enums_test.go deleted file mode 100644 index 1f8d1515b..000000000 --- a/x/dex/types/enums_test.go +++ /dev/null @@ -1,53 +0,0 @@ -package types_test - -import ( - "testing" - - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestGetPositionEffectFromStr(t *testing.T) { - effect := "Close" - expected := types.PositionEffect_CLOSE - actual, err := types.GetPositionEffectFromStr(effect) - - require.Nil(t, err) - require.Equal(t, expected, actual) - - // unidentified effect - effect = "invalid_effect" - _, err = types.GetPositionEffectFromStr(effect) - - require.NotNil(t, err) -} - -func TestGetPositionDirectionFromStr(t *testing.T) { - direction := "Long" - expected := types.PositionDirection_LONG - actual, err := types.GetPositionDirectionFromStr(direction) - - require.Nil(t, err) - require.Equal(t, expected, actual) - - // unidentified direction - direction = "invalid_direction" - _, err = types.GetPositionEffectFromStr(direction) - - require.NotNil(t, err) -} - -func TestGetOrderTypeFromStr(t *testing.T) { - orderType := "Market" - expected := types.OrderType_MARKET - actual, err := types.GetOrderTypeFromStr(orderType) - - require.Nil(t, err) - require.Equal(t, expected, actual) - - // unidentified direction - orderType = "invalid" - _, err = types.GetPositionEffectFromStr(orderType) - - require.NotNil(t, err) -} diff --git a/x/dex/types/errors.go b/x/dex/types/errors.go deleted file mode 100644 index ecdd0253d..000000000 --- a/x/dex/types/errors.go +++ /dev/null @@ -1,28 +0,0 @@ -package types - -// DONTCOVER - -import ( - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" -) - -// x/dex module sentinel errors -var ( - ErrEncodeDexPlaceOrders = sdkerrors.Register(ModuleName, 2, "Error while encoding dex order placement msg in wasmd") - ErrEncodeDexCancelOrders = sdkerrors.Register(ModuleName, 3, "Error while encoding dex order cancellation msg in wasmd") - ErrParsingSeiDexQuery = sdkerrors.Register(ModuleName, 4, "Error parsing SeiDexQuery") - ErrEncodingDexTwaps = sdkerrors.Register(ModuleName, 6, "Error encoding dex twaps as JSON") - ErrEncodingOrders = sdkerrors.Register(ModuleName, 8, "Error encoding orders as JSON") - ErrEncodingOrder = sdkerrors.Register(ModuleName, 10, "Error encoding order as JSON") - ErrEncodingOrderSimulation = sdkerrors.Register(ModuleName, 12, "Error encoding order simulation as JSON") - ErrInvalidOrderID = sdkerrors.Register(ModuleName, 13, "Error order id not found") - ErrEncodingLatestPrice = sdkerrors.Register(ModuleName, 14, "Error encoding latest price as JSON") - ErrUnknownSeiDexQuery = sdkerrors.Register(ModuleName, 15, "Error unknown sei dex query") - ErrPairNotRegistered = sdkerrors.Register(ModuleName, 16, "pair is not registered") - ErrContractNotExists = sdkerrors.Register(ModuleName, 17, "Error finding contract info") - ErrParsingContractInfo = sdkerrors.Register(ModuleName, 18, "Error parsing contract info") - ErrInsufficientRent = sdkerrors.Register(ModuleName, 19, "Error contract does not have sufficient fee") - ErrCircularContractDependency = sdkerrors.Register(ModuleName, 1103, "circular contract dependency detected") - ErrContractSuspended = sdkerrors.Register(ModuleName, 1104, "contract suspended") - ErrContractNotSuspended = sdkerrors.Register(ModuleName, 1105, "contract not suspended") -) diff --git a/x/dex/types/events.go b/x/dex/types/events.go deleted file mode 100644 index a4a34ae5d..000000000 --- a/x/dex/types/events.go +++ /dev/null @@ -1,21 +0,0 @@ -package types - -const ( - EventTypePlaceOrder = "place_order" - EventTypeCancelOrder = "cancel_order" - EventTypeDepositRent = "deposit_rent" - EventTypeRegisterContract = "register_contract" - EventTypeUnregisterContract = "unregister_contract" - EventTypeRegisterPair = "register_pair" - EventTypeSetQuantityTickSize = "set_quantity_tick_size" - EventTypeSetPriceTickSize = "set_price_tick_size" - - AttributeKeyOrderID = "order_id" - AttributeKeyCancellationID = "cancellation_id" - AttributeKeyContractAddress = "contract_address" - AttributeKeyRentBalance = "rent_balance" - AttributeKeyPriceDenom = "price_denom" - AttributeKeyAssetDenom = "asset_denom" - - AttributeValueCategory = ModuleName -) diff --git a/x/dex/types/expected_keepers.go b/x/dex/types/expected_keepers.go deleted file mode 100644 index 6aa6e9778..000000000 --- a/x/dex/types/expected_keepers.go +++ /dev/null @@ -1,18 +0,0 @@ -package types - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth/types" -) - -// AccountKeeper defines the expected account keeper used for simulations (noalias) -type AccountKeeper interface { - GetAccount(ctx sdk.Context, addr sdk.AccAddress) types.AccountI - // Methods imported from account should be defined here -} - -// BankKeeper defines the expected interface needed to retrieve account balances. -type BankKeeper interface { - SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins - // Methods imported from bank should be defined here -} diff --git a/x/dex/types/genesis.go b/x/dex/types/genesis.go deleted file mode 100644 index 9c8f79642..000000000 --- a/x/dex/types/genesis.go +++ /dev/null @@ -1,75 +0,0 @@ -package types - -import ( - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// DefaultGenesis returns the default Capability genesis state -func DefaultGenesis() *GenesisState { - return &GenesisState{ - Params: DefaultParams(), - ContractState: []ContractState{}, - } -} - -// Validate performs basic genesis state validation returning an error upon any -// failure. -func (gs GenesisState) Validate() error { - paramErr := gs.Params.Validate() - if paramErr != nil { - return paramErr - } - for _, cs := range gs.ContractState { - csErr := cs.Validate() - if csErr != nil { - return csErr - } - } - return nil -} - -func (cs ContractState) Validate() error { - if len(cs.ContractInfo.ContractAddr) == 0 { - return fmt.Errorf("empty contract addr") - } - if _, err := sdk.AccAddressFromBech32(cs.ContractInfo.ContractAddr); err != nil { - return fmt.Errorf("contract address is invalid") - } - // Check for duplicated price in a single market - // Can only be a one price per pair per contract - type MarketPrice struct { - priceDenom string - assetDenom string - price uint64 - } - - // Check for duplication in longbook - longBookPriceMap := make(map[MarketPrice]struct{}) - for _, elem := range cs.LongBookList { - priceElem := MarketPrice{ - priceDenom: elem.Entry.PriceDenom, - assetDenom: elem.Entry.AssetDenom, - price: elem.Price.BigInt().Uint64(), - } - if _, ok := longBookPriceMap[priceElem]; ok { - return fmt.Errorf("duplicated price for longBook") - } - longBookPriceMap[priceElem] = struct{}{} - } - // Check for duplication in shortbook - shortBookPriceMap := make(map[MarketPrice]struct{}) - for _, elem := range cs.ShortBookList { - priceElem := MarketPrice{ - priceDenom: elem.Entry.PriceDenom, - assetDenom: elem.Entry.AssetDenom, - price: elem.Price.BigInt().Uint64(), - } - if _, ok := shortBookPriceMap[priceElem]; ok { - return fmt.Errorf("duplicated price for shortBook") - } - shortBookPriceMap[priceElem] = struct{}{} - } - return nil -} diff --git a/x/dex/types/genesis.pb.go b/x/dex/types/genesis.pb.go deleted file mode 100644 index 4bd5241f6..000000000 --- a/x/dex/types/genesis.pb.go +++ /dev/null @@ -1,1188 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: dex/genesis.proto - -package types - -import ( - fmt "fmt" - _ "github.com/gogo/protobuf/gogoproto" - proto "github.com/gogo/protobuf/proto" - io "io" - math "math" - math_bits "math/bits" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package - -// GenesisState defines the dex module's genesis state. -type GenesisState struct { - Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` - ContractState []ContractState `protobuf:"bytes,2,rep,name=contractState,proto3" json:"contractState"` - LastEpoch uint64 `protobuf:"varint,3,opt,name=lastEpoch,proto3" json:"lastEpoch,omitempty"` -} - -func (m *GenesisState) Reset() { *m = GenesisState{} } -func (m *GenesisState) String() string { return proto.CompactTextString(m) } -func (*GenesisState) ProtoMessage() {} -func (*GenesisState) Descriptor() ([]byte, []int) { - return fileDescriptor_a803aaabd08db59d, []int{0} -} -func (m *GenesisState) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *GenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_GenesisState.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *GenesisState) XXX_Merge(src proto.Message) { - xxx_messageInfo_GenesisState.Merge(m, src) -} -func (m *GenesisState) XXX_Size() int { - return m.Size() -} -func (m *GenesisState) XXX_DiscardUnknown() { - xxx_messageInfo_GenesisState.DiscardUnknown(m) -} - -var xxx_messageInfo_GenesisState proto.InternalMessageInfo - -func (m *GenesisState) GetParams() Params { - if m != nil { - return m.Params - } - return Params{} -} - -func (m *GenesisState) GetContractState() []ContractState { - if m != nil { - return m.ContractState - } - return nil -} - -func (m *GenesisState) GetLastEpoch() uint64 { - if m != nil { - return m.LastEpoch - } - return 0 -} - -type ContractState struct { - ContractInfo ContractInfoV2 `protobuf:"bytes,1,opt,name=contractInfo,proto3" json:"contractInfo"` - LongBookList []LongBook `protobuf:"bytes,2,rep,name=longBookList,proto3" json:"longBookList"` - ShortBookList []ShortBook `protobuf:"bytes,3,rep,name=shortBookList,proto3" json:"shortBookList"` - TriggeredOrdersList []Order `protobuf:"bytes,4,rep,name=triggeredOrdersList,proto3" json:"triggeredOrdersList"` - PairList []Pair `protobuf:"bytes,5,rep,name=pairList,proto3" json:"pairList"` - PriceList []ContractPairPrices `protobuf:"bytes,6,rep,name=priceList,proto3" json:"priceList"` - NextOrderId uint64 `protobuf:"varint,7,opt,name=nextOrderId,proto3" json:"nextOrderId,omitempty"` -} - -func (m *ContractState) Reset() { *m = ContractState{} } -func (m *ContractState) String() string { return proto.CompactTextString(m) } -func (*ContractState) ProtoMessage() {} -func (*ContractState) Descriptor() ([]byte, []int) { - return fileDescriptor_a803aaabd08db59d, []int{1} -} -func (m *ContractState) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *ContractState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_ContractState.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *ContractState) XXX_Merge(src proto.Message) { - xxx_messageInfo_ContractState.Merge(m, src) -} -func (m *ContractState) XXX_Size() int { - return m.Size() -} -func (m *ContractState) XXX_DiscardUnknown() { - xxx_messageInfo_ContractState.DiscardUnknown(m) -} - -var xxx_messageInfo_ContractState proto.InternalMessageInfo - -func (m *ContractState) GetContractInfo() ContractInfoV2 { - if m != nil { - return m.ContractInfo - } - return ContractInfoV2{} -} - -func (m *ContractState) GetLongBookList() []LongBook { - if m != nil { - return m.LongBookList - } - return nil -} - -func (m *ContractState) GetShortBookList() []ShortBook { - if m != nil { - return m.ShortBookList - } - return nil -} - -func (m *ContractState) GetTriggeredOrdersList() []Order { - if m != nil { - return m.TriggeredOrdersList - } - return nil -} - -func (m *ContractState) GetPairList() []Pair { - if m != nil { - return m.PairList - } - return nil -} - -func (m *ContractState) GetPriceList() []ContractPairPrices { - if m != nil { - return m.PriceList - } - return nil -} - -func (m *ContractState) GetNextOrderId() uint64 { - if m != nil { - return m.NextOrderId - } - return 0 -} - -type ContractPairPrices struct { - PricePair Pair `protobuf:"bytes,1,opt,name=pricePair,proto3" json:"pricePair"` - Prices []*Price `protobuf:"bytes,2,rep,name=prices,proto3" json:"prices,omitempty"` -} - -func (m *ContractPairPrices) Reset() { *m = ContractPairPrices{} } -func (m *ContractPairPrices) String() string { return proto.CompactTextString(m) } -func (*ContractPairPrices) ProtoMessage() {} -func (*ContractPairPrices) Descriptor() ([]byte, []int) { - return fileDescriptor_a803aaabd08db59d, []int{2} -} -func (m *ContractPairPrices) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *ContractPairPrices) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_ContractPairPrices.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *ContractPairPrices) XXX_Merge(src proto.Message) { - xxx_messageInfo_ContractPairPrices.Merge(m, src) -} -func (m *ContractPairPrices) XXX_Size() int { - return m.Size() -} -func (m *ContractPairPrices) XXX_DiscardUnknown() { - xxx_messageInfo_ContractPairPrices.DiscardUnknown(m) -} - -var xxx_messageInfo_ContractPairPrices proto.InternalMessageInfo - -func (m *ContractPairPrices) GetPricePair() Pair { - if m != nil { - return m.PricePair - } - return Pair{} -} - -func (m *ContractPairPrices) GetPrices() []*Price { - if m != nil { - return m.Prices - } - return nil -} - -func init() { - proto.RegisterType((*GenesisState)(nil), "seiprotocol.seichain.dex.GenesisState") - proto.RegisterType((*ContractState)(nil), "seiprotocol.seichain.dex.ContractState") - proto.RegisterType((*ContractPairPrices)(nil), "seiprotocol.seichain.dex.ContractPairPrices") -} - -func init() { proto.RegisterFile("dex/genesis.proto", fileDescriptor_a803aaabd08db59d) } - -var fileDescriptor_a803aaabd08db59d = []byte{ - // 497 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x93, 0x4f, 0x6f, 0xd3, 0x30, - 0x18, 0xc6, 0x1b, 0x5a, 0x0a, 0x73, 0x5b, 0xfe, 0x78, 0x3b, 0x44, 0x15, 0xca, 0xa2, 0x72, 0xa0, - 0x07, 0x96, 0x48, 0xe5, 0xc0, 0x0d, 0xa1, 0x22, 0x34, 0x4d, 0xaa, 0xb4, 0xaa, 0x95, 0x40, 0xe2, - 0x82, 0xd2, 0xc4, 0xa4, 0xd6, 0xba, 0xbc, 0x91, 0x6d, 0xa4, 0xf2, 0x2d, 0xd8, 0x47, 0xe2, 0xb6, - 0xe3, 0x8e, 0x9c, 0x10, 0x6a, 0xbf, 0x08, 0xf2, 0x1b, 0x7b, 0x4d, 0x04, 0x59, 0xb9, 0xc5, 0x8f, - 0x9f, 0xf7, 0xe7, 0xf7, 0xb5, 0x9f, 0x90, 0xa7, 0x09, 0x5b, 0x87, 0x29, 0xcb, 0x98, 0xe4, 0x32, - 0xc8, 0x05, 0x28, 0xa0, 0xae, 0x64, 0x1c, 0xbf, 0x62, 0x58, 0x05, 0x92, 0xf1, 0x78, 0x19, 0xf1, - 0x2c, 0x48, 0xd8, 0xba, 0x7f, 0x94, 0x42, 0x0a, 0xb8, 0x15, 0xea, 0xaf, 0xc2, 0xdf, 0x7f, 0xa2, - 0x11, 0x79, 0x24, 0xa2, 0x4b, 0x43, 0xe8, 0x1f, 0x6a, 0x65, 0x05, 0x59, 0xfa, 0x79, 0x01, 0x70, - 0x61, 0xc4, 0x23, 0x2d, 0xca, 0x25, 0x08, 0x55, 0x56, 0x1f, 0x6b, 0x15, 0x44, 0xc2, 0x84, 0x11, - 0xa8, 0x16, 0x62, 0xc8, 0x94, 0x88, 0x62, 0x65, 0xb4, 0x47, 0xc5, 0x09, 0x5c, 0x94, 0x8b, 0x72, - 0xc1, 0x63, 0x56, 0x08, 0x83, 0x1f, 0x0e, 0xe9, 0x9e, 0x16, 0x43, 0xcc, 0x55, 0xa4, 0x18, 0x7d, - 0x43, 0xda, 0x45, 0x47, 0xae, 0xe3, 0x3b, 0xc3, 0xce, 0xc8, 0x0f, 0xea, 0x86, 0x0a, 0xa6, 0xe8, - 0x1b, 0xb7, 0xae, 0x7f, 0x1d, 0x37, 0x66, 0xa6, 0x8a, 0xce, 0x49, 0xcf, 0xf6, 0x80, 0x40, 0xf7, - 0x9e, 0xdf, 0x1c, 0x76, 0x46, 0x2f, 0xea, 0x31, 0xef, 0xca, 0x76, 0x43, 0xab, 0x32, 0xe8, 0x33, - 0x72, 0xb0, 0x8a, 0xa4, 0x7a, 0x9f, 0x43, 0xbc, 0x74, 0x9b, 0xbe, 0x33, 0x6c, 0xcd, 0x76, 0xc2, - 0xe0, 0xaa, 0x45, 0x7a, 0x15, 0x08, 0x9d, 0x91, 0xae, 0x05, 0x9c, 0x65, 0x5f, 0xc0, 0x8c, 0x32, - 0xdc, 0xdf, 0x83, 0x76, 0x7f, 0x18, 0x99, 0x26, 0x2a, 0x0c, 0x3a, 0x21, 0x5d, 0xfd, 0x30, 0x63, - 0x80, 0x8b, 0x09, 0x97, 0xca, 0xcc, 0x35, 0xa8, 0x67, 0x4e, 0x8c, 0xdb, 0xd2, 0xca, 0xd5, 0xf4, - 0x9c, 0xf4, 0xf0, 0x45, 0x6f, 0x71, 0x4d, 0xc4, 0x3d, 0xaf, 0xc7, 0xcd, 0xad, 0xdd, 0x5e, 0x51, - 0xa5, 0x9e, 0x7e, 0x24, 0x87, 0x4a, 0xf0, 0x34, 0x65, 0x82, 0x25, 0xe7, 0x3a, 0x15, 0x12, 0xb1, - 0x2d, 0xc4, 0x1e, 0xd7, 0x63, 0xd1, 0x6b, 0x90, 0xff, 0x22, 0xd0, 0xb7, 0xe4, 0xa1, 0x0e, 0x10, - 0xd2, 0xee, 0x23, 0xcd, 0xbb, 0x2b, 0x12, 0xdc, 0xc2, 0x6e, 0xab, 0xe8, 0x94, 0x1c, 0x60, 0xe4, - 0x10, 0xd1, 0x46, 0xc4, 0xcb, 0xfd, 0x4f, 0xa1, 0x51, 0x53, 0x5d, 0x66, 0x13, 0xb6, 0x83, 0x50, - 0x9f, 0x74, 0x32, 0xb6, 0x56, 0xd8, 0xe5, 0x59, 0xe2, 0x3e, 0xc0, 0x44, 0x94, 0xa5, 0xc1, 0x95, - 0x43, 0xe8, 0xdf, 0x24, 0x3a, 0x36, 0xad, 0x68, 0xc9, 0xa4, 0xe2, 0xff, 0xa6, 0xd9, 0x95, 0xd1, - 0xd7, 0xa4, 0x8d, 0x0b, 0x69, 0x22, 0x70, 0xc7, 0xe5, 0xe2, 0xa9, 0x33, 0x63, 0x1f, 0x9f, 0x5e, - 0x6f, 0x3c, 0xe7, 0x66, 0xe3, 0x39, 0xbf, 0x37, 0x9e, 0xf3, 0x7d, 0xeb, 0x35, 0x6e, 0xb6, 0x5e, - 0xe3, 0xe7, 0xd6, 0x6b, 0x7c, 0x3a, 0x49, 0xb9, 0x5a, 0x7e, 0x5d, 0x04, 0x31, 0x5c, 0x86, 0x92, - 0xf1, 0x13, 0x4b, 0xc3, 0x05, 0xe2, 0xc2, 0x75, 0xa8, 0x7f, 0x5d, 0xf5, 0x2d, 0x67, 0x72, 0xd1, - 0xc6, 0xfd, 0x57, 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, 0x8f, 0x4d, 0x7c, 0x7f, 0x83, 0x04, 0x00, - 0x00, -} - -func (m *GenesisState) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *GenesisState) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.LastEpoch != 0 { - i = encodeVarintGenesis(dAtA, i, uint64(m.LastEpoch)) - i-- - dAtA[i] = 0x18 - } - if len(m.ContractState) > 0 { - for iNdEx := len(m.ContractState) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.ContractState[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenesis(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - } - } - { - size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenesis(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil -} - -func (m *ContractState) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *ContractState) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *ContractState) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.NextOrderId != 0 { - i = encodeVarintGenesis(dAtA, i, uint64(m.NextOrderId)) - i-- - dAtA[i] = 0x38 - } - if len(m.PriceList) > 0 { - for iNdEx := len(m.PriceList) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.PriceList[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenesis(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x32 - } - } - if len(m.PairList) > 0 { - for iNdEx := len(m.PairList) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.PairList[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenesis(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x2a - } - } - if len(m.TriggeredOrdersList) > 0 { - for iNdEx := len(m.TriggeredOrdersList) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.TriggeredOrdersList[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenesis(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x22 - } - } - if len(m.ShortBookList) > 0 { - for iNdEx := len(m.ShortBookList) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.ShortBookList[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenesis(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x1a - } - } - if len(m.LongBookList) > 0 { - for iNdEx := len(m.LongBookList) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.LongBookList[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenesis(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - } - } - { - size, err := m.ContractInfo.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenesis(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil -} - -func (m *ContractPairPrices) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *ContractPairPrices) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *ContractPairPrices) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Prices) > 0 { - for iNdEx := len(m.Prices) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Prices[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenesis(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - } - } - { - size, err := m.PricePair.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenesis(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil -} - -func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { - offset -= sovGenesis(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *GenesisState) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = m.Params.Size() - n += 1 + l + sovGenesis(uint64(l)) - if len(m.ContractState) > 0 { - for _, e := range m.ContractState { - l = e.Size() - n += 1 + l + sovGenesis(uint64(l)) - } - } - if m.LastEpoch != 0 { - n += 1 + sovGenesis(uint64(m.LastEpoch)) - } - return n -} - -func (m *ContractState) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = m.ContractInfo.Size() - n += 1 + l + sovGenesis(uint64(l)) - if len(m.LongBookList) > 0 { - for _, e := range m.LongBookList { - l = e.Size() - n += 1 + l + sovGenesis(uint64(l)) - } - } - if len(m.ShortBookList) > 0 { - for _, e := range m.ShortBookList { - l = e.Size() - n += 1 + l + sovGenesis(uint64(l)) - } - } - if len(m.TriggeredOrdersList) > 0 { - for _, e := range m.TriggeredOrdersList { - l = e.Size() - n += 1 + l + sovGenesis(uint64(l)) - } - } - if len(m.PairList) > 0 { - for _, e := range m.PairList { - l = e.Size() - n += 1 + l + sovGenesis(uint64(l)) - } - } - if len(m.PriceList) > 0 { - for _, e := range m.PriceList { - l = e.Size() - n += 1 + l + sovGenesis(uint64(l)) - } - } - if m.NextOrderId != 0 { - n += 1 + sovGenesis(uint64(m.NextOrderId)) - } - return n -} - -func (m *ContractPairPrices) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = m.PricePair.Size() - n += 1 + l + sovGenesis(uint64(l)) - if len(m.Prices) > 0 { - for _, e := range m.Prices { - l = e.Size() - n += 1 + l + sovGenesis(uint64(l)) - } - } - return n -} - -func sovGenesis(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozGenesis(x uint64) (n int) { - return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *GenesisState) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: GenesisState: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthGenesis - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenesis - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractState", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthGenesis - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenesis - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ContractState = append(m.ContractState, ContractState{}) - if err := m.ContractState[len(m.ContractState)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field LastEpoch", wireType) - } - m.LastEpoch = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.LastEpoch |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipGenesis(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthGenesis - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *ContractState) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: ContractState: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: ContractState: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractInfo", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthGenesis - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenesis - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.ContractInfo.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field LongBookList", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthGenesis - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenesis - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.LongBookList = append(m.LongBookList, LongBook{}) - if err := m.LongBookList[len(m.LongBookList)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ShortBookList", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthGenesis - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenesis - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ShortBookList = append(m.ShortBookList, ShortBook{}) - if err := m.ShortBookList[len(m.ShortBookList)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field TriggeredOrdersList", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthGenesis - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenesis - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.TriggeredOrdersList = append(m.TriggeredOrdersList, Order{}) - if err := m.TriggeredOrdersList[len(m.TriggeredOrdersList)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 5: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PairList", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthGenesis - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenesis - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.PairList = append(m.PairList, Pair{}) - if err := m.PairList[len(m.PairList)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 6: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PriceList", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthGenesis - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenesis - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.PriceList = append(m.PriceList, ContractPairPrices{}) - if err := m.PriceList[len(m.PriceList)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 7: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field NextOrderId", wireType) - } - m.NextOrderId = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.NextOrderId |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipGenesis(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthGenesis - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *ContractPairPrices) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: ContractPairPrices: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: ContractPairPrices: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PricePair", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthGenesis - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenesis - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.PricePair.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Prices", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthGenesis - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenesis - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Prices = append(m.Prices, &Price{}) - if err := m.Prices[len(m.Prices)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipGenesis(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthGenesis - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipGenesis(dAtA []byte) (n int, err error) { - l := len(dAtA) - iNdEx := 0 - depth := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowGenesis - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowGenesis - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - iNdEx++ - if dAtA[iNdEx-1] < 0x80 { - break - } - } - case 1: - iNdEx += 8 - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowGenesis - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if length < 0 { - return 0, ErrInvalidLengthGenesis - } - iNdEx += length - case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupGenesis - } - depth-- - case 5: - iNdEx += 4 - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - if iNdEx < 0 { - return 0, ErrInvalidLengthGenesis - } - if depth == 0 { - return iNdEx, nil - } - } - return 0, io.ErrUnexpectedEOF -} - -var ( - ErrInvalidLengthGenesis = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowGenesis = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupGenesis = fmt.Errorf("proto: unexpected end of group") -) diff --git a/x/dex/types/genesis_test.go b/x/dex/types/genesis_test.go deleted file mode 100644 index 49384da41..000000000 --- a/x/dex/types/genesis_test.go +++ /dev/null @@ -1,228 +0,0 @@ -package types_test - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestGenesisState_Validate(t *testing.T) { - for _, tc := range []struct { - desc string - genState *types.GenesisState - valid bool - }{ - { - desc: "default is valid", - genState: types.DefaultGenesis(), - valid: true, - }, - { - desc: "valid genesis state", - genState: &types.GenesisState{ - Params: types.DefaultParams(), - ContractState: []types.ContractState{ - { - LongBookList: []types.LongBook{ - { - Price: sdk.NewDec(0), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(0), - PriceDenom: "SEI", - AssetDenom: "ATOM", - }, - }, - { - Price: sdk.NewDec(1), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(0), - PriceDenom: "SEI", - AssetDenom: "ATOM", - }, - }, - }, - ShortBookList: []types.ShortBook{ - { - Price: sdk.NewDec(0), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(0), - PriceDenom: "SEI", - AssetDenom: "ATOM", - }, - }, - { - Price: sdk.NewDec(1), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(0), - PriceDenom: "SEI", - AssetDenom: "ATOM", - }, - }, - }, - ContractInfo: types.ContractInfoV2{ - CodeId: uint64(1), - ContractAddr: "sei14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sh9m79m", - }, - }, - }, - // this line is used by starport scaffolding # types/genesis/validField - }, - valid: true, - }, - { - desc: "same price multiple markets", - genState: &types.GenesisState{ - Params: types.DefaultParams(), - ContractState: []types.ContractState{ - { - LongBookList: []types.LongBook{ - { - Price: sdk.NewDec(0), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(0), - PriceDenom: "SEI", - AssetDenom: "ATOM", - }, - }, - { - Price: sdk.NewDec(0), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(0), - PriceDenom: "USDC", - AssetDenom: "ATOM", - }, - }, - }, - ShortBookList: []types.ShortBook{ - { - Price: sdk.NewDec(0), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(0), - PriceDenom: "SEI", - AssetDenom: "ATOM", - }, - }, - { - Price: sdk.NewDec(1), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(0), - PriceDenom: "SEI", - AssetDenom: "ATOM", - }, - }, - }, - ContractInfo: types.ContractInfoV2{ - CodeId: uint64(1), - ContractAddr: "sei14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sh9m79m", - }, - }, - }, - // this line is used by starport scaffolding # types/genesis/validField - }, - valid: true, - }, - { - desc: "duplicated longBook", - genState: &types.GenesisState{ - Params: types.DefaultParams(), - ContractState: []types.ContractState{ - { - LongBookList: []types.LongBook{ - { - Price: sdk.NewDec(0), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(0), - PriceDenom: "SEI", - AssetDenom: "ATOM", - }, - }, - { - Price: sdk.NewDec(0), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(0), - PriceDenom: "SEI", - AssetDenom: "ATOM", - }, - }, - }, - ContractInfo: types.ContractInfoV2{ - CodeId: uint64(1), - ContractAddr: "sei14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sh9m79m", - }, - }, - }, - }, - valid: false, - }, - { - desc: "duplicated shortBook", - genState: &types.GenesisState{ - Params: types.DefaultParams(), - ContractState: []types.ContractState{ - { - ShortBookList: []types.ShortBook{ - { - Price: sdk.NewDec(0), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(0), - PriceDenom: "SEI", - AssetDenom: "ATOM", - }, - }, - { - Price: sdk.NewDec(0), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(0), - PriceDenom: "SEI", - AssetDenom: "ATOM", - }, - }, - }, - ContractInfo: types.ContractInfoV2{ - CodeId: uint64(1), - ContractAddr: "sei14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sh9m79m", - }, - }, - }, - }, - valid: false, - }, - { - desc: "invalid contract addr", - genState: &types.GenesisState{ - Params: types.DefaultParams(), - ContractState: []types.ContractState{ - { - ShortBookList: []types.ShortBook{ - { - Price: sdk.NewDec(0), - Entry: &types.OrderEntry{ - Price: sdk.NewDec(0), - PriceDenom: "SEI", - AssetDenom: "ATOM", - }, - }, - }, - ContractInfo: types.ContractInfoV2{ - CodeId: uint64(1), - ContractAddr: "invalid", - }, - }, - }, - }, - valid: false, - }, - // this line is used by starport scaffolding # types/genesis/testcase - } { - t.Run(tc.desc, func(t *testing.T) { - err := tc.genState.Validate() - if tc.valid { - require.NoError(t, err) - } else { - require.Error(t, err) - } - }) - } -} diff --git a/x/dex/types/gov.go b/x/dex/types/gov.go deleted file mode 100644 index 72cd85c4c..000000000 --- a/x/dex/types/gov.go +++ /dev/null @@ -1,57 +0,0 @@ -package types - -import ( - "fmt" - "strings" - - sdk "github.com/cosmos/cosmos-sdk/types" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" -) - -const ( - ProposalTypeAddAssetMetadata = "AddAssetMetadata" -) - -func init() { - // for routing - govtypes.RegisterProposalType(ProposalTypeAddAssetMetadata) - // for marshal and unmarshal - govtypes.RegisterProposalTypeCodec(&AddAssetMetadataProposal{}, "dex/AddAssetMetadataProposal") -} - -func (p *AddAssetMetadataProposal) GetTitle() string { return p.Title } - -func (p *AddAssetMetadataProposal) GetDescription() string { return p.Description } - -func (p *AddAssetMetadataProposal) ProposalRoute() string { return RouterKey } - -func (p *AddAssetMetadataProposal) ProposalType() string { - return ProposalTypeAddAssetMetadata -} - -func (p *AddAssetMetadataProposal) ValidateBasic() error { - // Verify base denoms specified in proposal are well formed - for _, asset := range p.AssetList { - err := sdk.ValidateDenom(asset.Metadata.Base) - if err != nil { - return err - } - } - - err := govtypes.ValidateAbstract(p) - return err -} - -func (p AddAssetMetadataProposal) String() string { - assetRecords := "" - for _, asset := range p.AssetList { - assetRecords += asset.String() - } - var b strings.Builder - b.WriteString(fmt.Sprintf(`Add Asset Metadata Proposal: - Title: %s - Description: %s - Records: %s -`, p.Title, p.Description, assetRecords)) - return b.String() -} diff --git a/x/dex/types/gov.pb.go b/x/dex/types/gov.pb.go deleted file mode 100644 index cbfe56b15..000000000 --- a/x/dex/types/gov.pb.go +++ /dev/null @@ -1,418 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: dex/gov.proto - -package types - -import ( - fmt "fmt" - _ "github.com/gogo/protobuf/gogoproto" - proto "github.com/gogo/protobuf/proto" - io "io" - math "math" - math_bits "math/bits" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package - -// AddAssetMetadataProposal is a gov Content type for adding a new asset -// to the dex module's asset list. -type AddAssetMetadataProposal struct { - Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty" yaml:"title"` - Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty" yaml:"description"` - AssetList []AssetMetadata `protobuf:"bytes,3,rep,name=assetList,proto3" json:"assetList" yaml:"asset_list"` -} - -func (m *AddAssetMetadataProposal) Reset() { *m = AddAssetMetadataProposal{} } -func (*AddAssetMetadataProposal) ProtoMessage() {} -func (*AddAssetMetadataProposal) Descriptor() ([]byte, []int) { - return fileDescriptor_dab07ca1a96062d0, []int{0} -} -func (m *AddAssetMetadataProposal) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *AddAssetMetadataProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_AddAssetMetadataProposal.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *AddAssetMetadataProposal) XXX_Merge(src proto.Message) { - xxx_messageInfo_AddAssetMetadataProposal.Merge(m, src) -} -func (m *AddAssetMetadataProposal) XXX_Size() int { - return m.Size() -} -func (m *AddAssetMetadataProposal) XXX_DiscardUnknown() { - xxx_messageInfo_AddAssetMetadataProposal.DiscardUnknown(m) -} - -var xxx_messageInfo_AddAssetMetadataProposal proto.InternalMessageInfo - -func init() { - proto.RegisterType((*AddAssetMetadataProposal)(nil), "seiprotocol.seichain.dex.AddAssetMetadataProposal") -} - -func init() { proto.RegisterFile("dex/gov.proto", fileDescriptor_dab07ca1a96062d0) } - -var fileDescriptor_dab07ca1a96062d0 = []byte{ - // 307 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4d, 0x49, 0xad, 0xd0, - 0x4f, 0xcf, 0x2f, 0xd3, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x92, 0x28, 0x4e, 0xcd, 0x04, 0xb3, - 0x92, 0xf3, 0x73, 0xf4, 0x8a, 0x53, 0x33, 0x93, 0x33, 0x12, 0x33, 0xf3, 0xf4, 0x52, 0x52, 0x2b, - 0xa4, 0x44, 0xd2, 0xf3, 0xd3, 0xf3, 0xc1, 0x52, 0xfa, 0x20, 0x16, 0x44, 0xbd, 0x94, 0x08, 0x48, - 0x7b, 0x62, 0x71, 0x71, 0x6a, 0x49, 0x7c, 0x4e, 0x66, 0x71, 0x09, 0x44, 0x54, 0xe9, 0x0d, 0x23, - 0x97, 0x84, 0x63, 0x4a, 0x8a, 0x23, 0x48, 0xdc, 0x37, 0xb5, 0x24, 0x31, 0x25, 0xb1, 0x24, 0x31, - 0xa0, 0x28, 0xbf, 0x20, 0xbf, 0x38, 0x31, 0x47, 0x48, 0x8d, 0x8b, 0xb5, 0x24, 0xb3, 0x24, 0x27, - 0x55, 0x82, 0x51, 0x81, 0x51, 0x83, 0xd3, 0x49, 0xe0, 0xd3, 0x3d, 0x79, 0x9e, 0xca, 0xc4, 0xdc, - 0x1c, 0x2b, 0x25, 0xb0, 0xb0, 0x52, 0x10, 0x44, 0x5a, 0xc8, 0x82, 0x8b, 0x3b, 0x25, 0xb5, 0x38, - 0xb9, 0x28, 0xb3, 0xa0, 0x24, 0x33, 0x3f, 0x4f, 0x82, 0x09, 0xac, 0x5a, 0xec, 0xd3, 0x3d, 0x79, - 0x21, 0x88, 0x6a, 0x24, 0x49, 0xa5, 0x20, 0x64, 0xa5, 0x42, 0x09, 0x5c, 0x9c, 0x60, 0x27, 0xf9, - 0x64, 0x16, 0x97, 0x48, 0x30, 0x2b, 0x30, 0x6b, 0x70, 0x1b, 0xa9, 0xeb, 0xe1, 0xf2, 0x98, 0x1e, - 0x8a, 0x2b, 0x9d, 0x24, 0x4f, 0xdc, 0x93, 0x67, 0xf8, 0x74, 0x4f, 0x5e, 0x10, 0x62, 0x09, 0xc2, - 0x6b, 0x4a, 0x41, 0x08, 0x43, 0xad, 0x78, 0x3a, 0x16, 0xc8, 0x33, 0xcc, 0x58, 0x20, 0xcf, 0xf0, - 0x62, 0x81, 0x3c, 0x83, 0x93, 0xfb, 0x89, 0x47, 0x72, 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e, 0x78, - 0x24, 0xc7, 0x38, 0xe1, 0xb1, 0x1c, 0xc3, 0x85, 0xc7, 0x72, 0x0c, 0x37, 0x1e, 0xcb, 0x31, 0x44, - 0xe9, 0xa6, 0x67, 0x96, 0x64, 0x94, 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0xea, 0x17, 0xa7, 0x66, 0xea, - 0xc2, 0x5c, 0x00, 0xe6, 0x80, 0x9d, 0xa0, 0x5f, 0xa1, 0x0f, 0x0a, 0xc2, 0x92, 0xca, 0x82, 0xd4, - 0xe2, 0x24, 0x36, 0xb0, 0xbc, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0xce, 0xe9, 0x08, 0x1a, 0x95, - 0x01, 0x00, 0x00, -} - -func (m *AddAssetMetadataProposal) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *AddAssetMetadataProposal) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *AddAssetMetadataProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.AssetList) > 0 { - for iNdEx := len(m.AssetList) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.AssetList[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGov(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x1a - } - } - if len(m.Description) > 0 { - i -= len(m.Description) - copy(dAtA[i:], m.Description) - i = encodeVarintGov(dAtA, i, uint64(len(m.Description))) - i-- - dAtA[i] = 0x12 - } - if len(m.Title) > 0 { - i -= len(m.Title) - copy(dAtA[i:], m.Title) - i = encodeVarintGov(dAtA, i, uint64(len(m.Title))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func encodeVarintGov(dAtA []byte, offset int, v uint64) int { - offset -= sovGov(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *AddAssetMetadataProposal) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Title) - if l > 0 { - n += 1 + l + sovGov(uint64(l)) - } - l = len(m.Description) - if l > 0 { - n += 1 + l + sovGov(uint64(l)) - } - if len(m.AssetList) > 0 { - for _, e := range m.AssetList { - l = e.Size() - n += 1 + l + sovGov(uint64(l)) - } - } - return n -} - -func sovGov(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozGov(x uint64) (n int) { - return sovGov(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *AddAssetMetadataProposal) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGov - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: AddAssetMetadataProposal: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: AddAssetMetadataProposal: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Title", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGov - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthGov - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGov - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Title = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGov - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthGov - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGov - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Description = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field AssetList", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGov - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthGov - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGov - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.AssetList = append(m.AssetList, AssetMetadata{}) - if err := m.AssetList[len(m.AssetList)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipGov(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthGov - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipGov(dAtA []byte) (n int, err error) { - l := len(dAtA) - iNdEx := 0 - depth := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowGov - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowGov - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - iNdEx++ - if dAtA[iNdEx-1] < 0x80 { - break - } - } - case 1: - iNdEx += 8 - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowGov - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if length < 0 { - return 0, ErrInvalidLengthGov - } - iNdEx += length - case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupGov - } - depth-- - case 5: - iNdEx += 4 - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - if iNdEx < 0 { - return 0, ErrInvalidLengthGov - } - if depth == 0 { - return iNdEx, nil - } - } - return 0, io.ErrUnexpectedEOF -} - -var ( - ErrInvalidLengthGov = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowGov = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupGov = fmt.Errorf("proto: unexpected end of group") -) diff --git a/x/dex/types/keys.go b/x/dex/types/keys.go deleted file mode 100644 index c56c1be90..000000000 --- a/x/dex/types/keys.go +++ /dev/null @@ -1,190 +0,0 @@ -package types - -import ( - "encoding/binary" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/address" -) - -const ( - // ModuleName defines the module name - ModuleName = "dex" - - // StoreKey defines the primary module store key - StoreKey = ModuleName - - // RouterKey is the message route for slashing - RouterKey = ModuleName - - // QuerierRoute defines the module's query routing key - QuerierRoute = ModuleName - - // MemStoreKey defines the in-memory store key - MemStoreKey = "mem_dex" -) - -func KeyPrefix(p string) []byte { - return []byte(p) -} - -func AddressKeyPrefix(contractAddr string) []byte { - addr, _ := sdk.AccAddressFromBech32(contractAddr) - return address.MustLengthPrefix(addr) -} - -func ContractKeyPrefix(p string, contractAddr string) []byte { - return append([]byte(p), AddressKeyPrefix(contractAddr)...) -} - -func DenomPrefix(denom string) []byte { - length := uint16(len(denom)) - bz := make([]byte, 2) - binary.BigEndian.PutUint16(bz, length) - return append(bz, []byte(denom)...) -} - -func PairPrefix(priceDenom string, assetDenom string) []byte { - return append(DenomPrefix(priceDenom), DenomPrefix(assetDenom)...) -} - -func OrderBookPrefix(long bool, contractAddr string, priceDenom string, assetDenom string) []byte { - return append( - OrderBookContractPrefix(long, contractAddr), - PairPrefix(priceDenom, assetDenom)..., - ) -} - -func OrderBookContractPrefix(long bool, contractAddr string) []byte { - var prefix []byte - if long { - prefix = KeyPrefix(LongBookKey) - } else { - prefix = KeyPrefix(ShortBookKey) - } - return append(prefix, AddressKeyPrefix(contractAddr)...) -} - -// `Price` constant + contract + price denom + asset denom -func PricePrefix(contractAddr string, priceDenom string, assetDenom string) []byte { - return append( - PriceContractPrefix(contractAddr), - PairPrefix(priceDenom, assetDenom)..., - ) -} - -func PriceContractPrefix(contractAddr string) []byte { - return append(KeyPrefix(PriceKey), AddressKeyPrefix(contractAddr)...) -} - -func RegisteredPairPrefix(contractAddr string) []byte { - return append(KeyPrefix(RegisteredPairKey), AddressKeyPrefix(contractAddr)...) -} - -func OrderPrefix(contractAddr string) []byte { - return append(KeyPrefix(OrderKey), AddressKeyPrefix(contractAddr)...) -} - -func AssetListPrefix(assetDenom string) []byte { - return append(KeyPrefix(AssetListKey), DenomPrefix(assetDenom)...) -} - -func NextOrderIDPrefix(contractAddr string) []byte { - return append(KeyPrefix(NextOrderIDKey), AddressKeyPrefix(contractAddr)...) -} - -func MatchResultPrefix(contractAddr string) []byte { - return append(KeyPrefix(MatchResultKey), AddressKeyPrefix(contractAddr)...) -} - -func GetSettlementOrderIDPrefix(orderID uint64, account string) []byte { - accountBytes := append([]byte(account), []byte("|")...) - orderIDBytes := make([]byte, 8) - binary.BigEndian.PutUint64(orderIDBytes, orderID) - return append(accountBytes, orderIDBytes...) -} - -func GetSettlementKey(orderID uint64, account string, settlementID uint64) []byte { - settlementIDBytes := make([]byte, 8) - binary.BigEndian.PutUint64(settlementIDBytes, settlementID) - return append(GetSettlementOrderIDPrefix(orderID, account), settlementIDBytes...) -} - -func MemOrderPrefixForPair(contractAddr string, priceDenom string, assetDenom string) []byte { - return append( - append(KeyPrefix(MemOrderKey), AddressKeyPrefix(contractAddr)...), - PairPrefix(priceDenom, assetDenom)..., - ) -} - -func MemCancelPrefixForPair(contractAddr string, priceDenom string, assetDenom string) []byte { - return append( - append(KeyPrefix(MemCancelKey), AddressKeyPrefix(contractAddr)...), - PairPrefix(priceDenom, assetDenom)..., - ) -} - -func MemOrderPrefix(contractAddr string) []byte { - return append(KeyPrefix(MemOrderKey), AddressKeyPrefix(contractAddr)...) -} - -func MemCancelPrefix(contractAddr string) []byte { - return append(KeyPrefix(MemCancelKey), AddressKeyPrefix(contractAddr)...) -} - -func MemDepositPrefix(contractAddr string) []byte { - return append(KeyPrefix(MemDepositKey), AddressKeyPrefix(contractAddr)...) -} - -func MemDepositSubprefix(creator, denom string) []byte { - return append([]byte(creator), DenomPrefix(denom)...) -} - -func MemContractsToProcessKey(contractAddr string) []byte { - return append(KeyPrefix(MemContractsToProcess), AddressKeyPrefix(contractAddr)...) -} - -func MemDownstreamContractsKey(contractAddr string) []byte { - return append(KeyPrefix(MemDownstreamContracts), AddressKeyPrefix(contractAddr)...) -} - -func ContractKey(contractAddr string) []byte { - return AddressKeyPrefix(contractAddr) -} - -func OrderCountPrefix(contractAddr string, priceDenom string, assetDenom string, long bool) []byte { - var prefix []byte - if long { - prefix = KeyPrefix(LongOrderCountKey) - } else { - prefix = KeyPrefix(ShortOrderCountKey) - } - return append(prefix, append(AddressKeyPrefix(contractAddr), PairPrefix(priceDenom, assetDenom)...)...) -} - -const ( - LongBookKey = "LongBook-value-" - - ShortBookKey = "ShortBook-value-" - - OrderKey = "order" - AccountActiveOrdersKey = "account-active-orders" - CancelKey = "cancel" - - TwapKey = "TWAP-" - PriceKey = "Price-" - SettlementEntryKey = "SettlementEntry-" - NextSettlementIDKey = "NextSettlementID-" - NextOrderIDKey = "noid" - RegisteredPairKey = "rp" - AssetListKey = "AssetList-" - MatchResultKey = "MatchResult-" - LongOrderCountKey = "loc-" - ShortOrderCountKey = "soc-" - - MemOrderKey = "MemOrder-" - MemDepositKey = "MemDeposit-" - MemCancelKey = "MemCancel-" - MemContractsToProcess = "MemContractsToProcess-" - MemDownstreamContracts = "MemDownstreamContracts-" -) diff --git a/x/dex/types/keys_test.go b/x/dex/types/keys_test.go deleted file mode 100644 index a635435ba..000000000 --- a/x/dex/types/keys_test.go +++ /dev/null @@ -1,29 +0,0 @@ -package types_test - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/address" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestOrderPrefix(t *testing.T) { - testContract := "sei14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sh9m79m" - addr, _ := sdk.AccAddressFromBech32(testContract) - addr = address.MustLengthPrefix(addr) - expected := append([]byte(types.OrderKey), addr...) - require.Equal(t, expected, types.OrderPrefix(testContract)) -} - -func TestPricePrefix(t *testing.T) { - testContract := "sei14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sh9m79m" - testPriceDenom := "SEI" - testAssetDenom := "ATOM" - address := types.AddressKeyPrefix(testContract) - priceContractBytes := append([]byte(types.PriceKey), address...) - pairBytes := types.PairPrefix(testPriceDenom, testAssetDenom) - expectedKey := append(priceContractBytes, pairBytes...) - require.Equal(t, expectedKey, types.PricePrefix(testContract, testPriceDenom, testAssetDenom)) -} diff --git a/x/dex/types/long_book.pb.go b/x/dex/types/long_book.pb.go deleted file mode 100644 index 2f5167c99..000000000 --- a/x/dex/types/long_book.pb.go +++ /dev/null @@ -1,380 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: dex/long_book.proto - -package types - -import ( - fmt "fmt" - github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" - _ "github.com/gogo/protobuf/gogoproto" - proto "github.com/gogo/protobuf/proto" - io "io" - math "math" - math_bits "math/bits" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package - -type LongBook struct { - Price github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,1,opt,name=price,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"price" yaml:"price"` - Entry *OrderEntry `protobuf:"bytes,2,opt,name=entry,proto3" json:"entry"` -} - -func (m *LongBook) Reset() { *m = LongBook{} } -func (m *LongBook) String() string { return proto.CompactTextString(m) } -func (*LongBook) ProtoMessage() {} -func (*LongBook) Descriptor() ([]byte, []int) { - return fileDescriptor_daa9d9e2359557c9, []int{0} -} -func (m *LongBook) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *LongBook) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_LongBook.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *LongBook) XXX_Merge(src proto.Message) { - xxx_messageInfo_LongBook.Merge(m, src) -} -func (m *LongBook) XXX_Size() int { - return m.Size() -} -func (m *LongBook) XXX_DiscardUnknown() { - xxx_messageInfo_LongBook.DiscardUnknown(m) -} - -var xxx_messageInfo_LongBook proto.InternalMessageInfo - -func (m *LongBook) GetEntry() *OrderEntry { - if m != nil { - return m.Entry - } - return nil -} - -func init() { - proto.RegisterType((*LongBook)(nil), "seiprotocol.seichain.dex.LongBook") -} - -func init() { proto.RegisterFile("dex/long_book.proto", fileDescriptor_daa9d9e2359557c9) } - -var fileDescriptor_daa9d9e2359557c9 = []byte{ - // 278 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x4e, 0x49, 0xad, 0xd0, - 0xcf, 0xc9, 0xcf, 0x4b, 0x8f, 0x4f, 0xca, 0xcf, 0xcf, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, - 0x92, 0x28, 0x4e, 0xcd, 0x04, 0xb3, 0x92, 0xf3, 0x73, 0xf4, 0x8a, 0x53, 0x33, 0x93, 0x33, 0x12, - 0x33, 0xf3, 0xf4, 0x52, 0x52, 0x2b, 0xa4, 0x44, 0x41, 0xca, 0xf3, 0x8b, 0x52, 0x52, 0x8b, 0xe2, - 0x53, 0xf3, 0x4a, 0x8a, 0x2a, 0x21, 0x1a, 0xa4, 0x44, 0xd2, 0xf3, 0xd3, 0xf3, 0xc1, 0x4c, 0x7d, - 0x10, 0x0b, 0x22, 0xaa, 0xb4, 0x81, 0x91, 0x8b, 0xc3, 0x27, 0x3f, 0x2f, 0xdd, 0x29, 0x3f, 0x3f, - 0x5b, 0x28, 0x96, 0x8b, 0xb5, 0xa0, 0x28, 0x33, 0x39, 0x55, 0x82, 0x51, 0x81, 0x51, 0x83, 0xd3, - 0xc9, 0xfd, 0xc4, 0x3d, 0x79, 0x86, 0x5b, 0xf7, 0xe4, 0xd5, 0xd2, 0x33, 0x4b, 0x32, 0x4a, 0x93, - 0xf4, 0x92, 0xf3, 0x73, 0xf5, 0x93, 0xf3, 0x8b, 0x73, 0xf3, 0x8b, 0xa1, 0x94, 0x6e, 0x71, 0x4a, - 0xb6, 0x7e, 0x49, 0x65, 0x41, 0x6a, 0xb1, 0x9e, 0x4b, 0x6a, 0xf2, 0xab, 0x7b, 0xf2, 0x10, 0xed, - 0x9f, 0xee, 0xc9, 0xf3, 0x54, 0x26, 0xe6, 0xe6, 0x58, 0x29, 0x81, 0xb9, 0x4a, 0x41, 0x10, 0x61, - 0x21, 0x57, 0x2e, 0x56, 0xb0, 0x83, 0x24, 0x98, 0x14, 0x18, 0x35, 0xb8, 0x8d, 0x54, 0xf4, 0x70, - 0x79, 0x41, 0xcf, 0x1f, 0xe4, 0x7a, 0x57, 0x90, 0x5a, 0x27, 0x4e, 0x90, 0xb1, 0x60, 0x6d, 0x41, - 0x10, 0xca, 0xc9, 0xfd, 0xc4, 0x23, 0x39, 0xc6, 0x0b, 0x8f, 0xe4, 0x18, 0x1f, 0x3c, 0x92, 0x63, - 0x9c, 0xf0, 0x58, 0x8e, 0xe1, 0xc2, 0x63, 0x39, 0x86, 0x1b, 0x8f, 0xe5, 0x18, 0xa2, 0x74, 0x91, - 0x1c, 0x5a, 0x9c, 0x9a, 0xa9, 0x0b, 0x33, 0x1c, 0xcc, 0x01, 0x9b, 0xae, 0x5f, 0xa1, 0x0f, 0x0a, - 0x1d, 0xb0, 0x9b, 0x93, 0xd8, 0xc0, 0xf2, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x3e, 0xf1, - 0xb1, 0x25, 0x60, 0x01, 0x00, 0x00, -} - -func (m *LongBook) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *LongBook) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *LongBook) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Entry != nil { - { - size, err := m.Entry.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintLongBook(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - } - { - size := m.Price.Size() - i -= size - if _, err := m.Price.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintLongBook(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil -} - -func encodeVarintLongBook(dAtA []byte, offset int, v uint64) int { - offset -= sovLongBook(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *LongBook) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = m.Price.Size() - n += 1 + l + sovLongBook(uint64(l)) - if m.Entry != nil { - l = m.Entry.Size() - n += 1 + l + sovLongBook(uint64(l)) - } - return n -} - -func sovLongBook(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozLongBook(x uint64) (n int) { - return sovLongBook(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *LongBook) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowLongBook - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: LongBook: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: LongBook: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Price", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowLongBook - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthLongBook - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthLongBook - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.Price.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Entry", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowLongBook - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthLongBook - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthLongBook - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Entry == nil { - m.Entry = &OrderEntry{} - } - if err := m.Entry.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipLongBook(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthLongBook - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipLongBook(dAtA []byte) (n int, err error) { - l := len(dAtA) - iNdEx := 0 - depth := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowLongBook - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowLongBook - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - iNdEx++ - if dAtA[iNdEx-1] < 0x80 { - break - } - } - case 1: - iNdEx += 8 - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowLongBook - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if length < 0 { - return 0, ErrInvalidLengthLongBook - } - iNdEx += length - case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupLongBook - } - depth-- - case 5: - iNdEx += 4 - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - if iNdEx < 0 { - return 0, ErrInvalidLengthLongBook - } - if depth == 0 { - return iNdEx, nil - } - } - return 0, io.ErrUnexpectedEOF -} - -var ( - ErrInvalidLengthLongBook = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowLongBook = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupLongBook = fmt.Errorf("proto: unexpected end of group") -) diff --git a/x/dex/types/match_result.go b/x/dex/types/match_result.go deleted file mode 100644 index d77c3767d..000000000 --- a/x/dex/types/match_result.go +++ /dev/null @@ -1,28 +0,0 @@ -package types - -import ( - "sort" -) - -func NewMatchResult( - orders []*Order, - cancellations []*Cancellation, - settlements []*SettlementEntry, -) *MatchResult { - // Note that we use string comparator since it is more robust. E.g. in the case that 2 orders match - // on the same orderId, we will then sort on the next field - sort.SliceStable(orders, func(i, j int) bool { - return orders[i].String() < orders[j].String() - }) - sort.SliceStable(cancellations, func(i, j int) bool { - return cancellations[i].String() < cancellations[j].String() - }) - sort.SliceStable(settlements, func(i, j int) bool { - return settlements[i].String() < settlements[j].String() - }) - return &MatchResult{ - Orders: orders, - Cancellations: cancellations, - Settlements: settlements, - } -} diff --git a/x/dex/types/match_result.pb.go b/x/dex/types/match_result.pb.go deleted file mode 100644 index 82966f289..000000000 --- a/x/dex/types/match_result.pb.go +++ /dev/null @@ -1,548 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: dex/match_result.proto - -package types - -import ( - fmt "fmt" - _ "github.com/gogo/protobuf/gogoproto" - proto "github.com/gogo/protobuf/proto" - io "io" - math "math" - math_bits "math/bits" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package - -type MatchResult struct { - Height int64 `protobuf:"varint,1,opt,name=height,proto3" json:"height"` - ContractAddr string `protobuf:"bytes,2,opt,name=contractAddr,proto3" json:"contract_address"` - Orders []*Order `protobuf:"bytes,3,rep,name=orders,proto3" json:"orders"` - Settlements []*SettlementEntry `protobuf:"bytes,4,rep,name=settlements,proto3" json:"settlements"` - Cancellations []*Cancellation `protobuf:"bytes,5,rep,name=cancellations,proto3" json:"cancellations"` -} - -func (m *MatchResult) Reset() { *m = MatchResult{} } -func (m *MatchResult) String() string { return proto.CompactTextString(m) } -func (*MatchResult) ProtoMessage() {} -func (*MatchResult) Descriptor() ([]byte, []int) { - return fileDescriptor_9225b122096d4ce7, []int{0} -} -func (m *MatchResult) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MatchResult) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MatchResult.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *MatchResult) XXX_Merge(src proto.Message) { - xxx_messageInfo_MatchResult.Merge(m, src) -} -func (m *MatchResult) XXX_Size() int { - return m.Size() -} -func (m *MatchResult) XXX_DiscardUnknown() { - xxx_messageInfo_MatchResult.DiscardUnknown(m) -} - -var xxx_messageInfo_MatchResult proto.InternalMessageInfo - -func (m *MatchResult) GetHeight() int64 { - if m != nil { - return m.Height - } - return 0 -} - -func (m *MatchResult) GetContractAddr() string { - if m != nil { - return m.ContractAddr - } - return "" -} - -func (m *MatchResult) GetOrders() []*Order { - if m != nil { - return m.Orders - } - return nil -} - -func (m *MatchResult) GetSettlements() []*SettlementEntry { - if m != nil { - return m.Settlements - } - return nil -} - -func (m *MatchResult) GetCancellations() []*Cancellation { - if m != nil { - return m.Cancellations - } - return nil -} - -func init() { - proto.RegisterType((*MatchResult)(nil), "seiprotocol.seichain.dex.MatchResult") -} - -func init() { proto.RegisterFile("dex/match_result.proto", fileDescriptor_9225b122096d4ce7) } - -var fileDescriptor_9225b122096d4ce7 = []byte{ - // 345 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x91, 0xc1, 0x6a, 0xfa, 0x40, - 0x10, 0xc6, 0x8d, 0xfe, 0xff, 0x42, 0xd7, 0x16, 0xdb, 0x20, 0x25, 0x78, 0x48, 0xc4, 0x43, 0xb1, - 0x07, 0x13, 0x68, 0x2f, 0xbd, 0x36, 0x52, 0x7a, 0x2a, 0x85, 0xf4, 0x56, 0x0a, 0x12, 0x77, 0x87, - 0x64, 0x21, 0x66, 0x65, 0x77, 0x04, 0x7d, 0x8b, 0x3e, 0x56, 0x8f, 0x1e, 0x7b, 0x0a, 0x45, 0x6f, - 0xb9, 0xf4, 0x15, 0xca, 0x6e, 0xb4, 0xd5, 0x83, 0xa7, 0x99, 0xf9, 0xf2, 0xcd, 0xef, 0xcb, 0xb0, - 0xe4, 0x92, 0xc1, 0x22, 0x98, 0xc6, 0x48, 0xd3, 0xb1, 0x04, 0x35, 0xcf, 0xd0, 0x9f, 0x49, 0x81, - 0xc2, 0x76, 0x14, 0x70, 0xd3, 0x51, 0x91, 0xf9, 0x0a, 0x38, 0x4d, 0x63, 0x9e, 0xfb, 0x0c, 0x16, - 0xdd, 0xb6, 0xde, 0x10, 0x92, 0x81, 0xac, 0xac, 0xdd, 0x8e, 0x16, 0x14, 0x20, 0x66, 0x30, 0x85, - 0x1c, 0x77, 0x6a, 0x22, 0x12, 0x61, 0xda, 0x40, 0x77, 0x95, 0xda, 0xff, 0xae, 0x93, 0xd6, 0x93, - 0x4e, 0x8b, 0x4c, 0x98, 0xdd, 0x27, 0xcd, 0x14, 0x78, 0x92, 0xa2, 0x63, 0xf5, 0xac, 0x41, 0x23, - 0x24, 0x65, 0xe1, 0x6d, 0x95, 0x68, 0x5b, 0xed, 0x3b, 0x72, 0x4a, 0x45, 0x8e, 0x32, 0xa6, 0x78, - 0xcf, 0x98, 0x74, 0xea, 0x3d, 0x6b, 0x70, 0x12, 0x76, 0xca, 0xc2, 0x3b, 0xdf, 0xe9, 0xe3, 0x98, - 0x31, 0x09, 0x4a, 0x45, 0x07, 0x4e, 0x7b, 0x44, 0x9a, 0xe6, 0x47, 0x95, 0xd3, 0xe8, 0x35, 0x06, - 0xad, 0x1b, 0xcf, 0x3f, 0x76, 0x95, 0xff, 0xac, 0x7d, 0x55, 0x7c, 0xb5, 0x12, 0x6d, 0xab, 0xfd, - 0x46, 0x5a, 0x7f, 0xc7, 0x29, 0xe7, 0x9f, 0x21, 0x5d, 0x1f, 0x27, 0xbd, 0xfc, 0x9a, 0x1f, 0x72, - 0x94, 0xcb, 0xb0, 0x5d, 0x16, 0xde, 0x3e, 0x21, 0xda, 0x1f, 0xec, 0x31, 0x39, 0xa3, 0x71, 0x4e, - 0x21, 0xcb, 0x62, 0xe4, 0x22, 0x57, 0xce, 0x7f, 0xc3, 0xbf, 0x3a, 0xce, 0x1f, 0xed, 0xd9, 0xc3, - 0x8b, 0xb2, 0xf0, 0x0e, 0x01, 0xd1, 0xe1, 0x18, 0x3e, 0x7e, 0xac, 0x5d, 0x6b, 0xb5, 0x76, 0xad, - 0xaf, 0xb5, 0x6b, 0xbd, 0x6f, 0xdc, 0xda, 0x6a, 0xe3, 0xd6, 0x3e, 0x37, 0x6e, 0xed, 0x75, 0x98, - 0x70, 0x4c, 0xe7, 0x13, 0x9f, 0x8a, 0x69, 0xa0, 0x80, 0x0f, 0x77, 0x71, 0x66, 0x30, 0x79, 0xc1, - 0x22, 0xd0, 0x6f, 0x8b, 0xcb, 0x19, 0xa8, 0x49, 0xd3, 0x7c, 0xbf, 0xfd, 0x09, 0x00, 0x00, 0xff, - 0xff, 0x40, 0xd8, 0xfe, 0x79, 0x32, 0x02, 0x00, 0x00, -} - -func (m *MatchResult) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *MatchResult) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MatchResult) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Cancellations) > 0 { - for iNdEx := len(m.Cancellations) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Cancellations[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintMatchResult(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x2a - } - } - if len(m.Settlements) > 0 { - for iNdEx := len(m.Settlements) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Settlements[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintMatchResult(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x22 - } - } - if len(m.Orders) > 0 { - for iNdEx := len(m.Orders) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Orders[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintMatchResult(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x1a - } - } - if len(m.ContractAddr) > 0 { - i -= len(m.ContractAddr) - copy(dAtA[i:], m.ContractAddr) - i = encodeVarintMatchResult(dAtA, i, uint64(len(m.ContractAddr))) - i-- - dAtA[i] = 0x12 - } - if m.Height != 0 { - i = encodeVarintMatchResult(dAtA, i, uint64(m.Height)) - i-- - dAtA[i] = 0x8 - } - return len(dAtA) - i, nil -} - -func encodeVarintMatchResult(dAtA []byte, offset int, v uint64) int { - offset -= sovMatchResult(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *MatchResult) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Height != 0 { - n += 1 + sovMatchResult(uint64(m.Height)) - } - l = len(m.ContractAddr) - if l > 0 { - n += 1 + l + sovMatchResult(uint64(l)) - } - if len(m.Orders) > 0 { - for _, e := range m.Orders { - l = e.Size() - n += 1 + l + sovMatchResult(uint64(l)) - } - } - if len(m.Settlements) > 0 { - for _, e := range m.Settlements { - l = e.Size() - n += 1 + l + sovMatchResult(uint64(l)) - } - } - if len(m.Cancellations) > 0 { - for _, e := range m.Cancellations { - l = e.Size() - n += 1 + l + sovMatchResult(uint64(l)) - } - } - return n -} - -func sovMatchResult(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozMatchResult(x uint64) (n int) { - return sovMatchResult(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *MatchResult) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMatchResult - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MatchResult: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MatchResult: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Height", wireType) - } - m.Height = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMatchResult - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Height |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractAddr", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMatchResult - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthMatchResult - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthMatchResult - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ContractAddr = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Orders", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMatchResult - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthMatchResult - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthMatchResult - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Orders = append(m.Orders, &Order{}) - if err := m.Orders[len(m.Orders)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Settlements", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMatchResult - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthMatchResult - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthMatchResult - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Settlements = append(m.Settlements, &SettlementEntry{}) - if err := m.Settlements[len(m.Settlements)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 5: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Cancellations", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMatchResult - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthMatchResult - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthMatchResult - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Cancellations = append(m.Cancellations, &Cancellation{}) - if err := m.Cancellations[len(m.Cancellations)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipMatchResult(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthMatchResult - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipMatchResult(dAtA []byte) (n int, err error) { - l := len(dAtA) - iNdEx := 0 - depth := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowMatchResult - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowMatchResult - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - iNdEx++ - if dAtA[iNdEx-1] < 0x80 { - break - } - } - case 1: - iNdEx += 8 - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowMatchResult - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if length < 0 { - return 0, ErrInvalidLengthMatchResult - } - iNdEx += length - case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupMatchResult - } - depth-- - case 5: - iNdEx += 4 - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - if iNdEx < 0 { - return 0, ErrInvalidLengthMatchResult - } - if depth == 0 { - return iNdEx, nil - } - } - return 0, io.ErrUnexpectedEOF -} - -var ( - ErrInvalidLengthMatchResult = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowMatchResult = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupMatchResult = fmt.Errorf("proto: unexpected end of group") -) diff --git a/x/dex/types/match_result_test.go b/x/dex/types/match_result_test.go deleted file mode 100644 index 79da33ec3..000000000 --- a/x/dex/types/match_result_test.go +++ /dev/null @@ -1,54 +0,0 @@ -package types_test - -import ( - "testing" - - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestMatchResultSorted(t *testing.T) { - // Test stable sorting - order1 := &types.Order{ - Id: 1, - } - order2 := &types.Order{ - Id: 1, - } - order3 := &types.Order{ - Id: 2, - } - - // Test sort on different field - cancellation1 := &types.Cancellation{ - Id: 1, - AssetDenom: "a", - } - cancellation2 := &types.Cancellation{ - Id: 1, - AssetDenom: "b", - } - - // Test sort on string - settlement1 := &types.SettlementEntry{ - Account: "a", - } - settlement2 := &types.SettlementEntry{ - Account: "b", - } - - orders := []*types.Order{order3, order1, order2} - cancellations := []*types.Cancellation{cancellation2, cancellation1} - settlements := []*types.SettlementEntry{settlement2, settlement1} - - matchResult := types.NewMatchResult(orders, cancellations, settlements) - expectedOrders := []*types.Order{order1, order2, order3} - expectedCancellations := []*types.Cancellation{cancellation1, cancellation2} - expectedSettlements := []*types.SettlementEntry{settlement1, settlement2} - require.Equal(t, expectedOrders, matchResult.Orders) - // Check actual elements, since slice match above don't seem to capture if the orders point to different objects - require.True(t, order1 == matchResult.Orders[0]) - require.True(t, order2 == matchResult.Orders[1]) - require.Equal(t, expectedCancellations, matchResult.Cancellations) - require.Equal(t, expectedSettlements, matchResult.Settlements) -} diff --git a/x/dex/types/message_cancel_orders.go b/x/dex/types/message_cancel_orders.go deleted file mode 100644 index e211e6b2c..000000000 --- a/x/dex/types/message_cancel_orders.go +++ /dev/null @@ -1,72 +0,0 @@ -package types - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" -) - -const TypeMsgCancelOrders = "cancel_orders" - -var _ sdk.Msg = &MsgCancelOrders{} - -func NewMsgCancelOrders( - creator string, - cancellations []*Cancellation, - contractAddr string, -) *MsgCancelOrders { - return &MsgCancelOrders{ - Creator: creator, - Cancellations: cancellations, - ContractAddr: contractAddr, - } -} - -func (msg *MsgCancelOrders) Route() string { - return RouterKey -} - -func (msg *MsgCancelOrders) Type() string { - return TypeMsgCancelOrders -} - -func (msg *MsgCancelOrders) GetSigners() []sdk.AccAddress { - creator, err := sdk.AccAddressFromBech32(msg.Creator) - if err != nil { - panic(err) - } - return []sdk.AccAddress{creator} -} - -func (msg *MsgCancelOrders) GetSignBytes() []byte { - bz := ModuleCdc.MustMarshalJSON(msg) - return sdk.MustSortJSON(bz) -} - -func (msg *MsgCancelOrders) ValidateBasic() error { - _, err := sdk.AccAddressFromBech32(msg.Creator) - if err != nil { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err) - } - - _, err = sdk.AccAddressFromBech32(msg.ContractAddr) - if err != nil { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid contract address (%s)", err) - } - - for _, cancellation := range msg.Cancellations { - if cancellation.Price.IsNil() { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid cancellation price (%s)", err) - } - if cancellation.Price.IsNegative() { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid cancellation price (cannot be negative) (%s)", err) - } - if len(cancellation.AssetDenom) == 0 || sdk.ValidateDenom(cancellation.AssetDenom) != nil { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid cancellation, asset denom is empty or invalid (%s)", err) - } - if len(cancellation.PriceDenom) == 0 || sdk.ValidateDenom(cancellation.PriceDenom) != nil { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid cancellation, price denom is empty or invalid (%s)", err) - } - } - - return nil -} diff --git a/x/dex/types/message_cancel_orders_test.go b/x/dex/types/message_cancel_orders_test.go deleted file mode 100644 index 1dff4ec30..000000000 --- a/x/dex/types/message_cancel_orders_test.go +++ /dev/null @@ -1,42 +0,0 @@ -package types_test - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestValidateMsgCancelOrder(t *testing.T) { - msg := &types.MsgCancelOrders{ - Creator: "sei1yezq49upxhunjjhudql2fnj5dgvcwjj87pn2wx", - ContractAddr: "sei1ghd753shjuwexxywmgs4xz7x2q732vcnkm6h2pyv9s6ah3hylvrqladqwc", - Cancellations: []*types.Cancellation{{ - Price: sdk.OneDec().Neg(), - AssetDenom: "denom1", - PriceDenom: "denom2", - }}, - } - require.Error(t, msg.ValidateBasic()) - msg = &types.MsgCancelOrders{ - Creator: "sei1yezq49upxhunjjhudql2fnj5dgvcwjj87pn2wx", - ContractAddr: "sei1ghd753shjuwexxywmgs4xz7x2q732vcnkm6h2pyv9s6ah3hylvrqladqwc", - Cancellations: []*types.Cancellation{{ - Price: sdk.OneDec(), - AssetDenom: "invalid denom", - PriceDenom: "denom2", - }}, - } - require.Error(t, msg.ValidateBasic()) - msg = &types.MsgCancelOrders{ - Creator: "sei1yezq49upxhunjjhudql2fnj5dgvcwjj87pn2wx", - ContractAddr: "sei1ghd753shjuwexxywmgs4xz7x2q732vcnkm6h2pyv9s6ah3hylvrqladqwc", - Cancellations: []*types.Cancellation{{ - Price: sdk.OneDec(), - AssetDenom: "denom1", - PriceDenom: "invalid denom", - }}, - } - require.Error(t, msg.ValidateBasic()) -} diff --git a/x/dex/types/message_contract_deposit_rent.go b/x/dex/types/message_contract_deposit_rent.go deleted file mode 100644 index 7b94c93bf..000000000 --- a/x/dex/types/message_contract_deposit_rent.go +++ /dev/null @@ -1,56 +0,0 @@ -package types - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" -) - -const TypeMsgContractDepositRent = "contract_deposit_rent" - -var _ sdk.Msg = &MsgContractDepositRent{} - -func NewMsgContractDepositRent( - contractAddr string, - amount uint64, - sender string, -) *MsgContractDepositRent { - return &MsgContractDepositRent{ - Sender: sender, - ContractAddr: contractAddr, - Amount: amount, - } -} - -func (msg *MsgContractDepositRent) Route() string { - return RouterKey -} - -func (msg *MsgContractDepositRent) Type() string { - return TypeMsgContractDepositRent -} - -func (msg *MsgContractDepositRent) GetSigners() []sdk.AccAddress { - creator, err := sdk.AccAddressFromBech32(msg.Sender) - if err != nil { - panic(err) - } - return []sdk.AccAddress{creator} -} - -func (msg *MsgContractDepositRent) GetSignBytes() []byte { - bz := ModuleCdc.MustMarshalJSON(msg) - return sdk.MustSortJSON(bz) -} - -func (msg *MsgContractDepositRent) ValidateBasic() error { - _, err := sdk.AccAddressFromBech32(msg.Sender) - if err != nil { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err) - } - - _, err = sdk.AccAddressFromBech32(msg.ContractAddr) - if err != nil { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid contract address (%s)", err) - } - return nil -} diff --git a/x/dex/types/message_place_orders.go b/x/dex/types/message_place_orders.go deleted file mode 100644 index 839dad45a..000000000 --- a/x/dex/types/message_place_orders.go +++ /dev/null @@ -1,85 +0,0 @@ -package types - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" -) - -const TypeMsgPlaceOrders = "place_orders" - -var _ sdk.Msg = &MsgPlaceOrders{} - -func NewMsgPlaceOrders( - creator string, - orders []*Order, - contractAddr string, - fund sdk.Coins, -) *MsgPlaceOrders { - return &MsgPlaceOrders{ - Creator: creator, - Orders: orders, - ContractAddr: contractAddr, - Funds: fund, - } -} - -func (msg *MsgPlaceOrders) Route() string { - return RouterKey -} - -func (msg *MsgPlaceOrders) Type() string { - return TypeMsgPlaceOrders -} - -func (msg *MsgPlaceOrders) GetSigners() []sdk.AccAddress { - creator, err := sdk.AccAddressFromBech32(msg.Creator) - if err != nil { - panic(err) - } - return []sdk.AccAddress{creator} -} - -func (msg *MsgPlaceOrders) GetSignBytes() []byte { - bz := ModuleCdc.MustMarshalJSON(msg) - return sdk.MustSortJSON(bz) -} - -// perform statelss check on basic property of msg like sig verification -func (msg *MsgPlaceOrders) ValidateBasic() error { - _, err := sdk.AccAddressFromBech32(msg.Creator) - if err != nil { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err) - } - - _, err = sdk.AccAddressFromBech32(msg.ContractAddr) - if err != nil { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid contract address (%s)", err) - } - - if len(msg.Orders) == 0 { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "at least one order needs to be placed (%s)", err) - } - - for _, order := range msg.Orders { - if order.Quantity.IsNil() || order.Quantity.IsNegative() { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid order quantity (%s)", err) - } - if order.Price.IsNil() || order.Price.IsNegative() { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid order price (%s)", err) - } - if len(order.AssetDenom) == 0 || sdk.ValidateDenom(order.AssetDenom) != nil { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid order, asset denom is empty or invalid (%s)", err) - } - if len(order.PriceDenom) == 0 || sdk.ValidateDenom(order.PriceDenom) != nil { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid order, price denom is empty or invalid (%s)", err) - } - if order.OrderType == OrderType_FOKMARKETBYVALUE || order.OrderType == OrderType_FOKMARKET { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "FOK orders are temporarily disabled") - } - if order.OrderType == OrderType_STOPLIMIT || order.OrderType == OrderType_STOPLOSS { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "stop loss/limit order (%s) are not supported yet", err) - } - } - - return nil -} diff --git a/x/dex/types/message_place_orders_test.go b/x/dex/types/message_place_orders_test.go deleted file mode 100644 index 470de9cd1..000000000 --- a/x/dex/types/message_place_orders_test.go +++ /dev/null @@ -1,102 +0,0 @@ -package types_test - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - "testing" - - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestValidateMsgPlaceOrder(t *testing.T) { - TEST_CONTRACT := "sei1ghd753shjuwexxywmgs4xz7x2q732vcnkm6h2pyv9s6ah3hylvrqladqwc" - msg := &types.MsgPlaceOrders{ - Creator: "sei1yezq49upxhunjjhudql2fnj5dgvcwjj87pn2wx", - ContractAddr: TEST_CONTRACT, - Orders: []*types.Order{ - { - Id: 1, - Account: "test", - ContractAddr: TEST_CONTRACT, - Quantity: sdk.OneDec(), - Price: sdk.OneDec(), - AssetDenom: "denom1", - PriceDenom: "denom2", - }, - }, - } - require.NoError(t, msg.ValidateBasic()) - - // Empty orders - msg = &types.MsgPlaceOrders{ - Creator: "sei1yezq49upxhunjjhudql2fnj5dgvcwjj87pn2wx", - ContractAddr: TEST_CONTRACT, - Orders: []*types.Order{}, - } - require.Error(t, msg.ValidateBasic()) - - // Test various invalid orders field - msg = &types.MsgPlaceOrders{ - Creator: "sei1yezq49upxhunjjhudql2fnj5dgvcwjj87pn2wx", - ContractAddr: TEST_CONTRACT, - Orders: []*types.Order{ - { - Id: 1, - Account: "test", - ContractAddr: TEST_CONTRACT, - Quantity: sdk.OneDec().Neg(), - Price: sdk.OneDec(), - AssetDenom: "denom1", - PriceDenom: "denom2", - }, - }, - } - require.Error(t, msg.ValidateBasic()) - msg = &types.MsgPlaceOrders{ - Creator: "sei1yezq49upxhunjjhudql2fnj5dgvcwjj87pn2wx", - ContractAddr: TEST_CONTRACT, - Orders: []*types.Order{ - { - Id: 1, - Account: "test", - ContractAddr: TEST_CONTRACT, - Quantity: sdk.OneDec(), - AssetDenom: "denom1", - PriceDenom: "denom2", - }, - }, - } - require.Error(t, msg.ValidateBasic()) - msg = &types.MsgPlaceOrders{ - Creator: "sei1yezq49upxhunjjhudql2fnj5dgvcwjj87pn2wx", - ContractAddr: TEST_CONTRACT, - Orders: []*types.Order{ - { - Id: 1, - Account: "test", - ContractAddr: TEST_CONTRACT, - Quantity: sdk.OneDec(), - Price: sdk.OneDec(), - AssetDenom: "invalid denom", - PriceDenom: "denom2", - }, - }, - } - require.Error(t, msg.ValidateBasic()) - msg = &types.MsgPlaceOrders{ - Creator: "sei1yezq49upxhunjjhudql2fnj5dgvcwjj87pn2wx", - ContractAddr: TEST_CONTRACT, - Orders: []*types.Order{ - { - Id: 1, - Account: "test", - ContractAddr: TEST_CONTRACT, - Quantity: sdk.OneDec().Neg(), - Price: sdk.OneDec(), - AssetDenom: "denom1", - PriceDenom: "invalid denom", - }, - }, - } - require.Error(t, msg.ValidateBasic()) -} diff --git a/x/dex/types/message_register_contract.go b/x/dex/types/message_register_contract.go deleted file mode 100644 index 2ac7240ea..000000000 --- a/x/dex/types/message_register_contract.go +++ /dev/null @@ -1,75 +0,0 @@ -package types - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" -) - -const TypeMsgRegisterContract = "register_contract" - -var _ sdk.Msg = &MsgRegisterContract{} - -func NewMsgRegisterContract( - creator string, - codeID uint64, - contractAddr string, - needOrderMatching bool, - dependencies []*ContractDependencyInfo, - deposit uint64, -) *MsgRegisterContract { - return &MsgRegisterContract{ - Creator: creator, - Contract: &ContractInfoV2{ - CodeId: codeID, - ContractAddr: contractAddr, - NeedOrderMatching: needOrderMatching, - Dependencies: dependencies, - Creator: creator, - RentBalance: deposit, - }, - } -} - -func (msg *MsgRegisterContract) Route() string { - return RouterKey -} - -func (msg *MsgRegisterContract) Type() string { - return TypeMsgRegisterContract -} - -func (msg *MsgRegisterContract) GetSigners() []sdk.AccAddress { - creator, err := sdk.AccAddressFromBech32(msg.Creator) - if err != nil { - panic(err) - } - return []sdk.AccAddress{creator} -} - -func (msg *MsgRegisterContract) GetSignBytes() []byte { - bz := ModuleCdc.MustMarshalJSON(msg) - return sdk.MustSortJSON(bz) -} - -func (msg *MsgRegisterContract) ValidateBasic() error { - _, err := sdk.AccAddressFromBech32(msg.Creator) - if err != nil { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err) - } - - _, err = sdk.AccAddressFromBech32(msg.Contract.ContractAddr) - if err != nil { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid contract address (%s)", err) - } - - for _, dependency := range msg.Contract.Dependencies { - contractAddress := dependency.Dependency - - _, err = sdk.AccAddressFromBech32(contractAddress) - if err != nil { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid dependency contract address (%s)", err) - } - } - - return nil -} diff --git a/x/dex/types/message_register_pairs.go b/x/dex/types/message_register_pairs.go deleted file mode 100644 index 47fb42af1..000000000 --- a/x/dex/types/message_register_pairs.go +++ /dev/null @@ -1,83 +0,0 @@ -package types - -import ( - "errors" - - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" -) - -const TypeMsgRegisterPairs = "register_pairs" - -var _ sdk.Msg = &MsgRegisterPairs{} - -func NewMsgRegisterPairs( - creator string, - contractPairs []BatchContractPair, -) *MsgRegisterPairs { - return &MsgRegisterPairs{ - Creator: creator, - Batchcontractpair: contractPairs, - } -} - -func (msg *MsgRegisterPairs) Route() string { - return RouterKey -} - -func (msg *MsgRegisterPairs) Type() string { - return TypeMsgRegisterPairs -} - -func (msg *MsgRegisterPairs) GetSigners() []sdk.AccAddress { - creator, err := sdk.AccAddressFromBech32(msg.Creator) - if err != nil { - panic(err) - } - return []sdk.AccAddress{creator} -} - -func (msg *MsgRegisterPairs) GetSignBytes() []byte { - bz := ModuleCdc.MustMarshalJSON(msg) - return sdk.MustSortJSON(bz) -} - -func (msg *MsgRegisterPairs) ValidateBasic() error { - if msg.Creator == "" { - return errors.New("creator address is empty") - } - - _, err := sdk.AccAddressFromBech32(msg.Creator) - if err != nil { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err) - } - - if len(msg.Batchcontractpair) == 0 { - return errors.New("no data provided in register pairs transaction") - } - - for _, batchContractPair := range msg.Batchcontractpair { - contractAddress := batchContractPair.ContractAddr - - if contractAddress == "" { - return errors.New("contract address is empty") - } - - _, err = sdk.AccAddressFromBech32(contractAddress) - if err != nil { - return errors.New("contract address format is not bech32") - } - - if len(batchContractPair.Pairs) == 0 { - return errors.New("no pairs provided in register pairs transaction") - } - - for _, pair := range batchContractPair.Pairs { - if pair == nil { - return errors.New("empty pair info") - } - } - } - - return nil -} diff --git a/x/dex/types/message_unregister_contract.go b/x/dex/types/message_unregister_contract.go deleted file mode 100644 index 667805c66..000000000 --- a/x/dex/types/message_unregister_contract.go +++ /dev/null @@ -1,55 +0,0 @@ -package types - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" -) - -const TypeMsgUnregisterContract = "unregister_contract" - -var _ sdk.Msg = &MsgUnregisterContract{} - -func NewMsgUnregisterContract( - creator string, - contractAddr string, -) *MsgUnregisterContract { - return &MsgUnregisterContract{ - Creator: creator, - ContractAddr: contractAddr, - } -} - -func (msg *MsgUnregisterContract) Route() string { - return RouterKey -} - -func (msg *MsgUnregisterContract) Type() string { - return TypeMsgUnregisterContract -} - -func (msg *MsgUnregisterContract) GetSigners() []sdk.AccAddress { - creator, err := sdk.AccAddressFromBech32(msg.Creator) - if err != nil { - panic(err) - } - return []sdk.AccAddress{creator} -} - -func (msg *MsgUnregisterContract) GetSignBytes() []byte { - bz := ModuleCdc.MustMarshalJSON(msg) - return sdk.MustSortJSON(bz) -} - -func (msg *MsgUnregisterContract) ValidateBasic() error { - _, err := sdk.AccAddressFromBech32(msg.Creator) - if err != nil { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err) - } - - _, err = sdk.AccAddressFromBech32(msg.ContractAddr) - if err != nil { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid contract address (%s)", err) - } - - return nil -} diff --git a/x/dex/types/message_unsuspend_contract.go b/x/dex/types/message_unsuspend_contract.go deleted file mode 100644 index 75581625e..000000000 --- a/x/dex/types/message_unsuspend_contract.go +++ /dev/null @@ -1,55 +0,0 @@ -package types - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" -) - -const TypeMsgUnsuspendContract = "unsuspend_contract" - -var _ sdk.Msg = &MsgUnsuspendContract{} - -func NewMsgUnsuspendContract( - creator string, - contractAddr string, -) *MsgUnsuspendContract { - return &MsgUnsuspendContract{ - Creator: creator, - ContractAddr: contractAddr, - } -} - -func (msg *MsgUnsuspendContract) Route() string { - return RouterKey -} - -func (msg *MsgUnsuspendContract) Type() string { - return TypeMsgUnsuspendContract -} - -func (msg *MsgUnsuspendContract) GetSigners() []sdk.AccAddress { - creator, err := sdk.AccAddressFromBech32(msg.Creator) - if err != nil { - panic(err) - } - return []sdk.AccAddress{creator} -} - -func (msg *MsgUnsuspendContract) GetSignBytes() []byte { - bz := ModuleCdc.MustMarshalJSON(msg) - return sdk.MustSortJSON(bz) -} - -func (msg *MsgUnsuspendContract) ValidateBasic() error { - _, err := sdk.AccAddressFromBech32(msg.Creator) - if err != nil { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err) - } - - _, err = sdk.AccAddressFromBech32(msg.ContractAddr) - if err != nil { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid contract address (%s)", err) - } - - return nil -} diff --git a/x/dex/types/message_update_price_tick_size.go b/x/dex/types/message_update_price_tick_size.go deleted file mode 100644 index 1594bcffb..000000000 --- a/x/dex/types/message_update_price_tick_size.go +++ /dev/null @@ -1,69 +0,0 @@ -package types - -import ( - "errors" - - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" -) - -const TypeMsgUpdatePriceTickSize = "update_price_tick_size" - -var _ sdk.Msg = &MsgUpdatePriceTickSize{} - -func NewMsgUpdatePriceTickSize( - creator string, - tickSizeList []TickSize, -) *MsgUpdatePriceTickSize { - return &MsgUpdatePriceTickSize{ - Creator: creator, - TickSizeList: tickSizeList, - } -} - -func (msg *MsgUpdatePriceTickSize) Route() string { - return RouterKey -} - -func (msg *MsgUpdatePriceTickSize) Type() string { - return TypeMsgUpdatePriceTickSize -} - -func (msg *MsgUpdatePriceTickSize) GetSigners() []sdk.AccAddress { - creator, err := sdk.AccAddressFromBech32(msg.Creator) - if err != nil { - panic(err) - } - return []sdk.AccAddress{creator} -} - -func (msg *MsgUpdatePriceTickSize) GetSignBytes() []byte { - bz := ModuleCdc.MustMarshalJSON(msg) - return sdk.MustSortJSON(bz) -} - -func (msg *MsgUpdatePriceTickSize) ValidateBasic() error { - _, err := sdk.AccAddressFromBech32(msg.Creator) - if err != nil { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err) - } - - if len(msg.TickSizeList) == 0 { - return errors.New("no data provided in update price tick size transaction") - } - - for _, tickSize := range msg.TickSizeList { - contractAddress := tickSize.ContractAddr - - _, err = sdk.AccAddressFromBech32(contractAddress) - if err != nil { - return errors.New("contract address format is not bech32") - } - - if tickSize.Pair == nil { - return errors.New("empty pair info") - } - } - - return nil -} diff --git a/x/dex/types/message_update_quantity_tick_size.go b/x/dex/types/message_update_quantity_tick_size.go deleted file mode 100644 index 7beafec5d..000000000 --- a/x/dex/types/message_update_quantity_tick_size.go +++ /dev/null @@ -1,69 +0,0 @@ -package types - -import ( - "errors" - - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" -) - -const TypeMsgUpdateQuantityTickSize = "update_quantity_tick_size" - -var _ sdk.Msg = &MsgUpdateQuantityTickSize{} - -func NewMsgUpdateQuantityTickSize( - creator string, - tickSizeList []TickSize, -) *MsgUpdateQuantityTickSize { - return &MsgUpdateQuantityTickSize{ - Creator: creator, - TickSizeList: tickSizeList, - } -} - -func (msg *MsgUpdateQuantityTickSize) Route() string { - return RouterKey -} - -func (msg *MsgUpdateQuantityTickSize) Type() string { - return TypeMsgUpdateQuantityTickSize -} - -func (msg *MsgUpdateQuantityTickSize) GetSigners() []sdk.AccAddress { - creator, err := sdk.AccAddressFromBech32(msg.Creator) - if err != nil { - panic(err) - } - return []sdk.AccAddress{creator} -} - -func (msg *MsgUpdateQuantityTickSize) GetSignBytes() []byte { - bz := ModuleCdc.MustMarshalJSON(msg) - return sdk.MustSortJSON(bz) -} - -func (msg *MsgUpdateQuantityTickSize) ValidateBasic() error { - _, err := sdk.AccAddressFromBech32(msg.Creator) - if err != nil { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err) - } - - if len(msg.TickSizeList) == 0 { - return errors.New("no data provided in update quantity tick size transaction") - } - - for _, tickSize := range msg.TickSizeList { - contractAddress := tickSize.ContractAddr - - _, err = sdk.AccAddressFromBech32(contractAddress) - if err != nil { - return errors.New("contract address format is not bech32") - } - - if tickSize.Pair == nil { - return errors.New("empty pair info") - } - } - - return nil -} diff --git a/x/dex/types/order.pb.go b/x/dex/types/order.pb.go deleted file mode 100644 index 69c89707d..000000000 --- a/x/dex/types/order.pb.go +++ /dev/null @@ -1,1680 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: dex/order.proto - -package types - -import ( - fmt "fmt" - github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" - _ "github.com/gogo/protobuf/gogoproto" - proto "github.com/gogo/protobuf/proto" - io "io" - math "math" - math_bits "math/bits" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package - -type Order struct { - Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id"` - Status OrderStatus `protobuf:"varint,2,opt,name=status,proto3,enum=seiprotocol.seichain.dex.OrderStatus" json:"status"` - Account string `protobuf:"bytes,3,opt,name=account,proto3" json:"account"` - ContractAddr string `protobuf:"bytes,4,opt,name=contractAddr,proto3" json:"contract_address"` - Price github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,5,opt,name=price,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"price" yaml:"price"` - Quantity github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,6,opt,name=quantity,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"quantity" yaml:"quantity"` - PriceDenom string `protobuf:"bytes,7,opt,name=priceDenom,proto3" json:"price_denom"` - AssetDenom string `protobuf:"bytes,8,opt,name=assetDenom,proto3" json:"asset_denom"` - OrderType OrderType `protobuf:"varint,9,opt,name=orderType,proto3,enum=seiprotocol.seichain.dex.OrderType" json:"order_type"` - PositionDirection PositionDirection `protobuf:"varint,10,opt,name=positionDirection,proto3,enum=seiprotocol.seichain.dex.PositionDirection" json:"position_direction"` - Data string `protobuf:"bytes,11,opt,name=data,proto3" json:"data"` - StatusDescription string `protobuf:"bytes,12,opt,name=statusDescription,proto3" json:"status_description"` - Nominal github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,13,opt,name=nominal,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"nominal" yaml:"nominal"` - TriggerPrice github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,14,opt,name=triggerPrice,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"trigger_price" yaml:"trigger_price"` - TriggerStatus bool `protobuf:"varint,15,opt,name=triggerStatus,proto3" json:"trigger_status"` -} - -func (m *Order) Reset() { *m = Order{} } -func (m *Order) String() string { return proto.CompactTextString(m) } -func (*Order) ProtoMessage() {} -func (*Order) Descriptor() ([]byte, []int) { - return fileDescriptor_c2d5fab85368797d, []int{0} -} -func (m *Order) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *Order) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_Order.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *Order) XXX_Merge(src proto.Message) { - xxx_messageInfo_Order.Merge(m, src) -} -func (m *Order) XXX_Size() int { - return m.Size() -} -func (m *Order) XXX_DiscardUnknown() { - xxx_messageInfo_Order.DiscardUnknown(m) -} - -var xxx_messageInfo_Order proto.InternalMessageInfo - -func (m *Order) GetId() uint64 { - if m != nil { - return m.Id - } - return 0 -} - -func (m *Order) GetStatus() OrderStatus { - if m != nil { - return m.Status - } - return OrderStatus_PLACED -} - -func (m *Order) GetAccount() string { - if m != nil { - return m.Account - } - return "" -} - -func (m *Order) GetContractAddr() string { - if m != nil { - return m.ContractAddr - } - return "" -} - -func (m *Order) GetPriceDenom() string { - if m != nil { - return m.PriceDenom - } - return "" -} - -func (m *Order) GetAssetDenom() string { - if m != nil { - return m.AssetDenom - } - return "" -} - -func (m *Order) GetOrderType() OrderType { - if m != nil { - return m.OrderType - } - return OrderType_LIMIT -} - -func (m *Order) GetPositionDirection() PositionDirection { - if m != nil { - return m.PositionDirection - } - return PositionDirection_LONG -} - -func (m *Order) GetData() string { - if m != nil { - return m.Data - } - return "" -} - -func (m *Order) GetStatusDescription() string { - if m != nil { - return m.StatusDescription - } - return "" -} - -func (m *Order) GetTriggerStatus() bool { - if m != nil { - return m.TriggerStatus - } - return false -} - -type Cancellation struct { - Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id"` - Initiator CancellationInitiator `protobuf:"varint,2,opt,name=initiator,proto3,enum=seiprotocol.seichain.dex.CancellationInitiator" json:"initiator"` - Creator string `protobuf:"bytes,3,opt,name=creator,proto3" json:"creator"` - ContractAddr string `protobuf:"bytes,4,opt,name=contractAddr,proto3" json:"contract_address"` - PriceDenom string `protobuf:"bytes,5,opt,name=priceDenom,proto3" json:"price_denom"` - AssetDenom string `protobuf:"bytes,6,opt,name=assetDenom,proto3" json:"asset_denom"` - PositionDirection PositionDirection `protobuf:"varint,7,opt,name=positionDirection,proto3,enum=seiprotocol.seichain.dex.PositionDirection" json:"position_direction"` - Price github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,8,opt,name=price,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"price" yaml:"price"` -} - -func (m *Cancellation) Reset() { *m = Cancellation{} } -func (m *Cancellation) String() string { return proto.CompactTextString(m) } -func (*Cancellation) ProtoMessage() {} -func (*Cancellation) Descriptor() ([]byte, []int) { - return fileDescriptor_c2d5fab85368797d, []int{1} -} -func (m *Cancellation) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *Cancellation) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_Cancellation.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *Cancellation) XXX_Merge(src proto.Message) { - xxx_messageInfo_Cancellation.Merge(m, src) -} -func (m *Cancellation) XXX_Size() int { - return m.Size() -} -func (m *Cancellation) XXX_DiscardUnknown() { - xxx_messageInfo_Cancellation.DiscardUnknown(m) -} - -var xxx_messageInfo_Cancellation proto.InternalMessageInfo - -func (m *Cancellation) GetId() uint64 { - if m != nil { - return m.Id - } - return 0 -} - -func (m *Cancellation) GetInitiator() CancellationInitiator { - if m != nil { - return m.Initiator - } - return CancellationInitiator_USER -} - -func (m *Cancellation) GetCreator() string { - if m != nil { - return m.Creator - } - return "" -} - -func (m *Cancellation) GetContractAddr() string { - if m != nil { - return m.ContractAddr - } - return "" -} - -func (m *Cancellation) GetPriceDenom() string { - if m != nil { - return m.PriceDenom - } - return "" -} - -func (m *Cancellation) GetAssetDenom() string { - if m != nil { - return m.AssetDenom - } - return "" -} - -func (m *Cancellation) GetPositionDirection() PositionDirection { - if m != nil { - return m.PositionDirection - } - return PositionDirection_LONG -} - -type ActiveOrders struct { - Ids []uint64 `protobuf:"varint,1,rep,packed,name=ids,proto3" json:"ids"` -} - -func (m *ActiveOrders) Reset() { *m = ActiveOrders{} } -func (m *ActiveOrders) String() string { return proto.CompactTextString(m) } -func (*ActiveOrders) ProtoMessage() {} -func (*ActiveOrders) Descriptor() ([]byte, []int) { - return fileDescriptor_c2d5fab85368797d, []int{2} -} -func (m *ActiveOrders) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *ActiveOrders) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_ActiveOrders.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *ActiveOrders) XXX_Merge(src proto.Message) { - xxx_messageInfo_ActiveOrders.Merge(m, src) -} -func (m *ActiveOrders) XXX_Size() int { - return m.Size() -} -func (m *ActiveOrders) XXX_DiscardUnknown() { - xxx_messageInfo_ActiveOrders.DiscardUnknown(m) -} - -var xxx_messageInfo_ActiveOrders proto.InternalMessageInfo - -func (m *ActiveOrders) GetIds() []uint64 { - if m != nil { - return m.Ids - } - return nil -} - -func init() { - proto.RegisterType((*Order)(nil), "seiprotocol.seichain.dex.Order") - proto.RegisterType((*Cancellation)(nil), "seiprotocol.seichain.dex.Cancellation") - proto.RegisterType((*ActiveOrders)(nil), "seiprotocol.seichain.dex.ActiveOrders") -} - -func init() { proto.RegisterFile("dex/order.proto", fileDescriptor_c2d5fab85368797d) } - -var fileDescriptor_c2d5fab85368797d = []byte{ - // 737 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0xcd, 0x6a, 0xdb, 0x4c, - 0x14, 0xb5, 0x1c, 0xff, 0x4e, 0x1c, 0xfb, 0xcb, 0x10, 0x82, 0xbe, 0x50, 0x2c, 0xa3, 0xd2, 0xe2, - 0x50, 0x62, 0x41, 0xbb, 0x09, 0xa5, 0x9b, 0xa8, 0x86, 0x50, 0x4a, 0x68, 0x3a, 0x2d, 0x14, 0x4a, - 0x8b, 0x51, 0x34, 0x83, 0x33, 0xd4, 0xd6, 0x38, 0x9a, 0x71, 0x89, 0xe9, 0x4b, 0xf4, 0x05, 0xfa, - 0x3e, 0xd9, 0x35, 0xcb, 0xd2, 0x85, 0x28, 0xc9, 0x4e, 0xcb, 0x3c, 0x41, 0xd1, 0x95, 0x26, 0xb6, - 0xf3, 0x43, 0xea, 0x45, 0x36, 0xd6, 0x9d, 0x73, 0xcf, 0x39, 0x57, 0x9a, 0x99, 0x7b, 0x8d, 0x1a, - 0x94, 0x1d, 0x3b, 0x22, 0xa4, 0x2c, 0xec, 0x8c, 0x42, 0xa1, 0x04, 0x36, 0x25, 0xe3, 0x10, 0xf9, - 0x62, 0xd0, 0x91, 0x8c, 0xfb, 0x87, 0x1e, 0x0f, 0x3a, 0x94, 0x1d, 0x6f, 0xac, 0xf5, 0x45, 0x5f, - 0x40, 0xca, 0x49, 0xa2, 0x94, 0xbf, 0x01, 0x06, 0x2c, 0x18, 0x0f, 0x65, 0x0a, 0xd8, 0x3f, 0x2b, - 0xa8, 0xf8, 0x26, 0x31, 0xc4, 0x1b, 0x28, 0xcf, 0xa9, 0x69, 0xb4, 0x8c, 0x76, 0xc1, 0x45, 0x27, - 0x91, 0x65, 0xc4, 0x91, 0x95, 0xe7, 0x94, 0xe4, 0x39, 0xc5, 0x7b, 0xa8, 0x24, 0x95, 0xa7, 0xc6, - 0xd2, 0xcc, 0xb7, 0x8c, 0x76, 0xfd, 0xe9, 0xa3, 0xce, 0x6d, 0x75, 0x3b, 0x60, 0xf6, 0x0e, 0xc8, - 0x6e, 0x3d, 0xb3, 0xc9, 0xc4, 0x24, 0x7b, 0xe2, 0x4d, 0x54, 0xf6, 0x7c, 0x5f, 0x8c, 0x03, 0x65, - 0x2e, 0xb5, 0x8c, 0x76, 0xd5, 0x6d, 0x64, 0x44, 0x0d, 0x13, 0x1d, 0xe0, 0x17, 0xa8, 0xe6, 0x8b, - 0x40, 0x85, 0x9e, 0xaf, 0x76, 0x28, 0x0d, 0xcd, 0x02, 0xf0, 0xcd, 0x8c, 0xff, 0x9f, 0xce, 0xf5, - 0x3c, 0x4a, 0x43, 0x26, 0x25, 0x99, 0x63, 0xe3, 0xcf, 0xa8, 0x38, 0x0a, 0xb9, 0xcf, 0xcc, 0x22, - 0xc8, 0x76, 0x4f, 0x22, 0x2b, 0xf7, 0x3b, 0xb2, 0x1e, 0xf7, 0xb9, 0x3a, 0x1c, 0x1f, 0x74, 0x7c, - 0x31, 0x74, 0x7c, 0x21, 0x87, 0x42, 0x66, 0x8f, 0x2d, 0x49, 0xbf, 0x38, 0x6a, 0x32, 0x62, 0xb2, - 0xd3, 0x65, 0x7e, 0x1c, 0x59, 0xa9, 0xfc, 0x22, 0xb2, 0x6a, 0x13, 0x6f, 0x38, 0x78, 0x6e, 0xc3, - 0xd2, 0x26, 0x29, 0x8c, 0x39, 0xaa, 0x1c, 0x8d, 0xbd, 0x40, 0x71, 0x35, 0x31, 0x4b, 0x50, 0x61, - 0x6f, 0xe1, 0x0a, 0x97, 0x0e, 0x17, 0x91, 0xd5, 0x48, 0x8b, 0x68, 0xc4, 0x26, 0x97, 0x49, 0xec, - 0x20, 0x04, 0x35, 0xbb, 0x2c, 0x10, 0x43, 0xb3, 0x9c, 0xee, 0x5a, 0x1c, 0x59, 0xcb, 0x80, 0xf6, - 0x68, 0x02, 0x93, 0x19, 0x4a, 0x22, 0xf0, 0xa4, 0x64, 0x2a, 0x15, 0x54, 0xa6, 0x02, 0x40, 0xb5, - 0x60, 0x4a, 0xc1, 0x6f, 0x51, 0x15, 0x6e, 0xd6, 0xfb, 0xc9, 0x88, 0x99, 0x55, 0x38, 0xe6, 0x87, - 0x77, 0x1c, 0x73, 0x42, 0x75, 0xeb, 0x71, 0x64, 0x21, 0x50, 0xf6, 0x92, 0xef, 0x22, 0x53, 0x17, - 0x7c, 0x84, 0x56, 0x47, 0x42, 0x72, 0xc5, 0x45, 0xd0, 0xe5, 0x21, 0xf3, 0x93, 0xc0, 0x44, 0x60, - 0xfd, 0xe4, 0x76, 0xeb, 0xfd, 0xab, 0x12, 0x77, 0x3d, 0x8e, 0x2c, 0xac, 0x9d, 0x7a, 0x54, 0xe3, - 0xe4, 0xba, 0x3b, 0x7e, 0x80, 0x0a, 0xd4, 0x53, 0x9e, 0xb9, 0x0c, 0x1f, 0x5c, 0x89, 0x23, 0x0b, - 0xd6, 0x04, 0x7e, 0x71, 0x17, 0xad, 0xa6, 0x57, 0xb0, 0xcb, 0xa4, 0x1f, 0xf2, 0x11, 0xbc, 0x50, - 0x0d, 0xa8, 0x50, 0x23, 0x4d, 0xf6, 0xe8, 0x34, 0x4b, 0xae, 0x0b, 0x30, 0x43, 0xe5, 0x40, 0x0c, - 0x79, 0xe0, 0x0d, 0xcc, 0x15, 0xd0, 0xbe, 0x5e, 0xf8, 0xd4, 0xb5, 0xc1, 0x45, 0x64, 0xd5, 0xd3, - 0x43, 0xcf, 0x00, 0x9b, 0xe8, 0x14, 0xfe, 0x86, 0x6a, 0x2a, 0xe4, 0xfd, 0x3e, 0x0b, 0xf7, 0xe1, - 0x0e, 0xd7, 0xa1, 0xd6, 0x87, 0x85, 0x6b, 0xad, 0x64, 0x2e, 0x3d, 0x7d, 0x97, 0xd7, 0xd2, 0x8a, - 0x73, 0xb0, 0x4d, 0xe6, 0x8a, 0xe1, 0x6d, 0xa4, 0x65, 0x69, 0x2f, 0x9b, 0x8d, 0x96, 0xd1, 0xae, - 0xb8, 0x38, 0x8e, 0xac, 0xba, 0x16, 0x66, 0x5d, 0x3d, 0x4f, 0xb4, 0x7f, 0x14, 0x50, 0xed, 0xa5, - 0x17, 0xf8, 0x6c, 0x30, 0xf0, 0x60, 0xbb, 0xd6, 0x67, 0x06, 0x4b, 0x69, 0x66, 0xa8, 0x7c, 0x42, - 0x55, 0x1e, 0x70, 0xc5, 0x3d, 0x25, 0xc2, 0x6c, 0xae, 0x38, 0xb7, 0xdf, 0x8a, 0x59, 0xcb, 0x57, - 0x5a, 0xe6, 0xae, 0xc4, 0x91, 0x35, 0x75, 0x21, 0xd3, 0x30, 0x99, 0x31, 0x7e, 0xc8, 0xc0, 0xfb, - 0xca, 0x8c, 0xc9, 0x60, 0xa2, 0x03, 0xbc, 0x7d, 0xe3, 0x8c, 0x59, 0xfb, 0x87, 0xf9, 0x32, 0xdf, - 0x95, 0xc5, 0x45, 0xbb, 0xb2, 0x74, 0x77, 0x57, 0xde, 0xd8, 0x42, 0xe5, 0x7b, 0x6d, 0xa1, 0xcb, - 0xa1, 0x59, 0xb9, 0x8f, 0xa1, 0x69, 0x6f, 0xa2, 0xda, 0x8e, 0xaf, 0xf8, 0x57, 0x06, 0x23, 0x44, - 0xe2, 0xff, 0xd1, 0x12, 0xa7, 0xd2, 0x34, 0x5a, 0x4b, 0xed, 0x82, 0x5b, 0x8e, 0x23, 0x2b, 0x59, - 0x92, 0xe4, 0xc7, 0xdd, 0x3d, 0x39, 0x6b, 0x1a, 0xa7, 0x67, 0x4d, 0xe3, 0xcf, 0x59, 0xd3, 0xf8, - 0x7e, 0xde, 0xcc, 0x9d, 0x9e, 0x37, 0x73, 0xbf, 0xce, 0x9b, 0xb9, 0x8f, 0x5b, 0x33, 0x2f, 0x23, - 0x19, 0xdf, 0xd2, 0xdb, 0x00, 0x0b, 0xd8, 0x07, 0xe7, 0xd8, 0x49, 0xfe, 0xeb, 0xe0, 0xbd, 0x0e, - 0x4a, 0x90, 0x7f, 0xf6, 0x37, 0x00, 0x00, 0xff, 0xff, 0xa3, 0x4e, 0x8b, 0xbe, 0x40, 0x07, 0x00, - 0x00, -} - -func (m *Order) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *Order) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *Order) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.TriggerStatus { - i-- - if m.TriggerStatus { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i-- - dAtA[i] = 0x78 - } - { - size := m.TriggerPrice.Size() - i -= size - if _, err := m.TriggerPrice.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintOrder(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x72 - { - size := m.Nominal.Size() - i -= size - if _, err := m.Nominal.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintOrder(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x6a - if len(m.StatusDescription) > 0 { - i -= len(m.StatusDescription) - copy(dAtA[i:], m.StatusDescription) - i = encodeVarintOrder(dAtA, i, uint64(len(m.StatusDescription))) - i-- - dAtA[i] = 0x62 - } - if len(m.Data) > 0 { - i -= len(m.Data) - copy(dAtA[i:], m.Data) - i = encodeVarintOrder(dAtA, i, uint64(len(m.Data))) - i-- - dAtA[i] = 0x5a - } - if m.PositionDirection != 0 { - i = encodeVarintOrder(dAtA, i, uint64(m.PositionDirection)) - i-- - dAtA[i] = 0x50 - } - if m.OrderType != 0 { - i = encodeVarintOrder(dAtA, i, uint64(m.OrderType)) - i-- - dAtA[i] = 0x48 - } - if len(m.AssetDenom) > 0 { - i -= len(m.AssetDenom) - copy(dAtA[i:], m.AssetDenom) - i = encodeVarintOrder(dAtA, i, uint64(len(m.AssetDenom))) - i-- - dAtA[i] = 0x42 - } - if len(m.PriceDenom) > 0 { - i -= len(m.PriceDenom) - copy(dAtA[i:], m.PriceDenom) - i = encodeVarintOrder(dAtA, i, uint64(len(m.PriceDenom))) - i-- - dAtA[i] = 0x3a - } - { - size := m.Quantity.Size() - i -= size - if _, err := m.Quantity.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintOrder(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x32 - { - size := m.Price.Size() - i -= size - if _, err := m.Price.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintOrder(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x2a - if len(m.ContractAddr) > 0 { - i -= len(m.ContractAddr) - copy(dAtA[i:], m.ContractAddr) - i = encodeVarintOrder(dAtA, i, uint64(len(m.ContractAddr))) - i-- - dAtA[i] = 0x22 - } - if len(m.Account) > 0 { - i -= len(m.Account) - copy(dAtA[i:], m.Account) - i = encodeVarintOrder(dAtA, i, uint64(len(m.Account))) - i-- - dAtA[i] = 0x1a - } - if m.Status != 0 { - i = encodeVarintOrder(dAtA, i, uint64(m.Status)) - i-- - dAtA[i] = 0x10 - } - if m.Id != 0 { - i = encodeVarintOrder(dAtA, i, uint64(m.Id)) - i-- - dAtA[i] = 0x8 - } - return len(dAtA) - i, nil -} - -func (m *Cancellation) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *Cancellation) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *Cancellation) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - { - size := m.Price.Size() - i -= size - if _, err := m.Price.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintOrder(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x42 - if m.PositionDirection != 0 { - i = encodeVarintOrder(dAtA, i, uint64(m.PositionDirection)) - i-- - dAtA[i] = 0x38 - } - if len(m.AssetDenom) > 0 { - i -= len(m.AssetDenom) - copy(dAtA[i:], m.AssetDenom) - i = encodeVarintOrder(dAtA, i, uint64(len(m.AssetDenom))) - i-- - dAtA[i] = 0x32 - } - if len(m.PriceDenom) > 0 { - i -= len(m.PriceDenom) - copy(dAtA[i:], m.PriceDenom) - i = encodeVarintOrder(dAtA, i, uint64(len(m.PriceDenom))) - i-- - dAtA[i] = 0x2a - } - if len(m.ContractAddr) > 0 { - i -= len(m.ContractAddr) - copy(dAtA[i:], m.ContractAddr) - i = encodeVarintOrder(dAtA, i, uint64(len(m.ContractAddr))) - i-- - dAtA[i] = 0x22 - } - if len(m.Creator) > 0 { - i -= len(m.Creator) - copy(dAtA[i:], m.Creator) - i = encodeVarintOrder(dAtA, i, uint64(len(m.Creator))) - i-- - dAtA[i] = 0x1a - } - if m.Initiator != 0 { - i = encodeVarintOrder(dAtA, i, uint64(m.Initiator)) - i-- - dAtA[i] = 0x10 - } - if m.Id != 0 { - i = encodeVarintOrder(dAtA, i, uint64(m.Id)) - i-- - dAtA[i] = 0x8 - } - return len(dAtA) - i, nil -} - -func (m *ActiveOrders) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *ActiveOrders) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *ActiveOrders) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Ids) > 0 { - dAtA2 := make([]byte, len(m.Ids)*10) - var j1 int - for _, num := range m.Ids { - for num >= 1<<7 { - dAtA2[j1] = uint8(uint64(num)&0x7f | 0x80) - num >>= 7 - j1++ - } - dAtA2[j1] = uint8(num) - j1++ - } - i -= j1 - copy(dAtA[i:], dAtA2[:j1]) - i = encodeVarintOrder(dAtA, i, uint64(j1)) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func encodeVarintOrder(dAtA []byte, offset int, v uint64) int { - offset -= sovOrder(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *Order) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Id != 0 { - n += 1 + sovOrder(uint64(m.Id)) - } - if m.Status != 0 { - n += 1 + sovOrder(uint64(m.Status)) - } - l = len(m.Account) - if l > 0 { - n += 1 + l + sovOrder(uint64(l)) - } - l = len(m.ContractAddr) - if l > 0 { - n += 1 + l + sovOrder(uint64(l)) - } - l = m.Price.Size() - n += 1 + l + sovOrder(uint64(l)) - l = m.Quantity.Size() - n += 1 + l + sovOrder(uint64(l)) - l = len(m.PriceDenom) - if l > 0 { - n += 1 + l + sovOrder(uint64(l)) - } - l = len(m.AssetDenom) - if l > 0 { - n += 1 + l + sovOrder(uint64(l)) - } - if m.OrderType != 0 { - n += 1 + sovOrder(uint64(m.OrderType)) - } - if m.PositionDirection != 0 { - n += 1 + sovOrder(uint64(m.PositionDirection)) - } - l = len(m.Data) - if l > 0 { - n += 1 + l + sovOrder(uint64(l)) - } - l = len(m.StatusDescription) - if l > 0 { - n += 1 + l + sovOrder(uint64(l)) - } - l = m.Nominal.Size() - n += 1 + l + sovOrder(uint64(l)) - l = m.TriggerPrice.Size() - n += 1 + l + sovOrder(uint64(l)) - if m.TriggerStatus { - n += 2 - } - return n -} - -func (m *Cancellation) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Id != 0 { - n += 1 + sovOrder(uint64(m.Id)) - } - if m.Initiator != 0 { - n += 1 + sovOrder(uint64(m.Initiator)) - } - l = len(m.Creator) - if l > 0 { - n += 1 + l + sovOrder(uint64(l)) - } - l = len(m.ContractAddr) - if l > 0 { - n += 1 + l + sovOrder(uint64(l)) - } - l = len(m.PriceDenom) - if l > 0 { - n += 1 + l + sovOrder(uint64(l)) - } - l = len(m.AssetDenom) - if l > 0 { - n += 1 + l + sovOrder(uint64(l)) - } - if m.PositionDirection != 0 { - n += 1 + sovOrder(uint64(m.PositionDirection)) - } - l = m.Price.Size() - n += 1 + l + sovOrder(uint64(l)) - return n -} - -func (m *ActiveOrders) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if len(m.Ids) > 0 { - l = 0 - for _, e := range m.Ids { - l += sovOrder(uint64(e)) - } - n += 1 + sovOrder(uint64(l)) + l - } - return n -} - -func sovOrder(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozOrder(x uint64) (n int) { - return sovOrder(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *Order) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowOrder - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: Order: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Order: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) - } - m.Id = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowOrder - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Id |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType) - } - m.Status = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowOrder - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Status |= OrderStatus(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Account", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowOrder - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthOrder - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthOrder - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Account = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractAddr", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowOrder - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthOrder - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthOrder - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ContractAddr = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 5: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Price", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowOrder - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthOrder - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthOrder - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.Price.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 6: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Quantity", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowOrder - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthOrder - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthOrder - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.Quantity.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 7: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PriceDenom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowOrder - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthOrder - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthOrder - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.PriceDenom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 8: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field AssetDenom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowOrder - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthOrder - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthOrder - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.AssetDenom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 9: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field OrderType", wireType) - } - m.OrderType = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowOrder - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.OrderType |= OrderType(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 10: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field PositionDirection", wireType) - } - m.PositionDirection = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowOrder - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.PositionDirection |= PositionDirection(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 11: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowOrder - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthOrder - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthOrder - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Data = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 12: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field StatusDescription", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowOrder - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthOrder - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthOrder - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.StatusDescription = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 13: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Nominal", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowOrder - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthOrder - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthOrder - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.Nominal.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 14: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field TriggerPrice", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowOrder - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthOrder - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthOrder - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.TriggerPrice.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 15: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field TriggerStatus", wireType) - } - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowOrder - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.TriggerStatus = bool(v != 0) - default: - iNdEx = preIndex - skippy, err := skipOrder(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthOrder - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *Cancellation) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowOrder - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: Cancellation: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Cancellation: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) - } - m.Id = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowOrder - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Id |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Initiator", wireType) - } - m.Initiator = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowOrder - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Initiator |= CancellationInitiator(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowOrder - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthOrder - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthOrder - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Creator = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractAddr", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowOrder - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthOrder - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthOrder - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ContractAddr = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 5: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PriceDenom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowOrder - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthOrder - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthOrder - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.PriceDenom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 6: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field AssetDenom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowOrder - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthOrder - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthOrder - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.AssetDenom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 7: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field PositionDirection", wireType) - } - m.PositionDirection = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowOrder - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.PositionDirection |= PositionDirection(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 8: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Price", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowOrder - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthOrder - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthOrder - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.Price.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipOrder(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthOrder - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *ActiveOrders) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowOrder - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: ActiveOrders: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: ActiveOrders: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType == 0 { - var v uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowOrder - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.Ids = append(m.Ids, v) - } else if wireType == 2 { - var packedLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowOrder - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - packedLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if packedLen < 0 { - return ErrInvalidLengthOrder - } - postIndex := iNdEx + packedLen - if postIndex < 0 { - return ErrInvalidLengthOrder - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - var elementCount int - var count int - for _, integer := range dAtA[iNdEx:postIndex] { - if integer < 128 { - count++ - } - } - elementCount = count - if elementCount != 0 && len(m.Ids) == 0 { - m.Ids = make([]uint64, 0, elementCount) - } - for iNdEx < postIndex { - var v uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowOrder - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.Ids = append(m.Ids, v) - } - } else { - return fmt.Errorf("proto: wrong wireType = %d for field Ids", wireType) - } - default: - iNdEx = preIndex - skippy, err := skipOrder(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthOrder - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipOrder(dAtA []byte) (n int, err error) { - l := len(dAtA) - iNdEx := 0 - depth := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowOrder - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowOrder - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - iNdEx++ - if dAtA[iNdEx-1] < 0x80 { - break - } - } - case 1: - iNdEx += 8 - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowOrder - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if length < 0 { - return 0, ErrInvalidLengthOrder - } - iNdEx += length - case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupOrder - } - depth-- - case 5: - iNdEx += 4 - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - if iNdEx < 0 { - return 0, ErrInvalidLengthOrder - } - if depth == 0 { - return iNdEx, nil - } - } - return 0, io.ErrUnexpectedEOF -} - -var ( - ErrInvalidLengthOrder = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowOrder = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupOrder = fmt.Errorf("proto: unexpected end of group") -) diff --git a/x/dex/types/order_cancellation.go b/x/dex/types/order_cancellation.go deleted file mode 100644 index 7067b98f6..000000000 --- a/x/dex/types/order_cancellation.go +++ /dev/null @@ -1,9 +0,0 @@ -package types - -type SudoOrderCancellationMsg struct { - OrderCancellations OrderCancellationMsgDetails `json:"bulk_order_cancellations"` -} - -type OrderCancellationMsgDetails struct { - IdsToCancel []uint64 `json:"ids"` -} diff --git a/x/dex/types/order_entry.pb.go b/x/dex/types/order_entry.pb.go deleted file mode 100644 index dafbc63fc..000000000 --- a/x/dex/types/order_entry.pb.go +++ /dev/null @@ -1,790 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: dex/order_entry.proto - -package types - -import ( - fmt "fmt" - github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" - _ "github.com/gogo/protobuf/gogoproto" - proto "github.com/gogo/protobuf/proto" - io "io" - math "math" - math_bits "math/bits" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package - -type OrderEntry struct { - Price github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,1,opt,name=price,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"price" yaml:"price"` - Quantity github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,2,opt,name=quantity,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"quantity" yaml:"quantity"` - Allocations []*Allocation `protobuf:"bytes,3,rep,name=allocations,proto3" json:"allocations"` - PriceDenom string `protobuf:"bytes,4,opt,name=priceDenom,proto3" json:"price_denom"` - AssetDenom string `protobuf:"bytes,5,opt,name=assetDenom,proto3" json:"asset_denom"` -} - -func (m *OrderEntry) Reset() { *m = OrderEntry{} } -func (m *OrderEntry) String() string { return proto.CompactTextString(m) } -func (*OrderEntry) ProtoMessage() {} -func (*OrderEntry) Descriptor() ([]byte, []int) { - return fileDescriptor_25878922effe12c2, []int{0} -} -func (m *OrderEntry) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *OrderEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_OrderEntry.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *OrderEntry) XXX_Merge(src proto.Message) { - xxx_messageInfo_OrderEntry.Merge(m, src) -} -func (m *OrderEntry) XXX_Size() int { - return m.Size() -} -func (m *OrderEntry) XXX_DiscardUnknown() { - xxx_messageInfo_OrderEntry.DiscardUnknown(m) -} - -var xxx_messageInfo_OrderEntry proto.InternalMessageInfo - -func (m *OrderEntry) GetAllocations() []*Allocation { - if m != nil { - return m.Allocations - } - return nil -} - -func (m *OrderEntry) GetPriceDenom() string { - if m != nil { - return m.PriceDenom - } - return "" -} - -func (m *OrderEntry) GetAssetDenom() string { - if m != nil { - return m.AssetDenom - } - return "" -} - -type Allocation struct { - OrderId uint64 `protobuf:"varint,1,opt,name=orderId,proto3" json:"order_id"` - Quantity github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,2,opt,name=quantity,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"quantity" yaml:"quantity"` - Account string `protobuf:"bytes,3,opt,name=account,proto3" json:"account"` -} - -func (m *Allocation) Reset() { *m = Allocation{} } -func (m *Allocation) String() string { return proto.CompactTextString(m) } -func (*Allocation) ProtoMessage() {} -func (*Allocation) Descriptor() ([]byte, []int) { - return fileDescriptor_25878922effe12c2, []int{1} -} -func (m *Allocation) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *Allocation) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_Allocation.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *Allocation) XXX_Merge(src proto.Message) { - xxx_messageInfo_Allocation.Merge(m, src) -} -func (m *Allocation) XXX_Size() int { - return m.Size() -} -func (m *Allocation) XXX_DiscardUnknown() { - xxx_messageInfo_Allocation.DiscardUnknown(m) -} - -var xxx_messageInfo_Allocation proto.InternalMessageInfo - -func (m *Allocation) GetOrderId() uint64 { - if m != nil { - return m.OrderId - } - return 0 -} - -func (m *Allocation) GetAccount() string { - if m != nil { - return m.Account - } - return "" -} - -func init() { - proto.RegisterType((*OrderEntry)(nil), "seiprotocol.seichain.dex.OrderEntry") - proto.RegisterType((*Allocation)(nil), "seiprotocol.seichain.dex.Allocation") -} - -func init() { proto.RegisterFile("dex/order_entry.proto", fileDescriptor_25878922effe12c2) } - -var fileDescriptor_25878922effe12c2 = []byte{ - // 395 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x52, 0xb1, 0x6a, 0xe3, 0x40, - 0x10, 0x95, 0x4e, 0xf6, 0xf9, 0x6e, 0x6d, 0x30, 0x88, 0x3b, 0x10, 0x29, 0x24, 0x23, 0x12, 0xe3, - 0xc6, 0x12, 0x24, 0x5d, 0xba, 0x08, 0x07, 0x93, 0x22, 0x04, 0xd4, 0x04, 0x02, 0xc1, 0xc8, 0xab, - 0xc5, 0x5e, 0x22, 0x69, 0x1d, 0xed, 0x1a, 0xac, 0xbf, 0x48, 0x7e, 0x2a, 0xb8, 0x74, 0x19, 0x52, - 0x88, 0x60, 0x77, 0x2e, 0xfd, 0x05, 0x61, 0x47, 0x91, 0xad, 0x26, 0x45, 0x9a, 0x54, 0x9a, 0x79, - 0x33, 0x6f, 0xde, 0xec, 0x3c, 0xa1, 0xff, 0x21, 0x59, 0xb8, 0x2c, 0x0d, 0x49, 0x3a, 0x22, 0x89, - 0x48, 0x33, 0x67, 0x96, 0x32, 0xc1, 0x74, 0x83, 0x13, 0x0a, 0x11, 0x66, 0x91, 0xc3, 0x09, 0xc5, - 0xd3, 0x80, 0x26, 0x4e, 0x48, 0x16, 0x47, 0xff, 0x26, 0x6c, 0xc2, 0xa0, 0xe4, 0xca, 0xa8, 0xe8, - 0xb7, 0x9f, 0x35, 0x84, 0x6e, 0xe4, 0x94, 0x4b, 0x39, 0x44, 0xbf, 0x47, 0xf5, 0x59, 0x4a, 0x31, - 0x31, 0xd4, 0x8e, 0xda, 0xfb, 0xeb, 0x0d, 0x97, 0xb9, 0xa5, 0xbc, 0xe5, 0x56, 0x77, 0x42, 0xc5, - 0x74, 0x3e, 0x76, 0x30, 0x8b, 0x5d, 0xcc, 0x78, 0xcc, 0xf8, 0xe7, 0xa7, 0xcf, 0xc3, 0x07, 0x57, - 0x64, 0x33, 0xc2, 0x9d, 0x01, 0xc1, 0xdb, 0xdc, 0x2a, 0xe8, 0xbb, 0xdc, 0x6a, 0x65, 0x41, 0x1c, - 0x9d, 0xdb, 0x90, 0xda, 0x7e, 0x01, 0xeb, 0x14, 0xfd, 0x79, 0x9c, 0x07, 0x89, 0xa0, 0x22, 0x33, - 0x7e, 0x81, 0xc2, 0xf5, 0xb7, 0x15, 0xf6, 0x13, 0x76, 0xb9, 0xd5, 0x2e, 0x44, 0x4a, 0xc4, 0xf6, - 0xf7, 0x45, 0xfd, 0x16, 0x35, 0x83, 0x28, 0x62, 0x38, 0x10, 0x94, 0x25, 0xdc, 0xd0, 0x3a, 0x5a, - 0xaf, 0x79, 0x7a, 0xec, 0x7c, 0x75, 0x1e, 0xe7, 0x62, 0xdf, 0xec, 0xb5, 0xb7, 0xb9, 0x55, 0x25, - 0xfb, 0xd5, 0x44, 0x77, 0x11, 0x82, 0xc7, 0x0c, 0x48, 0xc2, 0x62, 0xa3, 0x06, 0xaf, 0x00, 0x06, - 0xa0, 0xa3, 0x50, 0xc2, 0x7e, 0xa5, 0x45, 0x12, 0x02, 0xce, 0x89, 0x28, 0x08, 0xf5, 0x03, 0x01, - 0xd0, 0x92, 0x70, 0x68, 0xb1, 0x5f, 0x54, 0x84, 0x0e, 0xeb, 0xe8, 0x5d, 0xd4, 0x00, 0x9f, 0xaf, - 0x42, 0x70, 0xa5, 0xe6, 0xb5, 0xe4, 0x15, 0x0a, 0xeb, 0x69, 0xe8, 0x97, 0xc5, 0x9f, 0x3c, 0xee, - 0x09, 0x6a, 0x04, 0x18, 0xb3, 0x79, 0x22, 0x0c, 0x0d, 0x94, 0x9a, 0xdb, 0xdc, 0x2a, 0x21, 0xbf, - 0x0c, 0xbc, 0xe1, 0x72, 0x6d, 0xaa, 0xab, 0xb5, 0xa9, 0xbe, 0xaf, 0x4d, 0xf5, 0x69, 0x63, 0x2a, - 0xab, 0x8d, 0xa9, 0xbc, 0x6e, 0x4c, 0xe5, 0xae, 0x5f, 0xd9, 0x88, 0x13, 0xda, 0x2f, 0x3d, 0x81, - 0x04, 0x4c, 0x71, 0x17, 0xae, 0xfc, 0xc3, 0x61, 0xb9, 0xf1, 0x6f, 0xa8, 0x9f, 0x7d, 0x04, 0x00, - 0x00, 0xff, 0xff, 0x59, 0x65, 0xd6, 0x5e, 0xf5, 0x02, 0x00, 0x00, -} - -func (m *OrderEntry) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *OrderEntry) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *OrderEntry) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.AssetDenom) > 0 { - i -= len(m.AssetDenom) - copy(dAtA[i:], m.AssetDenom) - i = encodeVarintOrderEntry(dAtA, i, uint64(len(m.AssetDenom))) - i-- - dAtA[i] = 0x2a - } - if len(m.PriceDenom) > 0 { - i -= len(m.PriceDenom) - copy(dAtA[i:], m.PriceDenom) - i = encodeVarintOrderEntry(dAtA, i, uint64(len(m.PriceDenom))) - i-- - dAtA[i] = 0x22 - } - if len(m.Allocations) > 0 { - for iNdEx := len(m.Allocations) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Allocations[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintOrderEntry(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x1a - } - } - { - size := m.Quantity.Size() - i -= size - if _, err := m.Quantity.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintOrderEntry(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - { - size := m.Price.Size() - i -= size - if _, err := m.Price.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintOrderEntry(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil -} - -func (m *Allocation) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *Allocation) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *Allocation) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Account) > 0 { - i -= len(m.Account) - copy(dAtA[i:], m.Account) - i = encodeVarintOrderEntry(dAtA, i, uint64(len(m.Account))) - i-- - dAtA[i] = 0x1a - } - { - size := m.Quantity.Size() - i -= size - if _, err := m.Quantity.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintOrderEntry(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - if m.OrderId != 0 { - i = encodeVarintOrderEntry(dAtA, i, uint64(m.OrderId)) - i-- - dAtA[i] = 0x8 - } - return len(dAtA) - i, nil -} - -func encodeVarintOrderEntry(dAtA []byte, offset int, v uint64) int { - offset -= sovOrderEntry(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *OrderEntry) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = m.Price.Size() - n += 1 + l + sovOrderEntry(uint64(l)) - l = m.Quantity.Size() - n += 1 + l + sovOrderEntry(uint64(l)) - if len(m.Allocations) > 0 { - for _, e := range m.Allocations { - l = e.Size() - n += 1 + l + sovOrderEntry(uint64(l)) - } - } - l = len(m.PriceDenom) - if l > 0 { - n += 1 + l + sovOrderEntry(uint64(l)) - } - l = len(m.AssetDenom) - if l > 0 { - n += 1 + l + sovOrderEntry(uint64(l)) - } - return n -} - -func (m *Allocation) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.OrderId != 0 { - n += 1 + sovOrderEntry(uint64(m.OrderId)) - } - l = m.Quantity.Size() - n += 1 + l + sovOrderEntry(uint64(l)) - l = len(m.Account) - if l > 0 { - n += 1 + l + sovOrderEntry(uint64(l)) - } - return n -} - -func sovOrderEntry(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozOrderEntry(x uint64) (n int) { - return sovOrderEntry(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *OrderEntry) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowOrderEntry - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: OrderEntry: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: OrderEntry: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Price", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowOrderEntry - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthOrderEntry - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthOrderEntry - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.Price.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Quantity", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowOrderEntry - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthOrderEntry - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthOrderEntry - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.Quantity.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Allocations", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowOrderEntry - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthOrderEntry - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthOrderEntry - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Allocations = append(m.Allocations, &Allocation{}) - if err := m.Allocations[len(m.Allocations)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PriceDenom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowOrderEntry - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthOrderEntry - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthOrderEntry - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.PriceDenom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 5: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field AssetDenom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowOrderEntry - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthOrderEntry - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthOrderEntry - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.AssetDenom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipOrderEntry(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthOrderEntry - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *Allocation) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowOrderEntry - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: Allocation: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Allocation: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field OrderId", wireType) - } - m.OrderId = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowOrderEntry - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.OrderId |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Quantity", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowOrderEntry - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthOrderEntry - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthOrderEntry - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.Quantity.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Account", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowOrderEntry - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthOrderEntry - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthOrderEntry - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Account = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipOrderEntry(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthOrderEntry - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipOrderEntry(dAtA []byte) (n int, err error) { - l := len(dAtA) - iNdEx := 0 - depth := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowOrderEntry - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowOrderEntry - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - iNdEx++ - if dAtA[iNdEx-1] < 0x80 { - break - } - } - case 1: - iNdEx += 8 - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowOrderEntry - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if length < 0 { - return 0, ErrInvalidLengthOrderEntry - } - iNdEx += length - case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupOrderEntry - } - depth-- - case 5: - iNdEx += 4 - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - if iNdEx < 0 { - return 0, ErrInvalidLengthOrderEntry - } - if depth == 0 { - return iNdEx, nil - } - } - return 0, io.ErrUnexpectedEOF -} - -var ( - ErrInvalidLengthOrderEntry = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowOrderEntry = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupOrderEntry = fmt.Errorf("proto: unexpected end of group") -) diff --git a/x/dex/types/order_placement.go b/x/dex/types/order_placement.go deleted file mode 100644 index 1104e1e01..000000000 --- a/x/dex/types/order_placement.go +++ /dev/null @@ -1,31 +0,0 @@ -package types - -import ( - "fmt" -) - -type SudoOrderPlacementMsg struct { - OrderPlacements OrderPlacementMsgDetails `json:"bulk_order_placements"` -} - -type OrderPlacementMsgDetails struct { - Orders []Order `json:"orders"` - Deposits []ContractDepositInfo `json:"deposits"` -} - -func (m *SudoOrderPlacementMsg) IsEmpty() bool { - return len(m.OrderPlacements.Deposits) == 0 && len(m.OrderPlacements.Orders) == 0 -} - -type SudoOrderPlacementResponse struct { - UnsuccessfulOrders []UnsuccessfulOrder `json:"unsuccessful_orders"` -} - -type UnsuccessfulOrder struct { - ID uint64 `json:"id"` - Reason string `json:"reason"` -} - -func (r SudoOrderPlacementResponse) String() string { - return fmt.Sprintf("Unsuccessful orders count: %d", len(r.UnsuccessfulOrders)) -} diff --git a/x/dex/types/orders.go b/x/dex/types/orders.go deleted file mode 100644 index 54c0eaf77..000000000 --- a/x/dex/types/orders.go +++ /dev/null @@ -1,244 +0,0 @@ -package types - -import ( - "github.com/cosmos/cosmos-sdk/store/prefix" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/utils" -) - -type OrderBook struct { - Contract ContractAddress - Pair Pair - Longs *CachedSortedOrderBookEntries - Shorts *CachedSortedOrderBookEntries -} - -// entries are always sorted by prices in ascending order, regardless of side -type CachedSortedOrderBookEntries struct { - CachedEntries []OrderBookEntry - currentPtr int - currentChanged bool - - loader func(ctx sdk.Context, startingPriceExclusive sdk.Dec, withLimit bool) []OrderBookEntry - setter func(sdk.Context, OrderBookEntry) - deleter func(sdk.Context, OrderBookEntry) -} - -func NewCachedSortedOrderBookEntries( - loader func(ctx sdk.Context, startingPriceExclusive sdk.Dec, withLimit bool) []OrderBookEntry, - setter func(sdk.Context, OrderBookEntry), - deleter func(sdk.Context, OrderBookEntry), -) *CachedSortedOrderBookEntries { - return &CachedSortedOrderBookEntries{ - CachedEntries: []OrderBookEntry{}, - currentPtr: 0, - currentChanged: false, - loader: loader, - setter: setter, - deleter: deleter, - } -} - -func (c *CachedSortedOrderBookEntries) load(ctx sdk.Context) { - var loaded []OrderBookEntry - if len(c.CachedEntries) == 0 { - loaded = c.loader(ctx, sdk.ZeroDec(), false) - } else { - loaded = c.loader(ctx, c.CachedEntries[len(c.CachedEntries)-1].GetOrderEntry().Price, true) - } - c.CachedEntries = append(c.CachedEntries, loaded...) -} - -// Reduce quantity of the order book entry currently being pointed at by the specified quantity. -// Also remove/reduce allocations of the order book entry in FIFO order. If the order book entry -// does not have enough quantity to settle against, the returned `settled` value will equal to -// the quantity of the order book entry; otherwise it will equal to the specified quantity. -func (c *CachedSortedOrderBookEntries) SettleQuantity(_ sdk.Context, quantity sdk.Dec) (res []ToSettle, settled sdk.Dec) { - if quantity.IsZero() { - return []ToSettle{}, quantity - } - currentEntry := c.CachedEntries[c.currentPtr].GetOrderEntry() - c.currentChanged = true - - if quantity.GTE(currentEntry.Quantity) { - res = utils.Map(currentEntry.Allocations, AllocationToSettle) - settled = currentEntry.Quantity - currentEntry.Quantity = sdk.ZeroDec() - currentEntry.Allocations = []*Allocation{} - return res, settled - } - - settled = sdk.ZeroDec() - newFirstAllocationIdx := 0 - for idx, a := range currentEntry.Allocations { - postSettle := settled.Add(a.Quantity) - if postSettle.LTE(quantity) { - settled = postSettle - res = append(res, AllocationToSettle(a)) - } else { - newFirstAllocationIdx = idx - if settled.Equal(quantity) { - break - } - res = append(res, ToSettle{ - OrderID: a.OrderId, - Account: a.Account, - Amount: quantity.Sub(settled), - }) - a.Quantity = a.Quantity.Sub(quantity.Sub(settled)) - settled = quantity - break - } - } - currentEntry.Quantity = currentEntry.Quantity.Sub(quantity) - currentEntry.Allocations = currentEntry.Allocations[newFirstAllocationIdx:] - return res, settled -} - -// Discard all dirty changes and reload -func (c *CachedSortedOrderBookEntries) Refresh(ctx sdk.Context) { - c.CachedEntries = c.loader(ctx, sdk.ZeroDec(), false) - c.currentPtr = 0 - c.currentChanged = false -} - -func (c *CachedSortedOrderBookEntries) Flush(ctx sdk.Context) { - stop := c.currentPtr - if !c.currentChanged { - stop-- - } - for i := 0; i <= stop; i++ { - if i >= len(c.CachedEntries) { - break - } - entry := c.CachedEntries[i] - if entry.GetOrderEntry().Quantity.IsZero() { - c.deleter(ctx, entry) - } else { - c.setter(ctx, entry) - } - } - c.CachedEntries = c.CachedEntries[c.currentPtr:] - c.currentPtr = 0 - c.currentChanged = false -} - -// Next will only move on to the next order if the current order quantity hits zero. -// So it should not be used for read-only iteration -func (c *CachedSortedOrderBookEntries) Next(ctx sdk.Context) OrderBookEntry { - for c.currentPtr < len(c.CachedEntries) && c.CachedEntries[c.currentPtr].GetOrderEntry().Quantity.IsZero() { - c.currentPtr++ - c.currentChanged = false - } - if c.currentPtr >= len(c.CachedEntries) { - c.load(ctx) - // if nothing is loaded, we've reached the end - if c.currentPtr >= len(c.CachedEntries) { - return nil - } - } - return c.CachedEntries[c.currentPtr] -} - -type OrderBookEntry interface { - GetPrice() sdk.Dec - GetOrderEntry() *OrderEntry - DeepCopy() OrderBookEntry - SetEntry(*OrderEntry) - SetPrice(sdk.Dec) -} - -func (m *LongBook) SetPrice(p sdk.Dec) { - m.Price = p -} - -type PriceStore struct { - Store prefix.Store - PriceKeys [][]byte -} - -func (m *LongBook) GetPrice() sdk.Dec { - return m.Price -} - -func (m *LongBook) GetOrderEntry() *OrderEntry { - return m.Entry -} - -func (m *LongBook) SetEntry(newEntry *OrderEntry) { - m.Entry = newEntry -} - -func (m *LongBook) DeepCopy() OrderBookEntry { - allocations := []*Allocation{} - for _, allo := range m.Entry.Allocations { - allocations = append(allocations, &Allocation{ - OrderId: allo.OrderId, - Quantity: allo.Quantity, - Account: allo.Account, - }) - } - newOrderEntry := OrderEntry{ - Price: m.Entry.Price, - Quantity: m.Entry.Quantity, - PriceDenom: m.Entry.PriceDenom, - AssetDenom: m.Entry.AssetDenom, - Allocations: allocations, - } - return &LongBook{ - Price: m.Price, - Entry: &newOrderEntry, - } -} - -func (m *ShortBook) SetPrice(p sdk.Dec) { - m.Price = p -} - -func (m *ShortBook) GetPrice() sdk.Dec { - return m.Price -} - -func (m *ShortBook) GetOrderEntry() *OrderEntry { - return m.Entry -} - -func (m *ShortBook) SetEntry(newEntry *OrderEntry) { - m.Entry = newEntry -} - -func (m *ShortBook) DeepCopy() OrderBookEntry { - allocations := []*Allocation{} - for _, allo := range m.Entry.Allocations { - allocations = append(allocations, &Allocation{ - OrderId: allo.OrderId, - Quantity: allo.Quantity, - Account: allo.Account, - }) - } - newOrderEntry := OrderEntry{ - Price: m.Entry.Price, - Quantity: m.Entry.Quantity, - PriceDenom: m.Entry.PriceDenom, - AssetDenom: m.Entry.AssetDenom, - Allocations: allocations, - } - return &ShortBook{ - Price: m.Price, - Entry: &newOrderEntry, - } -} - -type ToSettle struct { - OrderID uint64 - Amount sdk.Dec - Account string -} - -func AllocationToSettle(a *Allocation) ToSettle { - return ToSettle{ - OrderID: a.OrderId, - Amount: a.Quantity, - Account: a.Account, - } -} diff --git a/x/dex/types/orders_test.go b/x/dex/types/orders_test.go deleted file mode 100644 index 65439dfc4..000000000 --- a/x/dex/types/orders_test.go +++ /dev/null @@ -1,166 +0,0 @@ -package types_test - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex/keeper" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -var TestEntryOne = types.OrderEntry{ - Price: sdk.MustNewDecFromStr("10"), - Quantity: sdk.MustNewDecFromStr("3"), - PriceDenom: keepertest.TestPriceDenom, - AssetDenom: keepertest.TestAssetDenom, - Allocations: []*types.Allocation{ - { - Quantity: sdk.MustNewDecFromStr("2"), - Account: "abc", - OrderId: 1, - }, { - Quantity: sdk.MustNewDecFromStr("1"), - Account: "def", - OrderId: 2, - }, - }, -} - -var TestEntryTwo = types.OrderEntry{ - Price: sdk.MustNewDecFromStr("11"), - Quantity: sdk.MustNewDecFromStr("2"), - PriceDenom: keepertest.TestPriceDenom, - AssetDenom: keepertest.TestAssetDenom, - Allocations: []*types.Allocation{ - { - Quantity: sdk.MustNewDecFromStr("2"), - Account: "ghi", - OrderId: 3, - }, - }, -} - -func getCachedSortedOrderBookEntries(keeper *keeper.Keeper) *types.CachedSortedOrderBookEntries { - loader := func(lctx sdk.Context, startExclusive sdk.Dec, withLimit bool) []types.OrderBookEntry { - if !withLimit { - return keeper.GetTopNLongBooksForPair(lctx, keepertest.TestContract, keepertest.TestPriceDenom, keepertest.TestAssetDenom, 1) - } - return keeper.GetTopNLongBooksForPairStarting(lctx, keepertest.TestContract, keepertest.TestPriceDenom, keepertest.TestAssetDenom, 1, startExclusive) - } - setter := func(lctx sdk.Context, o types.OrderBookEntry) { - keeper.SetLongOrderBookEntry(lctx, keepertest.TestContract, o) - } - deleter := func(lctx sdk.Context, o types.OrderBookEntry) { - keeper.RemoveLongBookByPrice(lctx, keepertest.TestContract, o.GetPrice(), keepertest.TestPriceDenom, keepertest.TestAssetDenom) - } - return types.NewCachedSortedOrderBookEntries(loader, setter, deleter) -} - -func populateEntries(ctx sdk.Context, keeper *keeper.Keeper) { - keeper.SetLongBook(ctx, keepertest.TestContract, types.LongBook{ - Price: TestEntryOne.Price, - Entry: &TestEntryOne, - }) - keeper.SetLongBook(ctx, keepertest.TestContract, types.LongBook{ - Price: TestEntryTwo.Price, - Entry: &TestEntryTwo, - }) -} - -func TestIterateAndMutate(t *testing.T) { - dexkeeper, ctx := keepertest.DexKeeper(t) - populateEntries(ctx, dexkeeper) - cache := getCachedSortedOrderBookEntries(dexkeeper) - // first Next should return entry two since its a higher priced long - entry := cache.Next(ctx) - require.NotNil(t, entry) - require.Equal(t, TestEntryTwo.Price, entry.GetPrice()) - require.Equal(t, TestEntryTwo, *entry.GetOrderEntry()) - res, settled := cache.SettleQuantity(ctx, sdk.OneDec()) - require.Equal(t, []types.ToSettle{{ - Amount: sdk.OneDec(), - Account: "ghi", - OrderID: 3, - }}, res) - require.Equal(t, sdk.OneDec(), settled) - - // second Next should still return entry two with decreased quantity - entry = cache.Next(ctx) - require.NotNil(t, entry) - require.Equal(t, TestEntryTwo.Price, entry.GetPrice()) - require.Equal(t, sdk.OneDec(), entry.GetOrderEntry().Quantity) - require.Equal(t, 1, len(entry.GetOrderEntry().Allocations)) - require.Equal(t, types.Allocation{ - Quantity: sdk.OneDec(), - Account: "ghi", - OrderId: 3, - }, *entry.GetOrderEntry().Allocations[0]) - res, settled = cache.SettleQuantity(ctx, sdk.OneDec()) - require.Equal(t, []types.ToSettle{{ - Amount: sdk.OneDec(), - Account: "ghi", - OrderID: 3, - }}, res) - require.Equal(t, sdk.OneDec(), settled) - - // third Next should return entry one since entry two has fully settled (whether flushed or not) - entry = cache.Next(ctx) - require.NotNil(t, entry) - require.Equal(t, TestEntryOne.Price, entry.GetPrice()) - require.Equal(t, TestEntryOne, *entry.GetOrderEntry()) - res, settled = cache.SettleQuantity(ctx, sdk.NewDec(4)) - require.Equal(t, []types.ToSettle{{ - Amount: sdk.NewDec(2), - Account: "abc", - OrderID: 1, - }, { - Amount: sdk.NewDec(1), - Account: "def", - OrderID: 2, - }}, res) - require.Equal(t, sdk.NewDec(3), settled) - - // fourth Next should return nil - entry = cache.Next(ctx) - require.Nil(t, entry) -} - -func TestRefreshAndFlush(t *testing.T) { - dexkeeper, ctx := keepertest.DexKeeper(t) - populateEntries(ctx, dexkeeper) - cache := getCachedSortedOrderBookEntries(dexkeeper) - _ = cache.Next(ctx) - _, _ = cache.SettleQuantity(ctx, sdk.OneDec()) - // refresh without flushing settle changes should undo the settle - cache.Refresh(ctx) - entry := cache.Next(ctx) - require.NotNil(t, entry) - require.Equal(t, TestEntryTwo.Price, entry.GetPrice()) - require.Equal(t, TestEntryTwo, *entry.GetOrderEntry()) - - _, _ = cache.SettleQuantity(ctx, sdk.OneDec()) - cache.Flush(ctx) - // refresh after flushing should reflect the settle change - cache.Refresh(ctx) - entry = cache.Next(ctx) - require.NotNil(t, entry) - require.Equal(t, TestEntryTwo.Price, entry.GetPrice()) - require.Equal(t, sdk.OneDec(), entry.GetOrderEntry().Quantity) - require.Equal(t, 1, len(entry.GetOrderEntry().Allocations)) - require.Equal(t, types.Allocation{ - Quantity: sdk.OneDec(), - Account: "ghi", - OrderId: 3, - }, *entry.GetOrderEntry().Allocations[0]) - - _, _ = cache.SettleQuantity(ctx, sdk.OneDec()) - cache.Flush(ctx) - // refresh after flushing a deleted entry should result in the next Next being the next entry - cache.Refresh(ctx) - entry = cache.Next(ctx) - require.NotNil(t, entry) - require.Equal(t, TestEntryOne.Price, entry.GetPrice()) - require.Equal(t, TestEntryOne, *entry.GetOrderEntry()) -} diff --git a/x/dex/types/pair.pb.go b/x/dex/types/pair.pb.go deleted file mode 100644 index 55841676d..000000000 --- a/x/dex/types/pair.pb.go +++ /dev/null @@ -1,718 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: dex/pair.proto - -package types - -import ( - fmt "fmt" - github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" - _ "github.com/gogo/protobuf/gogoproto" - proto "github.com/gogo/protobuf/proto" - io "io" - math "math" - math_bits "math/bits" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package - -type Pair struct { - PriceDenom string `protobuf:"bytes,1,opt,name=priceDenom,proto3" json:"price_denom"` - AssetDenom string `protobuf:"bytes,2,opt,name=assetDenom,proto3" json:"asset_denom"` - PriceTicksize *github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,3,opt,name=priceTicksize,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"price_tick_size"` - QuantityTicksize *github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,4,opt,name=quantityTicksize,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"quantity_tick_size"` -} - -func (m *Pair) Reset() { *m = Pair{} } -func (m *Pair) String() string { return proto.CompactTextString(m) } -func (*Pair) ProtoMessage() {} -func (*Pair) Descriptor() ([]byte, []int) { - return fileDescriptor_d4350ebee878f69a, []int{0} -} -func (m *Pair) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *Pair) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_Pair.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *Pair) XXX_Merge(src proto.Message) { - xxx_messageInfo_Pair.Merge(m, src) -} -func (m *Pair) XXX_Size() int { - return m.Size() -} -func (m *Pair) XXX_DiscardUnknown() { - xxx_messageInfo_Pair.DiscardUnknown(m) -} - -var xxx_messageInfo_Pair proto.InternalMessageInfo - -func (m *Pair) GetPriceDenom() string { - if m != nil { - return m.PriceDenom - } - return "" -} - -func (m *Pair) GetAssetDenom() string { - if m != nil { - return m.AssetDenom - } - return "" -} - -type BatchContractPair struct { - ContractAddr string `protobuf:"bytes,1,opt,name=contractAddr,proto3" json:"contract_addr"` - Pairs []*Pair `protobuf:"bytes,2,rep,name=pairs,proto3" json:"pairs"` -} - -func (m *BatchContractPair) Reset() { *m = BatchContractPair{} } -func (m *BatchContractPair) String() string { return proto.CompactTextString(m) } -func (*BatchContractPair) ProtoMessage() {} -func (*BatchContractPair) Descriptor() ([]byte, []int) { - return fileDescriptor_d4350ebee878f69a, []int{1} -} -func (m *BatchContractPair) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *BatchContractPair) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_BatchContractPair.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *BatchContractPair) XXX_Merge(src proto.Message) { - xxx_messageInfo_BatchContractPair.Merge(m, src) -} -func (m *BatchContractPair) XXX_Size() int { - return m.Size() -} -func (m *BatchContractPair) XXX_DiscardUnknown() { - xxx_messageInfo_BatchContractPair.DiscardUnknown(m) -} - -var xxx_messageInfo_BatchContractPair proto.InternalMessageInfo - -func (m *BatchContractPair) GetContractAddr() string { - if m != nil { - return m.ContractAddr - } - return "" -} - -func (m *BatchContractPair) GetPairs() []*Pair { - if m != nil { - return m.Pairs - } - return nil -} - -func init() { - proto.RegisterType((*Pair)(nil), "seiprotocol.seichain.dex.Pair") - proto.RegisterType((*BatchContractPair)(nil), "seiprotocol.seichain.dex.BatchContractPair") -} - -func init() { proto.RegisterFile("dex/pair.proto", fileDescriptor_d4350ebee878f69a) } - -var fileDescriptor_d4350ebee878f69a = []byte{ - // 368 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x52, 0x3f, 0x4f, 0xf2, 0x40, - 0x18, 0xa7, 0xc0, 0xfb, 0x26, 0x1c, 0x22, 0xd2, 0x38, 0x34, 0x0e, 0x2d, 0x61, 0x30, 0x2c, 0xf4, - 0x12, 0x8d, 0xb3, 0xa1, 0x92, 0xb8, 0x9a, 0xc6, 0xc9, 0x85, 0x1c, 0x77, 0x97, 0x72, 0x41, 0x7a, - 0xf5, 0xee, 0x48, 0xc0, 0xaf, 0xe0, 0xe2, 0x77, 0x72, 0x61, 0x64, 0x34, 0x0e, 0x8d, 0x81, 0xad, - 0x9f, 0xc2, 0xdc, 0x95, 0x0a, 0xc4, 0x38, 0x38, 0xdd, 0x3d, 0xbf, 0xe7, 0xf7, 0xa7, 0x7d, 0x9e, - 0x03, 0xc7, 0x84, 0xce, 0x61, 0x82, 0x98, 0xf0, 0x13, 0xc1, 0x15, 0xb7, 0x1d, 0x49, 0x99, 0xb9, - 0x61, 0xfe, 0xe8, 0x4b, 0xca, 0xf0, 0x18, 0xb1, 0xd8, 0x27, 0x74, 0x7e, 0x76, 0x1a, 0xf1, 0x88, - 0x9b, 0x16, 0xd4, 0xb7, 0x9c, 0xdf, 0x79, 0x2b, 0x83, 0xea, 0x1d, 0x62, 0xc2, 0x86, 0x00, 0x24, - 0x82, 0x61, 0x3a, 0xa0, 0x31, 0x9f, 0x3a, 0x56, 0xdb, 0xea, 0xd6, 0x82, 0x66, 0x96, 0x7a, 0x75, - 0x83, 0x0e, 0x89, 0x86, 0xc3, 0x3d, 0x8a, 0x16, 0x20, 0x29, 0xa9, 0xca, 0x05, 0xe5, 0x9d, 0xc0, - 0xa0, 0x85, 0x60, 0x47, 0xb1, 0x23, 0xd0, 0x30, 0xf2, 0x7b, 0x86, 0x27, 0x92, 0x3d, 0x53, 0xa7, - 0x62, 0x34, 0xfd, 0x65, 0xea, 0x59, 0x1f, 0xa9, 0x77, 0x1e, 0x31, 0x35, 0x9e, 0x8d, 0x7c, 0xcc, - 0xa7, 0x10, 0x73, 0x39, 0xe5, 0x72, 0x7b, 0xf4, 0x24, 0x99, 0x40, 0xb5, 0x48, 0xa8, 0xf4, 0x07, - 0x14, 0x67, 0xa9, 0xd7, 0xcc, 0x3f, 0x49, 0x31, 0x3c, 0x19, 0x6a, 0xa3, 0xf0, 0xd0, 0xd7, 0x4e, - 0xc0, 0xc9, 0xd3, 0x0c, 0xc5, 0x8a, 0xa9, 0xc5, 0x77, 0x56, 0xd5, 0x64, 0x0d, 0xfe, 0x9c, 0x65, - 0x17, 0x4e, 0x7b, 0x71, 0x3f, 0xdc, 0x3b, 0x2f, 0x16, 0x68, 0x05, 0x48, 0xe1, 0xf1, 0x0d, 0x8f, - 0x95, 0x40, 0x58, 0x99, 0x91, 0x5e, 0x81, 0x23, 0xbc, 0xad, 0xfb, 0x84, 0x88, 0xed, 0x50, 0x5b, - 0x59, 0xea, 0x35, 0x0a, 0x7c, 0x88, 0x08, 0x11, 0xe1, 0x01, 0xcd, 0xbe, 0x06, 0xff, 0xf4, 0x42, - 0xa5, 0x53, 0x6e, 0x57, 0xba, 0xf5, 0x0b, 0xd7, 0xff, 0x6d, 0xa5, 0xbe, 0x4e, 0x09, 0x6a, 0x59, - 0xea, 0xe5, 0x82, 0x30, 0x3f, 0x82, 0xdb, 0xe5, 0xda, 0xb5, 0x56, 0x6b, 0xd7, 0xfa, 0x5c, 0xbb, - 0xd6, 0xeb, 0xc6, 0x2d, 0xad, 0x36, 0x6e, 0xe9, 0x7d, 0xe3, 0x96, 0x1e, 0x7a, 0x7b, 0xff, 0x2d, - 0x29, 0xeb, 0x15, 0xb6, 0xa6, 0x30, 0xbe, 0x70, 0x0e, 0xf5, 0x8b, 0x32, 0x23, 0x18, 0xfd, 0x37, - 0xfd, 0xcb, 0xaf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xd0, 0x03, 0x32, 0x50, 0x65, 0x02, 0x00, 0x00, -} - -func (m *Pair) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *Pair) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *Pair) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.QuantityTicksize != nil { - { - size := m.QuantityTicksize.Size() - i -= size - if _, err := m.QuantityTicksize.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintPair(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x22 - } - if m.PriceTicksize != nil { - { - size := m.PriceTicksize.Size() - i -= size - if _, err := m.PriceTicksize.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintPair(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x1a - } - if len(m.AssetDenom) > 0 { - i -= len(m.AssetDenom) - copy(dAtA[i:], m.AssetDenom) - i = encodeVarintPair(dAtA, i, uint64(len(m.AssetDenom))) - i-- - dAtA[i] = 0x12 - } - if len(m.PriceDenom) > 0 { - i -= len(m.PriceDenom) - copy(dAtA[i:], m.PriceDenom) - i = encodeVarintPair(dAtA, i, uint64(len(m.PriceDenom))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *BatchContractPair) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *BatchContractPair) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *BatchContractPair) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Pairs) > 0 { - for iNdEx := len(m.Pairs) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Pairs[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintPair(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - } - } - if len(m.ContractAddr) > 0 { - i -= len(m.ContractAddr) - copy(dAtA[i:], m.ContractAddr) - i = encodeVarintPair(dAtA, i, uint64(len(m.ContractAddr))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func encodeVarintPair(dAtA []byte, offset int, v uint64) int { - offset -= sovPair(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *Pair) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.PriceDenom) - if l > 0 { - n += 1 + l + sovPair(uint64(l)) - } - l = len(m.AssetDenom) - if l > 0 { - n += 1 + l + sovPair(uint64(l)) - } - if m.PriceTicksize != nil { - l = m.PriceTicksize.Size() - n += 1 + l + sovPair(uint64(l)) - } - if m.QuantityTicksize != nil { - l = m.QuantityTicksize.Size() - n += 1 + l + sovPair(uint64(l)) - } - return n -} - -func (m *BatchContractPair) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.ContractAddr) - if l > 0 { - n += 1 + l + sovPair(uint64(l)) - } - if len(m.Pairs) > 0 { - for _, e := range m.Pairs { - l = e.Size() - n += 1 + l + sovPair(uint64(l)) - } - } - return n -} - -func sovPair(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozPair(x uint64) (n int) { - return sovPair(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *Pair) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowPair - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: Pair: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Pair: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PriceDenom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowPair - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthPair - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthPair - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.PriceDenom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field AssetDenom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowPair - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthPair - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthPair - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.AssetDenom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PriceTicksize", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowPair - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthPair - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthPair - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - var v github_com_cosmos_cosmos_sdk_types.Dec - m.PriceTicksize = &v - if err := m.PriceTicksize.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field QuantityTicksize", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowPair - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthPair - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthPair - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - var v github_com_cosmos_cosmos_sdk_types.Dec - m.QuantityTicksize = &v - if err := m.QuantityTicksize.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipPair(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthPair - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *BatchContractPair) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowPair - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: BatchContractPair: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: BatchContractPair: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractAddr", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowPair - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthPair - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthPair - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ContractAddr = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Pairs", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowPair - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthPair - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthPair - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Pairs = append(m.Pairs, &Pair{}) - if err := m.Pairs[len(m.Pairs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipPair(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthPair - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipPair(dAtA []byte) (n int, err error) { - l := len(dAtA) - iNdEx := 0 - depth := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowPair - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowPair - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - iNdEx++ - if dAtA[iNdEx-1] < 0x80 { - break - } - } - case 1: - iNdEx += 8 - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowPair - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if length < 0 { - return 0, ErrInvalidLengthPair - } - iNdEx += length - case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupPair - } - depth-- - case 5: - iNdEx += 4 - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - if iNdEx < 0 { - return 0, ErrInvalidLengthPair - } - if depth == 0 { - return iNdEx, nil - } - } - return 0, io.ErrUnexpectedEOF -} - -var ( - ErrInvalidLengthPair = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowPair = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupPair = fmt.Errorf("proto: unexpected end of group") -) diff --git a/x/dex/types/params.go b/x/dex/types/params.go deleted file mode 100644 index aa0f4cde7..000000000 --- a/x/dex/types/params.go +++ /dev/null @@ -1,143 +0,0 @@ -package types - -import ( - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" - paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - "gopkg.in/yaml.v2" -) - -var ( - KeyPriceSnapshotRetention = []byte("PriceSnapshotRetention") // number of epochs to retain price snapshots for - KeySudoCallGasPrice = []byte("KeySudoCallGasPrice") // gas price for sudo calls from endblock - KeyBeginBlockGasLimit = []byte("KeyBeginBlockGasLimit") - KeyEndBlockGasLimit = []byte("KeyEndBlockGasLimit") - KeyDefaultGasPerOrder = []byte("KeyDefaultGasPerOrder") - KeyDefaultGasPerCancel = []byte("KeyDefaultGasPerCancel") - KeyMinRentDeposit = []byte("KeyMinRentDeposit") - KeyGasAllowancePerSettlement = []byte("KeyGasAllowancePerSettlement") - KeyMinProcessableRent = []byte("KeyMinProcessableRent") - KeyOrderBookEntriesPerLoad = []byte("KeyOrderBookEntriesPerLoad") - KeyContractUnsuspendCost = []byte("KeyContractUnsuspendCost") - KeyMaxOrderPerPrice = []byte("KeyMaxOrderPerPrice") - KeyMaxPairsPerContract = []byte("KeyMaxPairsPerContract") - KeyDefaultGasPerOrderDataByte = []byte("KeyDefaultGasPerOrderDataByte") -) - -const ( - DefaultPriceSnapshotRetention = 24 * 3600 // default to one day - DefaultBeginBlockGasLimit = 200000000 // 200M - DefaultEndBlockGasLimit = 1000000000 // 1B - DefaultDefaultGasPerOrder = 55000 - DefaultDefaultGasPerCancel = 53000 - DefaultMinRentDeposit = 10000000 // 10 sei - DefaultGasAllowancePerSettlement = 10000 - DefaultMinProcessableRent = 100000 - DefaultOrderBookEntriesPerLoad = 10 - DefaultContractUnsuspendCost = 1000000 - DefaultMaxOrderPerPrice = 10000 - DefaultMaxPairsPerContract = 100 - DefaultDefaultGasPerOrderDataByte = 30 -) - -var DefaultSudoCallGasPrice = sdk.NewDecWithPrec(1, 1) // 0.1 - -var _ paramtypes.ParamSet = (*Params)(nil) - -// ParamKeyTable the param key table for launch module -func ParamKeyTable() paramtypes.KeyTable { - return paramtypes.NewKeyTable().RegisterParamSet(&Params{}) -} - -// DefaultParams returns a default set of parameters -func DefaultParams() Params { - return Params{ - PriceSnapshotRetention: DefaultPriceSnapshotRetention, - SudoCallGasPrice: DefaultSudoCallGasPrice, - BeginBlockGasLimit: DefaultBeginBlockGasLimit, - EndBlockGasLimit: DefaultEndBlockGasLimit, - DefaultGasPerOrder: DefaultDefaultGasPerOrder, - DefaultGasPerCancel: DefaultDefaultGasPerCancel, - MinRentDeposit: DefaultMinRentDeposit, - GasAllowancePerSettlement: DefaultGasAllowancePerSettlement, - MinProcessableRent: DefaultMinProcessableRent, - OrderBookEntriesPerLoad: DefaultOrderBookEntriesPerLoad, - ContractUnsuspendCost: DefaultContractUnsuspendCost, - MaxOrderPerPrice: DefaultMaxOrderPerPrice, - MaxPairsPerContract: DefaultMaxPairsPerContract, - DefaultGasPerOrderDataByte: DefaultDefaultGasPerOrderDataByte, - } -} - -// ParamSetPairs get the params.ParamSet -func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { - return paramtypes.ParamSetPairs{ - paramtypes.NewParamSetPair(KeyPriceSnapshotRetention, &p.PriceSnapshotRetention, validatePriceSnapshotRetention), - paramtypes.NewParamSetPair(KeySudoCallGasPrice, &p.SudoCallGasPrice, validateSudoCallGasPrice), - paramtypes.NewParamSetPair(KeyBeginBlockGasLimit, &p.BeginBlockGasLimit, validateUint64Param), - paramtypes.NewParamSetPair(KeyEndBlockGasLimit, &p.EndBlockGasLimit, validateUint64Param), - paramtypes.NewParamSetPair(KeyDefaultGasPerOrder, &p.DefaultGasPerOrder, validateUint64Param), - paramtypes.NewParamSetPair(KeyDefaultGasPerCancel, &p.DefaultGasPerCancel, validateUint64Param), - paramtypes.NewParamSetPair(KeyMinRentDeposit, &p.MinRentDeposit, validateUint64Param), - paramtypes.NewParamSetPair(KeyGasAllowancePerSettlement, &p.GasAllowancePerSettlement, validateUint64Param), - paramtypes.NewParamSetPair(KeyMinProcessableRent, &p.MinProcessableRent, validateUint64Param), - paramtypes.NewParamSetPair(KeyOrderBookEntriesPerLoad, &p.OrderBookEntriesPerLoad, validateUint64Param), - paramtypes.NewParamSetPair(KeyContractUnsuspendCost, &p.ContractUnsuspendCost, validateUint64Param), - paramtypes.NewParamSetPair(KeyMaxOrderPerPrice, &p.MaxOrderPerPrice, validateUint64Param), - paramtypes.NewParamSetPair(KeyMaxPairsPerContract, &p.MaxPairsPerContract, validateUint64Param), - paramtypes.NewParamSetPair(KeyDefaultGasPerOrderDataByte, &p.DefaultGasPerOrderDataByte, validateUint64Param), - } -} - -// Validate validates the set of params -func (p Params) Validate() error { - if err := validatePriceSnapshotRetention(p.PriceSnapshotRetention); err != nil { - return err - } - if err := validateSudoCallGasPrice(p.SudoCallGasPrice); err != nil { - return err - } - // it's not possible for other params to fail validation if they've already - // made it into Params' fields. - return nil -} - -// String implements the Stringer interface. -func (p Params) String() string { - out, _ := yaml.Marshal(p) - return string(out) -} - -func validatePriceSnapshotRetention(i interface{}) error { - v, ok := i.(uint64) - if !ok { - return fmt.Errorf("invalid parameter type: %T", i) - } - - if v == 0 { - return fmt.Errorf("price snapshot retention must be a positive integer: %d", v) - } - - return nil -} - -func validateSudoCallGasPrice(i interface{}) error { - price, ok := i.(sdk.Dec) - if !ok { - return fmt.Errorf("invalid parameter type: %T", i) - } - if !price.IsPositive() { - return fmt.Errorf("nonpositive sudo call price") - } - return nil -} - -func validateUint64Param(i interface{}) error { - _, ok := i.(uint64) - if !ok { - return fmt.Errorf("invalid parameter type: %T", i) - } - - return nil -} diff --git a/x/dex/types/params.pb.go b/x/dex/types/params.pb.go deleted file mode 100644 index 7322767bc..000000000 --- a/x/dex/types/params.pb.go +++ /dev/null @@ -1,870 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: dex/params.proto - -package types - -import ( - fmt "fmt" - github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" - _ "github.com/gogo/protobuf/gogoproto" - proto "github.com/gogo/protobuf/proto" - io "io" - math "math" - math_bits "math/bits" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package - -// Params defines the parameters for the module. -type Params struct { - PriceSnapshotRetention uint64 `protobuf:"varint,1,opt,name=price_snapshot_retention,json=priceSnapshotRetention,proto3" json:"price_snapshot_retention" yaml:"price_snapshot_retention"` - SudoCallGasPrice github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,2,opt,name=sudo_call_gas_price,json=sudoCallGasPrice,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"sudo_call_gas_price"` - BeginBlockGasLimit uint64 `protobuf:"varint,3,opt,name=begin_block_gas_limit,json=beginBlockGasLimit,proto3" json:"begin_block_gas_limit" yaml:"begin_block_gas_limit"` - EndBlockGasLimit uint64 `protobuf:"varint,4,opt,name=end_block_gas_limit,json=endBlockGasLimit,proto3" json:"end_block_gas_limit" yaml:"end_block_gas_limit"` - DefaultGasPerOrder uint64 `protobuf:"varint,5,opt,name=default_gas_per_order,json=defaultGasPerOrder,proto3" json:"default_gas_per_order" yaml:"default_gas_per_order"` - DefaultGasPerCancel uint64 `protobuf:"varint,6,opt,name=default_gas_per_cancel,json=defaultGasPerCancel,proto3" json:"default_gas_per_cancel" yaml:"default_gas_per_cancel"` - MinRentDeposit uint64 `protobuf:"varint,7,opt,name=min_rent_deposit,json=minRentDeposit,proto3" json:"min_rent_deposit" yaml:"min_rent_deposit"` - GasAllowancePerSettlement uint64 `protobuf:"varint,8,opt,name=gas_allowance_per_settlement,json=gasAllowancePerSettlement,proto3" json:"gas_allowance_per_settlement" yaml:"gas_allowance_per_settlement"` - MinProcessableRent uint64 `protobuf:"varint,9,opt,name=min_processable_rent,json=minProcessableRent,proto3" json:"min_processable_rent" yaml:"min_processable_rent"` - OrderBookEntriesPerLoad uint64 `protobuf:"varint,10,opt,name=order_book_entries_per_load,json=orderBookEntriesPerLoad,proto3" json:"order_book_entries_per_load" yaml:"order_book_entries_per_load"` - ContractUnsuspendCost uint64 `protobuf:"varint,11,opt,name=contract_unsuspend_cost,json=contractUnsuspendCost,proto3" json:"contract_unsuspend_cost" yaml:"contract_unsuspend_cost"` - MaxOrderPerPrice uint64 `protobuf:"varint,12,opt,name=max_order_per_price,json=maxOrderPerPrice,proto3" json:"max_order_per_price" yaml:"max_order_per_price"` - MaxPairsPerContract uint64 `protobuf:"varint,13,opt,name=max_pairs_per_contract,json=maxPairsPerContract,proto3" json:"max_pairs_per_contract" yaml:"max_pairs_per_contract"` - DefaultGasPerOrderDataByte uint64 `protobuf:"varint,14,opt,name=default_gas_per_order_data_byte,json=defaultGasPerOrderDataByte,proto3" json:"default_gas_per_order_data_byte" yaml:"default_gas_per_order_data_byte"` -} - -func (m *Params) Reset() { *m = Params{} } -func (*Params) ProtoMessage() {} -func (*Params) Descriptor() ([]byte, []int) { - return fileDescriptor_e49286500ccff43e, []int{0} -} -func (m *Params) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_Params.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *Params) XXX_Merge(src proto.Message) { - xxx_messageInfo_Params.Merge(m, src) -} -func (m *Params) XXX_Size() int { - return m.Size() -} -func (m *Params) XXX_DiscardUnknown() { - xxx_messageInfo_Params.DiscardUnknown(m) -} - -var xxx_messageInfo_Params proto.InternalMessageInfo - -func (m *Params) GetPriceSnapshotRetention() uint64 { - if m != nil { - return m.PriceSnapshotRetention - } - return 0 -} - -func (m *Params) GetBeginBlockGasLimit() uint64 { - if m != nil { - return m.BeginBlockGasLimit - } - return 0 -} - -func (m *Params) GetEndBlockGasLimit() uint64 { - if m != nil { - return m.EndBlockGasLimit - } - return 0 -} - -func (m *Params) GetDefaultGasPerOrder() uint64 { - if m != nil { - return m.DefaultGasPerOrder - } - return 0 -} - -func (m *Params) GetDefaultGasPerCancel() uint64 { - if m != nil { - return m.DefaultGasPerCancel - } - return 0 -} - -func (m *Params) GetMinRentDeposit() uint64 { - if m != nil { - return m.MinRentDeposit - } - return 0 -} - -func (m *Params) GetGasAllowancePerSettlement() uint64 { - if m != nil { - return m.GasAllowancePerSettlement - } - return 0 -} - -func (m *Params) GetMinProcessableRent() uint64 { - if m != nil { - return m.MinProcessableRent - } - return 0 -} - -func (m *Params) GetOrderBookEntriesPerLoad() uint64 { - if m != nil { - return m.OrderBookEntriesPerLoad - } - return 0 -} - -func (m *Params) GetContractUnsuspendCost() uint64 { - if m != nil { - return m.ContractUnsuspendCost - } - return 0 -} - -func (m *Params) GetMaxOrderPerPrice() uint64 { - if m != nil { - return m.MaxOrderPerPrice - } - return 0 -} - -func (m *Params) GetMaxPairsPerContract() uint64 { - if m != nil { - return m.MaxPairsPerContract - } - return 0 -} - -func (m *Params) GetDefaultGasPerOrderDataByte() uint64 { - if m != nil { - return m.DefaultGasPerOrderDataByte - } - return 0 -} - -func init() { - proto.RegisterType((*Params)(nil), "seiprotocol.seichain.dex.Params") -} - -func init() { proto.RegisterFile("dex/params.proto", fileDescriptor_e49286500ccff43e) } - -var fileDescriptor_e49286500ccff43e = []byte{ - // 787 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x95, 0xc1, 0x6f, 0x1b, 0x45, - 0x14, 0xc6, 0xbd, 0x50, 0x42, 0x3b, 0x94, 0xca, 0xda, 0x34, 0xc9, 0x92, 0x16, 0x4f, 0x35, 0x48, - 0x55, 0x2f, 0xb1, 0x0f, 0x08, 0x21, 0x8a, 0x10, 0xc2, 0x49, 0x94, 0x4b, 0x11, 0xd6, 0x54, 0x1c, - 0xe0, 0xb2, 0x1a, 0xef, 0x3e, 0x9c, 0x51, 0x66, 0x67, 0x56, 0x33, 0x63, 0x61, 0x9f, 0xb9, 0x70, - 0x44, 0x9c, 0x38, 0xf6, 0xcf, 0xe9, 0xb1, 0x47, 0xc4, 0x61, 0x84, 0x92, 0x0b, 0xda, 0xe3, 0xfe, - 0x05, 0x68, 0x66, 0x6d, 0x96, 0x24, 0x6b, 0xf7, 0x94, 0xcd, 0xf7, 0xfb, 0xb4, 0xdf, 0x7b, 0xde, - 0x79, 0x6f, 0x50, 0x3f, 0x87, 0xc5, 0xa8, 0x64, 0x9a, 0x15, 0x66, 0x58, 0x6a, 0x65, 0x55, 0x9c, - 0x18, 0xe0, 0xe1, 0x29, 0x53, 0x62, 0x68, 0x80, 0x67, 0xe7, 0x8c, 0xcb, 0x61, 0x0e, 0x8b, 0xc3, - 0x87, 0x33, 0x35, 0x53, 0x01, 0x8d, 0xfc, 0x53, 0xe3, 0x27, 0xf5, 0x7d, 0xb4, 0x33, 0x09, 0x2f, - 0x88, 0x97, 0x28, 0x29, 0x35, 0xcf, 0x20, 0x35, 0x92, 0x95, 0xe6, 0x5c, 0xd9, 0x54, 0x83, 0x05, - 0x69, 0xb9, 0x92, 0x49, 0xf4, 0x24, 0x7a, 0x76, 0x67, 0xfc, 0x75, 0xe5, 0xf0, 0x46, 0x4f, 0xed, - 0x30, 0x5e, 0xb2, 0x42, 0x3c, 0x27, 0x9b, 0x1c, 0x84, 0xee, 0x07, 0xf4, 0x72, 0x45, 0xe8, 0x1a, - 0xc4, 0x16, 0xed, 0x9a, 0x79, 0xae, 0xd2, 0x8c, 0x09, 0x91, 0xce, 0x98, 0x49, 0x83, 0x2f, 0x79, - 0xe7, 0x49, 0xf4, 0xec, 0xde, 0xf8, 0xf4, 0xb5, 0xc3, 0xbd, 0xbf, 0x1c, 0x7e, 0x3a, 0xe3, 0xf6, - 0x7c, 0x3e, 0x1d, 0x66, 0xaa, 0x18, 0x65, 0xca, 0x14, 0xca, 0xac, 0xfe, 0x1c, 0x99, 0xfc, 0x62, - 0x64, 0x97, 0x25, 0x98, 0xe1, 0x09, 0x64, 0x95, 0xc3, 0x5d, 0x2f, 0xa3, 0x7d, 0x2f, 0x1e, 0x33, - 0x21, 0xce, 0x98, 0x99, 0x78, 0x25, 0x16, 0x68, 0x6f, 0x0a, 0x33, 0x2e, 0xd3, 0xa9, 0x50, 0xd9, - 0x45, 0xb0, 0x0a, 0x5e, 0x70, 0x9b, 0xbc, 0x1b, 0xba, 0xfd, 0xa2, 0x72, 0xb8, 0xdb, 0x50, 0x3b, - 0xfc, 0xb8, 0x69, 0xb5, 0x13, 0x13, 0x1a, 0x07, 0x7d, 0xec, 0xe5, 0x33, 0x66, 0x5e, 0x78, 0x31, - 0xce, 0xd1, 0x2e, 0xc8, 0xfc, 0x56, 0xd6, 0x9d, 0x90, 0xf5, 0x99, 0xaf, 0xba, 0x03, 0xd7, 0x0e, - 0x1f, 0x36, 0x49, 0x1d, 0x90, 0xd0, 0x3e, 0xc8, 0xfc, 0x7a, 0x8a, 0x40, 0x7b, 0x39, 0xfc, 0xc4, - 0xe6, 0xc2, 0x36, 0xad, 0x83, 0x4e, 0x95, 0xce, 0x41, 0x27, 0xef, 0xb5, 0x3d, 0x75, 0x1a, 0xda, - 0x9e, 0x3a, 0x31, 0xa1, 0xf1, 0x4a, 0xf7, 0x3f, 0x1f, 0xe8, 0xef, 0xbc, 0x18, 0x97, 0x68, 0xff, - 0xa6, 0x3b, 0x63, 0x32, 0x03, 0x91, 0xec, 0x84, 0xb8, 0x2f, 0x2b, 0x87, 0x37, 0x38, 0x6a, 0x87, - 0x3f, 0xee, 0xce, 0x6b, 0x38, 0xa1, 0xbb, 0xd7, 0x02, 0x8f, 0x83, 0x1a, 0xff, 0x80, 0xfa, 0x05, - 0x97, 0xa9, 0x06, 0x69, 0xd3, 0x1c, 0x4a, 0x65, 0xb8, 0x4d, 0xde, 0x0f, 0x59, 0xa3, 0xca, 0xe1, - 0x5b, 0xac, 0x76, 0xf8, 0xa0, 0x49, 0xb9, 0x49, 0x08, 0x7d, 0x50, 0x70, 0x49, 0x41, 0xda, 0x93, - 0x46, 0x88, 0x7f, 0x8d, 0xd0, 0x63, 0x5f, 0x03, 0x13, 0x42, 0xfd, 0xec, 0xd3, 0x42, 0x35, 0x06, - 0xac, 0x15, 0x50, 0x80, 0xb4, 0xc9, 0xdd, 0x90, 0x73, 0x56, 0x39, 0xbc, 0xd5, 0x57, 0x3b, 0xfc, - 0x49, 0x93, 0xb9, 0xcd, 0x45, 0xe8, 0x47, 0x33, 0x66, 0xbe, 0x59, 0xd3, 0x09, 0xe8, 0x97, 0xff, - 0xb1, 0x98, 0xa3, 0x87, 0xbe, 0xde, 0x52, 0xab, 0x0c, 0x8c, 0x61, 0x53, 0x01, 0xa1, 0xf6, 0xe4, - 0x5e, 0xa8, 0xe0, 0xf3, 0xca, 0xe1, 0x4e, 0x5e, 0x3b, 0xfc, 0xa8, 0xed, 0xf6, 0x26, 0x25, 0x34, - 0x2e, 0xb8, 0x9c, 0xb4, 0xaa, 0x6f, 0x3e, 0xfe, 0x25, 0x42, 0x8f, 0xc2, 0x17, 0x4e, 0xa7, 0x4a, - 0x5d, 0xa4, 0x20, 0xad, 0xe6, 0xd0, 0x7c, 0x08, 0xa1, 0x58, 0x9e, 0xa0, 0x10, 0x79, 0x5a, 0x39, - 0xbc, 0xcd, 0x56, 0x3b, 0x4c, 0x9a, 0xe4, 0x2d, 0x26, 0x42, 0x0f, 0x02, 0x1d, 0x2b, 0x75, 0x71, - 0xda, 0xb0, 0x09, 0xe8, 0x17, 0x8a, 0xe5, 0xf1, 0x1c, 0x1d, 0x64, 0x4a, 0x5a, 0xcd, 0x32, 0x9b, - 0xce, 0xa5, 0x99, 0x9b, 0xd2, 0x9f, 0xf7, 0x4c, 0x19, 0x9b, 0x7c, 0x10, 0x0a, 0xf8, 0xaa, 0x72, - 0x78, 0x93, 0xa5, 0x76, 0x78, 0xd0, 0x84, 0x6f, 0x30, 0x10, 0xba, 0xb7, 0x26, 0xdf, 0xaf, 0xc1, - 0xb1, 0x32, 0x61, 0x26, 0x0b, 0xb6, 0x68, 0x4e, 0x78, 0x28, 0xb3, 0xd9, 0x3b, 0xf7, 0xdb, 0x99, - 0xec, 0xc0, 0xed, 0x4c, 0x76, 0x40, 0x42, 0xfb, 0x05, 0x5b, 0x84, 0xe9, 0x98, 0x80, 0x6e, 0xf6, - 0x4c, 0x89, 0xf6, 0xbd, 0xb3, 0x64, 0x5c, 0xaf, 0x4e, 0xf8, 0xaa, 0x98, 0xe4, 0xc3, 0x76, 0x4a, - 0xba, 0x1d, 0xed, 0x94, 0x74, 0x73, 0x42, 0x7d, 0x85, 0x13, 0xaf, 0xfb, 0x19, 0x59, 0xa9, 0xf1, - 0xef, 0x11, 0xc2, 0x9d, 0x63, 0x9c, 0xe6, 0xcc, 0xb2, 0x74, 0xba, 0xb4, 0x90, 0x3c, 0x08, 0xd9, - 0xdf, 0x56, 0x0e, 0xbf, 0xcd, 0x5a, 0x3b, 0xfc, 0x74, 0xcb, 0x6a, 0x68, 0x8d, 0x84, 0x1e, 0xde, - 0x5e, 0x12, 0x27, 0xcc, 0xb2, 0xf1, 0xd2, 0xc2, 0xf3, 0xbb, 0x7f, 0xbc, 0xc2, 0xbd, 0x7f, 0x5e, - 0xe1, 0x68, 0x7c, 0xf6, 0xfa, 0x72, 0x10, 0xbd, 0xb9, 0x1c, 0x44, 0x7f, 0x5f, 0x0e, 0xa2, 0xdf, - 0xae, 0x06, 0xbd, 0x37, 0x57, 0x83, 0xde, 0x9f, 0x57, 0x83, 0xde, 0x8f, 0x47, 0xff, 0xdb, 0xf1, - 0x06, 0xf8, 0xd1, 0xfa, 0x2a, 0x0b, 0xff, 0x84, 0xbb, 0x6c, 0xb4, 0x18, 0xf9, 0x4b, 0x2f, 0xac, - 0xfb, 0xe9, 0x4e, 0xe0, 0x9f, 0xfe, 0x1b, 0x00, 0x00, 0xff, 0xff, 0xff, 0x27, 0x82, 0x3c, 0x08, - 0x07, 0x00, 0x00, -} - -func (this *Params) Equal(that interface{}) bool { - if that == nil { - return this == nil - } - - that1, ok := that.(*Params) - if !ok { - that2, ok := that.(Params) - if ok { - that1 = &that2 - } else { - return false - } - } - if that1 == nil { - return this == nil - } else if this == nil { - return false - } - if this.PriceSnapshotRetention != that1.PriceSnapshotRetention { - return false - } - if !this.SudoCallGasPrice.Equal(that1.SudoCallGasPrice) { - return false - } - if this.BeginBlockGasLimit != that1.BeginBlockGasLimit { - return false - } - if this.EndBlockGasLimit != that1.EndBlockGasLimit { - return false - } - if this.DefaultGasPerOrder != that1.DefaultGasPerOrder { - return false - } - if this.DefaultGasPerCancel != that1.DefaultGasPerCancel { - return false - } - if this.MinRentDeposit != that1.MinRentDeposit { - return false - } - if this.GasAllowancePerSettlement != that1.GasAllowancePerSettlement { - return false - } - if this.MinProcessableRent != that1.MinProcessableRent { - return false - } - if this.OrderBookEntriesPerLoad != that1.OrderBookEntriesPerLoad { - return false - } - if this.ContractUnsuspendCost != that1.ContractUnsuspendCost { - return false - } - if this.MaxOrderPerPrice != that1.MaxOrderPerPrice { - return false - } - if this.MaxPairsPerContract != that1.MaxPairsPerContract { - return false - } - if this.DefaultGasPerOrderDataByte != that1.DefaultGasPerOrderDataByte { - return false - } - return true -} -func (m *Params) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *Params) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.DefaultGasPerOrderDataByte != 0 { - i = encodeVarintParams(dAtA, i, uint64(m.DefaultGasPerOrderDataByte)) - i-- - dAtA[i] = 0x70 - } - if m.MaxPairsPerContract != 0 { - i = encodeVarintParams(dAtA, i, uint64(m.MaxPairsPerContract)) - i-- - dAtA[i] = 0x68 - } - if m.MaxOrderPerPrice != 0 { - i = encodeVarintParams(dAtA, i, uint64(m.MaxOrderPerPrice)) - i-- - dAtA[i] = 0x60 - } - if m.ContractUnsuspendCost != 0 { - i = encodeVarintParams(dAtA, i, uint64(m.ContractUnsuspendCost)) - i-- - dAtA[i] = 0x58 - } - if m.OrderBookEntriesPerLoad != 0 { - i = encodeVarintParams(dAtA, i, uint64(m.OrderBookEntriesPerLoad)) - i-- - dAtA[i] = 0x50 - } - if m.MinProcessableRent != 0 { - i = encodeVarintParams(dAtA, i, uint64(m.MinProcessableRent)) - i-- - dAtA[i] = 0x48 - } - if m.GasAllowancePerSettlement != 0 { - i = encodeVarintParams(dAtA, i, uint64(m.GasAllowancePerSettlement)) - i-- - dAtA[i] = 0x40 - } - if m.MinRentDeposit != 0 { - i = encodeVarintParams(dAtA, i, uint64(m.MinRentDeposit)) - i-- - dAtA[i] = 0x38 - } - if m.DefaultGasPerCancel != 0 { - i = encodeVarintParams(dAtA, i, uint64(m.DefaultGasPerCancel)) - i-- - dAtA[i] = 0x30 - } - if m.DefaultGasPerOrder != 0 { - i = encodeVarintParams(dAtA, i, uint64(m.DefaultGasPerOrder)) - i-- - dAtA[i] = 0x28 - } - if m.EndBlockGasLimit != 0 { - i = encodeVarintParams(dAtA, i, uint64(m.EndBlockGasLimit)) - i-- - dAtA[i] = 0x20 - } - if m.BeginBlockGasLimit != 0 { - i = encodeVarintParams(dAtA, i, uint64(m.BeginBlockGasLimit)) - i-- - dAtA[i] = 0x18 - } - { - size := m.SudoCallGasPrice.Size() - i -= size - if _, err := m.SudoCallGasPrice.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintParams(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - if m.PriceSnapshotRetention != 0 { - i = encodeVarintParams(dAtA, i, uint64(m.PriceSnapshotRetention)) - i-- - dAtA[i] = 0x8 - } - return len(dAtA) - i, nil -} - -func encodeVarintParams(dAtA []byte, offset int, v uint64) int { - offset -= sovParams(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *Params) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.PriceSnapshotRetention != 0 { - n += 1 + sovParams(uint64(m.PriceSnapshotRetention)) - } - l = m.SudoCallGasPrice.Size() - n += 1 + l + sovParams(uint64(l)) - if m.BeginBlockGasLimit != 0 { - n += 1 + sovParams(uint64(m.BeginBlockGasLimit)) - } - if m.EndBlockGasLimit != 0 { - n += 1 + sovParams(uint64(m.EndBlockGasLimit)) - } - if m.DefaultGasPerOrder != 0 { - n += 1 + sovParams(uint64(m.DefaultGasPerOrder)) - } - if m.DefaultGasPerCancel != 0 { - n += 1 + sovParams(uint64(m.DefaultGasPerCancel)) - } - if m.MinRentDeposit != 0 { - n += 1 + sovParams(uint64(m.MinRentDeposit)) - } - if m.GasAllowancePerSettlement != 0 { - n += 1 + sovParams(uint64(m.GasAllowancePerSettlement)) - } - if m.MinProcessableRent != 0 { - n += 1 + sovParams(uint64(m.MinProcessableRent)) - } - if m.OrderBookEntriesPerLoad != 0 { - n += 1 + sovParams(uint64(m.OrderBookEntriesPerLoad)) - } - if m.ContractUnsuspendCost != 0 { - n += 1 + sovParams(uint64(m.ContractUnsuspendCost)) - } - if m.MaxOrderPerPrice != 0 { - n += 1 + sovParams(uint64(m.MaxOrderPerPrice)) - } - if m.MaxPairsPerContract != 0 { - n += 1 + sovParams(uint64(m.MaxPairsPerContract)) - } - if m.DefaultGasPerOrderDataByte != 0 { - n += 1 + sovParams(uint64(m.DefaultGasPerOrderDataByte)) - } - return n -} - -func sovParams(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozParams(x uint64) (n int) { - return sovParams(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *Params) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowParams - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: Params: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field PriceSnapshotRetention", wireType) - } - m.PriceSnapshotRetention = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowParams - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.PriceSnapshotRetention |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field SudoCallGasPrice", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowParams - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthParams - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthParams - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.SudoCallGasPrice.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field BeginBlockGasLimit", wireType) - } - m.BeginBlockGasLimit = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowParams - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.BeginBlockGasLimit |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field EndBlockGasLimit", wireType) - } - m.EndBlockGasLimit = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowParams - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.EndBlockGasLimit |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 5: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field DefaultGasPerOrder", wireType) - } - m.DefaultGasPerOrder = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowParams - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.DefaultGasPerOrder |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 6: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field DefaultGasPerCancel", wireType) - } - m.DefaultGasPerCancel = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowParams - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.DefaultGasPerCancel |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 7: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field MinRentDeposit", wireType) - } - m.MinRentDeposit = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowParams - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.MinRentDeposit |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 8: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field GasAllowancePerSettlement", wireType) - } - m.GasAllowancePerSettlement = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowParams - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.GasAllowancePerSettlement |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 9: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field MinProcessableRent", wireType) - } - m.MinProcessableRent = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowParams - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.MinProcessableRent |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 10: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field OrderBookEntriesPerLoad", wireType) - } - m.OrderBookEntriesPerLoad = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowParams - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.OrderBookEntriesPerLoad |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 11: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractUnsuspendCost", wireType) - } - m.ContractUnsuspendCost = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowParams - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.ContractUnsuspendCost |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 12: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field MaxOrderPerPrice", wireType) - } - m.MaxOrderPerPrice = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowParams - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.MaxOrderPerPrice |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 13: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field MaxPairsPerContract", wireType) - } - m.MaxPairsPerContract = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowParams - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.MaxPairsPerContract |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 14: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field DefaultGasPerOrderDataByte", wireType) - } - m.DefaultGasPerOrderDataByte = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowParams - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.DefaultGasPerOrderDataByte |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipParams(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthParams - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipParams(dAtA []byte) (n int, err error) { - l := len(dAtA) - iNdEx := 0 - depth := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowParams - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowParams - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - iNdEx++ - if dAtA[iNdEx-1] < 0x80 { - break - } - } - case 1: - iNdEx += 8 - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowParams - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if length < 0 { - return 0, ErrInvalidLengthParams - } - iNdEx += length - case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupParams - } - depth-- - case 5: - iNdEx += 4 - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - if iNdEx < 0 { - return 0, ErrInvalidLengthParams - } - if depth == 0 { - return iNdEx, nil - } - } - return 0, io.ErrUnexpectedEOF -} - -var ( - ErrInvalidLengthParams = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowParams = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupParams = fmt.Errorf("proto: unexpected end of group") -) diff --git a/x/dex/types/params_test.go b/x/dex/types/params_test.go deleted file mode 100644 index efd19a5cf..000000000 --- a/x/dex/types/params_test.go +++ /dev/null @@ -1,17 +0,0 @@ -package types_test - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestParamsValidate(t *testing.T) { - p := types.Params{PriceSnapshotRetention: 0} - require.Error(t, p.Validate()) - - p = types.Params{SudoCallGasPrice: sdk.ZeroDec()} - require.Error(t, p.Validate()) -} diff --git a/x/dex/types/price.pb.go b/x/dex/types/price.pb.go deleted file mode 100644 index b85e68649..000000000 --- a/x/dex/types/price.pb.go +++ /dev/null @@ -1,881 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: dex/price.proto - -package types - -import ( - fmt "fmt" - github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" - _ "github.com/gogo/protobuf/gogoproto" - proto "github.com/gogo/protobuf/proto" - io "io" - math "math" - math_bits "math/bits" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package - -type Price struct { - SnapshotTimestampInSeconds uint64 `protobuf:"varint,1,opt,name=snapshotTimestampInSeconds,proto3" json:"snapshot_timestamp_in_seconds"` - Price github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,2,opt,name=price,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"price" yaml:"price"` - Pair *Pair `protobuf:"bytes,3,opt,name=pair,proto3" json:"pair"` -} - -func (m *Price) Reset() { *m = Price{} } -func (m *Price) String() string { return proto.CompactTextString(m) } -func (*Price) ProtoMessage() {} -func (*Price) Descriptor() ([]byte, []int) { - return fileDescriptor_bd5d1c9d490efb8c, []int{0} -} -func (m *Price) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *Price) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_Price.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *Price) XXX_Merge(src proto.Message) { - xxx_messageInfo_Price.Merge(m, src) -} -func (m *Price) XXX_Size() int { - return m.Size() -} -func (m *Price) XXX_DiscardUnknown() { - xxx_messageInfo_Price.DiscardUnknown(m) -} - -var xxx_messageInfo_Price proto.InternalMessageInfo - -func (m *Price) GetSnapshotTimestampInSeconds() uint64 { - if m != nil { - return m.SnapshotTimestampInSeconds - } - return 0 -} - -func (m *Price) GetPair() *Pair { - if m != nil { - return m.Pair - } - return nil -} - -type PriceCandlestick struct { - BeginTimestamp uint64 `protobuf:"varint,1,opt,name=beginTimestamp,proto3" json:"begin_timestamp"` - EndTimestamp uint64 `protobuf:"varint,2,opt,name=endTimestamp,proto3" json:"end_timestamp"` - Open *github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,3,opt,name=open,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"open"` - High *github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,4,opt,name=high,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"high"` - Low *github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,5,opt,name=low,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"low"` - Close *github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,6,opt,name=close,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"close"` - Volume *github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,7,opt,name=volume,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"volume"` -} - -func (m *PriceCandlestick) Reset() { *m = PriceCandlestick{} } -func (m *PriceCandlestick) String() string { return proto.CompactTextString(m) } -func (*PriceCandlestick) ProtoMessage() {} -func (*PriceCandlestick) Descriptor() ([]byte, []int) { - return fileDescriptor_bd5d1c9d490efb8c, []int{1} -} -func (m *PriceCandlestick) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *PriceCandlestick) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_PriceCandlestick.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *PriceCandlestick) XXX_Merge(src proto.Message) { - xxx_messageInfo_PriceCandlestick.Merge(m, src) -} -func (m *PriceCandlestick) XXX_Size() int { - return m.Size() -} -func (m *PriceCandlestick) XXX_DiscardUnknown() { - xxx_messageInfo_PriceCandlestick.DiscardUnknown(m) -} - -var xxx_messageInfo_PriceCandlestick proto.InternalMessageInfo - -func (m *PriceCandlestick) GetBeginTimestamp() uint64 { - if m != nil { - return m.BeginTimestamp - } - return 0 -} - -func (m *PriceCandlestick) GetEndTimestamp() uint64 { - if m != nil { - return m.EndTimestamp - } - return 0 -} - -func init() { - proto.RegisterType((*Price)(nil), "seiprotocol.seichain.dex.Price") - proto.RegisterType((*PriceCandlestick)(nil), "seiprotocol.seichain.dex.PriceCandlestick") -} - -func init() { proto.RegisterFile("dex/price.proto", fileDescriptor_bd5d1c9d490efb8c) } - -var fileDescriptor_bd5d1c9d490efb8c = []byte{ - // 466 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x93, 0xcf, 0x6e, 0xd3, 0x40, - 0x10, 0xc6, 0xe3, 0xfc, 0x83, 0x2e, 0xa5, 0x85, 0x85, 0x83, 0x15, 0x09, 0x3b, 0xe4, 0x80, 0x72, - 0x89, 0x2d, 0x5a, 0xb8, 0x00, 0x27, 0x17, 0x51, 0x55, 0xe2, 0x50, 0x2d, 0x9c, 0x90, 0x50, 0xe4, - 0xac, 0x47, 0xf6, 0xaa, 0xf6, 0xae, 0x95, 0x75, 0x21, 0x7d, 0x02, 0xae, 0x3c, 0x56, 0x8f, 0x3d, - 0x22, 0x0e, 0x16, 0x4a, 0x6e, 0x3e, 0x22, 0x1e, 0x00, 0xed, 0x38, 0xa1, 0x01, 0x09, 0x24, 0x73, - 0x99, 0xd9, 0xf1, 0x7c, 0xdf, 0x4f, 0x9e, 0xf1, 0x9a, 0xec, 0x47, 0xb0, 0xf0, 0xf3, 0xb9, 0xe0, - 0xe0, 0xe5, 0x73, 0x55, 0x28, 0x6a, 0x6b, 0x10, 0x78, 0xe2, 0x2a, 0xf5, 0x34, 0x08, 0x9e, 0x84, - 0x42, 0x7a, 0x11, 0x2c, 0x06, 0xf7, 0x63, 0x15, 0x2b, 0x6c, 0xf9, 0xe6, 0x54, 0xeb, 0x07, 0x7b, - 0x08, 0x08, 0xc5, 0xbc, 0xae, 0x47, 0x9f, 0xda, 0xa4, 0x77, 0x6a, 0x78, 0x34, 0x24, 0x03, 0x2d, - 0xc3, 0x5c, 0x27, 0xaa, 0x78, 0x2b, 0x32, 0xd0, 0x45, 0x98, 0xe5, 0x27, 0xf2, 0x0d, 0x70, 0x25, - 0x23, 0x6d, 0x5b, 0x43, 0x6b, 0xdc, 0x0d, 0x1e, 0x56, 0xa5, 0xfb, 0x60, 0xa3, 0x9a, 0x16, 0x1b, - 0xd9, 0x54, 0xc8, 0xa9, 0xae, 0x85, 0xec, 0x1f, 0x10, 0xfa, 0x9e, 0xf4, 0xf0, 0xdd, 0xed, 0xf6, - 0xd0, 0x1a, 0xef, 0x04, 0xc7, 0x97, 0xa5, 0xdb, 0xfa, 0x5a, 0xba, 0x8f, 0x62, 0x51, 0x24, 0xe7, - 0x33, 0x8f, 0xab, 0xcc, 0xe7, 0x4a, 0x67, 0x4a, 0xaf, 0xd3, 0x44, 0x47, 0x67, 0x7e, 0x71, 0x91, - 0x83, 0xf6, 0x5e, 0x02, 0xaf, 0x4a, 0xb7, 0xb6, 0x7f, 0x2f, 0xdd, 0xdd, 0x8b, 0x30, 0x4b, 0x9f, - 0x8d, 0xb0, 0x1c, 0xb1, 0xfa, 0x31, 0x7d, 0x41, 0xba, 0x66, 0x32, 0xbb, 0x33, 0xb4, 0xc6, 0xb7, - 0x0e, 0x1c, 0xef, 0x6f, 0xab, 0xf1, 0x4e, 0x43, 0x31, 0x0f, 0x6e, 0x56, 0xa5, 0x8b, 0x7a, 0x86, - 0x71, 0xf4, 0xa3, 0x43, 0xee, 0xe0, 0x26, 0x8e, 0x42, 0x19, 0xa5, 0xa0, 0x0b, 0xc1, 0xcf, 0xe8, - 0x73, 0xb2, 0x37, 0x83, 0x58, 0xc8, 0x5f, 0xc3, 0xac, 0x17, 0x71, 0xaf, 0x2a, 0xdd, 0x7d, 0xec, - 0x5c, 0x6f, 0x81, 0xfd, 0x21, 0xa5, 0x4f, 0xc9, 0x2e, 0xc8, 0xe8, 0xda, 0xda, 0x46, 0xeb, 0xdd, - 0xaa, 0x74, 0x6f, 0x83, 0x8c, 0xb6, 0x8c, 0xbf, 0xc9, 0xe8, 0x2b, 0xd2, 0x55, 0x39, 0x48, 0x1c, - 0x63, 0x27, 0x38, 0x68, 0xb4, 0x20, 0x74, 0x32, 0x8c, 0x86, 0x93, 0x88, 0x38, 0xb1, 0xbb, 0xff, - 0xc3, 0x31, 0x4e, 0x86, 0x91, 0x1e, 0x91, 0x4e, 0xaa, 0x3e, 0xda, 0x3d, 0xc4, 0x3c, 0x6e, 0x84, - 0x31, 0x46, 0x66, 0x02, 0x3d, 0x21, 0x3d, 0x9e, 0x2a, 0x0d, 0x76, 0x1f, 0x31, 0x87, 0xcd, 0x3e, - 0x3b, 0x5a, 0x59, 0x9d, 0xe8, 0x6b, 0xd2, 0xff, 0xa0, 0xd2, 0xf3, 0x0c, 0xec, 0x1b, 0xc8, 0x7a, - 0xd2, 0x88, 0xb5, 0xf6, 0xb2, 0x75, 0x0e, 0x8e, 0x2f, 0x97, 0x8e, 0x75, 0xb5, 0x74, 0xac, 0x6f, - 0x4b, 0xc7, 0xfa, 0xbc, 0x72, 0x5a, 0x57, 0x2b, 0xa7, 0xf5, 0x65, 0xe5, 0xb4, 0xde, 0x4d, 0xb6, - 0x98, 0x1a, 0xc4, 0x64, 0x73, 0x97, 0xb0, 0xc0, 0xcb, 0xe4, 0x2f, 0x7c, 0xf3, 0x3b, 0x21, 0x7e, - 0xd6, 0xc7, 0xfe, 0xe1, 0xcf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa8, 0xe7, 0x11, 0xeb, 0xa3, 0x03, - 0x00, 0x00, -} - -func (m *Price) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *Price) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *Price) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Pair != nil { - { - size, err := m.Pair.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintPrice(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x1a - } - { - size := m.Price.Size() - i -= size - if _, err := m.Price.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintPrice(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - if m.SnapshotTimestampInSeconds != 0 { - i = encodeVarintPrice(dAtA, i, uint64(m.SnapshotTimestampInSeconds)) - i-- - dAtA[i] = 0x8 - } - return len(dAtA) - i, nil -} - -func (m *PriceCandlestick) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *PriceCandlestick) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *PriceCandlestick) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Volume != nil { - { - size := m.Volume.Size() - i -= size - if _, err := m.Volume.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintPrice(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x3a - } - if m.Close != nil { - { - size := m.Close.Size() - i -= size - if _, err := m.Close.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintPrice(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x32 - } - if m.Low != nil { - { - size := m.Low.Size() - i -= size - if _, err := m.Low.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintPrice(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x2a - } - if m.High != nil { - { - size := m.High.Size() - i -= size - if _, err := m.High.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintPrice(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x22 - } - if m.Open != nil { - { - size := m.Open.Size() - i -= size - if _, err := m.Open.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintPrice(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x1a - } - if m.EndTimestamp != 0 { - i = encodeVarintPrice(dAtA, i, uint64(m.EndTimestamp)) - i-- - dAtA[i] = 0x10 - } - if m.BeginTimestamp != 0 { - i = encodeVarintPrice(dAtA, i, uint64(m.BeginTimestamp)) - i-- - dAtA[i] = 0x8 - } - return len(dAtA) - i, nil -} - -func encodeVarintPrice(dAtA []byte, offset int, v uint64) int { - offset -= sovPrice(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *Price) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.SnapshotTimestampInSeconds != 0 { - n += 1 + sovPrice(uint64(m.SnapshotTimestampInSeconds)) - } - l = m.Price.Size() - n += 1 + l + sovPrice(uint64(l)) - if m.Pair != nil { - l = m.Pair.Size() - n += 1 + l + sovPrice(uint64(l)) - } - return n -} - -func (m *PriceCandlestick) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.BeginTimestamp != 0 { - n += 1 + sovPrice(uint64(m.BeginTimestamp)) - } - if m.EndTimestamp != 0 { - n += 1 + sovPrice(uint64(m.EndTimestamp)) - } - if m.Open != nil { - l = m.Open.Size() - n += 1 + l + sovPrice(uint64(l)) - } - if m.High != nil { - l = m.High.Size() - n += 1 + l + sovPrice(uint64(l)) - } - if m.Low != nil { - l = m.Low.Size() - n += 1 + l + sovPrice(uint64(l)) - } - if m.Close != nil { - l = m.Close.Size() - n += 1 + l + sovPrice(uint64(l)) - } - if m.Volume != nil { - l = m.Volume.Size() - n += 1 + l + sovPrice(uint64(l)) - } - return n -} - -func sovPrice(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozPrice(x uint64) (n int) { - return sovPrice(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *Price) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowPrice - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: Price: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Price: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field SnapshotTimestampInSeconds", wireType) - } - m.SnapshotTimestampInSeconds = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowPrice - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.SnapshotTimestampInSeconds |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Price", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowPrice - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthPrice - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthPrice - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.Price.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Pair", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowPrice - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthPrice - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthPrice - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Pair == nil { - m.Pair = &Pair{} - } - if err := m.Pair.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipPrice(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthPrice - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *PriceCandlestick) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowPrice - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: PriceCandlestick: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: PriceCandlestick: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field BeginTimestamp", wireType) - } - m.BeginTimestamp = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowPrice - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.BeginTimestamp |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field EndTimestamp", wireType) - } - m.EndTimestamp = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowPrice - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.EndTimestamp |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Open", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowPrice - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthPrice - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthPrice - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - var v github_com_cosmos_cosmos_sdk_types.Dec - m.Open = &v - if err := m.Open.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field High", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowPrice - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthPrice - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthPrice - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - var v github_com_cosmos_cosmos_sdk_types.Dec - m.High = &v - if err := m.High.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 5: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Low", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowPrice - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthPrice - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthPrice - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - var v github_com_cosmos_cosmos_sdk_types.Dec - m.Low = &v - if err := m.Low.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 6: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Close", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowPrice - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthPrice - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthPrice - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - var v github_com_cosmos_cosmos_sdk_types.Dec - m.Close = &v - if err := m.Close.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 7: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Volume", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowPrice - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthPrice - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthPrice - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - var v github_com_cosmos_cosmos_sdk_types.Dec - m.Volume = &v - if err := m.Volume.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipPrice(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthPrice - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipPrice(dAtA []byte) (n int, err error) { - l := len(dAtA) - iNdEx := 0 - depth := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowPrice - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowPrice - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - iNdEx++ - if dAtA[iNdEx-1] < 0x80 { - break - } - } - case 1: - iNdEx += 8 - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowPrice - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if length < 0 { - return 0, ErrInvalidLengthPrice - } - iNdEx += length - case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupPrice - } - depth-- - case 5: - iNdEx += 4 - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - if iNdEx < 0 { - return 0, ErrInvalidLengthPrice - } - if depth == 0 { - return iNdEx, nil - } - } - return 0, io.ErrUnexpectedEOF -} - -var ( - ErrInvalidLengthPrice = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowPrice = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupPrice = fmt.Errorf("proto: unexpected end of group") -) diff --git a/x/dex/types/query.pb.go b/x/dex/types/query.pb.go deleted file mode 100644 index 931520f80..000000000 --- a/x/dex/types/query.pb.go +++ /dev/null @@ -1,10031 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: dex/query.proto - -package types - -import ( - context "context" - fmt "fmt" - github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" - query "github.com/cosmos/cosmos-sdk/types/query" - _ "github.com/gogo/protobuf/gogoproto" - grpc1 "github.com/gogo/protobuf/grpc" - proto "github.com/gogo/protobuf/proto" - _ "google.golang.org/genproto/googleapis/api/annotations" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" - io "io" - math "math" - math_bits "math/bits" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package - -// QueryParamsRequest is request type for the Query/Params RPC method. -type QueryParamsRequest struct { -} - -func (m *QueryParamsRequest) Reset() { *m = QueryParamsRequest{} } -func (m *QueryParamsRequest) String() string { return proto.CompactTextString(m) } -func (*QueryParamsRequest) ProtoMessage() {} -func (*QueryParamsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{0} -} -func (m *QueryParamsRequest) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryParamsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryParamsRequest.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryParamsRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryParamsRequest.Merge(m, src) -} -func (m *QueryParamsRequest) XXX_Size() int { - return m.Size() -} -func (m *QueryParamsRequest) XXX_DiscardUnknown() { - xxx_messageInfo_QueryParamsRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryParamsRequest proto.InternalMessageInfo - -// QueryParamsResponse is response type for the Query/Params RPC method. -type QueryParamsResponse struct { - // params holds all the parameters of this module. - Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` -} - -func (m *QueryParamsResponse) Reset() { *m = QueryParamsResponse{} } -func (m *QueryParamsResponse) String() string { return proto.CompactTextString(m) } -func (*QueryParamsResponse) ProtoMessage() {} -func (*QueryParamsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{1} -} -func (m *QueryParamsResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryParamsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryParamsResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryParamsResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryParamsResponse.Merge(m, src) -} -func (m *QueryParamsResponse) XXX_Size() int { - return m.Size() -} -func (m *QueryParamsResponse) XXX_DiscardUnknown() { - xxx_messageInfo_QueryParamsResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryParamsResponse proto.InternalMessageInfo - -func (m *QueryParamsResponse) GetParams() Params { - if m != nil { - return m.Params - } - return Params{} -} - -type QueryGetLongBookRequest struct { - Price string `protobuf:"bytes,1,opt,name=price,proto3" json:"price,omitempty"` - ContractAddr string `protobuf:"bytes,2,opt,name=contractAddr,proto3" json:"contractAddr,omitempty"` - PriceDenom string `protobuf:"bytes,3,opt,name=priceDenom,proto3" json:"priceDenom,omitempty"` - AssetDenom string `protobuf:"bytes,4,opt,name=assetDenom,proto3" json:"assetDenom,omitempty"` -} - -func (m *QueryGetLongBookRequest) Reset() { *m = QueryGetLongBookRequest{} } -func (m *QueryGetLongBookRequest) String() string { return proto.CompactTextString(m) } -func (*QueryGetLongBookRequest) ProtoMessage() {} -func (*QueryGetLongBookRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{2} -} -func (m *QueryGetLongBookRequest) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryGetLongBookRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryGetLongBookRequest.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryGetLongBookRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryGetLongBookRequest.Merge(m, src) -} -func (m *QueryGetLongBookRequest) XXX_Size() int { - return m.Size() -} -func (m *QueryGetLongBookRequest) XXX_DiscardUnknown() { - xxx_messageInfo_QueryGetLongBookRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryGetLongBookRequest proto.InternalMessageInfo - -func (m *QueryGetLongBookRequest) GetPrice() string { - if m != nil { - return m.Price - } - return "" -} - -func (m *QueryGetLongBookRequest) GetContractAddr() string { - if m != nil { - return m.ContractAddr - } - return "" -} - -func (m *QueryGetLongBookRequest) GetPriceDenom() string { - if m != nil { - return m.PriceDenom - } - return "" -} - -func (m *QueryGetLongBookRequest) GetAssetDenom() string { - if m != nil { - return m.AssetDenom - } - return "" -} - -type QueryGetLongBookResponse struct { - LongBook LongBook `protobuf:"bytes,1,opt,name=LongBook,proto3" json:"LongBook"` -} - -func (m *QueryGetLongBookResponse) Reset() { *m = QueryGetLongBookResponse{} } -func (m *QueryGetLongBookResponse) String() string { return proto.CompactTextString(m) } -func (*QueryGetLongBookResponse) ProtoMessage() {} -func (*QueryGetLongBookResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{3} -} -func (m *QueryGetLongBookResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryGetLongBookResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryGetLongBookResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryGetLongBookResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryGetLongBookResponse.Merge(m, src) -} -func (m *QueryGetLongBookResponse) XXX_Size() int { - return m.Size() -} -func (m *QueryGetLongBookResponse) XXX_DiscardUnknown() { - xxx_messageInfo_QueryGetLongBookResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryGetLongBookResponse proto.InternalMessageInfo - -func (m *QueryGetLongBookResponse) GetLongBook() LongBook { - if m != nil { - return m.LongBook - } - return LongBook{} -} - -type QueryAllLongBookRequest struct { - Pagination *query.PageRequest `protobuf:"bytes,1,opt,name=pagination,proto3" json:"pagination,omitempty"` - ContractAddr string `protobuf:"bytes,2,opt,name=contractAddr,proto3" json:"contractAddr,omitempty"` - PriceDenom string `protobuf:"bytes,3,opt,name=priceDenom,proto3" json:"priceDenom,omitempty"` - AssetDenom string `protobuf:"bytes,4,opt,name=assetDenom,proto3" json:"assetDenom,omitempty"` -} - -func (m *QueryAllLongBookRequest) Reset() { *m = QueryAllLongBookRequest{} } -func (m *QueryAllLongBookRequest) String() string { return proto.CompactTextString(m) } -func (*QueryAllLongBookRequest) ProtoMessage() {} -func (*QueryAllLongBookRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{4} -} -func (m *QueryAllLongBookRequest) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryAllLongBookRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryAllLongBookRequest.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryAllLongBookRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryAllLongBookRequest.Merge(m, src) -} -func (m *QueryAllLongBookRequest) XXX_Size() int { - return m.Size() -} -func (m *QueryAllLongBookRequest) XXX_DiscardUnknown() { - xxx_messageInfo_QueryAllLongBookRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryAllLongBookRequest proto.InternalMessageInfo - -func (m *QueryAllLongBookRequest) GetPagination() *query.PageRequest { - if m != nil { - return m.Pagination - } - return nil -} - -func (m *QueryAllLongBookRequest) GetContractAddr() string { - if m != nil { - return m.ContractAddr - } - return "" -} - -func (m *QueryAllLongBookRequest) GetPriceDenom() string { - if m != nil { - return m.PriceDenom - } - return "" -} - -func (m *QueryAllLongBookRequest) GetAssetDenom() string { - if m != nil { - return m.AssetDenom - } - return "" -} - -type QueryAllLongBookResponse struct { - LongBook []LongBook `protobuf:"bytes,1,rep,name=LongBook,proto3" json:"LongBook"` - Pagination *query.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` -} - -func (m *QueryAllLongBookResponse) Reset() { *m = QueryAllLongBookResponse{} } -func (m *QueryAllLongBookResponse) String() string { return proto.CompactTextString(m) } -func (*QueryAllLongBookResponse) ProtoMessage() {} -func (*QueryAllLongBookResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{5} -} -func (m *QueryAllLongBookResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryAllLongBookResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryAllLongBookResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryAllLongBookResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryAllLongBookResponse.Merge(m, src) -} -func (m *QueryAllLongBookResponse) XXX_Size() int { - return m.Size() -} -func (m *QueryAllLongBookResponse) XXX_DiscardUnknown() { - xxx_messageInfo_QueryAllLongBookResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryAllLongBookResponse proto.InternalMessageInfo - -func (m *QueryAllLongBookResponse) GetLongBook() []LongBook { - if m != nil { - return m.LongBook - } - return nil -} - -func (m *QueryAllLongBookResponse) GetPagination() *query.PageResponse { - if m != nil { - return m.Pagination - } - return nil -} - -type QueryGetShortBookRequest struct { - Price string `protobuf:"bytes,1,opt,name=price,proto3" json:"price,omitempty"` - ContractAddr string `protobuf:"bytes,2,opt,name=contractAddr,proto3" json:"contractAddr,omitempty"` - PriceDenom string `protobuf:"bytes,3,opt,name=priceDenom,proto3" json:"priceDenom,omitempty"` - AssetDenom string `protobuf:"bytes,4,opt,name=assetDenom,proto3" json:"assetDenom,omitempty"` -} - -func (m *QueryGetShortBookRequest) Reset() { *m = QueryGetShortBookRequest{} } -func (m *QueryGetShortBookRequest) String() string { return proto.CompactTextString(m) } -func (*QueryGetShortBookRequest) ProtoMessage() {} -func (*QueryGetShortBookRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{6} -} -func (m *QueryGetShortBookRequest) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryGetShortBookRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryGetShortBookRequest.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryGetShortBookRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryGetShortBookRequest.Merge(m, src) -} -func (m *QueryGetShortBookRequest) XXX_Size() int { - return m.Size() -} -func (m *QueryGetShortBookRequest) XXX_DiscardUnknown() { - xxx_messageInfo_QueryGetShortBookRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryGetShortBookRequest proto.InternalMessageInfo - -func (m *QueryGetShortBookRequest) GetPrice() string { - if m != nil { - return m.Price - } - return "" -} - -func (m *QueryGetShortBookRequest) GetContractAddr() string { - if m != nil { - return m.ContractAddr - } - return "" -} - -func (m *QueryGetShortBookRequest) GetPriceDenom() string { - if m != nil { - return m.PriceDenom - } - return "" -} - -func (m *QueryGetShortBookRequest) GetAssetDenom() string { - if m != nil { - return m.AssetDenom - } - return "" -} - -type QueryGetShortBookResponse struct { - ShortBook ShortBook `protobuf:"bytes,1,opt,name=ShortBook,proto3" json:"ShortBook"` -} - -func (m *QueryGetShortBookResponse) Reset() { *m = QueryGetShortBookResponse{} } -func (m *QueryGetShortBookResponse) String() string { return proto.CompactTextString(m) } -func (*QueryGetShortBookResponse) ProtoMessage() {} -func (*QueryGetShortBookResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{7} -} -func (m *QueryGetShortBookResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryGetShortBookResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryGetShortBookResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryGetShortBookResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryGetShortBookResponse.Merge(m, src) -} -func (m *QueryGetShortBookResponse) XXX_Size() int { - return m.Size() -} -func (m *QueryGetShortBookResponse) XXX_DiscardUnknown() { - xxx_messageInfo_QueryGetShortBookResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryGetShortBookResponse proto.InternalMessageInfo - -func (m *QueryGetShortBookResponse) GetShortBook() ShortBook { - if m != nil { - return m.ShortBook - } - return ShortBook{} -} - -type QueryAllShortBookRequest struct { - Pagination *query.PageRequest `protobuf:"bytes,1,opt,name=pagination,proto3" json:"pagination,omitempty"` - ContractAddr string `protobuf:"bytes,2,opt,name=contractAddr,proto3" json:"contractAddr,omitempty"` - PriceDenom string `protobuf:"bytes,3,opt,name=priceDenom,proto3" json:"priceDenom,omitempty"` - AssetDenom string `protobuf:"bytes,4,opt,name=assetDenom,proto3" json:"assetDenom,omitempty"` -} - -func (m *QueryAllShortBookRequest) Reset() { *m = QueryAllShortBookRequest{} } -func (m *QueryAllShortBookRequest) String() string { return proto.CompactTextString(m) } -func (*QueryAllShortBookRequest) ProtoMessage() {} -func (*QueryAllShortBookRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{8} -} -func (m *QueryAllShortBookRequest) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryAllShortBookRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryAllShortBookRequest.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryAllShortBookRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryAllShortBookRequest.Merge(m, src) -} -func (m *QueryAllShortBookRequest) XXX_Size() int { - return m.Size() -} -func (m *QueryAllShortBookRequest) XXX_DiscardUnknown() { - xxx_messageInfo_QueryAllShortBookRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryAllShortBookRequest proto.InternalMessageInfo - -func (m *QueryAllShortBookRequest) GetPagination() *query.PageRequest { - if m != nil { - return m.Pagination - } - return nil -} - -func (m *QueryAllShortBookRequest) GetContractAddr() string { - if m != nil { - return m.ContractAddr - } - return "" -} - -func (m *QueryAllShortBookRequest) GetPriceDenom() string { - if m != nil { - return m.PriceDenom - } - return "" -} - -func (m *QueryAllShortBookRequest) GetAssetDenom() string { - if m != nil { - return m.AssetDenom - } - return "" -} - -type QueryAllShortBookResponse struct { - ShortBook []ShortBook `protobuf:"bytes,1,rep,name=ShortBook,proto3" json:"ShortBook"` - Pagination *query.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` -} - -func (m *QueryAllShortBookResponse) Reset() { *m = QueryAllShortBookResponse{} } -func (m *QueryAllShortBookResponse) String() string { return proto.CompactTextString(m) } -func (*QueryAllShortBookResponse) ProtoMessage() {} -func (*QueryAllShortBookResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{9} -} -func (m *QueryAllShortBookResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryAllShortBookResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryAllShortBookResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryAllShortBookResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryAllShortBookResponse.Merge(m, src) -} -func (m *QueryAllShortBookResponse) XXX_Size() int { - return m.Size() -} -func (m *QueryAllShortBookResponse) XXX_DiscardUnknown() { - xxx_messageInfo_QueryAllShortBookResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryAllShortBookResponse proto.InternalMessageInfo - -func (m *QueryAllShortBookResponse) GetShortBook() []ShortBook { - if m != nil { - return m.ShortBook - } - return nil -} - -func (m *QueryAllShortBookResponse) GetPagination() *query.PageResponse { - if m != nil { - return m.Pagination - } - return nil -} - -type QueryGetPricesRequest struct { - PriceDenom string `protobuf:"bytes,1,opt,name=priceDenom,proto3" json:"priceDenom,omitempty"` - AssetDenom string `protobuf:"bytes,2,opt,name=assetDenom,proto3" json:"assetDenom,omitempty"` - ContractAddr string `protobuf:"bytes,3,opt,name=contractAddr,proto3" json:"contractAddr,omitempty"` -} - -func (m *QueryGetPricesRequest) Reset() { *m = QueryGetPricesRequest{} } -func (m *QueryGetPricesRequest) String() string { return proto.CompactTextString(m) } -func (*QueryGetPricesRequest) ProtoMessage() {} -func (*QueryGetPricesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{10} -} -func (m *QueryGetPricesRequest) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryGetPricesRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryGetPricesRequest.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryGetPricesRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryGetPricesRequest.Merge(m, src) -} -func (m *QueryGetPricesRequest) XXX_Size() int { - return m.Size() -} -func (m *QueryGetPricesRequest) XXX_DiscardUnknown() { - xxx_messageInfo_QueryGetPricesRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryGetPricesRequest proto.InternalMessageInfo - -func (m *QueryGetPricesRequest) GetPriceDenom() string { - if m != nil { - return m.PriceDenom - } - return "" -} - -func (m *QueryGetPricesRequest) GetAssetDenom() string { - if m != nil { - return m.AssetDenom - } - return "" -} - -func (m *QueryGetPricesRequest) GetContractAddr() string { - if m != nil { - return m.ContractAddr - } - return "" -} - -type QueryGetPricesResponse struct { - Prices []*Price `protobuf:"bytes,1,rep,name=prices,proto3" json:"prices,omitempty"` -} - -func (m *QueryGetPricesResponse) Reset() { *m = QueryGetPricesResponse{} } -func (m *QueryGetPricesResponse) String() string { return proto.CompactTextString(m) } -func (*QueryGetPricesResponse) ProtoMessage() {} -func (*QueryGetPricesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{11} -} -func (m *QueryGetPricesResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryGetPricesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryGetPricesResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryGetPricesResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryGetPricesResponse.Merge(m, src) -} -func (m *QueryGetPricesResponse) XXX_Size() int { - return m.Size() -} -func (m *QueryGetPricesResponse) XXX_DiscardUnknown() { - xxx_messageInfo_QueryGetPricesResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryGetPricesResponse proto.InternalMessageInfo - -func (m *QueryGetPricesResponse) GetPrices() []*Price { - if m != nil { - return m.Prices - } - return nil -} - -type QueryGetPriceRequest struct { - PriceDenom string `protobuf:"bytes,1,opt,name=priceDenom,proto3" json:"priceDenom,omitempty"` - AssetDenom string `protobuf:"bytes,2,opt,name=assetDenom,proto3" json:"assetDenom,omitempty"` - ContractAddr string `protobuf:"bytes,3,opt,name=contractAddr,proto3" json:"contractAddr,omitempty"` - Timestamp uint64 `protobuf:"varint,4,opt,name=timestamp,proto3" json:"timestamp,omitempty"` -} - -func (m *QueryGetPriceRequest) Reset() { *m = QueryGetPriceRequest{} } -func (m *QueryGetPriceRequest) String() string { return proto.CompactTextString(m) } -func (*QueryGetPriceRequest) ProtoMessage() {} -func (*QueryGetPriceRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{12} -} -func (m *QueryGetPriceRequest) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryGetPriceRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryGetPriceRequest.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryGetPriceRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryGetPriceRequest.Merge(m, src) -} -func (m *QueryGetPriceRequest) XXX_Size() int { - return m.Size() -} -func (m *QueryGetPriceRequest) XXX_DiscardUnknown() { - xxx_messageInfo_QueryGetPriceRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryGetPriceRequest proto.InternalMessageInfo - -func (m *QueryGetPriceRequest) GetPriceDenom() string { - if m != nil { - return m.PriceDenom - } - return "" -} - -func (m *QueryGetPriceRequest) GetAssetDenom() string { - if m != nil { - return m.AssetDenom - } - return "" -} - -func (m *QueryGetPriceRequest) GetContractAddr() string { - if m != nil { - return m.ContractAddr - } - return "" -} - -func (m *QueryGetPriceRequest) GetTimestamp() uint64 { - if m != nil { - return m.Timestamp - } - return 0 -} - -type QueryGetPriceResponse struct { - Price *Price `protobuf:"bytes,1,opt,name=price,proto3" json:"price,omitempty"` - Found bool `protobuf:"varint,2,opt,name=found,proto3" json:"found,omitempty"` -} - -func (m *QueryGetPriceResponse) Reset() { *m = QueryGetPriceResponse{} } -func (m *QueryGetPriceResponse) String() string { return proto.CompactTextString(m) } -func (*QueryGetPriceResponse) ProtoMessage() {} -func (*QueryGetPriceResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{13} -} -func (m *QueryGetPriceResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryGetPriceResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryGetPriceResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryGetPriceResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryGetPriceResponse.Merge(m, src) -} -func (m *QueryGetPriceResponse) XXX_Size() int { - return m.Size() -} -func (m *QueryGetPriceResponse) XXX_DiscardUnknown() { - xxx_messageInfo_QueryGetPriceResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryGetPriceResponse proto.InternalMessageInfo - -func (m *QueryGetPriceResponse) GetPrice() *Price { - if m != nil { - return m.Price - } - return nil -} - -func (m *QueryGetPriceResponse) GetFound() bool { - if m != nil { - return m.Found - } - return false -} - -type QueryGetLatestPriceRequest struct { - PriceDenom string `protobuf:"bytes,1,opt,name=priceDenom,proto3" json:"price_denom"` - AssetDenom string `protobuf:"bytes,2,opt,name=assetDenom,proto3" json:"asset_denom"` - ContractAddr string `protobuf:"bytes,3,opt,name=contractAddr,proto3" json:"contract_address"` -} - -func (m *QueryGetLatestPriceRequest) Reset() { *m = QueryGetLatestPriceRequest{} } -func (m *QueryGetLatestPriceRequest) String() string { return proto.CompactTextString(m) } -func (*QueryGetLatestPriceRequest) ProtoMessage() {} -func (*QueryGetLatestPriceRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{14} -} -func (m *QueryGetLatestPriceRequest) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryGetLatestPriceRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryGetLatestPriceRequest.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryGetLatestPriceRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryGetLatestPriceRequest.Merge(m, src) -} -func (m *QueryGetLatestPriceRequest) XXX_Size() int { - return m.Size() -} -func (m *QueryGetLatestPriceRequest) XXX_DiscardUnknown() { - xxx_messageInfo_QueryGetLatestPriceRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryGetLatestPriceRequest proto.InternalMessageInfo - -func (m *QueryGetLatestPriceRequest) GetPriceDenom() string { - if m != nil { - return m.PriceDenom - } - return "" -} - -func (m *QueryGetLatestPriceRequest) GetAssetDenom() string { - if m != nil { - return m.AssetDenom - } - return "" -} - -func (m *QueryGetLatestPriceRequest) GetContractAddr() string { - if m != nil { - return m.ContractAddr - } - return "" -} - -type QueryGetLatestPriceResponse struct { - Price *Price `protobuf:"bytes,1,opt,name=price,proto3" json:"price,omitempty"` -} - -func (m *QueryGetLatestPriceResponse) Reset() { *m = QueryGetLatestPriceResponse{} } -func (m *QueryGetLatestPriceResponse) String() string { return proto.CompactTextString(m) } -func (*QueryGetLatestPriceResponse) ProtoMessage() {} -func (*QueryGetLatestPriceResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{15} -} -func (m *QueryGetLatestPriceResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryGetLatestPriceResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryGetLatestPriceResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryGetLatestPriceResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryGetLatestPriceResponse.Merge(m, src) -} -func (m *QueryGetLatestPriceResponse) XXX_Size() int { - return m.Size() -} -func (m *QueryGetLatestPriceResponse) XXX_DiscardUnknown() { - xxx_messageInfo_QueryGetLatestPriceResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryGetLatestPriceResponse proto.InternalMessageInfo - -func (m *QueryGetLatestPriceResponse) GetPrice() *Price { - if m != nil { - return m.Price - } - return nil -} - -type QueryGetTwapsRequest struct { - ContractAddr string `protobuf:"bytes,1,opt,name=contractAddr,proto3" json:"contract_address"` - LookbackSeconds uint64 `protobuf:"varint,2,opt,name=lookbackSeconds,proto3" json:"lookback_seconds"` -} - -func (m *QueryGetTwapsRequest) Reset() { *m = QueryGetTwapsRequest{} } -func (m *QueryGetTwapsRequest) String() string { return proto.CompactTextString(m) } -func (*QueryGetTwapsRequest) ProtoMessage() {} -func (*QueryGetTwapsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{16} -} -func (m *QueryGetTwapsRequest) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryGetTwapsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryGetTwapsRequest.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryGetTwapsRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryGetTwapsRequest.Merge(m, src) -} -func (m *QueryGetTwapsRequest) XXX_Size() int { - return m.Size() -} -func (m *QueryGetTwapsRequest) XXX_DiscardUnknown() { - xxx_messageInfo_QueryGetTwapsRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryGetTwapsRequest proto.InternalMessageInfo - -func (m *QueryGetTwapsRequest) GetContractAddr() string { - if m != nil { - return m.ContractAddr - } - return "" -} - -func (m *QueryGetTwapsRequest) GetLookbackSeconds() uint64 { - if m != nil { - return m.LookbackSeconds - } - return 0 -} - -type QueryGetTwapsResponse struct { - Twaps []*Twap `protobuf:"bytes,1,rep,name=twaps,proto3" json:"twaps"` -} - -func (m *QueryGetTwapsResponse) Reset() { *m = QueryGetTwapsResponse{} } -func (m *QueryGetTwapsResponse) String() string { return proto.CompactTextString(m) } -func (*QueryGetTwapsResponse) ProtoMessage() {} -func (*QueryGetTwapsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{17} -} -func (m *QueryGetTwapsResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryGetTwapsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryGetTwapsResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryGetTwapsResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryGetTwapsResponse.Merge(m, src) -} -func (m *QueryGetTwapsResponse) XXX_Size() int { - return m.Size() -} -func (m *QueryGetTwapsResponse) XXX_DiscardUnknown() { - xxx_messageInfo_QueryGetTwapsResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryGetTwapsResponse proto.InternalMessageInfo - -func (m *QueryGetTwapsResponse) GetTwaps() []*Twap { - if m != nil { - return m.Twaps - } - return nil -} - -type QueryAssetListRequest struct { -} - -func (m *QueryAssetListRequest) Reset() { *m = QueryAssetListRequest{} } -func (m *QueryAssetListRequest) String() string { return proto.CompactTextString(m) } -func (*QueryAssetListRequest) ProtoMessage() {} -func (*QueryAssetListRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{18} -} -func (m *QueryAssetListRequest) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryAssetListRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryAssetListRequest.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryAssetListRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryAssetListRequest.Merge(m, src) -} -func (m *QueryAssetListRequest) XXX_Size() int { - return m.Size() -} -func (m *QueryAssetListRequest) XXX_DiscardUnknown() { - xxx_messageInfo_QueryAssetListRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryAssetListRequest proto.InternalMessageInfo - -type QueryAssetListResponse struct { - AssetList []AssetMetadata `protobuf:"bytes,1,rep,name=assetList,proto3" json:"assetList"` -} - -func (m *QueryAssetListResponse) Reset() { *m = QueryAssetListResponse{} } -func (m *QueryAssetListResponse) String() string { return proto.CompactTextString(m) } -func (*QueryAssetListResponse) ProtoMessage() {} -func (*QueryAssetListResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{19} -} -func (m *QueryAssetListResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryAssetListResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryAssetListResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryAssetListResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryAssetListResponse.Merge(m, src) -} -func (m *QueryAssetListResponse) XXX_Size() int { - return m.Size() -} -func (m *QueryAssetListResponse) XXX_DiscardUnknown() { - xxx_messageInfo_QueryAssetListResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryAssetListResponse proto.InternalMessageInfo - -func (m *QueryAssetListResponse) GetAssetList() []AssetMetadata { - if m != nil { - return m.AssetList - } - return nil -} - -type QueryAssetMetadataRequest struct { - Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty"` -} - -func (m *QueryAssetMetadataRequest) Reset() { *m = QueryAssetMetadataRequest{} } -func (m *QueryAssetMetadataRequest) String() string { return proto.CompactTextString(m) } -func (*QueryAssetMetadataRequest) ProtoMessage() {} -func (*QueryAssetMetadataRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{20} -} -func (m *QueryAssetMetadataRequest) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryAssetMetadataRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryAssetMetadataRequest.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryAssetMetadataRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryAssetMetadataRequest.Merge(m, src) -} -func (m *QueryAssetMetadataRequest) XXX_Size() int { - return m.Size() -} -func (m *QueryAssetMetadataRequest) XXX_DiscardUnknown() { - xxx_messageInfo_QueryAssetMetadataRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryAssetMetadataRequest proto.InternalMessageInfo - -func (m *QueryAssetMetadataRequest) GetDenom() string { - if m != nil { - return m.Denom - } - return "" -} - -type QueryAssetMetadataResponse struct { - Metadata *AssetMetadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` -} - -func (m *QueryAssetMetadataResponse) Reset() { *m = QueryAssetMetadataResponse{} } -func (m *QueryAssetMetadataResponse) String() string { return proto.CompactTextString(m) } -func (*QueryAssetMetadataResponse) ProtoMessage() {} -func (*QueryAssetMetadataResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{21} -} -func (m *QueryAssetMetadataResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryAssetMetadataResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryAssetMetadataResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryAssetMetadataResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryAssetMetadataResponse.Merge(m, src) -} -func (m *QueryAssetMetadataResponse) XXX_Size() int { - return m.Size() -} -func (m *QueryAssetMetadataResponse) XXX_DiscardUnknown() { - xxx_messageInfo_QueryAssetMetadataResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryAssetMetadataResponse proto.InternalMessageInfo - -func (m *QueryAssetMetadataResponse) GetMetadata() *AssetMetadata { - if m != nil { - return m.Metadata - } - return nil -} - -type QueryRegisteredPairsRequest struct { - ContractAddr string `protobuf:"bytes,1,opt,name=contractAddr,proto3" json:"contract_address"` -} - -func (m *QueryRegisteredPairsRequest) Reset() { *m = QueryRegisteredPairsRequest{} } -func (m *QueryRegisteredPairsRequest) String() string { return proto.CompactTextString(m) } -func (*QueryRegisteredPairsRequest) ProtoMessage() {} -func (*QueryRegisteredPairsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{22} -} -func (m *QueryRegisteredPairsRequest) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryRegisteredPairsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryRegisteredPairsRequest.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryRegisteredPairsRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryRegisteredPairsRequest.Merge(m, src) -} -func (m *QueryRegisteredPairsRequest) XXX_Size() int { - return m.Size() -} -func (m *QueryRegisteredPairsRequest) XXX_DiscardUnknown() { - xxx_messageInfo_QueryRegisteredPairsRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryRegisteredPairsRequest proto.InternalMessageInfo - -func (m *QueryRegisteredPairsRequest) GetContractAddr() string { - if m != nil { - return m.ContractAddr - } - return "" -} - -type QueryRegisteredPairsResponse struct { - Pairs []Pair `protobuf:"bytes,1,rep,name=pairs,proto3" json:"pairs"` -} - -func (m *QueryRegisteredPairsResponse) Reset() { *m = QueryRegisteredPairsResponse{} } -func (m *QueryRegisteredPairsResponse) String() string { return proto.CompactTextString(m) } -func (*QueryRegisteredPairsResponse) ProtoMessage() {} -func (*QueryRegisteredPairsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{23} -} -func (m *QueryRegisteredPairsResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryRegisteredPairsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryRegisteredPairsResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryRegisteredPairsResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryRegisteredPairsResponse.Merge(m, src) -} -func (m *QueryRegisteredPairsResponse) XXX_Size() int { - return m.Size() -} -func (m *QueryRegisteredPairsResponse) XXX_DiscardUnknown() { - xxx_messageInfo_QueryRegisteredPairsResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryRegisteredPairsResponse proto.InternalMessageInfo - -func (m *QueryRegisteredPairsResponse) GetPairs() []Pair { - if m != nil { - return m.Pairs - } - return nil -} - -type QueryRegisteredContractRequest struct { - ContractAddr string `protobuf:"bytes,1,opt,name=contractAddr,proto3" json:"contract_address"` -} - -func (m *QueryRegisteredContractRequest) Reset() { *m = QueryRegisteredContractRequest{} } -func (m *QueryRegisteredContractRequest) String() string { return proto.CompactTextString(m) } -func (*QueryRegisteredContractRequest) ProtoMessage() {} -func (*QueryRegisteredContractRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{24} -} -func (m *QueryRegisteredContractRequest) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryRegisteredContractRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryRegisteredContractRequest.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryRegisteredContractRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryRegisteredContractRequest.Merge(m, src) -} -func (m *QueryRegisteredContractRequest) XXX_Size() int { - return m.Size() -} -func (m *QueryRegisteredContractRequest) XXX_DiscardUnknown() { - xxx_messageInfo_QueryRegisteredContractRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryRegisteredContractRequest proto.InternalMessageInfo - -func (m *QueryRegisteredContractRequest) GetContractAddr() string { - if m != nil { - return m.ContractAddr - } - return "" -} - -type QueryRegisteredContractResponse struct { - ContractInfo *ContractInfoV2 `protobuf:"bytes,1,opt,name=contract_info,json=contractInfo,proto3" json:"contract_info,omitempty"` -} - -func (m *QueryRegisteredContractResponse) Reset() { *m = QueryRegisteredContractResponse{} } -func (m *QueryRegisteredContractResponse) String() string { return proto.CompactTextString(m) } -func (*QueryRegisteredContractResponse) ProtoMessage() {} -func (*QueryRegisteredContractResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{25} -} -func (m *QueryRegisteredContractResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryRegisteredContractResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryRegisteredContractResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryRegisteredContractResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryRegisteredContractResponse.Merge(m, src) -} -func (m *QueryRegisteredContractResponse) XXX_Size() int { - return m.Size() -} -func (m *QueryRegisteredContractResponse) XXX_DiscardUnknown() { - xxx_messageInfo_QueryRegisteredContractResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryRegisteredContractResponse proto.InternalMessageInfo - -func (m *QueryRegisteredContractResponse) GetContractInfo() *ContractInfoV2 { - if m != nil { - return m.ContractInfo - } - return nil -} - -type QueryGetOrdersRequest struct { - ContractAddr string `protobuf:"bytes,1,opt,name=contractAddr,proto3" json:"contract_address"` - Account string `protobuf:"bytes,2,opt,name=account,proto3" json:"account"` -} - -func (m *QueryGetOrdersRequest) Reset() { *m = QueryGetOrdersRequest{} } -func (m *QueryGetOrdersRequest) String() string { return proto.CompactTextString(m) } -func (*QueryGetOrdersRequest) ProtoMessage() {} -func (*QueryGetOrdersRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{26} -} -func (m *QueryGetOrdersRequest) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryGetOrdersRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryGetOrdersRequest.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryGetOrdersRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryGetOrdersRequest.Merge(m, src) -} -func (m *QueryGetOrdersRequest) XXX_Size() int { - return m.Size() -} -func (m *QueryGetOrdersRequest) XXX_DiscardUnknown() { - xxx_messageInfo_QueryGetOrdersRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryGetOrdersRequest proto.InternalMessageInfo - -func (m *QueryGetOrdersRequest) GetContractAddr() string { - if m != nil { - return m.ContractAddr - } - return "" -} - -func (m *QueryGetOrdersRequest) GetAccount() string { - if m != nil { - return m.Account - } - return "" -} - -type QueryGetOrdersResponse struct { - Orders []*Order `protobuf:"bytes,1,rep,name=orders,proto3" json:"orders"` -} - -func (m *QueryGetOrdersResponse) Reset() { *m = QueryGetOrdersResponse{} } -func (m *QueryGetOrdersResponse) String() string { return proto.CompactTextString(m) } -func (*QueryGetOrdersResponse) ProtoMessage() {} -func (*QueryGetOrdersResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{27} -} -func (m *QueryGetOrdersResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryGetOrdersResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryGetOrdersResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryGetOrdersResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryGetOrdersResponse.Merge(m, src) -} -func (m *QueryGetOrdersResponse) XXX_Size() int { - return m.Size() -} -func (m *QueryGetOrdersResponse) XXX_DiscardUnknown() { - xxx_messageInfo_QueryGetOrdersResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryGetOrdersResponse proto.InternalMessageInfo - -func (m *QueryGetOrdersResponse) GetOrders() []*Order { - if m != nil { - return m.Orders - } - return nil -} - -type QueryGetOrderByIDRequest struct { - ContractAddr string `protobuf:"bytes,1,opt,name=contractAddr,proto3" json:"contract_address"` - PriceDenom string `protobuf:"bytes,2,opt,name=priceDenom,proto3" json:"price_denom"` - AssetDenom string `protobuf:"bytes,3,opt,name=assetDenom,proto3" json:"asset_denom"` - Id uint64 `protobuf:"varint,4,opt,name=id,proto3" json:"id"` -} - -func (m *QueryGetOrderByIDRequest) Reset() { *m = QueryGetOrderByIDRequest{} } -func (m *QueryGetOrderByIDRequest) String() string { return proto.CompactTextString(m) } -func (*QueryGetOrderByIDRequest) ProtoMessage() {} -func (*QueryGetOrderByIDRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{28} -} -func (m *QueryGetOrderByIDRequest) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryGetOrderByIDRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryGetOrderByIDRequest.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryGetOrderByIDRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryGetOrderByIDRequest.Merge(m, src) -} -func (m *QueryGetOrderByIDRequest) XXX_Size() int { - return m.Size() -} -func (m *QueryGetOrderByIDRequest) XXX_DiscardUnknown() { - xxx_messageInfo_QueryGetOrderByIDRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryGetOrderByIDRequest proto.InternalMessageInfo - -func (m *QueryGetOrderByIDRequest) GetContractAddr() string { - if m != nil { - return m.ContractAddr - } - return "" -} - -func (m *QueryGetOrderByIDRequest) GetPriceDenom() string { - if m != nil { - return m.PriceDenom - } - return "" -} - -func (m *QueryGetOrderByIDRequest) GetAssetDenom() string { - if m != nil { - return m.AssetDenom - } - return "" -} - -func (m *QueryGetOrderByIDRequest) GetId() uint64 { - if m != nil { - return m.Id - } - return 0 -} - -type QueryGetOrderByIDResponse struct { - Order *Order `protobuf:"bytes,1,opt,name=order,proto3" json:"order"` -} - -func (m *QueryGetOrderByIDResponse) Reset() { *m = QueryGetOrderByIDResponse{} } -func (m *QueryGetOrderByIDResponse) String() string { return proto.CompactTextString(m) } -func (*QueryGetOrderByIDResponse) ProtoMessage() {} -func (*QueryGetOrderByIDResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{29} -} -func (m *QueryGetOrderByIDResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryGetOrderByIDResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryGetOrderByIDResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryGetOrderByIDResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryGetOrderByIDResponse.Merge(m, src) -} -func (m *QueryGetOrderByIDResponse) XXX_Size() int { - return m.Size() -} -func (m *QueryGetOrderByIDResponse) XXX_DiscardUnknown() { - xxx_messageInfo_QueryGetOrderByIDResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryGetOrderByIDResponse proto.InternalMessageInfo - -func (m *QueryGetOrderByIDResponse) GetOrder() *Order { - if m != nil { - return m.Order - } - return nil -} - -type QueryGetHistoricalPricesRequest struct { - ContractAddr string `protobuf:"bytes,1,opt,name=contractAddr,proto3" json:"contract_address"` - PriceDenom string `protobuf:"bytes,2,opt,name=priceDenom,proto3" json:"price_denom"` - AssetDenom string `protobuf:"bytes,3,opt,name=assetDenom,proto3" json:"asset_denom"` - PeriodLengthInSeconds uint64 `protobuf:"varint,4,opt,name=periodLengthInSeconds,proto3" json:"period_length_in_seconds"` - NumOfPeriods uint64 `protobuf:"varint,5,opt,name=numOfPeriods,proto3" json:"number_of_periods"` -} - -func (m *QueryGetHistoricalPricesRequest) Reset() { *m = QueryGetHistoricalPricesRequest{} } -func (m *QueryGetHistoricalPricesRequest) String() string { return proto.CompactTextString(m) } -func (*QueryGetHistoricalPricesRequest) ProtoMessage() {} -func (*QueryGetHistoricalPricesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{30} -} -func (m *QueryGetHistoricalPricesRequest) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryGetHistoricalPricesRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryGetHistoricalPricesRequest.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryGetHistoricalPricesRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryGetHistoricalPricesRequest.Merge(m, src) -} -func (m *QueryGetHistoricalPricesRequest) XXX_Size() int { - return m.Size() -} -func (m *QueryGetHistoricalPricesRequest) XXX_DiscardUnknown() { - xxx_messageInfo_QueryGetHistoricalPricesRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryGetHistoricalPricesRequest proto.InternalMessageInfo - -func (m *QueryGetHistoricalPricesRequest) GetContractAddr() string { - if m != nil { - return m.ContractAddr - } - return "" -} - -func (m *QueryGetHistoricalPricesRequest) GetPriceDenom() string { - if m != nil { - return m.PriceDenom - } - return "" -} - -func (m *QueryGetHistoricalPricesRequest) GetAssetDenom() string { - if m != nil { - return m.AssetDenom - } - return "" -} - -func (m *QueryGetHistoricalPricesRequest) GetPeriodLengthInSeconds() uint64 { - if m != nil { - return m.PeriodLengthInSeconds - } - return 0 -} - -func (m *QueryGetHistoricalPricesRequest) GetNumOfPeriods() uint64 { - if m != nil { - return m.NumOfPeriods - } - return 0 -} - -type QueryGetHistoricalPricesResponse struct { - Prices []*PriceCandlestick `protobuf:"bytes,1,rep,name=prices,proto3" json:"prices"` -} - -func (m *QueryGetHistoricalPricesResponse) Reset() { *m = QueryGetHistoricalPricesResponse{} } -func (m *QueryGetHistoricalPricesResponse) String() string { return proto.CompactTextString(m) } -func (*QueryGetHistoricalPricesResponse) ProtoMessage() {} -func (*QueryGetHistoricalPricesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{31} -} -func (m *QueryGetHistoricalPricesResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryGetHistoricalPricesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryGetHistoricalPricesResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryGetHistoricalPricesResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryGetHistoricalPricesResponse.Merge(m, src) -} -func (m *QueryGetHistoricalPricesResponse) XXX_Size() int { - return m.Size() -} -func (m *QueryGetHistoricalPricesResponse) XXX_DiscardUnknown() { - xxx_messageInfo_QueryGetHistoricalPricesResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryGetHistoricalPricesResponse proto.InternalMessageInfo - -func (m *QueryGetHistoricalPricesResponse) GetPrices() []*PriceCandlestick { - if m != nil { - return m.Prices - } - return nil -} - -type QueryGetMarketSummaryRequest struct { - ContractAddr string `protobuf:"bytes,1,opt,name=contractAddr,proto3" json:"contract_address"` - PriceDenom string `protobuf:"bytes,2,opt,name=priceDenom,proto3" json:"price_denom"` - AssetDenom string `protobuf:"bytes,3,opt,name=assetDenom,proto3" json:"asset_denom"` - LookbackInSeconds uint64 `protobuf:"varint,4,opt,name=lookbackInSeconds,proto3" json:"lookback_in_seconds"` -} - -func (m *QueryGetMarketSummaryRequest) Reset() { *m = QueryGetMarketSummaryRequest{} } -func (m *QueryGetMarketSummaryRequest) String() string { return proto.CompactTextString(m) } -func (*QueryGetMarketSummaryRequest) ProtoMessage() {} -func (*QueryGetMarketSummaryRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{32} -} -func (m *QueryGetMarketSummaryRequest) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryGetMarketSummaryRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryGetMarketSummaryRequest.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryGetMarketSummaryRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryGetMarketSummaryRequest.Merge(m, src) -} -func (m *QueryGetMarketSummaryRequest) XXX_Size() int { - return m.Size() -} -func (m *QueryGetMarketSummaryRequest) XXX_DiscardUnknown() { - xxx_messageInfo_QueryGetMarketSummaryRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryGetMarketSummaryRequest proto.InternalMessageInfo - -func (m *QueryGetMarketSummaryRequest) GetContractAddr() string { - if m != nil { - return m.ContractAddr - } - return "" -} - -func (m *QueryGetMarketSummaryRequest) GetPriceDenom() string { - if m != nil { - return m.PriceDenom - } - return "" -} - -func (m *QueryGetMarketSummaryRequest) GetAssetDenom() string { - if m != nil { - return m.AssetDenom - } - return "" -} - -func (m *QueryGetMarketSummaryRequest) GetLookbackInSeconds() uint64 { - if m != nil { - return m.LookbackInSeconds - } - return 0 -} - -type QueryGetMarketSummaryResponse struct { - TotalVolume *github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,1,opt,name=totalVolume,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"total_volume"` - TotalVolumeNotional *github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,2,opt,name=totalVolumeNotional,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"total_volume_notional"` - HighPrice *github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,3,opt,name=highPrice,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"high_price"` - LowPrice *github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,4,opt,name=lowPrice,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"low_price"` - LastPrice *github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,5,opt,name=lastPrice,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"last_price"` -} - -func (m *QueryGetMarketSummaryResponse) Reset() { *m = QueryGetMarketSummaryResponse{} } -func (m *QueryGetMarketSummaryResponse) String() string { return proto.CompactTextString(m) } -func (*QueryGetMarketSummaryResponse) ProtoMessage() {} -func (*QueryGetMarketSummaryResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{33} -} -func (m *QueryGetMarketSummaryResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryGetMarketSummaryResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryGetMarketSummaryResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryGetMarketSummaryResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryGetMarketSummaryResponse.Merge(m, src) -} -func (m *QueryGetMarketSummaryResponse) XXX_Size() int { - return m.Size() -} -func (m *QueryGetMarketSummaryResponse) XXX_DiscardUnknown() { - xxx_messageInfo_QueryGetMarketSummaryResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryGetMarketSummaryResponse proto.InternalMessageInfo - -type QueryOrderSimulationRequest struct { - Order *Order `protobuf:"bytes,1,opt,name=order,proto3" json:"order"` - ContractAddr string `protobuf:"bytes,2,opt,name=contractAddr,proto3" json:"contract_address"` -} - -func (m *QueryOrderSimulationRequest) Reset() { *m = QueryOrderSimulationRequest{} } -func (m *QueryOrderSimulationRequest) String() string { return proto.CompactTextString(m) } -func (*QueryOrderSimulationRequest) ProtoMessage() {} -func (*QueryOrderSimulationRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{34} -} -func (m *QueryOrderSimulationRequest) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryOrderSimulationRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryOrderSimulationRequest.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryOrderSimulationRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryOrderSimulationRequest.Merge(m, src) -} -func (m *QueryOrderSimulationRequest) XXX_Size() int { - return m.Size() -} -func (m *QueryOrderSimulationRequest) XXX_DiscardUnknown() { - xxx_messageInfo_QueryOrderSimulationRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryOrderSimulationRequest proto.InternalMessageInfo - -func (m *QueryOrderSimulationRequest) GetOrder() *Order { - if m != nil { - return m.Order - } - return nil -} - -func (m *QueryOrderSimulationRequest) GetContractAddr() string { - if m != nil { - return m.ContractAddr - } - return "" -} - -type QueryOrderSimulationResponse struct { - ExecutedQuantity *github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,1,opt,name=ExecutedQuantity,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"executed_quantity"` -} - -func (m *QueryOrderSimulationResponse) Reset() { *m = QueryOrderSimulationResponse{} } -func (m *QueryOrderSimulationResponse) String() string { return proto.CompactTextString(m) } -func (*QueryOrderSimulationResponse) ProtoMessage() {} -func (*QueryOrderSimulationResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{35} -} -func (m *QueryOrderSimulationResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryOrderSimulationResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryOrderSimulationResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryOrderSimulationResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryOrderSimulationResponse.Merge(m, src) -} -func (m *QueryOrderSimulationResponse) XXX_Size() int { - return m.Size() -} -func (m *QueryOrderSimulationResponse) XXX_DiscardUnknown() { - xxx_messageInfo_QueryOrderSimulationResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryOrderSimulationResponse proto.InternalMessageInfo - -type QueryGetMatchResultRequest struct { - ContractAddr string `protobuf:"bytes,1,opt,name=contractAddr,proto3" json:"contract_address"` -} - -func (m *QueryGetMatchResultRequest) Reset() { *m = QueryGetMatchResultRequest{} } -func (m *QueryGetMatchResultRequest) String() string { return proto.CompactTextString(m) } -func (*QueryGetMatchResultRequest) ProtoMessage() {} -func (*QueryGetMatchResultRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{36} -} -func (m *QueryGetMatchResultRequest) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryGetMatchResultRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryGetMatchResultRequest.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryGetMatchResultRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryGetMatchResultRequest.Merge(m, src) -} -func (m *QueryGetMatchResultRequest) XXX_Size() int { - return m.Size() -} -func (m *QueryGetMatchResultRequest) XXX_DiscardUnknown() { - xxx_messageInfo_QueryGetMatchResultRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryGetMatchResultRequest proto.InternalMessageInfo - -func (m *QueryGetMatchResultRequest) GetContractAddr() string { - if m != nil { - return m.ContractAddr - } - return "" -} - -type QueryGetMatchResultResponse struct { - Result *MatchResult `protobuf:"bytes,1,opt,name=result,proto3" json:"result"` -} - -func (m *QueryGetMatchResultResponse) Reset() { *m = QueryGetMatchResultResponse{} } -func (m *QueryGetMatchResultResponse) String() string { return proto.CompactTextString(m) } -func (*QueryGetMatchResultResponse) ProtoMessage() {} -func (*QueryGetMatchResultResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{37} -} -func (m *QueryGetMatchResultResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryGetMatchResultResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryGetMatchResultResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryGetMatchResultResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryGetMatchResultResponse.Merge(m, src) -} -func (m *QueryGetMatchResultResponse) XXX_Size() int { - return m.Size() -} -func (m *QueryGetMatchResultResponse) XXX_DiscardUnknown() { - xxx_messageInfo_QueryGetMatchResultResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryGetMatchResultResponse proto.InternalMessageInfo - -func (m *QueryGetMatchResultResponse) GetResult() *MatchResult { - if m != nil { - return m.Result - } - return nil -} - -type QueryGetOrderCountRequest struct { - ContractAddr string `protobuf:"bytes,1,opt,name=contractAddr,proto3" json:"contract_address"` - PriceDenom string `protobuf:"bytes,2,opt,name=priceDenom,proto3" json:"price_denom"` - AssetDenom string `protobuf:"bytes,3,opt,name=assetDenom,proto3" json:"asset_denom"` - Price *github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,4,opt,name=price,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"price"` - PositionDirection PositionDirection `protobuf:"varint,5,opt,name=positionDirection,proto3,enum=seiprotocol.seichain.dex.PositionDirection" json:"position_direction"` -} - -func (m *QueryGetOrderCountRequest) Reset() { *m = QueryGetOrderCountRequest{} } -func (m *QueryGetOrderCountRequest) String() string { return proto.CompactTextString(m) } -func (*QueryGetOrderCountRequest) ProtoMessage() {} -func (*QueryGetOrderCountRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{38} -} -func (m *QueryGetOrderCountRequest) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryGetOrderCountRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryGetOrderCountRequest.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryGetOrderCountRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryGetOrderCountRequest.Merge(m, src) -} -func (m *QueryGetOrderCountRequest) XXX_Size() int { - return m.Size() -} -func (m *QueryGetOrderCountRequest) XXX_DiscardUnknown() { - xxx_messageInfo_QueryGetOrderCountRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryGetOrderCountRequest proto.InternalMessageInfo - -func (m *QueryGetOrderCountRequest) GetContractAddr() string { - if m != nil { - return m.ContractAddr - } - return "" -} - -func (m *QueryGetOrderCountRequest) GetPriceDenom() string { - if m != nil { - return m.PriceDenom - } - return "" -} - -func (m *QueryGetOrderCountRequest) GetAssetDenom() string { - if m != nil { - return m.AssetDenom - } - return "" -} - -func (m *QueryGetOrderCountRequest) GetPositionDirection() PositionDirection { - if m != nil { - return m.PositionDirection - } - return PositionDirection_LONG -} - -type QueryGetOrderCountResponse struct { - Count uint64 `protobuf:"varint,1,opt,name=count,proto3" json:"count"` -} - -func (m *QueryGetOrderCountResponse) Reset() { *m = QueryGetOrderCountResponse{} } -func (m *QueryGetOrderCountResponse) String() string { return proto.CompactTextString(m) } -func (*QueryGetOrderCountResponse) ProtoMessage() {} -func (*QueryGetOrderCountResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d8e98105e6e08a59, []int{39} -} -func (m *QueryGetOrderCountResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryGetOrderCountResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryGetOrderCountResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryGetOrderCountResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryGetOrderCountResponse.Merge(m, src) -} -func (m *QueryGetOrderCountResponse) XXX_Size() int { - return m.Size() -} -func (m *QueryGetOrderCountResponse) XXX_DiscardUnknown() { - xxx_messageInfo_QueryGetOrderCountResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryGetOrderCountResponse proto.InternalMessageInfo - -func (m *QueryGetOrderCountResponse) GetCount() uint64 { - if m != nil { - return m.Count - } - return 0 -} - -func init() { - proto.RegisterType((*QueryParamsRequest)(nil), "seiprotocol.seichain.dex.QueryParamsRequest") - proto.RegisterType((*QueryParamsResponse)(nil), "seiprotocol.seichain.dex.QueryParamsResponse") - proto.RegisterType((*QueryGetLongBookRequest)(nil), "seiprotocol.seichain.dex.QueryGetLongBookRequest") - proto.RegisterType((*QueryGetLongBookResponse)(nil), "seiprotocol.seichain.dex.QueryGetLongBookResponse") - proto.RegisterType((*QueryAllLongBookRequest)(nil), "seiprotocol.seichain.dex.QueryAllLongBookRequest") - proto.RegisterType((*QueryAllLongBookResponse)(nil), "seiprotocol.seichain.dex.QueryAllLongBookResponse") - proto.RegisterType((*QueryGetShortBookRequest)(nil), "seiprotocol.seichain.dex.QueryGetShortBookRequest") - proto.RegisterType((*QueryGetShortBookResponse)(nil), "seiprotocol.seichain.dex.QueryGetShortBookResponse") - proto.RegisterType((*QueryAllShortBookRequest)(nil), "seiprotocol.seichain.dex.QueryAllShortBookRequest") - proto.RegisterType((*QueryAllShortBookResponse)(nil), "seiprotocol.seichain.dex.QueryAllShortBookResponse") - proto.RegisterType((*QueryGetPricesRequest)(nil), "seiprotocol.seichain.dex.QueryGetPricesRequest") - proto.RegisterType((*QueryGetPricesResponse)(nil), "seiprotocol.seichain.dex.QueryGetPricesResponse") - proto.RegisterType((*QueryGetPriceRequest)(nil), "seiprotocol.seichain.dex.QueryGetPriceRequest") - proto.RegisterType((*QueryGetPriceResponse)(nil), "seiprotocol.seichain.dex.QueryGetPriceResponse") - proto.RegisterType((*QueryGetLatestPriceRequest)(nil), "seiprotocol.seichain.dex.QueryGetLatestPriceRequest") - proto.RegisterType((*QueryGetLatestPriceResponse)(nil), "seiprotocol.seichain.dex.QueryGetLatestPriceResponse") - proto.RegisterType((*QueryGetTwapsRequest)(nil), "seiprotocol.seichain.dex.QueryGetTwapsRequest") - proto.RegisterType((*QueryGetTwapsResponse)(nil), "seiprotocol.seichain.dex.QueryGetTwapsResponse") - proto.RegisterType((*QueryAssetListRequest)(nil), "seiprotocol.seichain.dex.QueryAssetListRequest") - proto.RegisterType((*QueryAssetListResponse)(nil), "seiprotocol.seichain.dex.QueryAssetListResponse") - proto.RegisterType((*QueryAssetMetadataRequest)(nil), "seiprotocol.seichain.dex.QueryAssetMetadataRequest") - proto.RegisterType((*QueryAssetMetadataResponse)(nil), "seiprotocol.seichain.dex.QueryAssetMetadataResponse") - proto.RegisterType((*QueryRegisteredPairsRequest)(nil), "seiprotocol.seichain.dex.QueryRegisteredPairsRequest") - proto.RegisterType((*QueryRegisteredPairsResponse)(nil), "seiprotocol.seichain.dex.QueryRegisteredPairsResponse") - proto.RegisterType((*QueryRegisteredContractRequest)(nil), "seiprotocol.seichain.dex.QueryRegisteredContractRequest") - proto.RegisterType((*QueryRegisteredContractResponse)(nil), "seiprotocol.seichain.dex.QueryRegisteredContractResponse") - proto.RegisterType((*QueryGetOrdersRequest)(nil), "seiprotocol.seichain.dex.QueryGetOrdersRequest") - proto.RegisterType((*QueryGetOrdersResponse)(nil), "seiprotocol.seichain.dex.QueryGetOrdersResponse") - proto.RegisterType((*QueryGetOrderByIDRequest)(nil), "seiprotocol.seichain.dex.QueryGetOrderByIDRequest") - proto.RegisterType((*QueryGetOrderByIDResponse)(nil), "seiprotocol.seichain.dex.QueryGetOrderByIDResponse") - proto.RegisterType((*QueryGetHistoricalPricesRequest)(nil), "seiprotocol.seichain.dex.QueryGetHistoricalPricesRequest") - proto.RegisterType((*QueryGetHistoricalPricesResponse)(nil), "seiprotocol.seichain.dex.QueryGetHistoricalPricesResponse") - proto.RegisterType((*QueryGetMarketSummaryRequest)(nil), "seiprotocol.seichain.dex.QueryGetMarketSummaryRequest") - proto.RegisterType((*QueryGetMarketSummaryResponse)(nil), "seiprotocol.seichain.dex.QueryGetMarketSummaryResponse") - proto.RegisterType((*QueryOrderSimulationRequest)(nil), "seiprotocol.seichain.dex.QueryOrderSimulationRequest") - proto.RegisterType((*QueryOrderSimulationResponse)(nil), "seiprotocol.seichain.dex.QueryOrderSimulationResponse") - proto.RegisterType((*QueryGetMatchResultRequest)(nil), "seiprotocol.seichain.dex.QueryGetMatchResultRequest") - proto.RegisterType((*QueryGetMatchResultResponse)(nil), "seiprotocol.seichain.dex.QueryGetMatchResultResponse") - proto.RegisterType((*QueryGetOrderCountRequest)(nil), "seiprotocol.seichain.dex.QueryGetOrderCountRequest") - proto.RegisterType((*QueryGetOrderCountResponse)(nil), "seiprotocol.seichain.dex.QueryGetOrderCountResponse") -} - -func init() { proto.RegisterFile("dex/query.proto", fileDescriptor_d8e98105e6e08a59) } - -var fileDescriptor_d8e98105e6e08a59 = []byte{ - // 2281 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x59, 0xcb, 0x6f, 0x1c, 0x49, - 0x1d, 0x76, 0x8f, 0x63, 0x63, 0x97, 0xf3, 0x2c, 0xdb, 0x89, 0x19, 0xc2, 0x4c, 0xa8, 0x55, 0x36, - 0xcb, 0x2e, 0x9e, 0x26, 0x4e, 0xb2, 0x79, 0x48, 0x9b, 0x6c, 0xc6, 0xce, 0x1a, 0x8b, 0x38, 0x71, - 0xda, 0x89, 0x37, 0x84, 0x0d, 0xbd, 0xe5, 0xe9, 0xf2, 0x4c, 0xe3, 0x9e, 0xae, 0x49, 0x77, 0xcf, - 0xc6, 0x96, 0x19, 0xf1, 0x12, 0x17, 0xb8, 0x44, 0x5a, 0x0e, 0xec, 0x81, 0x3f, 0x00, 0x09, 0x0e, - 0x5c, 0xd0, 0x8a, 0x3b, 0xab, 0x95, 0x40, 0x4b, 0xa4, 0x05, 0x09, 0x81, 0x34, 0x42, 0x09, 0xa7, - 0xb9, 0x23, 0xc4, 0x6d, 0xd5, 0x55, 0xd5, 0xef, 0x19, 0x77, 0x77, 0x1c, 0xad, 0xb2, 0xa7, 0xf6, - 0x54, 0xd7, 0xf7, 0xab, 0xdf, 0xf7, 0xd5, 0xaf, 0x1e, 0xfd, 0x19, 0x1c, 0xd2, 0xc8, 0x96, 0xfc, - 0xa0, 0x4d, 0xac, 0xed, 0x4a, 0xcb, 0xa2, 0x0e, 0x85, 0x33, 0x36, 0xd1, 0xd9, 0x5f, 0x35, 0x6a, - 0x54, 0x6c, 0xa2, 0xd7, 0x1a, 0x58, 0x37, 0x2b, 0x1a, 0xd9, 0x2a, 0x4e, 0xd5, 0x69, 0x9d, 0xb2, - 0x57, 0xb2, 0xfb, 0x17, 0xef, 0x5f, 0x3c, 0x5e, 0xa7, 0xb4, 0x6e, 0x10, 0x19, 0xb7, 0x74, 0x19, - 0x9b, 0x26, 0x75, 0xb0, 0xa3, 0x53, 0xd3, 0x16, 0x6f, 0x5f, 0xad, 0x51, 0xbb, 0x49, 0x6d, 0x79, - 0x1d, 0xdb, 0x84, 0x0f, 0x23, 0xbf, 0x77, 0x7a, 0x9d, 0x38, 0xf8, 0xb4, 0xdc, 0xc2, 0x75, 0xdd, - 0x64, 0x9d, 0x45, 0xdf, 0xc3, 0x6e, 0x2a, 0x2d, 0x6c, 0xe1, 0xa6, 0x87, 0x9e, 0x74, 0x5b, 0x0c, - 0x6a, 0xd6, 0xd5, 0x75, 0x4a, 0x37, 0x45, 0xe3, 0x94, 0xdb, 0x68, 0x37, 0xa8, 0xe5, 0x84, 0x5b, - 0x19, 0x8f, 0x96, 0xa5, 0xd7, 0x88, 0x68, 0x80, 0x6e, 0x43, 0x8d, 0x9a, 0x8e, 0x85, 0x6b, 0x8e, - 0x68, 0x3b, 0xe8, 0xb6, 0x39, 0x0f, 0x71, 0x2b, 0x1c, 0x0a, 0xdb, 0x36, 0x71, 0x54, 0x43, 0xb7, - 0x23, 0xbd, 0x5a, 0x58, 0xb7, 0xc2, 0xa1, 0xa9, 0xa5, 0x11, 0xaf, 0xe1, 0xa8, 0xdb, 0xd0, 0xc4, - 0x4e, 0xad, 0xa1, 0x5a, 0xc4, 0x6e, 0x1b, 0x4e, 0xb8, 0x23, 0x31, 0xdb, 0x5e, 0xfe, 0x68, 0x0a, - 0xc0, 0x5b, 0x2e, 0xe7, 0x15, 0x46, 0x4a, 0x21, 0x0f, 0xda, 0xc4, 0x76, 0xd0, 0x1d, 0x30, 0x19, - 0x69, 0xb5, 0x5b, 0xd4, 0xb4, 0x09, 0xbc, 0x0c, 0x46, 0x39, 0xf9, 0x19, 0xe9, 0x84, 0xf4, 0xca, - 0xc4, 0xdc, 0x89, 0xca, 0xa0, 0x99, 0xa8, 0x70, 0x64, 0x75, 0xdf, 0xc7, 0xdd, 0xf2, 0x90, 0x22, - 0x50, 0xe8, 0x7d, 0x09, 0x1c, 0x63, 0x71, 0x17, 0x89, 0x73, 0x9d, 0x9a, 0xf5, 0x2a, 0xa5, 0x9b, - 0x62, 0x48, 0x38, 0x05, 0x46, 0x98, 0x36, 0x2c, 0xf4, 0xb8, 0xc2, 0x7f, 0x40, 0x04, 0xf6, 0x7b, - 0x02, 0x5d, 0xd5, 0x34, 0x6b, 0xa6, 0xc0, 0x5e, 0x46, 0xda, 0x60, 0x09, 0x00, 0xd6, 0x79, 0x81, - 0x98, 0xb4, 0x39, 0x33, 0xcc, 0x7a, 0x84, 0x5a, 0xdc, 0xf7, 0x4c, 0x40, 0xfe, 0x7e, 0x1f, 0x7f, - 0x1f, 0xb4, 0xa0, 0x77, 0xc1, 0x4c, 0x32, 0x29, 0xc1, 0x78, 0x01, 0x8c, 0x79, 0x6d, 0x82, 0x33, - 0x1a, 0xcc, 0xd9, 0xeb, 0x29, 0x58, 0xfb, 0x48, 0xf4, 0x27, 0x8f, 0xf7, 0x55, 0xc3, 0x88, 0xf3, - 0x7e, 0x0b, 0x80, 0xa0, 0xcc, 0xc4, 0x18, 0x2f, 0x57, 0x78, 0x4d, 0x56, 0xdc, 0x9a, 0xac, 0xf0, - 0xd2, 0x17, 0x35, 0x59, 0x59, 0xc1, 0x75, 0x22, 0xb0, 0x4a, 0x08, 0xf9, 0xb9, 0x28, 0xf5, 0x1b, - 0x49, 0x48, 0x15, 0xe1, 0xd1, 0x57, 0xaa, 0xe1, 0x67, 0x93, 0x0a, 0x2e, 0x46, 0xe4, 0x28, 0x30, - 0x39, 0x4e, 0xa5, 0xca, 0xc1, 0x53, 0x08, 0xeb, 0x81, 0x7e, 0x29, 0x05, 0xd3, 0xba, 0xea, 0x2e, - 0xc5, 0x17, 0xa3, 0xd8, 0x34, 0xf0, 0xe5, 0x3e, 0x59, 0x09, 0x09, 0x17, 0xc1, 0xb8, 0xdf, 0x28, - 0x4a, 0xe1, 0xa5, 0xc1, 0x1a, 0xfa, 0x5d, 0x85, 0x88, 0x01, 0x16, 0x7d, 0x14, 0x9a, 0xa8, 0x04, - 0xf9, 0x2f, 0x52, 0xc5, 0xfd, 0x4e, 0x12, 0x7a, 0x45, 0x89, 0xf4, 0xd7, 0x6b, 0xf8, 0x59, 0xf5, - 0x7a, 0x7e, 0x55, 0xb7, 0x03, 0xa6, 0xbd, 0xe9, 0x5d, 0x71, 0x59, 0x7a, 0x3b, 0x6a, 0x4c, 0x08, - 0x29, 0x45, 0x88, 0x42, 0x5c, 0x88, 0x84, 0xd8, 0xc3, 0x49, 0xb1, 0xd1, 0x2d, 0x70, 0x34, 0x3e, - 0xb8, 0x10, 0xea, 0x3c, 0x18, 0x65, 0x63, 0xd9, 0x42, 0xa5, 0xf2, 0x2e, 0x1b, 0xb7, 0xdb, 0x4f, - 0x11, 0xdd, 0xd1, 0xaf, 0x24, 0x30, 0x15, 0x89, 0xf9, 0x39, 0xf2, 0x81, 0xc7, 0xc1, 0xb8, 0xa3, - 0x37, 0x89, 0xed, 0xe0, 0x66, 0x8b, 0xd5, 0xc6, 0x3e, 0x25, 0x68, 0x40, 0x5a, 0x4c, 0x6a, 0x9f, - 0xec, 0xb9, 0xf0, 0xe2, 0xce, 0xc0, 0x55, 0xac, 0xfe, 0x29, 0x30, 0xb2, 0x41, 0xdb, 0xa6, 0xc6, - 0x92, 0x1d, 0x53, 0xf8, 0x0f, 0xf4, 0xa1, 0x04, 0x8a, 0xfe, 0xe9, 0x80, 0x1d, 0x62, 0x47, 0x65, - 0x90, 0x93, 0x32, 0x54, 0x0f, 0xf5, 0xba, 0xe5, 0x09, 0xd6, 0xaa, 0x6a, 0x6e, 0x73, 0x44, 0x17, - 0x39, 0xa9, 0x0b, 0x07, 0xf0, 0x33, 0x5e, 0x00, 0x42, 0x42, 0x5d, 0xe8, 0x27, 0x54, 0x75, 0xaa, - 0xd7, 0x2d, 0x1f, 0xf6, 0xda, 0x55, 0xac, 0x69, 0x16, 0xb1, 0xed, 0x58, 0x39, 0xdc, 0x06, 0x5f, - 0xe9, 0x9b, 0xf9, 0x9e, 0x64, 0x42, 0x8f, 0x42, 0x15, 0x71, 0xfb, 0x21, 0x6e, 0xf9, 0x15, 0x1e, - 0x4f, 0x54, 0xca, 0x9a, 0x28, 0xbc, 0x0c, 0x0e, 0x19, 0x94, 0x6e, 0xae, 0xe3, 0xda, 0xe6, 0x2a, - 0xa9, 0x51, 0x53, 0xb3, 0x99, 0x30, 0xfb, 0x38, 0xd8, 0x7b, 0xa5, 0xda, 0xfc, 0x9d, 0x12, 0xef, - 0x8c, 0xee, 0x06, 0x95, 0x20, 0x32, 0x12, 0x14, 0xaf, 0x80, 0x11, 0xf7, 0x2a, 0xe5, 0x55, 0x7d, - 0x69, 0x30, 0x45, 0x17, 0x57, 0x1d, 0xef, 0x75, 0xcb, 0x1c, 0xa0, 0xf0, 0x07, 0x3a, 0x26, 0x22, - 0x5f, 0x75, 0xe7, 0xe3, 0xba, 0x6e, 0x3b, 0xde, 0x05, 0x89, 0x88, 0xa5, 0x16, 0x7a, 0x21, 0xc6, - 0xfc, 0x36, 0x18, 0xc7, 0x5e, 0xa3, 0x18, 0xf7, 0xd4, 0xe0, 0x71, 0x19, 0x7e, 0x99, 0x38, 0x58, - 0xc3, 0x0e, 0xf6, 0xf6, 0x25, 0x1f, 0x8f, 0x4e, 0x7b, 0xbb, 0x5f, 0xb8, 0x5b, 0xe8, 0x10, 0xd3, - 0x42, 0xab, 0x8f, 0xff, 0x40, 0x58, 0xd4, 0x6b, 0x0c, 0x22, 0xb2, 0x9b, 0x07, 0x63, 0x4d, 0xd1, - 0x26, 0xe6, 0x3d, 0x6b, 0x72, 0x8a, 0x0f, 0x44, 0x6f, 0x8b, 0xc2, 0x52, 0x48, 0x5d, 0xb7, 0x1d, - 0x62, 0x11, 0x6d, 0x05, 0xeb, 0xd6, 0xde, 0x0b, 0x01, 0xdd, 0x03, 0xc7, 0xfb, 0x07, 0x16, 0xd9, - 0x5f, 0x02, 0x23, 0xee, 0xa5, 0x37, 0xc3, 0x7c, 0xba, 0x38, 0x21, 0x27, 0x87, 0xa0, 0x7b, 0xa0, - 0x14, 0x8b, 0x3d, 0x2f, 0x86, 0xde, 0x7b, 0xde, 0x2d, 0x50, 0x1e, 0x18, 0x5b, 0xa4, 0xbe, 0x0c, - 0x0e, 0xf8, 0x41, 0x74, 0x73, 0x83, 0x0a, 0xf5, 0x5f, 0x19, 0x4c, 0xc1, 0x0b, 0xb1, 0x64, 0x6e, - 0xd0, 0xb5, 0xb9, 0x60, 0x44, 0xf7, 0x37, 0xda, 0x0a, 0x4a, 0xfe, 0xa6, 0x7b, 0xed, 0x7f, 0x0e, - 0xab, 0xf0, 0x24, 0xf8, 0x12, 0xae, 0xd5, 0x68, 0xdb, 0x74, 0xc4, 0xb6, 0x34, 0xd1, 0xeb, 0x96, - 0xbd, 0x26, 0xc5, 0xfb, 0x03, 0xdd, 0x0f, 0x0e, 0x19, 0x6f, 0x64, 0xbf, 0xb6, 0x46, 0xd9, 0x27, - 0x48, 0x86, 0x43, 0x86, 0x21, 0xab, 0xa0, 0xd7, 0x2d, 0x0b, 0x88, 0x22, 0x9e, 0xe8, 0x93, 0xd0, - 0xb5, 0x8d, 0xf7, 0xda, 0x5e, 0x5a, 0xd8, 0x3b, 0xb9, 0xe8, 0x3e, 0x5d, 0xc8, 0xbb, 0x4f, 0x0f, - 0xa7, 0xef, 0xd3, 0x47, 0x41, 0x41, 0xd7, 0xf8, 0x29, 0x55, 0x1d, 0xed, 0x75, 0xcb, 0x05, 0x5d, - 0x53, 0x0a, 0xba, 0x86, 0xee, 0x07, 0x17, 0xbe, 0x10, 0x1f, 0x21, 0xd9, 0x9b, 0x60, 0x84, 0xf1, - 0x4e, 0xdf, 0x83, 0x39, 0x96, 0xed, 0x50, 0x0c, 0xa1, 0xf0, 0x07, 0xfa, 0x4b, 0x41, 0xd4, 0xde, - 0x22, 0x71, 0xbe, 0xa5, 0xdb, 0x0e, 0xb5, 0xf4, 0x1a, 0x36, 0xa2, 0x77, 0x8f, 0x17, 0x59, 0x36, - 0x05, 0x4c, 0xb7, 0x88, 0xa5, 0x53, 0xed, 0x3a, 0x31, 0xeb, 0x4e, 0x63, 0xc9, 0xf4, 0x4e, 0x00, - 0xae, 0xe4, 0xf1, 0x5e, 0xb7, 0x3c, 0xc3, 0x3b, 0xa8, 0x06, 0xeb, 0xa1, 0xea, 0xa6, 0x7f, 0x12, - 0xf4, 0x87, 0xc2, 0x8b, 0x60, 0xbf, 0xd9, 0x6e, 0xde, 0xdc, 0x58, 0x61, 0x6f, 0xed, 0x99, 0x11, - 0x16, 0x6a, 0xba, 0xd7, 0x2d, 0x1f, 0x31, 0xdb, 0xcd, 0x75, 0x62, 0xa9, 0x74, 0x43, 0xe5, 0x50, - 0x5b, 0x89, 0x74, 0x45, 0x16, 0x38, 0x31, 0x58, 0x4d, 0x31, 0x69, 0x37, 0x62, 0x97, 0xa9, 0x57, - 0x53, 0x4e, 0xce, 0x79, 0x6c, 0x6a, 0x06, 0xb1, 0x1d, 0xbd, 0xb6, 0xc9, 0x4b, 0x9e, 0xa3, 0xfd, - 0x3b, 0xd6, 0x8f, 0x0b, 0x62, 0xdb, 0x5b, 0x24, 0xce, 0x32, 0xb6, 0x36, 0x89, 0xb3, 0xda, 0x6e, - 0x36, 0xb1, 0xbb, 0x9d, 0xbc, 0xf8, 0xf3, 0x77, 0x0d, 0x1c, 0xf1, 0x8e, 0xe3, 0xf8, 0xdc, 0x1d, - 0xeb, 0x75, 0xcb, 0x93, 0xfe, 0xe9, 0x1d, 0x9a, 0xb6, 0x24, 0x02, 0xfd, 0x7f, 0x18, 0x7c, 0x75, - 0x80, 0x06, 0x42, 0xf5, 0x77, 0xc0, 0x84, 0x43, 0x1d, 0x6c, 0xac, 0x51, 0xa3, 0xdd, 0x14, 0x1f, - 0x6e, 0xd5, 0x4b, 0xff, 0xec, 0x96, 0x5f, 0xae, 0xeb, 0x4e, 0xa3, 0xbd, 0x5e, 0xa9, 0xd1, 0xa6, - 0x2c, 0xac, 0x1c, 0xfe, 0x98, 0xb5, 0xb5, 0x4d, 0xd9, 0xd9, 0x6e, 0x11, 0xbb, 0xb2, 0x40, 0x6a, - 0xbd, 0x6e, 0x79, 0x3f, 0x0b, 0xa0, 0xbe, 0xc7, 0x22, 0x28, 0xe1, 0x70, 0xb0, 0x0d, 0x26, 0x43, - 0x3f, 0x6f, 0x50, 0xf7, 0x32, 0x8f, 0x0d, 0xa1, 0xd8, 0x7c, 0xae, 0x51, 0xa6, 0xc3, 0xa3, 0xa8, - 0xa6, 0x08, 0xa5, 0xf4, 0x8b, 0x0f, 0xd7, 0xc0, 0x78, 0x43, 0xaf, 0x37, 0x58, 0x99, 0x08, 0xb5, - 0x2f, 0xe4, 0x1a, 0x0c, 0xb8, 0x70, 0x95, 0x4d, 0xa0, 0x12, 0x84, 0x82, 0xab, 0x60, 0xcc, 0xa0, - 0x0f, 0x79, 0x58, 0xf6, 0x51, 0x55, 0x3d, 0x9f, 0x2b, 0xec, 0xb8, 0x41, 0x1f, 0x8a, 0xa8, 0x7e, - 0x20, 0x37, 0x59, 0x03, 0x8b, 0x5b, 0x24, 0x5b, 0x53, 0xb9, 0x93, 0x75, 0xe1, 0x5e, 0xb2, 0x7e, - 0x28, 0xf4, 0x81, 0x24, 0xee, 0x13, 0x6c, 0x8f, 0x5b, 0xd5, 0x9b, 0x6d, 0x83, 0x7d, 0x4c, 0x79, - 0xe5, 0xbf, 0xe7, 0x4d, 0x32, 0xb1, 0x80, 0x0a, 0x99, 0x4f, 0xf6, 0x5f, 0x48, 0x62, 0x6d, 0x26, - 0x72, 0x13, 0x65, 0xb9, 0x09, 0x0e, 0x5f, 0xdb, 0x22, 0xb5, 0xb6, 0x43, 0xb4, 0x5b, 0x6d, 0x6c, - 0x3a, 0xba, 0xb3, 0x2d, 0x6a, 0xf3, 0x4a, 0x2e, 0x6d, 0x8e, 0x10, 0x11, 0x45, 0x7d, 0x20, 0xc2, - 0x28, 0x89, 0xc0, 0x68, 0x2d, 0xf8, 0x16, 0x59, 0xc6, 0x4e, 0xad, 0xa1, 0x30, 0x6b, 0x6f, 0xef, - 0xf7, 0x97, 0x46, 0xf0, 0xa5, 0x10, 0x89, 0x2b, 0x38, 0x2e, 0x81, 0x51, 0x6e, 0x22, 0x8a, 0x19, - 0x38, 0x39, 0x78, 0x06, 0x42, 0x70, 0xbe, 0xd7, 0x71, 0xa0, 0x22, 0x9e, 0xe8, 0xbf, 0x85, 0xd8, - 0x71, 0x38, 0xcf, 0x6e, 0x17, 0x5f, 0x80, 0x8d, 0x6e, 0xc9, 0xfb, 0x5c, 0xe2, 0xeb, 0xe9, 0x4c, - 0xae, 0xd9, 0xe5, 0x50, 0xef, 0x4b, 0xf3, 0x01, 0x38, 0xd2, 0xa2, 0xb6, 0xee, 0xd6, 0xd1, 0x82, - 0x6e, 0x91, 0x1a, 0x33, 0x1d, 0xdc, 0x05, 0x75, 0x70, 0xee, 0xb5, 0x5d, 0xce, 0x92, 0x38, 0xa4, - 0x7a, 0xb4, 0xd7, 0x2d, 0x43, 0x2f, 0x92, 0xaa, 0x79, 0xed, 0x4a, 0x32, 0x3a, 0x7a, 0x23, 0xa8, - 0x9c, 0xb0, 0xec, 0x62, 0x82, 0xcb, 0x60, 0x84, 0x5f, 0xfc, 0x24, 0xb6, 0x71, 0xb3, 0x05, 0xc4, - 0xaf, 0x7d, 0xfc, 0x31, 0xf7, 0xdb, 0x12, 0x18, 0x61, 0x78, 0xf8, 0x48, 0x02, 0xa3, 0xdc, 0xdb, - 0x85, 0xdf, 0x18, 0x9c, 0x6b, 0xd2, 0x52, 0x2e, 0xce, 0x66, 0xec, 0xcd, 0x53, 0x42, 0x5f, 0xff, - 0xc9, 0xa7, 0xff, 0x79, 0xbf, 0xf0, 0x12, 0xfc, 0x9a, 0x6c, 0x13, 0x7d, 0xd6, 0xc3, 0xc9, 0x1e, - 0x4e, 0x0e, 0x8c, 0x78, 0xf8, 0x58, 0x0a, 0x9c, 0x47, 0x78, 0x3a, 0x65, 0x98, 0xa4, 0xf3, 0x5c, - 0x9c, 0xcb, 0x03, 0x11, 0xe9, 0xdd, 0x67, 0xe9, 0xbd, 0x0d, 0xef, 0xec, 0x92, 0x9e, 0xff, 0x5f, - 0x01, 0x79, 0x27, 0x5c, 0xab, 0x1d, 0x79, 0x27, 0xa8, 0xc3, 0x8e, 0xbc, 0x13, 0xd4, 0x98, 0xf7, - 0xa6, 0x03, 0xff, 0x2c, 0x81, 0x09, 0x6f, 0xcc, 0xab, 0x86, 0x91, 0xca, 0x2a, 0xe9, 0x2b, 0xa7, - 0xb2, 0xea, 0x63, 0xe1, 0xa2, 0x3b, 0x8c, 0xd5, 0x4d, 0xb8, 0xfc, 0x5c, 0x59, 0xc1, 0xbf, 0x49, - 0x21, 0x9f, 0x0e, 0x66, 0x90, 0x3b, 0x6e, 0x59, 0x16, 0xcf, 0xe4, 0xc2, 0x08, 0x36, 0xdf, 0x63, - 0x6c, 0xee, 0xc2, 0xb5, 0x5d, 0xd8, 0x04, 0xff, 0xa4, 0xc9, 0x3f, 0x49, 0x7f, 0x95, 0xc0, 0x7e, - 0x7f, 0x54, 0x77, 0x96, 0x32, 0x48, 0x9e, 0x9b, 0x59, 0x3f, 0xdf, 0x13, 0xad, 0x31, 0x66, 0x2b, - 0xf0, 0xc6, 0xf3, 0x65, 0x06, 0x3f, 0x91, 0xc0, 0x98, 0x67, 0xa7, 0xc1, 0x4a, 0xba, 0xe6, 0x61, - 0x2b, 0xac, 0x28, 0x67, 0xee, 0x2f, 0x58, 0x60, 0xc6, 0xe2, 0xbb, 0xf0, 0x3b, 0xbb, 0xb0, 0xa8, - 0x13, 0x71, 0x61, 0xc8, 0x31, 0x3d, 0xbe, 0x45, 0xd8, 0x81, 0xff, 0x92, 0xc0, 0xc1, 0xa8, 0xfd, - 0x05, 0xcf, 0x66, 0x58, 0xed, 0x09, 0x9f, 0xaf, 0x78, 0x2e, 0x27, 0x4a, 0x50, 0x7c, 0x87, 0x51, - 0x5c, 0x83, 0xb7, 0x53, 0x28, 0x1a, 0x0c, 0x9b, 0x93, 0x29, 0xfc, 0x48, 0x02, 0xe3, 0xbe, 0xd7, - 0x0b, 0xb3, 0xea, 0xef, 0xef, 0xc8, 0xdf, 0xcc, 0x0e, 0xc8, 0x51, 0x77, 0xfe, 0x8c, 0xd9, 0xd9, - 0x89, 0xfc, 0x91, 0xd7, 0x1d, 0x33, 0xef, 0xb2, 0xd4, 0x5d, 0xd8, 0x77, 0xcc, 0x52, 0x77, 0x11, - 0x57, 0x10, 0x2d, 0x33, 0x16, 0x8b, 0xf0, 0x5a, 0x0a, 0x0b, 0x66, 0x01, 0x26, 0x48, 0xc4, 0xcc, - 0xc7, 0x0e, 0xfc, 0xbd, 0x04, 0x0e, 0x44, 0x9c, 0x32, 0x98, 0xba, 0xa6, 0xfb, 0xb8, 0x79, 0xc5, - 0xb3, 0xf9, 0x40, 0x82, 0xcb, 0x39, 0xc6, 0x45, 0x86, 0xb3, 0xbb, 0x70, 0x09, 0xfe, 0x7b, 0x2c, - 0xef, 0x68, 0x5c, 0xf0, 0x5f, 0x4b, 0x60, 0xdc, 0xb7, 0x2e, 0x53, 0x2b, 0x27, 0xee, 0x7e, 0xa6, - 0x56, 0x4e, 0xc2, 0x15, 0x45, 0xb3, 0x2c, 0xcf, 0x53, 0xf0, 0x64, 0xa6, 0x3c, 0xe1, 0x87, 0x12, - 0x80, 0x8b, 0xc4, 0x89, 0xf9, 0x80, 0x30, 0x6d, 0x15, 0xf6, 0x37, 0x24, 0x8b, 0xaf, 0xe7, 0x85, - 0x89, 0xa4, 0xcf, 0xb0, 0xa4, 0x67, 0xe1, 0x6b, 0xbb, 0x24, 0x6d, 0xf9, 0x58, 0x95, 0xf9, 0x8c, - 0xf0, 0x53, 0x09, 0x4c, 0x47, 0x52, 0xf7, 0x7c, 0x3c, 0x78, 0x21, 0x73, 0x1a, 0x31, 0x67, 0xb2, - 0x78, 0xf1, 0x19, 0x90, 0x82, 0xc3, 0x35, 0xc6, 0xe1, 0x0a, 0x7c, 0x23, 0x1b, 0x07, 0xaf, 0xd8, - 0x63, 0x65, 0x0f, 0xff, 0xc0, 0xb7, 0x1a, 0xee, 0xf8, 0x65, 0xd9, 0x6a, 0x22, 0xae, 0x64, 0x96, - 0xad, 0x26, 0x6a, 0x26, 0xa2, 0xb7, 0x58, 0xde, 0x6f, 0xc2, 0xcb, 0x29, 0x8b, 0x94, 0xdb, 0x86, - 0x89, 0x55, 0x2a, 0xdc, 0xca, 0x0e, 0xfc, 0x3b, 0xdf, 0x5a, 0x58, 0xf4, 0x2c, 0x57, 0x8f, 0xb8, - 0xe7, 0x98, 0xe5, 0xea, 0x91, 0xf0, 0xf5, 0xd0, 0xbb, 0x2c, 0xfb, 0x7b, 0xf0, 0x6e, 0x96, 0xec, - 0xd5, 0xf5, 0x6d, 0x55, 0xd7, 0x72, 0x1c, 0x70, 0xba, 0xd6, 0x81, 0x1f, 0x14, 0xc0, 0x64, 0x1f, - 0x93, 0x0a, 0x5e, 0x4c, 0x4f, 0x77, 0x80, 0x4d, 0x58, 0xbc, 0xf4, 0x2c, 0x50, 0x41, 0xf8, 0xe7, - 0x12, 0x63, 0xfc, 0x53, 0x09, 0xfe, 0x48, 0x4a, 0xe1, 0xdc, 0xf0, 0x63, 0xe4, 0x3d, 0x27, 0xe4, - 0x9d, 0xbe, 0x7e, 0x5f, 0x47, 0xde, 0x09, 0x7b, 0x78, 0x1d, 0xf8, 0x3f, 0x09, 0x1c, 0x8e, 0xfb, - 0x48, 0xf0, 0xf5, 0x74, 0x76, 0xfd, 0xcc, 0xb7, 0xe2, 0xf9, 0xdc, 0x38, 0x21, 0x89, 0xc5, 0x14, - 0x31, 0xe0, 0xf7, 0x53, 0xf4, 0x68, 0x32, 0xb4, 0x6a, 0x73, 0x78, 0x0e, 0x31, 0x12, 0x2e, 0x5a, - 0x07, 0xfe, 0x8c, 0xef, 0x9b, 0x31, 0xb3, 0x22, 0x75, 0xdf, 0xec, 0x6f, 0xbc, 0xa4, 0xee, 0x9b, - 0x03, 0x3c, 0x11, 0x34, 0x04, 0x7f, 0xc8, 0xae, 0x5d, 0x21, 0x33, 0x20, 0xcb, 0xb5, 0x2b, 0x69, - 0x69, 0x64, 0xb9, 0x76, 0xf5, 0x31, 0x2c, 0xd0, 0x10, 0xfc, 0x01, 0x38, 0x10, 0xf9, 0xd4, 0x85, - 0x59, 0x97, 0x71, 0xd8, 0x8f, 0x28, 0x9e, 0xcd, 0x07, 0xf2, 0x46, 0xaf, 0x2e, 0x7e, 0xfc, 0xa4, - 0x24, 0x3d, 0x7e, 0x52, 0x92, 0xfe, 0xfd, 0xa4, 0x24, 0x3d, 0x7a, 0x5a, 0x1a, 0x7a, 0xfc, 0xb4, - 0x34, 0xf4, 0x8f, 0xa7, 0xa5, 0xa1, 0x7b, 0xb3, 0x21, 0xcb, 0x20, 0x5e, 0x16, 0xb3, 0xbc, 0x2e, - 0xb6, 0x58, 0x65, 0x30, 0xf7, 0x60, 0x7d, 0x94, 0xbd, 0x3f, 0xf3, 0x59, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xf0, 0x0a, 0x3f, 0x2b, 0x03, 0x27, 0x00, 0x00, -} - -// Reference imports to suppress errors if they are not otherwise used. -var _ context.Context -var _ grpc.ClientConn - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion4 - -// QueryClient is the client API for Query service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. -type QueryClient interface { - // Parameters queries the parameters of the module. - Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) - // Queries a LongBook by id. - LongBook(ctx context.Context, in *QueryGetLongBookRequest, opts ...grpc.CallOption) (*QueryGetLongBookResponse, error) - // Queries a list of LongBook items. - LongBookAll(ctx context.Context, in *QueryAllLongBookRequest, opts ...grpc.CallOption) (*QueryAllLongBookResponse, error) - // Queries a ShortBook by id. - ShortBook(ctx context.Context, in *QueryGetShortBookRequest, opts ...grpc.CallOption) (*QueryGetShortBookResponse, error) - // Queries a list of ShortBook items. - ShortBookAll(ctx context.Context, in *QueryAllShortBookRequest, opts ...grpc.CallOption) (*QueryAllShortBookResponse, error) - GetPrice(ctx context.Context, in *QueryGetPriceRequest, opts ...grpc.CallOption) (*QueryGetPriceResponse, error) - GetLatestPrice(ctx context.Context, in *QueryGetLatestPriceRequest, opts ...grpc.CallOption) (*QueryGetLatestPriceResponse, error) - GetPrices(ctx context.Context, in *QueryGetPricesRequest, opts ...grpc.CallOption) (*QueryGetPricesResponse, error) - GetTwaps(ctx context.Context, in *QueryGetTwapsRequest, opts ...grpc.CallOption) (*QueryGetTwapsResponse, error) - // Returns the metadata for a specified denom / display type - AssetMetadata(ctx context.Context, in *QueryAssetMetadataRequest, opts ...grpc.CallOption) (*QueryAssetMetadataResponse, error) - // Returns metadata for all the assets - AssetList(ctx context.Context, in *QueryAssetListRequest, opts ...grpc.CallOption) (*QueryAssetListResponse, error) - // Returns all registered pairs for specified contract address - GetRegisteredPairs(ctx context.Context, in *QueryRegisteredPairsRequest, opts ...grpc.CallOption) (*QueryRegisteredPairsResponse, error) - // Returns registered contract information - GetRegisteredContract(ctx context.Context, in *QueryRegisteredContractRequest, opts ...grpc.CallOption) (*QueryRegisteredContractResponse, error) - GetOrders(ctx context.Context, in *QueryGetOrdersRequest, opts ...grpc.CallOption) (*QueryGetOrdersResponse, error) - GetOrder(ctx context.Context, in *QueryGetOrderByIDRequest, opts ...grpc.CallOption) (*QueryGetOrderByIDResponse, error) - GetHistoricalPrices(ctx context.Context, in *QueryGetHistoricalPricesRequest, opts ...grpc.CallOption) (*QueryGetHistoricalPricesResponse, error) - GetMarketSummary(ctx context.Context, in *QueryGetMarketSummaryRequest, opts ...grpc.CallOption) (*QueryGetMarketSummaryResponse, error) - GetOrderSimulation(ctx context.Context, in *QueryOrderSimulationRequest, opts ...grpc.CallOption) (*QueryOrderSimulationResponse, error) - GetMatchResult(ctx context.Context, in *QueryGetMatchResultRequest, opts ...grpc.CallOption) (*QueryGetMatchResultResponse, error) - GetOrderCount(ctx context.Context, in *QueryGetOrderCountRequest, opts ...grpc.CallOption) (*QueryGetOrderCountResponse, error) -} - -type queryClient struct { - cc grpc1.ClientConn -} - -func NewQueryClient(cc grpc1.ClientConn) QueryClient { - return &queryClient{cc} -} - -func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) { - out := new(QueryParamsResponse) - err := c.cc.Invoke(ctx, "/seiprotocol.seichain.dex.Query/Params", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *queryClient) LongBook(ctx context.Context, in *QueryGetLongBookRequest, opts ...grpc.CallOption) (*QueryGetLongBookResponse, error) { - out := new(QueryGetLongBookResponse) - err := c.cc.Invoke(ctx, "/seiprotocol.seichain.dex.Query/LongBook", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *queryClient) LongBookAll(ctx context.Context, in *QueryAllLongBookRequest, opts ...grpc.CallOption) (*QueryAllLongBookResponse, error) { - out := new(QueryAllLongBookResponse) - err := c.cc.Invoke(ctx, "/seiprotocol.seichain.dex.Query/LongBookAll", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *queryClient) ShortBook(ctx context.Context, in *QueryGetShortBookRequest, opts ...grpc.CallOption) (*QueryGetShortBookResponse, error) { - out := new(QueryGetShortBookResponse) - err := c.cc.Invoke(ctx, "/seiprotocol.seichain.dex.Query/ShortBook", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *queryClient) ShortBookAll(ctx context.Context, in *QueryAllShortBookRequest, opts ...grpc.CallOption) (*QueryAllShortBookResponse, error) { - out := new(QueryAllShortBookResponse) - err := c.cc.Invoke(ctx, "/seiprotocol.seichain.dex.Query/ShortBookAll", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *queryClient) GetPrice(ctx context.Context, in *QueryGetPriceRequest, opts ...grpc.CallOption) (*QueryGetPriceResponse, error) { - out := new(QueryGetPriceResponse) - err := c.cc.Invoke(ctx, "/seiprotocol.seichain.dex.Query/GetPrice", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *queryClient) GetLatestPrice(ctx context.Context, in *QueryGetLatestPriceRequest, opts ...grpc.CallOption) (*QueryGetLatestPriceResponse, error) { - out := new(QueryGetLatestPriceResponse) - err := c.cc.Invoke(ctx, "/seiprotocol.seichain.dex.Query/GetLatestPrice", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *queryClient) GetPrices(ctx context.Context, in *QueryGetPricesRequest, opts ...grpc.CallOption) (*QueryGetPricesResponse, error) { - out := new(QueryGetPricesResponse) - err := c.cc.Invoke(ctx, "/seiprotocol.seichain.dex.Query/GetPrices", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *queryClient) GetTwaps(ctx context.Context, in *QueryGetTwapsRequest, opts ...grpc.CallOption) (*QueryGetTwapsResponse, error) { - out := new(QueryGetTwapsResponse) - err := c.cc.Invoke(ctx, "/seiprotocol.seichain.dex.Query/GetTwaps", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *queryClient) AssetMetadata(ctx context.Context, in *QueryAssetMetadataRequest, opts ...grpc.CallOption) (*QueryAssetMetadataResponse, error) { - out := new(QueryAssetMetadataResponse) - err := c.cc.Invoke(ctx, "/seiprotocol.seichain.dex.Query/AssetMetadata", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *queryClient) AssetList(ctx context.Context, in *QueryAssetListRequest, opts ...grpc.CallOption) (*QueryAssetListResponse, error) { - out := new(QueryAssetListResponse) - err := c.cc.Invoke(ctx, "/seiprotocol.seichain.dex.Query/AssetList", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *queryClient) GetRegisteredPairs(ctx context.Context, in *QueryRegisteredPairsRequest, opts ...grpc.CallOption) (*QueryRegisteredPairsResponse, error) { - out := new(QueryRegisteredPairsResponse) - err := c.cc.Invoke(ctx, "/seiprotocol.seichain.dex.Query/GetRegisteredPairs", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *queryClient) GetRegisteredContract(ctx context.Context, in *QueryRegisteredContractRequest, opts ...grpc.CallOption) (*QueryRegisteredContractResponse, error) { - out := new(QueryRegisteredContractResponse) - err := c.cc.Invoke(ctx, "/seiprotocol.seichain.dex.Query/GetRegisteredContract", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *queryClient) GetOrders(ctx context.Context, in *QueryGetOrdersRequest, opts ...grpc.CallOption) (*QueryGetOrdersResponse, error) { - out := new(QueryGetOrdersResponse) - err := c.cc.Invoke(ctx, "/seiprotocol.seichain.dex.Query/GetOrders", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *queryClient) GetOrder(ctx context.Context, in *QueryGetOrderByIDRequest, opts ...grpc.CallOption) (*QueryGetOrderByIDResponse, error) { - out := new(QueryGetOrderByIDResponse) - err := c.cc.Invoke(ctx, "/seiprotocol.seichain.dex.Query/GetOrder", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *queryClient) GetHistoricalPrices(ctx context.Context, in *QueryGetHistoricalPricesRequest, opts ...grpc.CallOption) (*QueryGetHistoricalPricesResponse, error) { - out := new(QueryGetHistoricalPricesResponse) - err := c.cc.Invoke(ctx, "/seiprotocol.seichain.dex.Query/GetHistoricalPrices", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *queryClient) GetMarketSummary(ctx context.Context, in *QueryGetMarketSummaryRequest, opts ...grpc.CallOption) (*QueryGetMarketSummaryResponse, error) { - out := new(QueryGetMarketSummaryResponse) - err := c.cc.Invoke(ctx, "/seiprotocol.seichain.dex.Query/GetMarketSummary", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *queryClient) GetOrderSimulation(ctx context.Context, in *QueryOrderSimulationRequest, opts ...grpc.CallOption) (*QueryOrderSimulationResponse, error) { - out := new(QueryOrderSimulationResponse) - err := c.cc.Invoke(ctx, "/seiprotocol.seichain.dex.Query/GetOrderSimulation", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *queryClient) GetMatchResult(ctx context.Context, in *QueryGetMatchResultRequest, opts ...grpc.CallOption) (*QueryGetMatchResultResponse, error) { - out := new(QueryGetMatchResultResponse) - err := c.cc.Invoke(ctx, "/seiprotocol.seichain.dex.Query/GetMatchResult", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *queryClient) GetOrderCount(ctx context.Context, in *QueryGetOrderCountRequest, opts ...grpc.CallOption) (*QueryGetOrderCountResponse, error) { - out := new(QueryGetOrderCountResponse) - err := c.cc.Invoke(ctx, "/seiprotocol.seichain.dex.Query/GetOrderCount", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// QueryServer is the server API for Query service. -type QueryServer interface { - // Parameters queries the parameters of the module. - Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) - // Queries a LongBook by id. - LongBook(context.Context, *QueryGetLongBookRequest) (*QueryGetLongBookResponse, error) - // Queries a list of LongBook items. - LongBookAll(context.Context, *QueryAllLongBookRequest) (*QueryAllLongBookResponse, error) - // Queries a ShortBook by id. - ShortBook(context.Context, *QueryGetShortBookRequest) (*QueryGetShortBookResponse, error) - // Queries a list of ShortBook items. - ShortBookAll(context.Context, *QueryAllShortBookRequest) (*QueryAllShortBookResponse, error) - GetPrice(context.Context, *QueryGetPriceRequest) (*QueryGetPriceResponse, error) - GetLatestPrice(context.Context, *QueryGetLatestPriceRequest) (*QueryGetLatestPriceResponse, error) - GetPrices(context.Context, *QueryGetPricesRequest) (*QueryGetPricesResponse, error) - GetTwaps(context.Context, *QueryGetTwapsRequest) (*QueryGetTwapsResponse, error) - // Returns the metadata for a specified denom / display type - AssetMetadata(context.Context, *QueryAssetMetadataRequest) (*QueryAssetMetadataResponse, error) - // Returns metadata for all the assets - AssetList(context.Context, *QueryAssetListRequest) (*QueryAssetListResponse, error) - // Returns all registered pairs for specified contract address - GetRegisteredPairs(context.Context, *QueryRegisteredPairsRequest) (*QueryRegisteredPairsResponse, error) - // Returns registered contract information - GetRegisteredContract(context.Context, *QueryRegisteredContractRequest) (*QueryRegisteredContractResponse, error) - GetOrders(context.Context, *QueryGetOrdersRequest) (*QueryGetOrdersResponse, error) - GetOrder(context.Context, *QueryGetOrderByIDRequest) (*QueryGetOrderByIDResponse, error) - GetHistoricalPrices(context.Context, *QueryGetHistoricalPricesRequest) (*QueryGetHistoricalPricesResponse, error) - GetMarketSummary(context.Context, *QueryGetMarketSummaryRequest) (*QueryGetMarketSummaryResponse, error) - GetOrderSimulation(context.Context, *QueryOrderSimulationRequest) (*QueryOrderSimulationResponse, error) - GetMatchResult(context.Context, *QueryGetMatchResultRequest) (*QueryGetMatchResultResponse, error) - GetOrderCount(context.Context, *QueryGetOrderCountRequest) (*QueryGetOrderCountResponse, error) -} - -// UnimplementedQueryServer can be embedded to have forward compatible implementations. -type UnimplementedQueryServer struct { -} - -func (*UnimplementedQueryServer) Params(ctx context.Context, req *QueryParamsRequest) (*QueryParamsResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method Params not implemented") -} -func (*UnimplementedQueryServer) LongBook(ctx context.Context, req *QueryGetLongBookRequest) (*QueryGetLongBookResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method LongBook not implemented") -} -func (*UnimplementedQueryServer) LongBookAll(ctx context.Context, req *QueryAllLongBookRequest) (*QueryAllLongBookResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method LongBookAll not implemented") -} -func (*UnimplementedQueryServer) ShortBook(ctx context.Context, req *QueryGetShortBookRequest) (*QueryGetShortBookResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method ShortBook not implemented") -} -func (*UnimplementedQueryServer) ShortBookAll(ctx context.Context, req *QueryAllShortBookRequest) (*QueryAllShortBookResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method ShortBookAll not implemented") -} -func (*UnimplementedQueryServer) GetPrice(ctx context.Context, req *QueryGetPriceRequest) (*QueryGetPriceResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetPrice not implemented") -} -func (*UnimplementedQueryServer) GetLatestPrice(ctx context.Context, req *QueryGetLatestPriceRequest) (*QueryGetLatestPriceResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetLatestPrice not implemented") -} -func (*UnimplementedQueryServer) GetPrices(ctx context.Context, req *QueryGetPricesRequest) (*QueryGetPricesResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetPrices not implemented") -} -func (*UnimplementedQueryServer) GetTwaps(ctx context.Context, req *QueryGetTwapsRequest) (*QueryGetTwapsResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetTwaps not implemented") -} -func (*UnimplementedQueryServer) AssetMetadata(ctx context.Context, req *QueryAssetMetadataRequest) (*QueryAssetMetadataResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method AssetMetadata not implemented") -} -func (*UnimplementedQueryServer) AssetList(ctx context.Context, req *QueryAssetListRequest) (*QueryAssetListResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method AssetList not implemented") -} -func (*UnimplementedQueryServer) GetRegisteredPairs(ctx context.Context, req *QueryRegisteredPairsRequest) (*QueryRegisteredPairsResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetRegisteredPairs not implemented") -} -func (*UnimplementedQueryServer) GetRegisteredContract(ctx context.Context, req *QueryRegisteredContractRequest) (*QueryRegisteredContractResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetRegisteredContract not implemented") -} -func (*UnimplementedQueryServer) GetOrders(ctx context.Context, req *QueryGetOrdersRequest) (*QueryGetOrdersResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetOrders not implemented") -} -func (*UnimplementedQueryServer) GetOrder(ctx context.Context, req *QueryGetOrderByIDRequest) (*QueryGetOrderByIDResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetOrder not implemented") -} -func (*UnimplementedQueryServer) GetHistoricalPrices(ctx context.Context, req *QueryGetHistoricalPricesRequest) (*QueryGetHistoricalPricesResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetHistoricalPrices not implemented") -} -func (*UnimplementedQueryServer) GetMarketSummary(ctx context.Context, req *QueryGetMarketSummaryRequest) (*QueryGetMarketSummaryResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetMarketSummary not implemented") -} -func (*UnimplementedQueryServer) GetOrderSimulation(ctx context.Context, req *QueryOrderSimulationRequest) (*QueryOrderSimulationResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetOrderSimulation not implemented") -} -func (*UnimplementedQueryServer) GetMatchResult(ctx context.Context, req *QueryGetMatchResultRequest) (*QueryGetMatchResultResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetMatchResult not implemented") -} -func (*UnimplementedQueryServer) GetOrderCount(ctx context.Context, req *QueryGetOrderCountRequest) (*QueryGetOrderCountResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetOrderCount not implemented") -} - -func RegisterQueryServer(s grpc1.Server, srv QueryServer) { - s.RegisterService(&_Query_serviceDesc, srv) -} - -func _Query_Params_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryParamsRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(QueryServer).Params(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/seiprotocol.seichain.dex.Query/Params", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(QueryServer).Params(ctx, req.(*QueryParamsRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Query_LongBook_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryGetLongBookRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(QueryServer).LongBook(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/seiprotocol.seichain.dex.Query/LongBook", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(QueryServer).LongBook(ctx, req.(*QueryGetLongBookRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Query_LongBookAll_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryAllLongBookRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(QueryServer).LongBookAll(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/seiprotocol.seichain.dex.Query/LongBookAll", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(QueryServer).LongBookAll(ctx, req.(*QueryAllLongBookRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Query_ShortBook_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryGetShortBookRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(QueryServer).ShortBook(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/seiprotocol.seichain.dex.Query/ShortBook", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(QueryServer).ShortBook(ctx, req.(*QueryGetShortBookRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Query_ShortBookAll_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryAllShortBookRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(QueryServer).ShortBookAll(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/seiprotocol.seichain.dex.Query/ShortBookAll", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(QueryServer).ShortBookAll(ctx, req.(*QueryAllShortBookRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Query_GetPrice_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryGetPriceRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(QueryServer).GetPrice(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/seiprotocol.seichain.dex.Query/GetPrice", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(QueryServer).GetPrice(ctx, req.(*QueryGetPriceRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Query_GetLatestPrice_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryGetLatestPriceRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(QueryServer).GetLatestPrice(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/seiprotocol.seichain.dex.Query/GetLatestPrice", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(QueryServer).GetLatestPrice(ctx, req.(*QueryGetLatestPriceRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Query_GetPrices_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryGetPricesRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(QueryServer).GetPrices(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/seiprotocol.seichain.dex.Query/GetPrices", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(QueryServer).GetPrices(ctx, req.(*QueryGetPricesRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Query_GetTwaps_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryGetTwapsRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(QueryServer).GetTwaps(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/seiprotocol.seichain.dex.Query/GetTwaps", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(QueryServer).GetTwaps(ctx, req.(*QueryGetTwapsRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Query_AssetMetadata_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryAssetMetadataRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(QueryServer).AssetMetadata(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/seiprotocol.seichain.dex.Query/AssetMetadata", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(QueryServer).AssetMetadata(ctx, req.(*QueryAssetMetadataRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Query_AssetList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryAssetListRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(QueryServer).AssetList(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/seiprotocol.seichain.dex.Query/AssetList", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(QueryServer).AssetList(ctx, req.(*QueryAssetListRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Query_GetRegisteredPairs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryRegisteredPairsRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(QueryServer).GetRegisteredPairs(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/seiprotocol.seichain.dex.Query/GetRegisteredPairs", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(QueryServer).GetRegisteredPairs(ctx, req.(*QueryRegisteredPairsRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Query_GetRegisteredContract_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryRegisteredContractRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(QueryServer).GetRegisteredContract(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/seiprotocol.seichain.dex.Query/GetRegisteredContract", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(QueryServer).GetRegisteredContract(ctx, req.(*QueryRegisteredContractRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Query_GetOrders_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryGetOrdersRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(QueryServer).GetOrders(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/seiprotocol.seichain.dex.Query/GetOrders", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(QueryServer).GetOrders(ctx, req.(*QueryGetOrdersRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Query_GetOrder_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryGetOrderByIDRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(QueryServer).GetOrder(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/seiprotocol.seichain.dex.Query/GetOrder", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(QueryServer).GetOrder(ctx, req.(*QueryGetOrderByIDRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Query_GetHistoricalPrices_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryGetHistoricalPricesRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(QueryServer).GetHistoricalPrices(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/seiprotocol.seichain.dex.Query/GetHistoricalPrices", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(QueryServer).GetHistoricalPrices(ctx, req.(*QueryGetHistoricalPricesRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Query_GetMarketSummary_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryGetMarketSummaryRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(QueryServer).GetMarketSummary(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/seiprotocol.seichain.dex.Query/GetMarketSummary", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(QueryServer).GetMarketSummary(ctx, req.(*QueryGetMarketSummaryRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Query_GetOrderSimulation_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryOrderSimulationRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(QueryServer).GetOrderSimulation(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/seiprotocol.seichain.dex.Query/GetOrderSimulation", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(QueryServer).GetOrderSimulation(ctx, req.(*QueryOrderSimulationRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Query_GetMatchResult_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryGetMatchResultRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(QueryServer).GetMatchResult(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/seiprotocol.seichain.dex.Query/GetMatchResult", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(QueryServer).GetMatchResult(ctx, req.(*QueryGetMatchResultRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Query_GetOrderCount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryGetOrderCountRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(QueryServer).GetOrderCount(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/seiprotocol.seichain.dex.Query/GetOrderCount", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(QueryServer).GetOrderCount(ctx, req.(*QueryGetOrderCountRequest)) - } - return interceptor(ctx, in, info, handler) -} - -var _Query_serviceDesc = grpc.ServiceDesc{ - ServiceName: "seiprotocol.seichain.dex.Query", - HandlerType: (*QueryServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "Params", - Handler: _Query_Params_Handler, - }, - { - MethodName: "LongBook", - Handler: _Query_LongBook_Handler, - }, - { - MethodName: "LongBookAll", - Handler: _Query_LongBookAll_Handler, - }, - { - MethodName: "ShortBook", - Handler: _Query_ShortBook_Handler, - }, - { - MethodName: "ShortBookAll", - Handler: _Query_ShortBookAll_Handler, - }, - { - MethodName: "GetPrice", - Handler: _Query_GetPrice_Handler, - }, - { - MethodName: "GetLatestPrice", - Handler: _Query_GetLatestPrice_Handler, - }, - { - MethodName: "GetPrices", - Handler: _Query_GetPrices_Handler, - }, - { - MethodName: "GetTwaps", - Handler: _Query_GetTwaps_Handler, - }, - { - MethodName: "AssetMetadata", - Handler: _Query_AssetMetadata_Handler, - }, - { - MethodName: "AssetList", - Handler: _Query_AssetList_Handler, - }, - { - MethodName: "GetRegisteredPairs", - Handler: _Query_GetRegisteredPairs_Handler, - }, - { - MethodName: "GetRegisteredContract", - Handler: _Query_GetRegisteredContract_Handler, - }, - { - MethodName: "GetOrders", - Handler: _Query_GetOrders_Handler, - }, - { - MethodName: "GetOrder", - Handler: _Query_GetOrder_Handler, - }, - { - MethodName: "GetHistoricalPrices", - Handler: _Query_GetHistoricalPrices_Handler, - }, - { - MethodName: "GetMarketSummary", - Handler: _Query_GetMarketSummary_Handler, - }, - { - MethodName: "GetOrderSimulation", - Handler: _Query_GetOrderSimulation_Handler, - }, - { - MethodName: "GetMatchResult", - Handler: _Query_GetMatchResult_Handler, - }, - { - MethodName: "GetOrderCount", - Handler: _Query_GetOrderCount_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "dex/query.proto", -} - -func (m *QueryParamsRequest) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryParamsRequest) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryParamsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - return len(dAtA) - i, nil -} - -func (m *QueryParamsResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryParamsResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - { - size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil -} - -func (m *QueryGetLongBookRequest) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryGetLongBookRequest) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryGetLongBookRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.AssetDenom) > 0 { - i -= len(m.AssetDenom) - copy(dAtA[i:], m.AssetDenom) - i = encodeVarintQuery(dAtA, i, uint64(len(m.AssetDenom))) - i-- - dAtA[i] = 0x22 - } - if len(m.PriceDenom) > 0 { - i -= len(m.PriceDenom) - copy(dAtA[i:], m.PriceDenom) - i = encodeVarintQuery(dAtA, i, uint64(len(m.PriceDenom))) - i-- - dAtA[i] = 0x1a - } - if len(m.ContractAddr) > 0 { - i -= len(m.ContractAddr) - copy(dAtA[i:], m.ContractAddr) - i = encodeVarintQuery(dAtA, i, uint64(len(m.ContractAddr))) - i-- - dAtA[i] = 0x12 - } - if len(m.Price) > 0 { - i -= len(m.Price) - copy(dAtA[i:], m.Price) - i = encodeVarintQuery(dAtA, i, uint64(len(m.Price))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *QueryGetLongBookResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryGetLongBookResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryGetLongBookResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - { - size, err := m.LongBook.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil -} - -func (m *QueryAllLongBookRequest) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryAllLongBookRequest) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryAllLongBookRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.AssetDenom) > 0 { - i -= len(m.AssetDenom) - copy(dAtA[i:], m.AssetDenom) - i = encodeVarintQuery(dAtA, i, uint64(len(m.AssetDenom))) - i-- - dAtA[i] = 0x22 - } - if len(m.PriceDenom) > 0 { - i -= len(m.PriceDenom) - copy(dAtA[i:], m.PriceDenom) - i = encodeVarintQuery(dAtA, i, uint64(len(m.PriceDenom))) - i-- - dAtA[i] = 0x1a - } - if len(m.ContractAddr) > 0 { - i -= len(m.ContractAddr) - copy(dAtA[i:], m.ContractAddr) - i = encodeVarintQuery(dAtA, i, uint64(len(m.ContractAddr))) - i-- - dAtA[i] = 0x12 - } - if m.Pagination != nil { - { - size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *QueryAllLongBookResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryAllLongBookResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryAllLongBookResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Pagination != nil { - { - size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - } - if len(m.LongBook) > 0 { - for iNdEx := len(m.LongBook) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.LongBook[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - } - return len(dAtA) - i, nil -} - -func (m *QueryGetShortBookRequest) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryGetShortBookRequest) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryGetShortBookRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.AssetDenom) > 0 { - i -= len(m.AssetDenom) - copy(dAtA[i:], m.AssetDenom) - i = encodeVarintQuery(dAtA, i, uint64(len(m.AssetDenom))) - i-- - dAtA[i] = 0x22 - } - if len(m.PriceDenom) > 0 { - i -= len(m.PriceDenom) - copy(dAtA[i:], m.PriceDenom) - i = encodeVarintQuery(dAtA, i, uint64(len(m.PriceDenom))) - i-- - dAtA[i] = 0x1a - } - if len(m.ContractAddr) > 0 { - i -= len(m.ContractAddr) - copy(dAtA[i:], m.ContractAddr) - i = encodeVarintQuery(dAtA, i, uint64(len(m.ContractAddr))) - i-- - dAtA[i] = 0x12 - } - if len(m.Price) > 0 { - i -= len(m.Price) - copy(dAtA[i:], m.Price) - i = encodeVarintQuery(dAtA, i, uint64(len(m.Price))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *QueryGetShortBookResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryGetShortBookResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryGetShortBookResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - { - size, err := m.ShortBook.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil -} - -func (m *QueryAllShortBookRequest) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryAllShortBookRequest) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryAllShortBookRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.AssetDenom) > 0 { - i -= len(m.AssetDenom) - copy(dAtA[i:], m.AssetDenom) - i = encodeVarintQuery(dAtA, i, uint64(len(m.AssetDenom))) - i-- - dAtA[i] = 0x22 - } - if len(m.PriceDenom) > 0 { - i -= len(m.PriceDenom) - copy(dAtA[i:], m.PriceDenom) - i = encodeVarintQuery(dAtA, i, uint64(len(m.PriceDenom))) - i-- - dAtA[i] = 0x1a - } - if len(m.ContractAddr) > 0 { - i -= len(m.ContractAddr) - copy(dAtA[i:], m.ContractAddr) - i = encodeVarintQuery(dAtA, i, uint64(len(m.ContractAddr))) - i-- - dAtA[i] = 0x12 - } - if m.Pagination != nil { - { - size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *QueryAllShortBookResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryAllShortBookResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryAllShortBookResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Pagination != nil { - { - size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - } - if len(m.ShortBook) > 0 { - for iNdEx := len(m.ShortBook) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.ShortBook[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - } - return len(dAtA) - i, nil -} - -func (m *QueryGetPricesRequest) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryGetPricesRequest) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryGetPricesRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.ContractAddr) > 0 { - i -= len(m.ContractAddr) - copy(dAtA[i:], m.ContractAddr) - i = encodeVarintQuery(dAtA, i, uint64(len(m.ContractAddr))) - i-- - dAtA[i] = 0x1a - } - if len(m.AssetDenom) > 0 { - i -= len(m.AssetDenom) - copy(dAtA[i:], m.AssetDenom) - i = encodeVarintQuery(dAtA, i, uint64(len(m.AssetDenom))) - i-- - dAtA[i] = 0x12 - } - if len(m.PriceDenom) > 0 { - i -= len(m.PriceDenom) - copy(dAtA[i:], m.PriceDenom) - i = encodeVarintQuery(dAtA, i, uint64(len(m.PriceDenom))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *QueryGetPricesResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryGetPricesResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryGetPricesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Prices) > 0 { - for iNdEx := len(m.Prices) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Prices[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - } - return len(dAtA) - i, nil -} - -func (m *QueryGetPriceRequest) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryGetPriceRequest) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryGetPriceRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Timestamp != 0 { - i = encodeVarintQuery(dAtA, i, uint64(m.Timestamp)) - i-- - dAtA[i] = 0x20 - } - if len(m.ContractAddr) > 0 { - i -= len(m.ContractAddr) - copy(dAtA[i:], m.ContractAddr) - i = encodeVarintQuery(dAtA, i, uint64(len(m.ContractAddr))) - i-- - dAtA[i] = 0x1a - } - if len(m.AssetDenom) > 0 { - i -= len(m.AssetDenom) - copy(dAtA[i:], m.AssetDenom) - i = encodeVarintQuery(dAtA, i, uint64(len(m.AssetDenom))) - i-- - dAtA[i] = 0x12 - } - if len(m.PriceDenom) > 0 { - i -= len(m.PriceDenom) - copy(dAtA[i:], m.PriceDenom) - i = encodeVarintQuery(dAtA, i, uint64(len(m.PriceDenom))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *QueryGetPriceResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryGetPriceResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryGetPriceResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Found { - i-- - if m.Found { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i-- - dAtA[i] = 0x10 - } - if m.Price != nil { - { - size, err := m.Price.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *QueryGetLatestPriceRequest) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryGetLatestPriceRequest) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryGetLatestPriceRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.ContractAddr) > 0 { - i -= len(m.ContractAddr) - copy(dAtA[i:], m.ContractAddr) - i = encodeVarintQuery(dAtA, i, uint64(len(m.ContractAddr))) - i-- - dAtA[i] = 0x1a - } - if len(m.AssetDenom) > 0 { - i -= len(m.AssetDenom) - copy(dAtA[i:], m.AssetDenom) - i = encodeVarintQuery(dAtA, i, uint64(len(m.AssetDenom))) - i-- - dAtA[i] = 0x12 - } - if len(m.PriceDenom) > 0 { - i -= len(m.PriceDenom) - copy(dAtA[i:], m.PriceDenom) - i = encodeVarintQuery(dAtA, i, uint64(len(m.PriceDenom))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *QueryGetLatestPriceResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryGetLatestPriceResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryGetLatestPriceResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Price != nil { - { - size, err := m.Price.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *QueryGetTwapsRequest) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryGetTwapsRequest) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryGetTwapsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.LookbackSeconds != 0 { - i = encodeVarintQuery(dAtA, i, uint64(m.LookbackSeconds)) - i-- - dAtA[i] = 0x10 - } - if len(m.ContractAddr) > 0 { - i -= len(m.ContractAddr) - copy(dAtA[i:], m.ContractAddr) - i = encodeVarintQuery(dAtA, i, uint64(len(m.ContractAddr))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *QueryGetTwapsResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryGetTwapsResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryGetTwapsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Twaps) > 0 { - for iNdEx := len(m.Twaps) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Twaps[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - } - return len(dAtA) - i, nil -} - -func (m *QueryAssetListRequest) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryAssetListRequest) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryAssetListRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - return len(dAtA) - i, nil -} - -func (m *QueryAssetListResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryAssetListResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryAssetListResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.AssetList) > 0 { - for iNdEx := len(m.AssetList) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.AssetList[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - } - return len(dAtA) - i, nil -} - -func (m *QueryAssetMetadataRequest) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryAssetMetadataRequest) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryAssetMetadataRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Denom) > 0 { - i -= len(m.Denom) - copy(dAtA[i:], m.Denom) - i = encodeVarintQuery(dAtA, i, uint64(len(m.Denom))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *QueryAssetMetadataResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryAssetMetadataResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryAssetMetadataResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Metadata != nil { - { - size, err := m.Metadata.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *QueryRegisteredPairsRequest) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryRegisteredPairsRequest) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryRegisteredPairsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.ContractAddr) > 0 { - i -= len(m.ContractAddr) - copy(dAtA[i:], m.ContractAddr) - i = encodeVarintQuery(dAtA, i, uint64(len(m.ContractAddr))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *QueryRegisteredPairsResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryRegisteredPairsResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryRegisteredPairsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Pairs) > 0 { - for iNdEx := len(m.Pairs) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Pairs[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - } - return len(dAtA) - i, nil -} - -func (m *QueryRegisteredContractRequest) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryRegisteredContractRequest) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryRegisteredContractRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.ContractAddr) > 0 { - i -= len(m.ContractAddr) - copy(dAtA[i:], m.ContractAddr) - i = encodeVarintQuery(dAtA, i, uint64(len(m.ContractAddr))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *QueryRegisteredContractResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryRegisteredContractResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryRegisteredContractResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.ContractInfo != nil { - { - size, err := m.ContractInfo.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *QueryGetOrdersRequest) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryGetOrdersRequest) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryGetOrdersRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Account) > 0 { - i -= len(m.Account) - copy(dAtA[i:], m.Account) - i = encodeVarintQuery(dAtA, i, uint64(len(m.Account))) - i-- - dAtA[i] = 0x12 - } - if len(m.ContractAddr) > 0 { - i -= len(m.ContractAddr) - copy(dAtA[i:], m.ContractAddr) - i = encodeVarintQuery(dAtA, i, uint64(len(m.ContractAddr))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *QueryGetOrdersResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryGetOrdersResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryGetOrdersResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Orders) > 0 { - for iNdEx := len(m.Orders) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Orders[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - } - return len(dAtA) - i, nil -} - -func (m *QueryGetOrderByIDRequest) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryGetOrderByIDRequest) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryGetOrderByIDRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Id != 0 { - i = encodeVarintQuery(dAtA, i, uint64(m.Id)) - i-- - dAtA[i] = 0x20 - } - if len(m.AssetDenom) > 0 { - i -= len(m.AssetDenom) - copy(dAtA[i:], m.AssetDenom) - i = encodeVarintQuery(dAtA, i, uint64(len(m.AssetDenom))) - i-- - dAtA[i] = 0x1a - } - if len(m.PriceDenom) > 0 { - i -= len(m.PriceDenom) - copy(dAtA[i:], m.PriceDenom) - i = encodeVarintQuery(dAtA, i, uint64(len(m.PriceDenom))) - i-- - dAtA[i] = 0x12 - } - if len(m.ContractAddr) > 0 { - i -= len(m.ContractAddr) - copy(dAtA[i:], m.ContractAddr) - i = encodeVarintQuery(dAtA, i, uint64(len(m.ContractAddr))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *QueryGetOrderByIDResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryGetOrderByIDResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryGetOrderByIDResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Order != nil { - { - size, err := m.Order.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *QueryGetHistoricalPricesRequest) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryGetHistoricalPricesRequest) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryGetHistoricalPricesRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.NumOfPeriods != 0 { - i = encodeVarintQuery(dAtA, i, uint64(m.NumOfPeriods)) - i-- - dAtA[i] = 0x28 - } - if m.PeriodLengthInSeconds != 0 { - i = encodeVarintQuery(dAtA, i, uint64(m.PeriodLengthInSeconds)) - i-- - dAtA[i] = 0x20 - } - if len(m.AssetDenom) > 0 { - i -= len(m.AssetDenom) - copy(dAtA[i:], m.AssetDenom) - i = encodeVarintQuery(dAtA, i, uint64(len(m.AssetDenom))) - i-- - dAtA[i] = 0x1a - } - if len(m.PriceDenom) > 0 { - i -= len(m.PriceDenom) - copy(dAtA[i:], m.PriceDenom) - i = encodeVarintQuery(dAtA, i, uint64(len(m.PriceDenom))) - i-- - dAtA[i] = 0x12 - } - if len(m.ContractAddr) > 0 { - i -= len(m.ContractAddr) - copy(dAtA[i:], m.ContractAddr) - i = encodeVarintQuery(dAtA, i, uint64(len(m.ContractAddr))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *QueryGetHistoricalPricesResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryGetHistoricalPricesResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryGetHistoricalPricesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Prices) > 0 { - for iNdEx := len(m.Prices) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Prices[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - } - return len(dAtA) - i, nil -} - -func (m *QueryGetMarketSummaryRequest) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryGetMarketSummaryRequest) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryGetMarketSummaryRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.LookbackInSeconds != 0 { - i = encodeVarintQuery(dAtA, i, uint64(m.LookbackInSeconds)) - i-- - dAtA[i] = 0x20 - } - if len(m.AssetDenom) > 0 { - i -= len(m.AssetDenom) - copy(dAtA[i:], m.AssetDenom) - i = encodeVarintQuery(dAtA, i, uint64(len(m.AssetDenom))) - i-- - dAtA[i] = 0x1a - } - if len(m.PriceDenom) > 0 { - i -= len(m.PriceDenom) - copy(dAtA[i:], m.PriceDenom) - i = encodeVarintQuery(dAtA, i, uint64(len(m.PriceDenom))) - i-- - dAtA[i] = 0x12 - } - if len(m.ContractAddr) > 0 { - i -= len(m.ContractAddr) - copy(dAtA[i:], m.ContractAddr) - i = encodeVarintQuery(dAtA, i, uint64(len(m.ContractAddr))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *QueryGetMarketSummaryResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryGetMarketSummaryResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryGetMarketSummaryResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.LastPrice != nil { - { - size := m.LastPrice.Size() - i -= size - if _, err := m.LastPrice.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x2a - } - if m.LowPrice != nil { - { - size := m.LowPrice.Size() - i -= size - if _, err := m.LowPrice.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x22 - } - if m.HighPrice != nil { - { - size := m.HighPrice.Size() - i -= size - if _, err := m.HighPrice.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x1a - } - if m.TotalVolumeNotional != nil { - { - size := m.TotalVolumeNotional.Size() - i -= size - if _, err := m.TotalVolumeNotional.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - } - if m.TotalVolume != nil { - { - size := m.TotalVolume.Size() - i -= size - if _, err := m.TotalVolume.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *QueryOrderSimulationRequest) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryOrderSimulationRequest) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryOrderSimulationRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.ContractAddr) > 0 { - i -= len(m.ContractAddr) - copy(dAtA[i:], m.ContractAddr) - i = encodeVarintQuery(dAtA, i, uint64(len(m.ContractAddr))) - i-- - dAtA[i] = 0x12 - } - if m.Order != nil { - { - size, err := m.Order.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *QueryOrderSimulationResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryOrderSimulationResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryOrderSimulationResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.ExecutedQuantity != nil { - { - size := m.ExecutedQuantity.Size() - i -= size - if _, err := m.ExecutedQuantity.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *QueryGetMatchResultRequest) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryGetMatchResultRequest) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryGetMatchResultRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.ContractAddr) > 0 { - i -= len(m.ContractAddr) - copy(dAtA[i:], m.ContractAddr) - i = encodeVarintQuery(dAtA, i, uint64(len(m.ContractAddr))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *QueryGetMatchResultResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryGetMatchResultResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryGetMatchResultResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Result != nil { - { - size, err := m.Result.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *QueryGetOrderCountRequest) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryGetOrderCountRequest) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryGetOrderCountRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.PositionDirection != 0 { - i = encodeVarintQuery(dAtA, i, uint64(m.PositionDirection)) - i-- - dAtA[i] = 0x28 - } - if m.Price != nil { - { - size := m.Price.Size() - i -= size - if _, err := m.Price.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x22 - } - if len(m.AssetDenom) > 0 { - i -= len(m.AssetDenom) - copy(dAtA[i:], m.AssetDenom) - i = encodeVarintQuery(dAtA, i, uint64(len(m.AssetDenom))) - i-- - dAtA[i] = 0x1a - } - if len(m.PriceDenom) > 0 { - i -= len(m.PriceDenom) - copy(dAtA[i:], m.PriceDenom) - i = encodeVarintQuery(dAtA, i, uint64(len(m.PriceDenom))) - i-- - dAtA[i] = 0x12 - } - if len(m.ContractAddr) > 0 { - i -= len(m.ContractAddr) - copy(dAtA[i:], m.ContractAddr) - i = encodeVarintQuery(dAtA, i, uint64(len(m.ContractAddr))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *QueryGetOrderCountResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryGetOrderCountResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryGetOrderCountResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Count != 0 { - i = encodeVarintQuery(dAtA, i, uint64(m.Count)) - i-- - dAtA[i] = 0x8 - } - return len(dAtA) - i, nil -} - -func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { - offset -= sovQuery(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *QueryParamsRequest) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - return n -} - -func (m *QueryParamsResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = m.Params.Size() - n += 1 + l + sovQuery(uint64(l)) - return n -} - -func (m *QueryGetLongBookRequest) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Price) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - l = len(m.ContractAddr) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - l = len(m.PriceDenom) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - l = len(m.AssetDenom) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - return n -} - -func (m *QueryGetLongBookResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = m.LongBook.Size() - n += 1 + l + sovQuery(uint64(l)) - return n -} - -func (m *QueryAllLongBookRequest) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Pagination != nil { - l = m.Pagination.Size() - n += 1 + l + sovQuery(uint64(l)) - } - l = len(m.ContractAddr) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - l = len(m.PriceDenom) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - l = len(m.AssetDenom) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - return n -} - -func (m *QueryAllLongBookResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if len(m.LongBook) > 0 { - for _, e := range m.LongBook { - l = e.Size() - n += 1 + l + sovQuery(uint64(l)) - } - } - if m.Pagination != nil { - l = m.Pagination.Size() - n += 1 + l + sovQuery(uint64(l)) - } - return n -} - -func (m *QueryGetShortBookRequest) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Price) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - l = len(m.ContractAddr) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - l = len(m.PriceDenom) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - l = len(m.AssetDenom) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - return n -} - -func (m *QueryGetShortBookResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = m.ShortBook.Size() - n += 1 + l + sovQuery(uint64(l)) - return n -} - -func (m *QueryAllShortBookRequest) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Pagination != nil { - l = m.Pagination.Size() - n += 1 + l + sovQuery(uint64(l)) - } - l = len(m.ContractAddr) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - l = len(m.PriceDenom) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - l = len(m.AssetDenom) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - return n -} - -func (m *QueryAllShortBookResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if len(m.ShortBook) > 0 { - for _, e := range m.ShortBook { - l = e.Size() - n += 1 + l + sovQuery(uint64(l)) - } - } - if m.Pagination != nil { - l = m.Pagination.Size() - n += 1 + l + sovQuery(uint64(l)) - } - return n -} - -func (m *QueryGetPricesRequest) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.PriceDenom) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - l = len(m.AssetDenom) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - l = len(m.ContractAddr) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - return n -} - -func (m *QueryGetPricesResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if len(m.Prices) > 0 { - for _, e := range m.Prices { - l = e.Size() - n += 1 + l + sovQuery(uint64(l)) - } - } - return n -} - -func (m *QueryGetPriceRequest) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.PriceDenom) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - l = len(m.AssetDenom) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - l = len(m.ContractAddr) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - if m.Timestamp != 0 { - n += 1 + sovQuery(uint64(m.Timestamp)) - } - return n -} - -func (m *QueryGetPriceResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Price != nil { - l = m.Price.Size() - n += 1 + l + sovQuery(uint64(l)) - } - if m.Found { - n += 2 - } - return n -} - -func (m *QueryGetLatestPriceRequest) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.PriceDenom) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - l = len(m.AssetDenom) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - l = len(m.ContractAddr) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - return n -} - -func (m *QueryGetLatestPriceResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Price != nil { - l = m.Price.Size() - n += 1 + l + sovQuery(uint64(l)) - } - return n -} - -func (m *QueryGetTwapsRequest) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.ContractAddr) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - if m.LookbackSeconds != 0 { - n += 1 + sovQuery(uint64(m.LookbackSeconds)) - } - return n -} - -func (m *QueryGetTwapsResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if len(m.Twaps) > 0 { - for _, e := range m.Twaps { - l = e.Size() - n += 1 + l + sovQuery(uint64(l)) - } - } - return n -} - -func (m *QueryAssetListRequest) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - return n -} - -func (m *QueryAssetListResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if len(m.AssetList) > 0 { - for _, e := range m.AssetList { - l = e.Size() - n += 1 + l + sovQuery(uint64(l)) - } - } - return n -} - -func (m *QueryAssetMetadataRequest) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Denom) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - return n -} - -func (m *QueryAssetMetadataResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Metadata != nil { - l = m.Metadata.Size() - n += 1 + l + sovQuery(uint64(l)) - } - return n -} - -func (m *QueryRegisteredPairsRequest) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.ContractAddr) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - return n -} - -func (m *QueryRegisteredPairsResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if len(m.Pairs) > 0 { - for _, e := range m.Pairs { - l = e.Size() - n += 1 + l + sovQuery(uint64(l)) - } - } - return n -} - -func (m *QueryRegisteredContractRequest) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.ContractAddr) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - return n -} - -func (m *QueryRegisteredContractResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.ContractInfo != nil { - l = m.ContractInfo.Size() - n += 1 + l + sovQuery(uint64(l)) - } - return n -} - -func (m *QueryGetOrdersRequest) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.ContractAddr) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - l = len(m.Account) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - return n -} - -func (m *QueryGetOrdersResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if len(m.Orders) > 0 { - for _, e := range m.Orders { - l = e.Size() - n += 1 + l + sovQuery(uint64(l)) - } - } - return n -} - -func (m *QueryGetOrderByIDRequest) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.ContractAddr) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - l = len(m.PriceDenom) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - l = len(m.AssetDenom) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - if m.Id != 0 { - n += 1 + sovQuery(uint64(m.Id)) - } - return n -} - -func (m *QueryGetOrderByIDResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Order != nil { - l = m.Order.Size() - n += 1 + l + sovQuery(uint64(l)) - } - return n -} - -func (m *QueryGetHistoricalPricesRequest) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.ContractAddr) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - l = len(m.PriceDenom) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - l = len(m.AssetDenom) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - if m.PeriodLengthInSeconds != 0 { - n += 1 + sovQuery(uint64(m.PeriodLengthInSeconds)) - } - if m.NumOfPeriods != 0 { - n += 1 + sovQuery(uint64(m.NumOfPeriods)) - } - return n -} - -func (m *QueryGetHistoricalPricesResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if len(m.Prices) > 0 { - for _, e := range m.Prices { - l = e.Size() - n += 1 + l + sovQuery(uint64(l)) - } - } - return n -} - -func (m *QueryGetMarketSummaryRequest) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.ContractAddr) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - l = len(m.PriceDenom) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - l = len(m.AssetDenom) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - if m.LookbackInSeconds != 0 { - n += 1 + sovQuery(uint64(m.LookbackInSeconds)) - } - return n -} - -func (m *QueryGetMarketSummaryResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.TotalVolume != nil { - l = m.TotalVolume.Size() - n += 1 + l + sovQuery(uint64(l)) - } - if m.TotalVolumeNotional != nil { - l = m.TotalVolumeNotional.Size() - n += 1 + l + sovQuery(uint64(l)) - } - if m.HighPrice != nil { - l = m.HighPrice.Size() - n += 1 + l + sovQuery(uint64(l)) - } - if m.LowPrice != nil { - l = m.LowPrice.Size() - n += 1 + l + sovQuery(uint64(l)) - } - if m.LastPrice != nil { - l = m.LastPrice.Size() - n += 1 + l + sovQuery(uint64(l)) - } - return n -} - -func (m *QueryOrderSimulationRequest) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Order != nil { - l = m.Order.Size() - n += 1 + l + sovQuery(uint64(l)) - } - l = len(m.ContractAddr) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - return n -} - -func (m *QueryOrderSimulationResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.ExecutedQuantity != nil { - l = m.ExecutedQuantity.Size() - n += 1 + l + sovQuery(uint64(l)) - } - return n -} - -func (m *QueryGetMatchResultRequest) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.ContractAddr) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - return n -} - -func (m *QueryGetMatchResultResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Result != nil { - l = m.Result.Size() - n += 1 + l + sovQuery(uint64(l)) - } - return n -} - -func (m *QueryGetOrderCountRequest) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.ContractAddr) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - l = len(m.PriceDenom) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - l = len(m.AssetDenom) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - if m.Price != nil { - l = m.Price.Size() - n += 1 + l + sovQuery(uint64(l)) - } - if m.PositionDirection != 0 { - n += 1 + sovQuery(uint64(m.PositionDirection)) - } - return n -} - -func (m *QueryGetOrderCountResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Count != 0 { - n += 1 + sovQuery(uint64(m.Count)) - } - return n -} - -func sovQuery(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozQuery(x uint64) (n int) { - return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *QueryParamsRequest) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryParamsRequest: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryParamsRequest: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryParamsResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryParamsResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryParamsResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryGetLongBookRequest) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryGetLongBookRequest: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryGetLongBookRequest: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Price", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Price = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractAddr", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ContractAddr = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PriceDenom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.PriceDenom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field AssetDenom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.AssetDenom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryGetLongBookResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryGetLongBookResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryGetLongBookResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field LongBook", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.LongBook.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryAllLongBookRequest) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryAllLongBookRequest: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryAllLongBookRequest: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Pagination == nil { - m.Pagination = &query.PageRequest{} - } - if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractAddr", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ContractAddr = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PriceDenom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.PriceDenom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field AssetDenom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.AssetDenom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryAllLongBookResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryAllLongBookResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryAllLongBookResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field LongBook", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.LongBook = append(m.LongBook, LongBook{}) - if err := m.LongBook[len(m.LongBook)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Pagination == nil { - m.Pagination = &query.PageResponse{} - } - if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryGetShortBookRequest) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryGetShortBookRequest: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryGetShortBookRequest: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Price", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Price = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractAddr", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ContractAddr = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PriceDenom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.PriceDenom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field AssetDenom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.AssetDenom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryGetShortBookResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryGetShortBookResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryGetShortBookResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ShortBook", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.ShortBook.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryAllShortBookRequest) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryAllShortBookRequest: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryAllShortBookRequest: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Pagination == nil { - m.Pagination = &query.PageRequest{} - } - if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractAddr", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ContractAddr = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PriceDenom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.PriceDenom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field AssetDenom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.AssetDenom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryAllShortBookResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryAllShortBookResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryAllShortBookResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ShortBook", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ShortBook = append(m.ShortBook, ShortBook{}) - if err := m.ShortBook[len(m.ShortBook)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Pagination == nil { - m.Pagination = &query.PageResponse{} - } - if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryGetPricesRequest) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryGetPricesRequest: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryGetPricesRequest: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PriceDenom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.PriceDenom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field AssetDenom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.AssetDenom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractAddr", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ContractAddr = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryGetPricesResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryGetPricesResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryGetPricesResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Prices", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Prices = append(m.Prices, &Price{}) - if err := m.Prices[len(m.Prices)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryGetPriceRequest) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryGetPriceRequest: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryGetPriceRequest: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PriceDenom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.PriceDenom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field AssetDenom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.AssetDenom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractAddr", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ContractAddr = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Timestamp", wireType) - } - m.Timestamp = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Timestamp |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryGetPriceResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryGetPriceResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryGetPriceResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Price", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Price == nil { - m.Price = &Price{} - } - if err := m.Price.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Found", wireType) - } - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.Found = bool(v != 0) - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryGetLatestPriceRequest) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryGetLatestPriceRequest: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryGetLatestPriceRequest: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PriceDenom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.PriceDenom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field AssetDenom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.AssetDenom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractAddr", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ContractAddr = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryGetLatestPriceResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryGetLatestPriceResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryGetLatestPriceResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Price", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Price == nil { - m.Price = &Price{} - } - if err := m.Price.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryGetTwapsRequest) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryGetTwapsRequest: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryGetTwapsRequest: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractAddr", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ContractAddr = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field LookbackSeconds", wireType) - } - m.LookbackSeconds = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.LookbackSeconds |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryGetTwapsResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryGetTwapsResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryGetTwapsResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Twaps", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Twaps = append(m.Twaps, &Twap{}) - if err := m.Twaps[len(m.Twaps)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryAssetListRequest) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryAssetListRequest: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryAssetListRequest: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryAssetListResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryAssetListResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryAssetListResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field AssetList", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.AssetList = append(m.AssetList, AssetMetadata{}) - if err := m.AssetList[len(m.AssetList)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryAssetMetadataRequest) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryAssetMetadataRequest: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryAssetMetadataRequest: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Denom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryAssetMetadataResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryAssetMetadataResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryAssetMetadataResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Metadata", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Metadata == nil { - m.Metadata = &AssetMetadata{} - } - if err := m.Metadata.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryRegisteredPairsRequest) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryRegisteredPairsRequest: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryRegisteredPairsRequest: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractAddr", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ContractAddr = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryRegisteredPairsResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryRegisteredPairsResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryRegisteredPairsResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Pairs", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Pairs = append(m.Pairs, Pair{}) - if err := m.Pairs[len(m.Pairs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryRegisteredContractRequest) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryRegisteredContractRequest: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryRegisteredContractRequest: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractAddr", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ContractAddr = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryRegisteredContractResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryRegisteredContractResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryRegisteredContractResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractInfo", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.ContractInfo == nil { - m.ContractInfo = &ContractInfoV2{} - } - if err := m.ContractInfo.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryGetOrdersRequest) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryGetOrdersRequest: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryGetOrdersRequest: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractAddr", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ContractAddr = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Account", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Account = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryGetOrdersResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryGetOrdersResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryGetOrdersResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Orders", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Orders = append(m.Orders, &Order{}) - if err := m.Orders[len(m.Orders)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryGetOrderByIDRequest) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryGetOrderByIDRequest: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryGetOrderByIDRequest: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractAddr", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ContractAddr = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PriceDenom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.PriceDenom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field AssetDenom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.AssetDenom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) - } - m.Id = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Id |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryGetOrderByIDResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryGetOrderByIDResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryGetOrderByIDResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Order", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Order == nil { - m.Order = &Order{} - } - if err := m.Order.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryGetHistoricalPricesRequest) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryGetHistoricalPricesRequest: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryGetHistoricalPricesRequest: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractAddr", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ContractAddr = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PriceDenom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.PriceDenom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field AssetDenom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.AssetDenom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field PeriodLengthInSeconds", wireType) - } - m.PeriodLengthInSeconds = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.PeriodLengthInSeconds |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 5: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field NumOfPeriods", wireType) - } - m.NumOfPeriods = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.NumOfPeriods |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryGetHistoricalPricesResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryGetHistoricalPricesResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryGetHistoricalPricesResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Prices", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Prices = append(m.Prices, &PriceCandlestick{}) - if err := m.Prices[len(m.Prices)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryGetMarketSummaryRequest) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryGetMarketSummaryRequest: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryGetMarketSummaryRequest: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractAddr", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ContractAddr = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PriceDenom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.PriceDenom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field AssetDenom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.AssetDenom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field LookbackInSeconds", wireType) - } - m.LookbackInSeconds = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.LookbackInSeconds |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryGetMarketSummaryResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryGetMarketSummaryResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryGetMarketSummaryResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field TotalVolume", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - var v github_com_cosmos_cosmos_sdk_types.Dec - m.TotalVolume = &v - if err := m.TotalVolume.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field TotalVolumeNotional", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - var v github_com_cosmos_cosmos_sdk_types.Dec - m.TotalVolumeNotional = &v - if err := m.TotalVolumeNotional.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field HighPrice", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - var v github_com_cosmos_cosmos_sdk_types.Dec - m.HighPrice = &v - if err := m.HighPrice.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field LowPrice", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - var v github_com_cosmos_cosmos_sdk_types.Dec - m.LowPrice = &v - if err := m.LowPrice.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 5: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field LastPrice", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - var v github_com_cosmos_cosmos_sdk_types.Dec - m.LastPrice = &v - if err := m.LastPrice.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryOrderSimulationRequest) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryOrderSimulationRequest: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryOrderSimulationRequest: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Order", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Order == nil { - m.Order = &Order{} - } - if err := m.Order.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractAddr", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ContractAddr = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryOrderSimulationResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryOrderSimulationResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryOrderSimulationResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ExecutedQuantity", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - var v github_com_cosmos_cosmos_sdk_types.Dec - m.ExecutedQuantity = &v - if err := m.ExecutedQuantity.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryGetMatchResultRequest) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryGetMatchResultRequest: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryGetMatchResultRequest: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractAddr", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ContractAddr = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryGetMatchResultResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryGetMatchResultResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryGetMatchResultResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Result", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Result == nil { - m.Result = &MatchResult{} - } - if err := m.Result.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryGetOrderCountRequest) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryGetOrderCountRequest: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryGetOrderCountRequest: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractAddr", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ContractAddr = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PriceDenom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.PriceDenom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field AssetDenom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.AssetDenom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Price", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - var v github_com_cosmos_cosmos_sdk_types.Dec - m.Price = &v - if err := m.Price.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 5: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field PositionDirection", wireType) - } - m.PositionDirection = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.PositionDirection |= PositionDirection(b&0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryGetOrderCountResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryGetOrderCountResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryGetOrderCountResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Count", wireType) - } - m.Count = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Count |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipQuery(dAtA []byte) (n int, err error) { - l := len(dAtA) - iNdEx := 0 - depth := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowQuery - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowQuery - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - iNdEx++ - if dAtA[iNdEx-1] < 0x80 { - break - } - } - case 1: - iNdEx += 8 - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowQuery - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if length < 0 { - return 0, ErrInvalidLengthQuery - } - iNdEx += length - case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupQuery - } - depth-- - case 5: - iNdEx += 4 - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - if iNdEx < 0 { - return 0, ErrInvalidLengthQuery - } - if depth == 0 { - return iNdEx, nil - } - } - return 0, io.ErrUnexpectedEOF -} - -var ( - ErrInvalidLengthQuery = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowQuery = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupQuery = fmt.Errorf("proto: unexpected end of group") -) diff --git a/x/dex/types/query.pb.gw.go b/x/dex/types/query.pb.gw.go deleted file mode 100644 index d7d13cf88..000000000 --- a/x/dex/types/query.pb.gw.go +++ /dev/null @@ -1,2389 +0,0 @@ -// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. -// source: dex/query.proto - -/* -Package types is a reverse proxy. - -It translates gRPC into RESTful JSON APIs. -*/ -package types - -import ( - "context" - "io" - "net/http" - - "github.com/golang/protobuf/descriptor" - "github.com/golang/protobuf/proto" - "github.com/grpc-ecosystem/grpc-gateway/runtime" - "github.com/grpc-ecosystem/grpc-gateway/utilities" - "google.golang.org/grpc" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/grpclog" - "google.golang.org/grpc/metadata" - "google.golang.org/grpc/status" -) - -// Suppress "imported and not used" errors -var _ codes.Code -var _ io.Reader -var _ status.Status -var _ = runtime.String -var _ = utilities.NewDoubleArray -var _ = descriptor.ForMessage -var _ = metadata.Join - -func request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryParamsRequest - var metadata runtime.ServerMetadata - - msg, err := client.Params(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryParamsRequest - var metadata runtime.ServerMetadata - - msg, err := server.Params(ctx, &protoReq) - return msg, metadata, err - -} - -func request_Query_LongBook_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryGetLongBookRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["contractAddr"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "contractAddr") - } - - protoReq.ContractAddr, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "contractAddr", err) - } - - val, ok = pathParams["priceDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "priceDenom") - } - - protoReq.PriceDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "priceDenom", err) - } - - val, ok = pathParams["assetDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "assetDenom") - } - - protoReq.AssetDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "assetDenom", err) - } - - val, ok = pathParams["price"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "price") - } - - protoReq.Price, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "price", err) - } - - msg, err := client.LongBook(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_Query_LongBook_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryGetLongBookRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["contractAddr"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "contractAddr") - } - - protoReq.ContractAddr, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "contractAddr", err) - } - - val, ok = pathParams["priceDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "priceDenom") - } - - protoReq.PriceDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "priceDenom", err) - } - - val, ok = pathParams["assetDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "assetDenom") - } - - protoReq.AssetDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "assetDenom", err) - } - - val, ok = pathParams["price"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "price") - } - - protoReq.Price, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "price", err) - } - - msg, err := server.LongBook(ctx, &protoReq) - return msg, metadata, err - -} - -var ( - filter_Query_LongBookAll_0 = &utilities.DoubleArray{Encoding: map[string]int{"contractAddr": 0, "priceDenom": 1, "assetDenom": 2}, Base: []int{1, 1, 2, 3, 0, 0, 0}, Check: []int{0, 1, 1, 1, 2, 3, 4}} -) - -func request_Query_LongBookAll_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryAllLongBookRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["contractAddr"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "contractAddr") - } - - protoReq.ContractAddr, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "contractAddr", err) - } - - val, ok = pathParams["priceDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "priceDenom") - } - - protoReq.PriceDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "priceDenom", err) - } - - val, ok = pathParams["assetDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "assetDenom") - } - - protoReq.AssetDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "assetDenom", err) - } - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_LongBookAll_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := client.LongBookAll(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_Query_LongBookAll_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryAllLongBookRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["contractAddr"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "contractAddr") - } - - protoReq.ContractAddr, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "contractAddr", err) - } - - val, ok = pathParams["priceDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "priceDenom") - } - - protoReq.PriceDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "priceDenom", err) - } - - val, ok = pathParams["assetDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "assetDenom") - } - - protoReq.AssetDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "assetDenom", err) - } - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_LongBookAll_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.LongBookAll(ctx, &protoReq) - return msg, metadata, err - -} - -func request_Query_ShortBook_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryGetShortBookRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["contractAddr"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "contractAddr") - } - - protoReq.ContractAddr, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "contractAddr", err) - } - - val, ok = pathParams["priceDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "priceDenom") - } - - protoReq.PriceDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "priceDenom", err) - } - - val, ok = pathParams["assetDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "assetDenom") - } - - protoReq.AssetDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "assetDenom", err) - } - - val, ok = pathParams["price"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "price") - } - - protoReq.Price, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "price", err) - } - - msg, err := client.ShortBook(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_Query_ShortBook_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryGetShortBookRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["contractAddr"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "contractAddr") - } - - protoReq.ContractAddr, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "contractAddr", err) - } - - val, ok = pathParams["priceDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "priceDenom") - } - - protoReq.PriceDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "priceDenom", err) - } - - val, ok = pathParams["assetDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "assetDenom") - } - - protoReq.AssetDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "assetDenom", err) - } - - val, ok = pathParams["price"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "price") - } - - protoReq.Price, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "price", err) - } - - msg, err := server.ShortBook(ctx, &protoReq) - return msg, metadata, err - -} - -var ( - filter_Query_ShortBookAll_0 = &utilities.DoubleArray{Encoding: map[string]int{"contractAddr": 0, "priceDenom": 1, "assetDenom": 2}, Base: []int{1, 1, 2, 3, 0, 0, 0}, Check: []int{0, 1, 1, 1, 2, 3, 4}} -) - -func request_Query_ShortBookAll_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryAllShortBookRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["contractAddr"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "contractAddr") - } - - protoReq.ContractAddr, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "contractAddr", err) - } - - val, ok = pathParams["priceDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "priceDenom") - } - - protoReq.PriceDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "priceDenom", err) - } - - val, ok = pathParams["assetDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "assetDenom") - } - - protoReq.AssetDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "assetDenom", err) - } - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_ShortBookAll_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := client.ShortBookAll(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_Query_ShortBookAll_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryAllShortBookRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["contractAddr"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "contractAddr") - } - - protoReq.ContractAddr, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "contractAddr", err) - } - - val, ok = pathParams["priceDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "priceDenom") - } - - protoReq.PriceDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "priceDenom", err) - } - - val, ok = pathParams["assetDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "assetDenom") - } - - protoReq.AssetDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "assetDenom", err) - } - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_ShortBookAll_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.ShortBookAll(ctx, &protoReq) - return msg, metadata, err - -} - -func request_Query_GetPrice_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryGetPriceRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["contractAddr"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "contractAddr") - } - - protoReq.ContractAddr, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "contractAddr", err) - } - - val, ok = pathParams["priceDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "priceDenom") - } - - protoReq.PriceDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "priceDenom", err) - } - - val, ok = pathParams["assetDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "assetDenom") - } - - protoReq.AssetDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "assetDenom", err) - } - - val, ok = pathParams["timestamp"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "timestamp") - } - - protoReq.Timestamp, err = runtime.Uint64(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "timestamp", err) - } - - msg, err := client.GetPrice(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_Query_GetPrice_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryGetPriceRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["contractAddr"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "contractAddr") - } - - protoReq.ContractAddr, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "contractAddr", err) - } - - val, ok = pathParams["priceDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "priceDenom") - } - - protoReq.PriceDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "priceDenom", err) - } - - val, ok = pathParams["assetDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "assetDenom") - } - - protoReq.AssetDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "assetDenom", err) - } - - val, ok = pathParams["timestamp"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "timestamp") - } - - protoReq.Timestamp, err = runtime.Uint64(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "timestamp", err) - } - - msg, err := server.GetPrice(ctx, &protoReq) - return msg, metadata, err - -} - -func request_Query_GetLatestPrice_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryGetLatestPriceRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["contractAddr"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "contractAddr") - } - - protoReq.ContractAddr, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "contractAddr", err) - } - - val, ok = pathParams["priceDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "priceDenom") - } - - protoReq.PriceDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "priceDenom", err) - } - - val, ok = pathParams["assetDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "assetDenom") - } - - protoReq.AssetDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "assetDenom", err) - } - - msg, err := client.GetLatestPrice(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_Query_GetLatestPrice_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryGetLatestPriceRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["contractAddr"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "contractAddr") - } - - protoReq.ContractAddr, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "contractAddr", err) - } - - val, ok = pathParams["priceDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "priceDenom") - } - - protoReq.PriceDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "priceDenom", err) - } - - val, ok = pathParams["assetDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "assetDenom") - } - - protoReq.AssetDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "assetDenom", err) - } - - msg, err := server.GetLatestPrice(ctx, &protoReq) - return msg, metadata, err - -} - -func request_Query_GetPrices_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryGetPricesRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["contractAddr"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "contractAddr") - } - - protoReq.ContractAddr, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "contractAddr", err) - } - - val, ok = pathParams["priceDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "priceDenom") - } - - protoReq.PriceDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "priceDenom", err) - } - - val, ok = pathParams["assetDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "assetDenom") - } - - protoReq.AssetDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "assetDenom", err) - } - - msg, err := client.GetPrices(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_Query_GetPrices_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryGetPricesRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["contractAddr"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "contractAddr") - } - - protoReq.ContractAddr, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "contractAddr", err) - } - - val, ok = pathParams["priceDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "priceDenom") - } - - protoReq.PriceDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "priceDenom", err) - } - - val, ok = pathParams["assetDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "assetDenom") - } - - protoReq.AssetDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "assetDenom", err) - } - - msg, err := server.GetPrices(ctx, &protoReq) - return msg, metadata, err - -} - -func request_Query_GetTwaps_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryGetTwapsRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["contractAddr"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "contractAddr") - } - - protoReq.ContractAddr, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "contractAddr", err) - } - - val, ok = pathParams["lookbackSeconds"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "lookbackSeconds") - } - - protoReq.LookbackSeconds, err = runtime.Uint64(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "lookbackSeconds", err) - } - - msg, err := client.GetTwaps(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_Query_GetTwaps_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryGetTwapsRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["contractAddr"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "contractAddr") - } - - protoReq.ContractAddr, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "contractAddr", err) - } - - val, ok = pathParams["lookbackSeconds"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "lookbackSeconds") - } - - protoReq.LookbackSeconds, err = runtime.Uint64(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "lookbackSeconds", err) - } - - msg, err := server.GetTwaps(ctx, &protoReq) - return msg, metadata, err - -} - -func request_Query_AssetMetadata_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryAssetMetadataRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["denom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "denom") - } - - protoReq.Denom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "denom", err) - } - - msg, err := client.AssetMetadata(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_Query_AssetMetadata_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryAssetMetadataRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["denom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "denom") - } - - protoReq.Denom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "denom", err) - } - - msg, err := server.AssetMetadata(ctx, &protoReq) - return msg, metadata, err - -} - -func request_Query_AssetList_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryAssetListRequest - var metadata runtime.ServerMetadata - - msg, err := client.AssetList(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_Query_AssetList_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryAssetListRequest - var metadata runtime.ServerMetadata - - msg, err := server.AssetList(ctx, &protoReq) - return msg, metadata, err - -} - -var ( - filter_Query_GetRegisteredPairs_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} -) - -func request_Query_GetRegisteredPairs_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryRegisteredPairsRequest - var metadata runtime.ServerMetadata - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_GetRegisteredPairs_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := client.GetRegisteredPairs(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_Query_GetRegisteredPairs_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryRegisteredPairsRequest - var metadata runtime.ServerMetadata - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_GetRegisteredPairs_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.GetRegisteredPairs(ctx, &protoReq) - return msg, metadata, err - -} - -func request_Query_GetRegisteredContract_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryRegisteredContractRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["contractAddr"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "contractAddr") - } - - protoReq.ContractAddr, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "contractAddr", err) - } - - msg, err := client.GetRegisteredContract(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_Query_GetRegisteredContract_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryRegisteredContractRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["contractAddr"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "contractAddr") - } - - protoReq.ContractAddr, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "contractAddr", err) - } - - msg, err := server.GetRegisteredContract(ctx, &protoReq) - return msg, metadata, err - -} - -func request_Query_GetOrders_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryGetOrdersRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["contractAddr"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "contractAddr") - } - - protoReq.ContractAddr, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "contractAddr", err) - } - - val, ok = pathParams["account"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "account") - } - - protoReq.Account, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "account", err) - } - - msg, err := client.GetOrders(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_Query_GetOrders_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryGetOrdersRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["contractAddr"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "contractAddr") - } - - protoReq.ContractAddr, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "contractAddr", err) - } - - val, ok = pathParams["account"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "account") - } - - protoReq.Account, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "account", err) - } - - msg, err := server.GetOrders(ctx, &protoReq) - return msg, metadata, err - -} - -func request_Query_GetOrder_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryGetOrderByIDRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["contractAddr"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "contractAddr") - } - - protoReq.ContractAddr, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "contractAddr", err) - } - - val, ok = pathParams["priceDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "priceDenom") - } - - protoReq.PriceDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "priceDenom", err) - } - - val, ok = pathParams["assetDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "assetDenom") - } - - protoReq.AssetDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "assetDenom", err) - } - - val, ok = pathParams["id"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") - } - - protoReq.Id, err = runtime.Uint64(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) - } - - msg, err := client.GetOrder(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_Query_GetOrder_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryGetOrderByIDRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["contractAddr"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "contractAddr") - } - - protoReq.ContractAddr, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "contractAddr", err) - } - - val, ok = pathParams["priceDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "priceDenom") - } - - protoReq.PriceDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "priceDenom", err) - } - - val, ok = pathParams["assetDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "assetDenom") - } - - protoReq.AssetDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "assetDenom", err) - } - - val, ok = pathParams["id"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") - } - - protoReq.Id, err = runtime.Uint64(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) - } - - msg, err := server.GetOrder(ctx, &protoReq) - return msg, metadata, err - -} - -func request_Query_GetHistoricalPrices_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryGetHistoricalPricesRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["contractAddr"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "contractAddr") - } - - protoReq.ContractAddr, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "contractAddr", err) - } - - val, ok = pathParams["priceDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "priceDenom") - } - - protoReq.PriceDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "priceDenom", err) - } - - val, ok = pathParams["assetDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "assetDenom") - } - - protoReq.AssetDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "assetDenom", err) - } - - val, ok = pathParams["periodLengthInSeconds"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "periodLengthInSeconds") - } - - protoReq.PeriodLengthInSeconds, err = runtime.Uint64(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "periodLengthInSeconds", err) - } - - val, ok = pathParams["numOfPeriods"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "numOfPeriods") - } - - protoReq.NumOfPeriods, err = runtime.Uint64(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "numOfPeriods", err) - } - - msg, err := client.GetHistoricalPrices(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_Query_GetHistoricalPrices_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryGetHistoricalPricesRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["contractAddr"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "contractAddr") - } - - protoReq.ContractAddr, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "contractAddr", err) - } - - val, ok = pathParams["priceDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "priceDenom") - } - - protoReq.PriceDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "priceDenom", err) - } - - val, ok = pathParams["assetDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "assetDenom") - } - - protoReq.AssetDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "assetDenom", err) - } - - val, ok = pathParams["periodLengthInSeconds"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "periodLengthInSeconds") - } - - protoReq.PeriodLengthInSeconds, err = runtime.Uint64(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "periodLengthInSeconds", err) - } - - val, ok = pathParams["numOfPeriods"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "numOfPeriods") - } - - protoReq.NumOfPeriods, err = runtime.Uint64(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "numOfPeriods", err) - } - - msg, err := server.GetHistoricalPrices(ctx, &protoReq) - return msg, metadata, err - -} - -func request_Query_GetMarketSummary_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryGetMarketSummaryRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["contractAddr"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "contractAddr") - } - - protoReq.ContractAddr, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "contractAddr", err) - } - - val, ok = pathParams["priceDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "priceDenom") - } - - protoReq.PriceDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "priceDenom", err) - } - - val, ok = pathParams["assetDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "assetDenom") - } - - protoReq.AssetDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "assetDenom", err) - } - - val, ok = pathParams["lookbackInSeconds"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "lookbackInSeconds") - } - - protoReq.LookbackInSeconds, err = runtime.Uint64(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "lookbackInSeconds", err) - } - - msg, err := client.GetMarketSummary(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_Query_GetMarketSummary_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryGetMarketSummaryRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["contractAddr"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "contractAddr") - } - - protoReq.ContractAddr, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "contractAddr", err) - } - - val, ok = pathParams["priceDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "priceDenom") - } - - protoReq.PriceDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "priceDenom", err) - } - - val, ok = pathParams["assetDenom"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "assetDenom") - } - - protoReq.AssetDenom, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "assetDenom", err) - } - - val, ok = pathParams["lookbackInSeconds"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "lookbackInSeconds") - } - - protoReq.LookbackInSeconds, err = runtime.Uint64(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "lookbackInSeconds", err) - } - - msg, err := server.GetMarketSummary(ctx, &protoReq) - return msg, metadata, err - -} - -// RegisterQueryHandlerServer registers the http handlers for service Query to "mux". -// UnaryRPC :call QueryServer directly. -// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. -// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterQueryHandlerFromEndpoint instead. -func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error { - - mux.Handle("GET", pattern_Query_Params_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_Query_Params_0(rctx, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_Query_LongBook_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_Query_LongBook_0(rctx, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_LongBook_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_Query_LongBookAll_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_Query_LongBookAll_0(rctx, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_LongBookAll_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_Query_ShortBook_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_Query_ShortBook_0(rctx, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_ShortBook_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_Query_ShortBookAll_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_Query_ShortBookAll_0(rctx, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_ShortBookAll_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_Query_GetPrice_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_Query_GetPrice_0(rctx, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_GetPrice_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_Query_GetLatestPrice_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_Query_GetLatestPrice_0(rctx, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_GetLatestPrice_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_Query_GetPrices_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_Query_GetPrices_0(rctx, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_GetPrices_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_Query_GetTwaps_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_Query_GetTwaps_0(rctx, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_GetTwaps_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_Query_AssetMetadata_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_Query_AssetMetadata_0(rctx, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_AssetMetadata_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_Query_AssetList_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_Query_AssetList_0(rctx, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_AssetList_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_Query_GetRegisteredPairs_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_Query_GetRegisteredPairs_0(rctx, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_GetRegisteredPairs_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_Query_GetRegisteredContract_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_Query_GetRegisteredContract_0(rctx, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_GetRegisteredContract_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_Query_GetOrders_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_Query_GetOrders_0(rctx, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_GetOrders_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_Query_GetOrder_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_Query_GetOrder_0(rctx, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_GetOrder_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_Query_GetHistoricalPrices_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_Query_GetHistoricalPrices_0(rctx, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_GetHistoricalPrices_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_Query_GetMarketSummary_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_Query_GetMarketSummary_0(rctx, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_GetMarketSummary_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - return nil -} - -// RegisterQueryHandlerFromEndpoint is same as RegisterQueryHandler but -// automatically dials to "endpoint" and closes the connection when "ctx" gets done. -func RegisterQueryHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { - conn, err := grpc.Dial(endpoint, opts...) - if err != nil { - return err - } - defer func() { - if err != nil { - if cerr := conn.Close(); cerr != nil { - grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) - } - return - } - go func() { - <-ctx.Done() - if cerr := conn.Close(); cerr != nil { - grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) - } - }() - }() - - return RegisterQueryHandler(ctx, mux, conn) -} - -// RegisterQueryHandler registers the http handlers for service Query to "mux". -// The handlers forward requests to the grpc endpoint over "conn". -func RegisterQueryHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { - return RegisterQueryHandlerClient(ctx, mux, NewQueryClient(conn)) -} - -// RegisterQueryHandlerClient registers the http handlers for service Query -// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "QueryClient". -// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "QueryClient" -// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in -// "QueryClient" to call the correct interceptors. -func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QueryClient) error { - - mux.Handle("GET", pattern_Query_Params_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_Query_Params_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_Query_LongBook_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_Query_LongBook_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_LongBook_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_Query_LongBookAll_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_Query_LongBookAll_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_LongBookAll_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_Query_ShortBook_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_Query_ShortBook_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_ShortBook_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_Query_ShortBookAll_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_Query_ShortBookAll_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_ShortBookAll_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_Query_GetPrice_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_Query_GetPrice_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_GetPrice_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_Query_GetLatestPrice_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_Query_GetLatestPrice_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_GetLatestPrice_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_Query_GetPrices_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_Query_GetPrices_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_GetPrices_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_Query_GetTwaps_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_Query_GetTwaps_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_GetTwaps_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_Query_AssetMetadata_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_Query_AssetMetadata_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_AssetMetadata_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_Query_AssetList_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_Query_AssetList_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_AssetList_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_Query_GetRegisteredPairs_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_Query_GetRegisteredPairs_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_GetRegisteredPairs_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_Query_GetRegisteredContract_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_Query_GetRegisteredContract_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_GetRegisteredContract_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_Query_GetOrders_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_Query_GetOrders_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_GetOrders_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_Query_GetOrder_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_Query_GetOrder_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_GetOrder_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_Query_GetHistoricalPrices_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_Query_GetHistoricalPrices_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_GetHistoricalPrices_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_Query_GetMarketSummary_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_Query_GetMarketSummary_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_GetMarketSummary_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - return nil -} - -var ( - pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"sei-protocol", "seichain", "dex", "params"}, "", runtime.AssumeColonVerbOpt(true))) - - pattern_Query_LongBook_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5, 1, 0, 4, 1, 5, 6, 1, 0, 4, 1, 5, 7}, []string{"sei-protocol", "seichain", "dex", "long_book", "contractAddr", "priceDenom", "assetDenom", "price"}, "", runtime.AssumeColonVerbOpt(true))) - - pattern_Query_LongBookAll_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5, 1, 0, 4, 1, 5, 6}, []string{"sei-protocol", "seichain", "dex", "long_book", "contractAddr", "priceDenom", "assetDenom"}, "", runtime.AssumeColonVerbOpt(true))) - - pattern_Query_ShortBook_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5, 1, 0, 4, 1, 5, 6, 1, 0, 4, 1, 5, 7}, []string{"sei-protocol", "seichain", "dex", "short_book", "contractAddr", "priceDenom", "assetDenom", "price"}, "", runtime.AssumeColonVerbOpt(true))) - - pattern_Query_ShortBookAll_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5, 1, 0, 4, 1, 5, 6}, []string{"sei-protocol", "seichain", "dex", "short_book", "contractAddr", "priceDenom", "assetDenom"}, "", runtime.AssumeColonVerbOpt(true))) - - pattern_Query_GetPrice_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5, 1, 0, 4, 1, 5, 6, 1, 0, 4, 1, 5, 7}, []string{"sei-protocol", "seichain", "dex", "get_price", "contractAddr", "priceDenom", "assetDenom", "timestamp"}, "", runtime.AssumeColonVerbOpt(true))) - - pattern_Query_GetLatestPrice_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5, 1, 0, 4, 1, 5, 6}, []string{"sei-protocol", "seichain", "dex", "get_latest_price", "contractAddr", "priceDenom", "assetDenom"}, "", runtime.AssumeColonVerbOpt(true))) - - pattern_Query_GetPrices_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5, 1, 0, 4, 1, 5, 6}, []string{"sei-protocol", "seichain", "dex", "get_prices", "contractAddr", "priceDenom", "assetDenom"}, "", runtime.AssumeColonVerbOpt(true))) - - pattern_Query_GetTwaps_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"sei-protocol", "seichain", "dex", "get_twaps", "contractAddr", "lookbackSeconds"}, "", runtime.AssumeColonVerbOpt(true))) - - pattern_Query_AssetMetadata_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"sei-protocol", "seichain", "dex", "asset_list", "denom"}, "", runtime.AssumeColonVerbOpt(true))) - - pattern_Query_AssetList_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"sei-protocol", "seichain", "dex", "asset_list"}, "", runtime.AssumeColonVerbOpt(true))) - - pattern_Query_GetRegisteredPairs_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"sei-protocol", "seichain", "dex", "registered_pairs"}, "", runtime.AssumeColonVerbOpt(true))) - - pattern_Query_GetRegisteredContract_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"sei-protocol", "seichain", "dex", "registered_contract", "contractAddr"}, "", runtime.AssumeColonVerbOpt(true))) - - pattern_Query_GetOrders_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"sei-protocol", "seichain", "dex", "get_orders", "contractAddr", "account"}, "", runtime.AssumeColonVerbOpt(true))) - - pattern_Query_GetOrder_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5, 1, 0, 4, 1, 5, 6, 1, 0, 4, 1, 5, 7}, []string{"sei-protocol", "seichain", "dex", "get_order_by_id", "contractAddr", "priceDenom", "assetDenom", "id"}, "", runtime.AssumeColonVerbOpt(true))) - - pattern_Query_GetHistoricalPrices_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5, 1, 0, 4, 1, 5, 6, 1, 0, 4, 1, 5, 7, 1, 0, 4, 1, 5, 8}, []string{"sei-protocol", "seichain", "dex", "get_historical_prices", "contractAddr", "priceDenom", "assetDenom", "periodLengthInSeconds", "numOfPeriods"}, "", runtime.AssumeColonVerbOpt(true))) - - pattern_Query_GetMarketSummary_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5, 1, 0, 4, 1, 5, 6, 1, 0, 4, 1, 5, 7}, []string{"sei-protocol", "seichain", "dex", "get_market_summary", "contractAddr", "priceDenom", "assetDenom", "lookbackInSeconds"}, "", runtime.AssumeColonVerbOpt(true))) -) - -var ( - forward_Query_Params_0 = runtime.ForwardResponseMessage - - forward_Query_LongBook_0 = runtime.ForwardResponseMessage - - forward_Query_LongBookAll_0 = runtime.ForwardResponseMessage - - forward_Query_ShortBook_0 = runtime.ForwardResponseMessage - - forward_Query_ShortBookAll_0 = runtime.ForwardResponseMessage - - forward_Query_GetPrice_0 = runtime.ForwardResponseMessage - - forward_Query_GetLatestPrice_0 = runtime.ForwardResponseMessage - - forward_Query_GetPrices_0 = runtime.ForwardResponseMessage - - forward_Query_GetTwaps_0 = runtime.ForwardResponseMessage - - forward_Query_AssetMetadata_0 = runtime.ForwardResponseMessage - - forward_Query_AssetList_0 = runtime.ForwardResponseMessage - - forward_Query_GetRegisteredPairs_0 = runtime.ForwardResponseMessage - - forward_Query_GetRegisteredContract_0 = runtime.ForwardResponseMessage - - forward_Query_GetOrders_0 = runtime.ForwardResponseMessage - - forward_Query_GetOrder_0 = runtime.ForwardResponseMessage - - forward_Query_GetHistoricalPrices_0 = runtime.ForwardResponseMessage - - forward_Query_GetMarketSummary_0 = runtime.ForwardResponseMessage -) diff --git a/x/dex/types/settlement.go b/x/dex/types/settlement.go deleted file mode 100644 index ee3d3378e..000000000 --- a/x/dex/types/settlement.go +++ /dev/null @@ -1,36 +0,0 @@ -package types - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" -) - -type SudoSettlementMsg struct { - Settlement Settlements `json:"settlement"` -} - -func NewSettlementEntry( - ctx sdk.Context, - orderID uint64, - account string, - direction PositionDirection, - priceDenom string, - assetDenom string, - quantity sdk.Dec, - executionCostOrProceed sdk.Dec, - expectedCostOrProceed sdk.Dec, - orderType OrderType, -) *SettlementEntry { - return &SettlementEntry{ - OrderId: orderID, - PositionDirection: GetContractPositionDirection(direction), - PriceDenom: priceDenom, - AssetDenom: assetDenom, - Quantity: quantity, - ExecutionCostOrProceed: executionCostOrProceed, - ExpectedCostOrProceed: expectedCostOrProceed, - Account: account, - OrderType: GetContractOrderType(orderType), - Timestamp: uint64(ctx.BlockTime().Unix()), - Height: uint64(ctx.BlockHeight()), - } -} diff --git a/x/dex/types/settlement.pb.go b/x/dex/types/settlement.pb.go deleted file mode 100644 index 0df73a0cc..000000000 --- a/x/dex/types/settlement.pb.go +++ /dev/null @@ -1,1044 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: dex/settlement.proto - -package types - -import ( - fmt "fmt" - github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" - _ "github.com/gogo/protobuf/gogoproto" - proto "github.com/gogo/protobuf/proto" - io "io" - math "math" - math_bits "math/bits" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package - -type SettlementEntry struct { - Account string `protobuf:"bytes,1,opt,name=account,proto3" json:"account"` - PriceDenom string `protobuf:"bytes,2,opt,name=priceDenom,proto3" json:"price_denom"` - AssetDenom string `protobuf:"bytes,3,opt,name=assetDenom,proto3" json:"asset_denom"` - Quantity github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,4,opt,name=quantity,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"quantity" yaml:"quantity"` - ExecutionCostOrProceed github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,5,opt,name=executionCostOrProceed,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"execution_cost_or_proceed" yaml:"execution_cost_or_proceed"` - ExpectedCostOrProceed github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,6,opt,name=expectedCostOrProceed,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"expected_cost_or_proceed" yaml:"expected_cost_or_proceed"` - PositionDirection string `protobuf:"bytes,7,opt,name=positionDirection,proto3" json:"position_direction"` - OrderType string `protobuf:"bytes,8,opt,name=orderType,proto3" json:"order_type"` - OrderId uint64 `protobuf:"varint,9,opt,name=orderId,proto3" json:"order_id"` - Timestamp uint64 `protobuf:"varint,10,opt,name=timestamp,proto3" json:"timestamp"` - Height uint64 `protobuf:"varint,11,opt,name=height,proto3" json:"height"` - SettlementId uint64 `protobuf:"varint,12,opt,name=settlementId,proto3" json:"settlement_id"` -} - -func (m *SettlementEntry) Reset() { *m = SettlementEntry{} } -func (m *SettlementEntry) String() string { return proto.CompactTextString(m) } -func (*SettlementEntry) ProtoMessage() {} -func (*SettlementEntry) Descriptor() ([]byte, []int) { - return fileDescriptor_c24d83c09612bb1c, []int{0} -} -func (m *SettlementEntry) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *SettlementEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_SettlementEntry.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *SettlementEntry) XXX_Merge(src proto.Message) { - xxx_messageInfo_SettlementEntry.Merge(m, src) -} -func (m *SettlementEntry) XXX_Size() int { - return m.Size() -} -func (m *SettlementEntry) XXX_DiscardUnknown() { - xxx_messageInfo_SettlementEntry.DiscardUnknown(m) -} - -var xxx_messageInfo_SettlementEntry proto.InternalMessageInfo - -func (m *SettlementEntry) GetAccount() string { - if m != nil { - return m.Account - } - return "" -} - -func (m *SettlementEntry) GetPriceDenom() string { - if m != nil { - return m.PriceDenom - } - return "" -} - -func (m *SettlementEntry) GetAssetDenom() string { - if m != nil { - return m.AssetDenom - } - return "" -} - -func (m *SettlementEntry) GetPositionDirection() string { - if m != nil { - return m.PositionDirection - } - return "" -} - -func (m *SettlementEntry) GetOrderType() string { - if m != nil { - return m.OrderType - } - return "" -} - -func (m *SettlementEntry) GetOrderId() uint64 { - if m != nil { - return m.OrderId - } - return 0 -} - -func (m *SettlementEntry) GetTimestamp() uint64 { - if m != nil { - return m.Timestamp - } - return 0 -} - -func (m *SettlementEntry) GetHeight() uint64 { - if m != nil { - return m.Height - } - return 0 -} - -func (m *SettlementEntry) GetSettlementId() uint64 { - if m != nil { - return m.SettlementId - } - return 0 -} - -type Settlements struct { - Epoch int64 `protobuf:"varint,1,opt,name=epoch,proto3" json:"epoch"` - Entries []*SettlementEntry `protobuf:"bytes,2,rep,name=entries,proto3" json:"entries"` -} - -func (m *Settlements) Reset() { *m = Settlements{} } -func (m *Settlements) String() string { return proto.CompactTextString(m) } -func (*Settlements) ProtoMessage() {} -func (*Settlements) Descriptor() ([]byte, []int) { - return fileDescriptor_c24d83c09612bb1c, []int{1} -} -func (m *Settlements) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *Settlements) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_Settlements.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *Settlements) XXX_Merge(src proto.Message) { - xxx_messageInfo_Settlements.Merge(m, src) -} -func (m *Settlements) XXX_Size() int { - return m.Size() -} -func (m *Settlements) XXX_DiscardUnknown() { - xxx_messageInfo_Settlements.DiscardUnknown(m) -} - -var xxx_messageInfo_Settlements proto.InternalMessageInfo - -func (m *Settlements) GetEpoch() int64 { - if m != nil { - return m.Epoch - } - return 0 -} - -func (m *Settlements) GetEntries() []*SettlementEntry { - if m != nil { - return m.Entries - } - return nil -} - -func init() { - proto.RegisterType((*SettlementEntry)(nil), "seiprotocol.seichain.dex.SettlementEntry") - proto.RegisterType((*Settlements)(nil), "seiprotocol.seichain.dex.Settlements") -} - -func init() { proto.RegisterFile("dex/settlement.proto", fileDescriptor_c24d83c09612bb1c) } - -var fileDescriptor_c24d83c09612bb1c = []byte{ - // 584 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x94, 0x3f, 0x6f, 0xdb, 0x3c, - 0x10, 0xc6, 0xad, 0xfc, 0xb1, 0x63, 0x3a, 0x79, 0x83, 0x10, 0x79, 0x03, 0xb6, 0x83, 0x68, 0x08, - 0x68, 0x90, 0xa2, 0x8d, 0x04, 0xb4, 0xe8, 0xd2, 0xd1, 0x75, 0x51, 0x64, 0x28, 0x1a, 0xb0, 0x9d, - 0xba, 0x08, 0x0a, 0x75, 0xb0, 0x89, 0x46, 0xa2, 0x2a, 0xd2, 0x80, 0xbd, 0xf5, 0x23, 0xf4, 0x3b, - 0x74, 0xe8, 0x57, 0xc9, 0x98, 0xb1, 0xe8, 0x40, 0x14, 0xc9, 0xa6, 0x31, 0x5b, 0xb7, 0x42, 0x94, - 0x65, 0x25, 0xad, 0x3d, 0x64, 0xe2, 0xf1, 0xb9, 0xdf, 0xdd, 0x3d, 0x86, 0x79, 0x42, 0xfb, 0x31, - 0x4c, 0x03, 0x05, 0x5a, 0x9f, 0x43, 0x02, 0xa9, 0xf6, 0xb3, 0x5c, 0x6a, 0x89, 0x89, 0x02, 0x61, - 0x23, 0x2e, 0xcf, 0x7d, 0x05, 0x82, 0x8f, 0x23, 0x91, 0xfa, 0x31, 0x4c, 0x1f, 0xee, 0x8f, 0xe4, - 0x48, 0xda, 0x54, 0x50, 0x46, 0x15, 0xef, 0xfd, 0x6e, 0xa3, 0xdd, 0xf7, 0x8b, 0x26, 0xaf, 0x53, - 0x9d, 0xcf, 0xf0, 0x23, 0xd4, 0x89, 0x38, 0x97, 0x93, 0x54, 0x13, 0xa7, 0xef, 0x1c, 0x75, 0x07, - 0xbd, 0xc2, 0xd0, 0x5a, 0x62, 0x75, 0x80, 0x03, 0x84, 0xb2, 0x5c, 0x70, 0x18, 0x42, 0x2a, 0x13, - 0xb2, 0x66, 0xc9, 0xdd, 0xc2, 0xd0, 0x9e, 0x55, 0xc3, 0xb8, 0x94, 0xd9, 0x2d, 0xa4, 0x2c, 0x88, - 0x94, 0x02, 0x5d, 0x15, 0xac, 0x37, 0x05, 0x56, 0xad, 0x0b, 0x1a, 0x04, 0x0b, 0xb4, 0xf5, 0x79, - 0x12, 0xa5, 0x5a, 0xe8, 0x19, 0xd9, 0xb0, 0xf8, 0xdb, 0x0b, 0x43, 0x5b, 0x3f, 0x0d, 0x3d, 0x1c, - 0x09, 0x3d, 0x9e, 0x9c, 0xf9, 0x5c, 0x26, 0x01, 0x97, 0x2a, 0x91, 0x6a, 0x7e, 0x1c, 0xab, 0xf8, - 0x53, 0xa0, 0x67, 0x19, 0x28, 0x7f, 0x08, 0xbc, 0x30, 0x74, 0xd1, 0xe1, 0xc6, 0xd0, 0xdd, 0x59, - 0x94, 0x9c, 0xbf, 0xf4, 0x6a, 0xc5, 0x63, 0x8b, 0x24, 0xfe, 0xee, 0xa0, 0x03, 0x98, 0x02, 0x9f, - 0x68, 0x21, 0xd3, 0x57, 0x52, 0xe9, 0x77, 0xf9, 0x69, 0x2e, 0x39, 0x40, 0x4c, 0x36, 0xed, 0x64, - 0x79, 0xef, 0xc9, 0x0f, 0x16, 0xfd, 0x42, 0x2e, 0x95, 0x0e, 0x65, 0x1e, 0x66, 0x55, 0xcb, 0x1b, - 0x43, 0xfb, 0x95, 0x95, 0x95, 0x88, 0xc7, 0x56, 0xd8, 0xc1, 0xdf, 0x1c, 0xf4, 0x3f, 0x4c, 0x33, - 0xe0, 0x1a, 0xe2, 0xbb, 0x46, 0xdb, 0xd6, 0x68, 0x72, 0x6f, 0xa3, 0xa4, 0x6e, 0xb7, 0xc4, 0x27, - 0xad, 0x7d, 0x2e, 0x27, 0x3c, 0xb6, 0xdc, 0x0b, 0x1e, 0xa2, 0xbd, 0x4c, 0x2a, 0x51, 0xda, 0x1f, - 0x8a, 0x1c, 0x78, 0x19, 0x90, 0x8e, 0x35, 0x78, 0x50, 0x18, 0x8a, 0xeb, 0x64, 0x18, 0xd7, 0x59, - 0xf6, 0x6f, 0x01, 0x7e, 0x8a, 0xba, 0x32, 0x8f, 0x21, 0xff, 0x30, 0xcb, 0x80, 0x6c, 0xd9, 0xea, - 0xff, 0x0a, 0x43, 0x91, 0x15, 0xc3, 0xf2, 0x37, 0xb0, 0x06, 0xc0, 0x87, 0xa8, 0x63, 0x2f, 0x27, - 0x31, 0xe9, 0xf6, 0x9d, 0xa3, 0x8d, 0xc1, 0x76, 0xf9, 0xff, 0x57, 0xac, 0x88, 0x59, 0x9d, 0xc4, - 0x4f, 0x50, 0x57, 0x8b, 0x04, 0x94, 0x8e, 0x92, 0x8c, 0x20, 0x4b, 0xee, 0x14, 0x86, 0x36, 0x22, - 0x6b, 0x42, 0xec, 0xa1, 0xf6, 0x18, 0xc4, 0x68, 0xac, 0x49, 0xcf, 0x92, 0xa8, 0x30, 0x74, 0xae, - 0xb0, 0xf9, 0x89, 0x5f, 0xa0, 0xed, 0x66, 0x11, 0x4f, 0x62, 0xb2, 0x6d, 0xc9, 0xbd, 0xc2, 0xd0, - 0x9d, 0x46, 0x2f, 0x2d, 0xdc, 0xc1, 0xbc, 0x2f, 0x0e, 0xea, 0x35, 0xbb, 0xa7, 0x30, 0x45, 0x9b, - 0x90, 0x49, 0x3e, 0xb6, 0x5b, 0xb7, 0x3e, 0xe8, 0x16, 0x86, 0x56, 0x02, 0xab, 0x0e, 0x7c, 0x8a, - 0x3a, 0x90, 0xea, 0x5c, 0x80, 0x22, 0x6b, 0xfd, 0xf5, 0xa3, 0xde, 0xb3, 0xc7, 0xfe, 0xaa, 0x75, - 0xf7, 0xff, 0x5a, 0xea, 0x6a, 0x87, 0xe7, 0xd5, 0xac, 0x0e, 0x06, 0x6f, 0x2e, 0xae, 0x5c, 0xe7, - 0xf2, 0xca, 0x75, 0x7e, 0x5d, 0xb9, 0xce, 0xd7, 0x6b, 0xb7, 0x75, 0x79, 0xed, 0xb6, 0x7e, 0x5c, - 0xbb, 0xad, 0x8f, 0xc7, 0xb7, 0x9e, 0x8f, 0x02, 0x71, 0x5c, 0x4f, 0xb1, 0x17, 0x3b, 0x26, 0x98, - 0x06, 0xe5, 0x27, 0xc8, 0xbe, 0xa4, 0xb3, 0xb6, 0xcd, 0x3f, 0xff, 0x13, 0x00, 0x00, 0xff, 0xff, - 0x07, 0xa3, 0x0d, 0xb2, 0x96, 0x04, 0x00, 0x00, -} - -func (m *SettlementEntry) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *SettlementEntry) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *SettlementEntry) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.SettlementId != 0 { - i = encodeVarintSettlement(dAtA, i, uint64(m.SettlementId)) - i-- - dAtA[i] = 0x60 - } - if m.Height != 0 { - i = encodeVarintSettlement(dAtA, i, uint64(m.Height)) - i-- - dAtA[i] = 0x58 - } - if m.Timestamp != 0 { - i = encodeVarintSettlement(dAtA, i, uint64(m.Timestamp)) - i-- - dAtA[i] = 0x50 - } - if m.OrderId != 0 { - i = encodeVarintSettlement(dAtA, i, uint64(m.OrderId)) - i-- - dAtA[i] = 0x48 - } - if len(m.OrderType) > 0 { - i -= len(m.OrderType) - copy(dAtA[i:], m.OrderType) - i = encodeVarintSettlement(dAtA, i, uint64(len(m.OrderType))) - i-- - dAtA[i] = 0x42 - } - if len(m.PositionDirection) > 0 { - i -= len(m.PositionDirection) - copy(dAtA[i:], m.PositionDirection) - i = encodeVarintSettlement(dAtA, i, uint64(len(m.PositionDirection))) - i-- - dAtA[i] = 0x3a - } - { - size := m.ExpectedCostOrProceed.Size() - i -= size - if _, err := m.ExpectedCostOrProceed.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintSettlement(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x32 - { - size := m.ExecutionCostOrProceed.Size() - i -= size - if _, err := m.ExecutionCostOrProceed.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintSettlement(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x2a - { - size := m.Quantity.Size() - i -= size - if _, err := m.Quantity.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintSettlement(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x22 - if len(m.AssetDenom) > 0 { - i -= len(m.AssetDenom) - copy(dAtA[i:], m.AssetDenom) - i = encodeVarintSettlement(dAtA, i, uint64(len(m.AssetDenom))) - i-- - dAtA[i] = 0x1a - } - if len(m.PriceDenom) > 0 { - i -= len(m.PriceDenom) - copy(dAtA[i:], m.PriceDenom) - i = encodeVarintSettlement(dAtA, i, uint64(len(m.PriceDenom))) - i-- - dAtA[i] = 0x12 - } - if len(m.Account) > 0 { - i -= len(m.Account) - copy(dAtA[i:], m.Account) - i = encodeVarintSettlement(dAtA, i, uint64(len(m.Account))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *Settlements) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *Settlements) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *Settlements) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Entries) > 0 { - for iNdEx := len(m.Entries) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Entries[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintSettlement(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - } - } - if m.Epoch != 0 { - i = encodeVarintSettlement(dAtA, i, uint64(m.Epoch)) - i-- - dAtA[i] = 0x8 - } - return len(dAtA) - i, nil -} - -func encodeVarintSettlement(dAtA []byte, offset int, v uint64) int { - offset -= sovSettlement(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *SettlementEntry) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Account) - if l > 0 { - n += 1 + l + sovSettlement(uint64(l)) - } - l = len(m.PriceDenom) - if l > 0 { - n += 1 + l + sovSettlement(uint64(l)) - } - l = len(m.AssetDenom) - if l > 0 { - n += 1 + l + sovSettlement(uint64(l)) - } - l = m.Quantity.Size() - n += 1 + l + sovSettlement(uint64(l)) - l = m.ExecutionCostOrProceed.Size() - n += 1 + l + sovSettlement(uint64(l)) - l = m.ExpectedCostOrProceed.Size() - n += 1 + l + sovSettlement(uint64(l)) - l = len(m.PositionDirection) - if l > 0 { - n += 1 + l + sovSettlement(uint64(l)) - } - l = len(m.OrderType) - if l > 0 { - n += 1 + l + sovSettlement(uint64(l)) - } - if m.OrderId != 0 { - n += 1 + sovSettlement(uint64(m.OrderId)) - } - if m.Timestamp != 0 { - n += 1 + sovSettlement(uint64(m.Timestamp)) - } - if m.Height != 0 { - n += 1 + sovSettlement(uint64(m.Height)) - } - if m.SettlementId != 0 { - n += 1 + sovSettlement(uint64(m.SettlementId)) - } - return n -} - -func (m *Settlements) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Epoch != 0 { - n += 1 + sovSettlement(uint64(m.Epoch)) - } - if len(m.Entries) > 0 { - for _, e := range m.Entries { - l = e.Size() - n += 1 + l + sovSettlement(uint64(l)) - } - } - return n -} - -func sovSettlement(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozSettlement(x uint64) (n int) { - return sovSettlement(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *SettlementEntry) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowSettlement - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: SettlementEntry: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: SettlementEntry: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Account", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowSettlement - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthSettlement - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthSettlement - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Account = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PriceDenom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowSettlement - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthSettlement - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthSettlement - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.PriceDenom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field AssetDenom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowSettlement - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthSettlement - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthSettlement - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.AssetDenom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Quantity", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowSettlement - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthSettlement - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthSettlement - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.Quantity.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 5: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ExecutionCostOrProceed", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowSettlement - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthSettlement - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthSettlement - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.ExecutionCostOrProceed.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 6: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ExpectedCostOrProceed", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowSettlement - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthSettlement - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthSettlement - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.ExpectedCostOrProceed.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 7: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PositionDirection", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowSettlement - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthSettlement - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthSettlement - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.PositionDirection = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 8: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field OrderType", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowSettlement - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthSettlement - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthSettlement - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.OrderType = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 9: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field OrderId", wireType) - } - m.OrderId = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowSettlement - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.OrderId |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 10: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Timestamp", wireType) - } - m.Timestamp = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowSettlement - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Timestamp |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 11: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Height", wireType) - } - m.Height = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowSettlement - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Height |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 12: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field SettlementId", wireType) - } - m.SettlementId = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowSettlement - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.SettlementId |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipSettlement(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthSettlement - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *Settlements) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowSettlement - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: Settlements: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Settlements: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Epoch", wireType) - } - m.Epoch = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowSettlement - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Epoch |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Entries", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowSettlement - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthSettlement - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthSettlement - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Entries = append(m.Entries, &SettlementEntry{}) - if err := m.Entries[len(m.Entries)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipSettlement(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthSettlement - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipSettlement(dAtA []byte) (n int, err error) { - l := len(dAtA) - iNdEx := 0 - depth := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowSettlement - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowSettlement - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - iNdEx++ - if dAtA[iNdEx-1] < 0x80 { - break - } - } - case 1: - iNdEx += 8 - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowSettlement - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if length < 0 { - return 0, ErrInvalidLengthSettlement - } - iNdEx += length - case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupSettlement - } - depth-- - case 5: - iNdEx += 4 - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - if iNdEx < 0 { - return 0, ErrInvalidLengthSettlement - } - if depth == 0 { - return iNdEx, nil - } - } - return 0, io.ErrUnexpectedEOF -} - -var ( - ErrInvalidLengthSettlement = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowSettlement = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupSettlement = fmt.Errorf("proto: unexpected end of group") -) diff --git a/x/dex/types/settlement_test.go b/x/dex/types/settlement_test.go deleted file mode 100644 index 245e33d05..000000000 --- a/x/dex/types/settlement_test.go +++ /dev/null @@ -1,31 +0,0 @@ -package types_test - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/dex/types" - "github.com/stretchr/testify/require" -) - -func TestNewSettlementEntry(t *testing.T) { - _, ctx := keepertest.DexKeeper(t) - ctx = ctx.WithBlockHeight(100) - sudoFinalizeBlockMsg := types.NewSettlementEntry( - ctx, - 1, - "TEST_ACCOUNT", - types.PositionDirection_LONG, - "USDC", - "ATOM", - sdk.MustNewDecFromStr("1"), - sdk.MustNewDecFromStr("2"), - sdk.MustNewDecFromStr("3"), - types.OrderType_MARKET, - ) - - require.Equal(t, "Long", sudoFinalizeBlockMsg.PositionDirection) - require.Equal(t, "Market", sudoFinalizeBlockMsg.OrderType) - require.Equal(t, uint64(100), sudoFinalizeBlockMsg.Height) -} diff --git a/x/dex/types/short_book.pb.go b/x/dex/types/short_book.pb.go deleted file mode 100644 index 83c969121..000000000 --- a/x/dex/types/short_book.pb.go +++ /dev/null @@ -1,380 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: dex/short_book.proto - -package types - -import ( - fmt "fmt" - github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" - _ "github.com/gogo/protobuf/gogoproto" - proto "github.com/gogo/protobuf/proto" - io "io" - math "math" - math_bits "math/bits" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package - -type ShortBook struct { - Price github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,1,opt,name=price,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"price" yaml:"price"` - Entry *OrderEntry `protobuf:"bytes,2,opt,name=entry,proto3" json:"entry"` -} - -func (m *ShortBook) Reset() { *m = ShortBook{} } -func (m *ShortBook) String() string { return proto.CompactTextString(m) } -func (*ShortBook) ProtoMessage() {} -func (*ShortBook) Descriptor() ([]byte, []int) { - return fileDescriptor_2554593a991dd89d, []int{0} -} -func (m *ShortBook) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *ShortBook) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_ShortBook.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *ShortBook) XXX_Merge(src proto.Message) { - xxx_messageInfo_ShortBook.Merge(m, src) -} -func (m *ShortBook) XXX_Size() int { - return m.Size() -} -func (m *ShortBook) XXX_DiscardUnknown() { - xxx_messageInfo_ShortBook.DiscardUnknown(m) -} - -var xxx_messageInfo_ShortBook proto.InternalMessageInfo - -func (m *ShortBook) GetEntry() *OrderEntry { - if m != nil { - return m.Entry - } - return nil -} - -func init() { - proto.RegisterType((*ShortBook)(nil), "seiprotocol.seichain.dex.ShortBook") -} - -func init() { proto.RegisterFile("dex/short_book.proto", fileDescriptor_2554593a991dd89d) } - -var fileDescriptor_2554593a991dd89d = []byte{ - // 278 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x49, 0x49, 0xad, 0xd0, - 0x2f, 0xce, 0xc8, 0x2f, 0x2a, 0x89, 0x4f, 0xca, 0xcf, 0xcf, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, - 0x17, 0x92, 0x28, 0x4e, 0xcd, 0x04, 0xb3, 0x92, 0xf3, 0x73, 0xf4, 0x8a, 0x53, 0x33, 0x93, 0x33, - 0x12, 0x33, 0xf3, 0xf4, 0x52, 0x52, 0x2b, 0xa4, 0x44, 0x41, 0xea, 0xf3, 0x8b, 0x52, 0x52, 0x8b, - 0xe2, 0x53, 0xf3, 0x4a, 0x8a, 0x2a, 0x21, 0x1a, 0xa4, 0x44, 0xd2, 0xf3, 0xd3, 0xf3, 0xc1, 0x4c, - 0x7d, 0x10, 0x0b, 0x22, 0xaa, 0xb4, 0x91, 0x91, 0x8b, 0x33, 0x18, 0x64, 0xb6, 0x53, 0x7e, 0x7e, - 0xb6, 0x50, 0x2c, 0x17, 0x6b, 0x41, 0x51, 0x66, 0x72, 0xaa, 0x04, 0xa3, 0x02, 0xa3, 0x06, 0xa7, - 0x93, 0xfb, 0x89, 0x7b, 0xf2, 0x0c, 0xb7, 0xee, 0xc9, 0xab, 0xa5, 0x67, 0x96, 0x64, 0x94, 0x26, - 0xe9, 0x25, 0xe7, 0xe7, 0xea, 0x27, 0xe7, 0x17, 0xe7, 0xe6, 0x17, 0x43, 0x29, 0xdd, 0xe2, 0x94, - 0x6c, 0xfd, 0x92, 0xca, 0x82, 0xd4, 0x62, 0x3d, 0x97, 0xd4, 0xe4, 0x57, 0xf7, 0xe4, 0x21, 0xda, - 0x3f, 0xdd, 0x93, 0xe7, 0xa9, 0x4c, 0xcc, 0xcd, 0xb1, 0x52, 0x02, 0x73, 0x95, 0x82, 0x20, 0xc2, - 0x42, 0xae, 0x5c, 0xac, 0x60, 0x17, 0x49, 0x30, 0x29, 0x30, 0x6a, 0x70, 0x1b, 0xa9, 0xe8, 0xe1, - 0xf2, 0x83, 0x9e, 0x3f, 0xc8, 0xf9, 0xae, 0x20, 0xb5, 0x4e, 0x9c, 0x20, 0x63, 0xc1, 0xda, 0x82, - 0x20, 0x94, 0x93, 0xfb, 0x89, 0x47, 0x72, 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e, 0x78, 0x24, 0xc7, - 0x38, 0xe1, 0xb1, 0x1c, 0xc3, 0x85, 0xc7, 0x72, 0x0c, 0x37, 0x1e, 0xcb, 0x31, 0x44, 0xe9, 0x22, - 0x39, 0xb4, 0x38, 0x35, 0x53, 0x17, 0x66, 0x38, 0x98, 0x03, 0x36, 0x5d, 0xbf, 0x42, 0x1f, 0x14, - 0x3c, 0x60, 0x37, 0x27, 0xb1, 0x81, 0xe5, 0x8d, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0x90, 0x12, - 0x40, 0x1c, 0x62, 0x01, 0x00, 0x00, -} - -func (m *ShortBook) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *ShortBook) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *ShortBook) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Entry != nil { - { - size, err := m.Entry.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintShortBook(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - } - { - size := m.Price.Size() - i -= size - if _, err := m.Price.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintShortBook(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil -} - -func encodeVarintShortBook(dAtA []byte, offset int, v uint64) int { - offset -= sovShortBook(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *ShortBook) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = m.Price.Size() - n += 1 + l + sovShortBook(uint64(l)) - if m.Entry != nil { - l = m.Entry.Size() - n += 1 + l + sovShortBook(uint64(l)) - } - return n -} - -func sovShortBook(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozShortBook(x uint64) (n int) { - return sovShortBook(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *ShortBook) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowShortBook - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: ShortBook: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: ShortBook: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Price", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowShortBook - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthShortBook - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthShortBook - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.Price.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Entry", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowShortBook - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthShortBook - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthShortBook - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Entry == nil { - m.Entry = &OrderEntry{} - } - if err := m.Entry.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipShortBook(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthShortBook - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipShortBook(dAtA []byte) (n int, err error) { - l := len(dAtA) - iNdEx := 0 - depth := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowShortBook - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowShortBook - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - iNdEx++ - if dAtA[iNdEx-1] < 0x80 { - break - } - } - case 1: - iNdEx += 8 - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowShortBook - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if length < 0 { - return 0, ErrInvalidLengthShortBook - } - iNdEx += length - case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupShortBook - } - depth-- - case 5: - iNdEx += 4 - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - if iNdEx < 0 { - return 0, ErrInvalidLengthShortBook - } - if depth == 0 { - return iNdEx, nil - } - } - return 0, io.ErrUnexpectedEOF -} - -var ( - ErrInvalidLengthShortBook = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowShortBook = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupShortBook = fmt.Errorf("proto: unexpected end of group") -) diff --git a/x/dex/types/tick_size.pb.go b/x/dex/types/tick_size.pb.go deleted file mode 100644 index c6f6a6f1e..000000000 --- a/x/dex/types/tick_size.pb.go +++ /dev/null @@ -1,433 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: dex/tick_size.proto - -package types - -import ( - fmt "fmt" - github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" - _ "github.com/gogo/protobuf/gogoproto" - proto "github.com/gogo/protobuf/proto" - io "io" - math "math" - math_bits "math/bits" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package - -type TickSize struct { - Pair *Pair `protobuf:"bytes,1,opt,name=pair,proto3" json:"pair"` - Ticksize github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,2,opt,name=ticksize,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"tick_size" yaml:"tick_size"` - ContractAddr string `protobuf:"bytes,3,opt,name=contractAddr,proto3" json:"contract_addr" yaml:"tick_size"` -} - -func (m *TickSize) Reset() { *m = TickSize{} } -func (m *TickSize) String() string { return proto.CompactTextString(m) } -func (*TickSize) ProtoMessage() {} -func (*TickSize) Descriptor() ([]byte, []int) { - return fileDescriptor_17c2b52038d2f694, []int{0} -} -func (m *TickSize) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *TickSize) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_TickSize.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *TickSize) XXX_Merge(src proto.Message) { - xxx_messageInfo_TickSize.Merge(m, src) -} -func (m *TickSize) XXX_Size() int { - return m.Size() -} -func (m *TickSize) XXX_DiscardUnknown() { - xxx_messageInfo_TickSize.DiscardUnknown(m) -} - -var xxx_messageInfo_TickSize proto.InternalMessageInfo - -func (m *TickSize) GetPair() *Pair { - if m != nil { - return m.Pair - } - return nil -} - -func (m *TickSize) GetContractAddr() string { - if m != nil { - return m.ContractAddr - } - return "" -} - -func init() { - proto.RegisterType((*TickSize)(nil), "seiprotocol.seichain.dex.TickSize") -} - -func init() { proto.RegisterFile("dex/tick_size.proto", fileDescriptor_17c2b52038d2f694) } - -var fileDescriptor_17c2b52038d2f694 = []byte{ - // 307 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x4e, 0x49, 0xad, 0xd0, - 0x2f, 0xc9, 0x4c, 0xce, 0x8e, 0x2f, 0xce, 0xac, 0x4a, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, - 0x92, 0x28, 0x4e, 0xcd, 0x04, 0xb3, 0x92, 0xf3, 0x73, 0xf4, 0x8a, 0x53, 0x33, 0x93, 0x33, 0x12, - 0x33, 0xf3, 0xf4, 0x52, 0x52, 0x2b, 0xa4, 0xf8, 0x40, 0xca, 0x0b, 0x12, 0x33, 0x8b, 0x20, 0x2a, - 0xa5, 0x44, 0xd2, 0xf3, 0xd3, 0xf3, 0xc1, 0x4c, 0x7d, 0x10, 0x0b, 0x22, 0xaa, 0xd4, 0xc0, 0xc4, - 0xc5, 0x11, 0x92, 0x99, 0x9c, 0x1d, 0x9c, 0x59, 0x95, 0x2a, 0x64, 0xc3, 0xc5, 0x02, 0xd2, 0x20, - 0xc1, 0xa8, 0xc0, 0xa8, 0xc1, 0x6d, 0x24, 0xa7, 0x87, 0xcb, 0x6c, 0xbd, 0x80, 0xc4, 0xcc, 0x22, - 0x27, 0x8e, 0x57, 0xf7, 0xe4, 0xc1, 0xea, 0x83, 0xc0, 0xa4, 0x50, 0x36, 0x17, 0x07, 0xc8, 0x75, - 0x20, 0xc7, 0x49, 0x30, 0x29, 0x30, 0x6a, 0x70, 0x3a, 0xf9, 0x9f, 0xb8, 0x27, 0xcf, 0x70, 0xeb, - 0x9e, 0xbc, 0x5a, 0x7a, 0x66, 0x49, 0x46, 0x69, 0x92, 0x5e, 0x72, 0x7e, 0xae, 0x7e, 0x72, 0x7e, - 0x71, 0x6e, 0x7e, 0x31, 0x94, 0xd2, 0x2d, 0x4e, 0xc9, 0xd6, 0x2f, 0xa9, 0x2c, 0x48, 0x2d, 0xd6, - 0x73, 0x49, 0x4d, 0x7e, 0x75, 0x4f, 0x9e, 0x13, 0xee, 0xbf, 0x4f, 0xf7, 0xe4, 0x05, 0x2a, 0x13, - 0x73, 0x73, 0xac, 0x94, 0xe0, 0x42, 0x4a, 0x41, 0x70, 0x0b, 0x84, 0x3c, 0xb9, 0x78, 0x92, 0xf3, - 0xf3, 0x4a, 0x8a, 0x12, 0x93, 0x4b, 0x1c, 0x53, 0x52, 0x8a, 0x24, 0x98, 0xc1, 0x16, 0xaa, 0xbe, - 0xba, 0x27, 0xcf, 0x0b, 0x13, 0x8f, 0x4f, 0x4c, 0x49, 0x29, 0xc2, 0x6a, 0x0c, 0x8a, 0x56, 0x27, - 0xf7, 0x13, 0x8f, 0xe4, 0x18, 0x2f, 0x3c, 0x92, 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, - 0x39, 0x86, 0x0b, 0x8f, 0xe5, 0x18, 0x6e, 0x3c, 0x96, 0x63, 0x88, 0xd2, 0x45, 0x72, 0x77, 0x71, - 0x6a, 0xa6, 0x2e, 0x2c, 0x30, 0xc0, 0x1c, 0x70, 0x68, 0xe8, 0x57, 0xe8, 0x83, 0x63, 0x05, 0xe4, - 0x85, 0x24, 0x36, 0xb0, 0xbc, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0x04, 0x0d, 0x45, 0x14, 0xa9, - 0x01, 0x00, 0x00, -} - -func (m *TickSize) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *TickSize) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *TickSize) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.ContractAddr) > 0 { - i -= len(m.ContractAddr) - copy(dAtA[i:], m.ContractAddr) - i = encodeVarintTickSize(dAtA, i, uint64(len(m.ContractAddr))) - i-- - dAtA[i] = 0x1a - } - { - size := m.Ticksize.Size() - i -= size - if _, err := m.Ticksize.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintTickSize(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - if m.Pair != nil { - { - size, err := m.Pair.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTickSize(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func encodeVarintTickSize(dAtA []byte, offset int, v uint64) int { - offset -= sovTickSize(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *TickSize) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Pair != nil { - l = m.Pair.Size() - n += 1 + l + sovTickSize(uint64(l)) - } - l = m.Ticksize.Size() - n += 1 + l + sovTickSize(uint64(l)) - l = len(m.ContractAddr) - if l > 0 { - n += 1 + l + sovTickSize(uint64(l)) - } - return n -} - -func sovTickSize(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozTickSize(x uint64) (n int) { - return sovTickSize(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *TickSize) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTickSize - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: TickSize: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: TickSize: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Pair", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTickSize - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthTickSize - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthTickSize - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Pair == nil { - m.Pair = &Pair{} - } - if err := m.Pair.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Ticksize", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTickSize - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTickSize - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTickSize - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.Ticksize.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractAddr", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTickSize - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTickSize - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTickSize - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ContractAddr = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipTickSize(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTickSize - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipTickSize(dAtA []byte) (n int, err error) { - l := len(dAtA) - iNdEx := 0 - depth := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowTickSize - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowTickSize - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - iNdEx++ - if dAtA[iNdEx-1] < 0x80 { - break - } - } - case 1: - iNdEx += 8 - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowTickSize - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if length < 0 { - return 0, ErrInvalidLengthTickSize - } - iNdEx += length - case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupTickSize - } - depth-- - case 5: - iNdEx += 4 - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - if iNdEx < 0 { - return 0, ErrInvalidLengthTickSize - } - if depth == 0 { - return iNdEx, nil - } - } - return 0, io.ErrUnexpectedEOF -} - -var ( - ErrInvalidLengthTickSize = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowTickSize = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupTickSize = fmt.Errorf("proto: unexpected end of group") -) diff --git a/x/dex/types/twap.pb.go b/x/dex/types/twap.pb.go deleted file mode 100644 index c1976c198..000000000 --- a/x/dex/types/twap.pb.go +++ /dev/null @@ -1,416 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: dex/twap.proto - -package types - -import ( - fmt "fmt" - github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" - _ "github.com/gogo/protobuf/gogoproto" - proto "github.com/gogo/protobuf/proto" - io "io" - math "math" - math_bits "math/bits" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package - -type Twap struct { - Pair *Pair `protobuf:"bytes,1,opt,name=pair,proto3" json:"pair"` - Twap github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,2,opt,name=twap,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"twap" yaml:"twap"` - LookbackSeconds uint64 `protobuf:"varint,3,opt,name=lookbackSeconds,proto3" json:"lookback_seconds"` -} - -func (m *Twap) Reset() { *m = Twap{} } -func (m *Twap) String() string { return proto.CompactTextString(m) } -func (*Twap) ProtoMessage() {} -func (*Twap) Descriptor() ([]byte, []int) { - return fileDescriptor_10aa4b136085207a, []int{0} -} -func (m *Twap) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *Twap) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_Twap.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *Twap) XXX_Merge(src proto.Message) { - xxx_messageInfo_Twap.Merge(m, src) -} -func (m *Twap) XXX_Size() int { - return m.Size() -} -func (m *Twap) XXX_DiscardUnknown() { - xxx_messageInfo_Twap.DiscardUnknown(m) -} - -var xxx_messageInfo_Twap proto.InternalMessageInfo - -func (m *Twap) GetPair() *Pair { - if m != nil { - return m.Pair - } - return nil -} - -func (m *Twap) GetLookbackSeconds() uint64 { - if m != nil { - return m.LookbackSeconds - } - return 0 -} - -func init() { - proto.RegisterType((*Twap)(nil), "seiprotocol.seichain.dex.Twap") -} - -func init() { proto.RegisterFile("dex/twap.proto", fileDescriptor_10aa4b136085207a) } - -var fileDescriptor_10aa4b136085207a = []byte{ - // 296 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4b, 0x49, 0xad, 0xd0, - 0x2f, 0x29, 0x4f, 0x2c, 0xd0, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x92, 0x28, 0x4e, 0xcd, 0x04, - 0xb3, 0x92, 0xf3, 0x73, 0xf4, 0x8a, 0x53, 0x33, 0x93, 0x33, 0x12, 0x33, 0xf3, 0xf4, 0x52, 0x52, - 0x2b, 0xa4, 0x44, 0xd2, 0xf3, 0xd3, 0xf3, 0xc1, 0x52, 0xfa, 0x20, 0x16, 0x44, 0xbd, 0x14, 0x58, - 0x7f, 0x41, 0x62, 0x66, 0x11, 0x84, 0xaf, 0x74, 0x9f, 0x91, 0x8b, 0x25, 0xa4, 0x3c, 0xb1, 0x40, - 0xc8, 0x86, 0x8b, 0x05, 0x24, 0x2c, 0xc1, 0xa8, 0xc0, 0xa8, 0xc1, 0x6d, 0x24, 0xa7, 0x87, 0xcb, - 0x5c, 0xbd, 0x80, 0xc4, 0xcc, 0x22, 0x27, 0x8e, 0x57, 0xf7, 0xe4, 0xc1, 0xea, 0x83, 0xc0, 0xa4, - 0x50, 0x24, 0x17, 0x0b, 0xc8, 0x51, 0x12, 0x4c, 0x0a, 0x8c, 0x1a, 0x9c, 0x4e, 0xae, 0x27, 0xee, - 0xc9, 0x33, 0xdc, 0xba, 0x27, 0xaf, 0x96, 0x9e, 0x59, 0x92, 0x51, 0x9a, 0xa4, 0x97, 0x9c, 0x9f, - 0xab, 0x9f, 0x9c, 0x5f, 0x9c, 0x9b, 0x5f, 0x0c, 0xa5, 0x74, 0x8b, 0x53, 0xb2, 0xf5, 0x4b, 0x2a, - 0x0b, 0x52, 0x8b, 0xf5, 0x5c, 0x52, 0x93, 0x41, 0x66, 0x81, 0x74, 0x7f, 0xba, 0x27, 0xcf, 0x5d, - 0x99, 0x98, 0x9b, 0x63, 0xa5, 0x04, 0xe2, 0x29, 0x05, 0x81, 0x05, 0x85, 0xec, 0xb8, 0xf8, 0x73, - 0xf2, 0xf3, 0xb3, 0x93, 0x12, 0x93, 0xb3, 0x83, 0x53, 0x93, 0xf3, 0xf3, 0x52, 0x8a, 0x25, 0x98, - 0x15, 0x18, 0x35, 0x58, 0x9c, 0x44, 0x5e, 0xdd, 0x93, 0x17, 0x80, 0x49, 0xc5, 0x17, 0x43, 0xe4, - 0x82, 0xd0, 0x15, 0x3b, 0xb9, 0x9f, 0x78, 0x24, 0xc7, 0x78, 0xe1, 0x91, 0x1c, 0xe3, 0x83, 0x47, - 0x72, 0x8c, 0x13, 0x1e, 0xcb, 0x31, 0x5c, 0x78, 0x2c, 0xc7, 0x70, 0xe3, 0xb1, 0x1c, 0x43, 0x94, - 0x2e, 0x92, 0xf3, 0x8a, 0x53, 0x33, 0x75, 0x61, 0xfe, 0x05, 0x73, 0xc0, 0x1e, 0xd6, 0xaf, 0xd0, - 0x07, 0x87, 0x37, 0xc8, 0xa5, 0x49, 0x6c, 0x60, 0x79, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x6e, 0x96, 0x9d, 0x05, 0x83, 0x01, 0x00, 0x00, -} - -func (m *Twap) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *Twap) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *Twap) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.LookbackSeconds != 0 { - i = encodeVarintTwap(dAtA, i, uint64(m.LookbackSeconds)) - i-- - dAtA[i] = 0x18 - } - { - size := m.Twap.Size() - i -= size - if _, err := m.Twap.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintTwap(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - if m.Pair != nil { - { - size, err := m.Pair.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTwap(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func encodeVarintTwap(dAtA []byte, offset int, v uint64) int { - offset -= sovTwap(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *Twap) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Pair != nil { - l = m.Pair.Size() - n += 1 + l + sovTwap(uint64(l)) - } - l = m.Twap.Size() - n += 1 + l + sovTwap(uint64(l)) - if m.LookbackSeconds != 0 { - n += 1 + sovTwap(uint64(m.LookbackSeconds)) - } - return n -} - -func sovTwap(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozTwap(x uint64) (n int) { - return sovTwap(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *Twap) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTwap - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: Twap: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Twap: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Pair", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTwap - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthTwap - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthTwap - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Pair == nil { - m.Pair = &Pair{} - } - if err := m.Pair.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Twap", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTwap - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTwap - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTwap - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.Twap.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field LookbackSeconds", wireType) - } - m.LookbackSeconds = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTwap - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.LookbackSeconds |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipTwap(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTwap - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipTwap(dAtA []byte) (n int, err error) { - l := len(dAtA) - iNdEx := 0 - depth := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowTwap - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowTwap - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - iNdEx++ - if dAtA[iNdEx-1] < 0x80 { - break - } - } - case 1: - iNdEx += 8 - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowTwap - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if length < 0 { - return 0, ErrInvalidLengthTwap - } - iNdEx += length - case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupTwap - } - depth-- - case 5: - iNdEx += 4 - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - if iNdEx < 0 { - return 0, ErrInvalidLengthTwap - } - if depth == 0 { - return iNdEx, nil - } - } - return 0, io.ErrUnexpectedEOF -} - -var ( - ErrInvalidLengthTwap = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowTwap = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupTwap = fmt.Errorf("proto: unexpected end of group") -) diff --git a/x/dex/types/tx.pb.go b/x/dex/types/tx.pb.go deleted file mode 100644 index 88c844095..000000000 --- a/x/dex/types/tx.pb.go +++ /dev/null @@ -1,3884 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: dex/tx.proto - -package types - -import ( - context "context" - fmt "fmt" - github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" - types "github.com/cosmos/cosmos-sdk/types" - _ "github.com/gogo/protobuf/gogoproto" - grpc1 "github.com/gogo/protobuf/grpc" - proto "github.com/gogo/protobuf/proto" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" - io "io" - math "math" - math_bits "math/bits" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package - -type MsgPlaceOrders struct { - Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator"` - Orders []*Order `protobuf:"bytes,2,rep,name=orders,proto3" json:"orders"` - ContractAddr string `protobuf:"bytes,3,opt,name=contractAddr,proto3" json:"contract_address"` - Funds github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,4,rep,name=funds,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"funds"` -} - -func (m *MsgPlaceOrders) Reset() { *m = MsgPlaceOrders{} } -func (m *MsgPlaceOrders) String() string { return proto.CompactTextString(m) } -func (*MsgPlaceOrders) ProtoMessage() {} -func (*MsgPlaceOrders) Descriptor() ([]byte, []int) { - return fileDescriptor_463701e671e5a5e0, []int{0} -} -func (m *MsgPlaceOrders) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MsgPlaceOrders) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MsgPlaceOrders.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *MsgPlaceOrders) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgPlaceOrders.Merge(m, src) -} -func (m *MsgPlaceOrders) XXX_Size() int { - return m.Size() -} -func (m *MsgPlaceOrders) XXX_DiscardUnknown() { - xxx_messageInfo_MsgPlaceOrders.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgPlaceOrders proto.InternalMessageInfo - -func (m *MsgPlaceOrders) GetCreator() string { - if m != nil { - return m.Creator - } - return "" -} - -func (m *MsgPlaceOrders) GetOrders() []*Order { - if m != nil { - return m.Orders - } - return nil -} - -func (m *MsgPlaceOrders) GetContractAddr() string { - if m != nil { - return m.ContractAddr - } - return "" -} - -func (m *MsgPlaceOrders) GetFunds() github_com_cosmos_cosmos_sdk_types.Coins { - if m != nil { - return m.Funds - } - return nil -} - -type MsgPlaceOrdersResponse struct { - OrderIds []uint64 `protobuf:"varint,1,rep,packed,name=orderIds,proto3" json:"order_ids" yaml:"order_ids"` -} - -func (m *MsgPlaceOrdersResponse) Reset() { *m = MsgPlaceOrdersResponse{} } -func (m *MsgPlaceOrdersResponse) String() string { return proto.CompactTextString(m) } -func (*MsgPlaceOrdersResponse) ProtoMessage() {} -func (*MsgPlaceOrdersResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_463701e671e5a5e0, []int{1} -} -func (m *MsgPlaceOrdersResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MsgPlaceOrdersResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MsgPlaceOrdersResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *MsgPlaceOrdersResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgPlaceOrdersResponse.Merge(m, src) -} -func (m *MsgPlaceOrdersResponse) XXX_Size() int { - return m.Size() -} -func (m *MsgPlaceOrdersResponse) XXX_DiscardUnknown() { - xxx_messageInfo_MsgPlaceOrdersResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgPlaceOrdersResponse proto.InternalMessageInfo - -func (m *MsgPlaceOrdersResponse) GetOrderIds() []uint64 { - if m != nil { - return m.OrderIds - } - return nil -} - -type MsgCancelOrders struct { - Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator"` - Cancellations []*Cancellation `protobuf:"bytes,2,rep,name=cancellations,proto3" json:"cancellations"` - ContractAddr string `protobuf:"bytes,3,opt,name=contractAddr,proto3" json:"contract_address"` -} - -func (m *MsgCancelOrders) Reset() { *m = MsgCancelOrders{} } -func (m *MsgCancelOrders) String() string { return proto.CompactTextString(m) } -func (*MsgCancelOrders) ProtoMessage() {} -func (*MsgCancelOrders) Descriptor() ([]byte, []int) { - return fileDescriptor_463701e671e5a5e0, []int{2} -} -func (m *MsgCancelOrders) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MsgCancelOrders) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MsgCancelOrders.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *MsgCancelOrders) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgCancelOrders.Merge(m, src) -} -func (m *MsgCancelOrders) XXX_Size() int { - return m.Size() -} -func (m *MsgCancelOrders) XXX_DiscardUnknown() { - xxx_messageInfo_MsgCancelOrders.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgCancelOrders proto.InternalMessageInfo - -func (m *MsgCancelOrders) GetCreator() string { - if m != nil { - return m.Creator - } - return "" -} - -func (m *MsgCancelOrders) GetCancellations() []*Cancellation { - if m != nil { - return m.Cancellations - } - return nil -} - -func (m *MsgCancelOrders) GetContractAddr() string { - if m != nil { - return m.ContractAddr - } - return "" -} - -type MsgCancelOrdersResponse struct { -} - -func (m *MsgCancelOrdersResponse) Reset() { *m = MsgCancelOrdersResponse{} } -func (m *MsgCancelOrdersResponse) String() string { return proto.CompactTextString(m) } -func (*MsgCancelOrdersResponse) ProtoMessage() {} -func (*MsgCancelOrdersResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_463701e671e5a5e0, []int{3} -} -func (m *MsgCancelOrdersResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MsgCancelOrdersResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MsgCancelOrdersResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *MsgCancelOrdersResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgCancelOrdersResponse.Merge(m, src) -} -func (m *MsgCancelOrdersResponse) XXX_Size() int { - return m.Size() -} -func (m *MsgCancelOrdersResponse) XXX_DiscardUnknown() { - xxx_messageInfo_MsgCancelOrdersResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgCancelOrdersResponse proto.InternalMessageInfo - -type MsgRegisterContract struct { - Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` - Contract *ContractInfoV2 `protobuf:"bytes,2,opt,name=contract,proto3" json:"contract,omitempty"` -} - -func (m *MsgRegisterContract) Reset() { *m = MsgRegisterContract{} } -func (m *MsgRegisterContract) String() string { return proto.CompactTextString(m) } -func (*MsgRegisterContract) ProtoMessage() {} -func (*MsgRegisterContract) Descriptor() ([]byte, []int) { - return fileDescriptor_463701e671e5a5e0, []int{4} -} -func (m *MsgRegisterContract) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MsgRegisterContract) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MsgRegisterContract.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *MsgRegisterContract) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgRegisterContract.Merge(m, src) -} -func (m *MsgRegisterContract) XXX_Size() int { - return m.Size() -} -func (m *MsgRegisterContract) XXX_DiscardUnknown() { - xxx_messageInfo_MsgRegisterContract.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgRegisterContract proto.InternalMessageInfo - -func (m *MsgRegisterContract) GetCreator() string { - if m != nil { - return m.Creator - } - return "" -} - -func (m *MsgRegisterContract) GetContract() *ContractInfoV2 { - if m != nil { - return m.Contract - } - return nil -} - -type MsgRegisterContractResponse struct { -} - -func (m *MsgRegisterContractResponse) Reset() { *m = MsgRegisterContractResponse{} } -func (m *MsgRegisterContractResponse) String() string { return proto.CompactTextString(m) } -func (*MsgRegisterContractResponse) ProtoMessage() {} -func (*MsgRegisterContractResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_463701e671e5a5e0, []int{5} -} -func (m *MsgRegisterContractResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MsgRegisterContractResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MsgRegisterContractResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *MsgRegisterContractResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgRegisterContractResponse.Merge(m, src) -} -func (m *MsgRegisterContractResponse) XXX_Size() int { - return m.Size() -} -func (m *MsgRegisterContractResponse) XXX_DiscardUnknown() { - xxx_messageInfo_MsgRegisterContractResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgRegisterContractResponse proto.InternalMessageInfo - -type MsgContractDepositRent struct { - ContractAddr string `protobuf:"bytes,1,opt,name=contractAddr,proto3" json:"contract_address"` - Amount uint64 `protobuf:"varint,2,opt,name=amount,proto3" json:"amount"` - Sender string `protobuf:"bytes,3,opt,name=sender,proto3" json:"sender"` -} - -func (m *MsgContractDepositRent) Reset() { *m = MsgContractDepositRent{} } -func (m *MsgContractDepositRent) String() string { return proto.CompactTextString(m) } -func (*MsgContractDepositRent) ProtoMessage() {} -func (*MsgContractDepositRent) Descriptor() ([]byte, []int) { - return fileDescriptor_463701e671e5a5e0, []int{6} -} -func (m *MsgContractDepositRent) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MsgContractDepositRent) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MsgContractDepositRent.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *MsgContractDepositRent) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgContractDepositRent.Merge(m, src) -} -func (m *MsgContractDepositRent) XXX_Size() int { - return m.Size() -} -func (m *MsgContractDepositRent) XXX_DiscardUnknown() { - xxx_messageInfo_MsgContractDepositRent.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgContractDepositRent proto.InternalMessageInfo - -func (m *MsgContractDepositRent) GetContractAddr() string { - if m != nil { - return m.ContractAddr - } - return "" -} - -func (m *MsgContractDepositRent) GetAmount() uint64 { - if m != nil { - return m.Amount - } - return 0 -} - -func (m *MsgContractDepositRent) GetSender() string { - if m != nil { - return m.Sender - } - return "" -} - -type MsgContractDepositRentResponse struct { -} - -func (m *MsgContractDepositRentResponse) Reset() { *m = MsgContractDepositRentResponse{} } -func (m *MsgContractDepositRentResponse) String() string { return proto.CompactTextString(m) } -func (*MsgContractDepositRentResponse) ProtoMessage() {} -func (*MsgContractDepositRentResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_463701e671e5a5e0, []int{7} -} -func (m *MsgContractDepositRentResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MsgContractDepositRentResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MsgContractDepositRentResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *MsgContractDepositRentResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgContractDepositRentResponse.Merge(m, src) -} -func (m *MsgContractDepositRentResponse) XXX_Size() int { - return m.Size() -} -func (m *MsgContractDepositRentResponse) XXX_DiscardUnknown() { - xxx_messageInfo_MsgContractDepositRentResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgContractDepositRentResponse proto.InternalMessageInfo - -type MsgUnregisterContract struct { - Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator"` - ContractAddr string `protobuf:"bytes,2,opt,name=contractAddr,proto3" json:"contract_address"` -} - -func (m *MsgUnregisterContract) Reset() { *m = MsgUnregisterContract{} } -func (m *MsgUnregisterContract) String() string { return proto.CompactTextString(m) } -func (*MsgUnregisterContract) ProtoMessage() {} -func (*MsgUnregisterContract) Descriptor() ([]byte, []int) { - return fileDescriptor_463701e671e5a5e0, []int{8} -} -func (m *MsgUnregisterContract) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MsgUnregisterContract) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MsgUnregisterContract.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *MsgUnregisterContract) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgUnregisterContract.Merge(m, src) -} -func (m *MsgUnregisterContract) XXX_Size() int { - return m.Size() -} -func (m *MsgUnregisterContract) XXX_DiscardUnknown() { - xxx_messageInfo_MsgUnregisterContract.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgUnregisterContract proto.InternalMessageInfo - -func (m *MsgUnregisterContract) GetCreator() string { - if m != nil { - return m.Creator - } - return "" -} - -func (m *MsgUnregisterContract) GetContractAddr() string { - if m != nil { - return m.ContractAddr - } - return "" -} - -type MsgUnregisterContractResponse struct { -} - -func (m *MsgUnregisterContractResponse) Reset() { *m = MsgUnregisterContractResponse{} } -func (m *MsgUnregisterContractResponse) String() string { return proto.CompactTextString(m) } -func (*MsgUnregisterContractResponse) ProtoMessage() {} -func (*MsgUnregisterContractResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_463701e671e5a5e0, []int{9} -} -func (m *MsgUnregisterContractResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MsgUnregisterContractResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MsgUnregisterContractResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *MsgUnregisterContractResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgUnregisterContractResponse.Merge(m, src) -} -func (m *MsgUnregisterContractResponse) XXX_Size() int { - return m.Size() -} -func (m *MsgUnregisterContractResponse) XXX_DiscardUnknown() { - xxx_messageInfo_MsgUnregisterContractResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgUnregisterContractResponse proto.InternalMessageInfo - -type MsgRegisterPairs struct { - Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` - Batchcontractpair []BatchContractPair `protobuf:"bytes,3,rep,name=batchcontractpair,proto3" json:"batch_contract_pair" yaml:"batch_contract_pair"` -} - -func (m *MsgRegisterPairs) Reset() { *m = MsgRegisterPairs{} } -func (m *MsgRegisterPairs) String() string { return proto.CompactTextString(m) } -func (*MsgRegisterPairs) ProtoMessage() {} -func (*MsgRegisterPairs) Descriptor() ([]byte, []int) { - return fileDescriptor_463701e671e5a5e0, []int{10} -} -func (m *MsgRegisterPairs) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MsgRegisterPairs) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MsgRegisterPairs.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *MsgRegisterPairs) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgRegisterPairs.Merge(m, src) -} -func (m *MsgRegisterPairs) XXX_Size() int { - return m.Size() -} -func (m *MsgRegisterPairs) XXX_DiscardUnknown() { - xxx_messageInfo_MsgRegisterPairs.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgRegisterPairs proto.InternalMessageInfo - -func (m *MsgRegisterPairs) GetCreator() string { - if m != nil { - return m.Creator - } - return "" -} - -func (m *MsgRegisterPairs) GetBatchcontractpair() []BatchContractPair { - if m != nil { - return m.Batchcontractpair - } - return nil -} - -type MsgRegisterPairsResponse struct { -} - -func (m *MsgRegisterPairsResponse) Reset() { *m = MsgRegisterPairsResponse{} } -func (m *MsgRegisterPairsResponse) String() string { return proto.CompactTextString(m) } -func (*MsgRegisterPairsResponse) ProtoMessage() {} -func (*MsgRegisterPairsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_463701e671e5a5e0, []int{11} -} -func (m *MsgRegisterPairsResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MsgRegisterPairsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MsgRegisterPairsResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *MsgRegisterPairsResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgRegisterPairsResponse.Merge(m, src) -} -func (m *MsgRegisterPairsResponse) XXX_Size() int { - return m.Size() -} -func (m *MsgRegisterPairsResponse) XXX_DiscardUnknown() { - xxx_messageInfo_MsgRegisterPairsResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgRegisterPairsResponse proto.InternalMessageInfo - -type MsgUpdatePriceTickSize struct { - Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator"` - TickSizeList []TickSize `protobuf:"bytes,2,rep,name=tickSizeList,proto3" json:"tick_size_list" yaml:"tick_size_list"` -} - -func (m *MsgUpdatePriceTickSize) Reset() { *m = MsgUpdatePriceTickSize{} } -func (m *MsgUpdatePriceTickSize) String() string { return proto.CompactTextString(m) } -func (*MsgUpdatePriceTickSize) ProtoMessage() {} -func (*MsgUpdatePriceTickSize) Descriptor() ([]byte, []int) { - return fileDescriptor_463701e671e5a5e0, []int{12} -} -func (m *MsgUpdatePriceTickSize) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MsgUpdatePriceTickSize) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MsgUpdatePriceTickSize.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *MsgUpdatePriceTickSize) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgUpdatePriceTickSize.Merge(m, src) -} -func (m *MsgUpdatePriceTickSize) XXX_Size() int { - return m.Size() -} -func (m *MsgUpdatePriceTickSize) XXX_DiscardUnknown() { - xxx_messageInfo_MsgUpdatePriceTickSize.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgUpdatePriceTickSize proto.InternalMessageInfo - -func (m *MsgUpdatePriceTickSize) GetCreator() string { - if m != nil { - return m.Creator - } - return "" -} - -func (m *MsgUpdatePriceTickSize) GetTickSizeList() []TickSize { - if m != nil { - return m.TickSizeList - } - return nil -} - -type MsgUpdateQuantityTickSize struct { - Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator"` - TickSizeList []TickSize `protobuf:"bytes,2,rep,name=tickSizeList,proto3" json:"tick_size_list" yaml:"tick_size_list"` -} - -func (m *MsgUpdateQuantityTickSize) Reset() { *m = MsgUpdateQuantityTickSize{} } -func (m *MsgUpdateQuantityTickSize) String() string { return proto.CompactTextString(m) } -func (*MsgUpdateQuantityTickSize) ProtoMessage() {} -func (*MsgUpdateQuantityTickSize) Descriptor() ([]byte, []int) { - return fileDescriptor_463701e671e5a5e0, []int{13} -} -func (m *MsgUpdateQuantityTickSize) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MsgUpdateQuantityTickSize) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MsgUpdateQuantityTickSize.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *MsgUpdateQuantityTickSize) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgUpdateQuantityTickSize.Merge(m, src) -} -func (m *MsgUpdateQuantityTickSize) XXX_Size() int { - return m.Size() -} -func (m *MsgUpdateQuantityTickSize) XXX_DiscardUnknown() { - xxx_messageInfo_MsgUpdateQuantityTickSize.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgUpdateQuantityTickSize proto.InternalMessageInfo - -func (m *MsgUpdateQuantityTickSize) GetCreator() string { - if m != nil { - return m.Creator - } - return "" -} - -func (m *MsgUpdateQuantityTickSize) GetTickSizeList() []TickSize { - if m != nil { - return m.TickSizeList - } - return nil -} - -type MsgUpdateTickSizeResponse struct { -} - -func (m *MsgUpdateTickSizeResponse) Reset() { *m = MsgUpdateTickSizeResponse{} } -func (m *MsgUpdateTickSizeResponse) String() string { return proto.CompactTextString(m) } -func (*MsgUpdateTickSizeResponse) ProtoMessage() {} -func (*MsgUpdateTickSizeResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_463701e671e5a5e0, []int{14} -} -func (m *MsgUpdateTickSizeResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MsgUpdateTickSizeResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MsgUpdateTickSizeResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *MsgUpdateTickSizeResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgUpdateTickSizeResponse.Merge(m, src) -} -func (m *MsgUpdateTickSizeResponse) XXX_Size() int { - return m.Size() -} -func (m *MsgUpdateTickSizeResponse) XXX_DiscardUnknown() { - xxx_messageInfo_MsgUpdateTickSizeResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgUpdateTickSizeResponse proto.InternalMessageInfo - -type MsgUnsuspendContract struct { - Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator"` - ContractAddr string `protobuf:"bytes,2,opt,name=contractAddr,proto3" json:"contract_address"` -} - -func (m *MsgUnsuspendContract) Reset() { *m = MsgUnsuspendContract{} } -func (m *MsgUnsuspendContract) String() string { return proto.CompactTextString(m) } -func (*MsgUnsuspendContract) ProtoMessage() {} -func (*MsgUnsuspendContract) Descriptor() ([]byte, []int) { - return fileDescriptor_463701e671e5a5e0, []int{15} -} -func (m *MsgUnsuspendContract) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MsgUnsuspendContract) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MsgUnsuspendContract.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *MsgUnsuspendContract) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgUnsuspendContract.Merge(m, src) -} -func (m *MsgUnsuspendContract) XXX_Size() int { - return m.Size() -} -func (m *MsgUnsuspendContract) XXX_DiscardUnknown() { - xxx_messageInfo_MsgUnsuspendContract.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgUnsuspendContract proto.InternalMessageInfo - -func (m *MsgUnsuspendContract) GetCreator() string { - if m != nil { - return m.Creator - } - return "" -} - -func (m *MsgUnsuspendContract) GetContractAddr() string { - if m != nil { - return m.ContractAddr - } - return "" -} - -type MsgUnsuspendContractResponse struct { -} - -func (m *MsgUnsuspendContractResponse) Reset() { *m = MsgUnsuspendContractResponse{} } -func (m *MsgUnsuspendContractResponse) String() string { return proto.CompactTextString(m) } -func (*MsgUnsuspendContractResponse) ProtoMessage() {} -func (*MsgUnsuspendContractResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_463701e671e5a5e0, []int{16} -} -func (m *MsgUnsuspendContractResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MsgUnsuspendContractResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MsgUnsuspendContractResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *MsgUnsuspendContractResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgUnsuspendContractResponse.Merge(m, src) -} -func (m *MsgUnsuspendContractResponse) XXX_Size() int { - return m.Size() -} -func (m *MsgUnsuspendContractResponse) XXX_DiscardUnknown() { - xxx_messageInfo_MsgUnsuspendContractResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgUnsuspendContractResponse proto.InternalMessageInfo - -func init() { - proto.RegisterType((*MsgPlaceOrders)(nil), "seiprotocol.seichain.dex.MsgPlaceOrders") - proto.RegisterType((*MsgPlaceOrdersResponse)(nil), "seiprotocol.seichain.dex.MsgPlaceOrdersResponse") - proto.RegisterType((*MsgCancelOrders)(nil), "seiprotocol.seichain.dex.MsgCancelOrders") - proto.RegisterType((*MsgCancelOrdersResponse)(nil), "seiprotocol.seichain.dex.MsgCancelOrdersResponse") - proto.RegisterType((*MsgRegisterContract)(nil), "seiprotocol.seichain.dex.MsgRegisterContract") - proto.RegisterType((*MsgRegisterContractResponse)(nil), "seiprotocol.seichain.dex.MsgRegisterContractResponse") - proto.RegisterType((*MsgContractDepositRent)(nil), "seiprotocol.seichain.dex.MsgContractDepositRent") - proto.RegisterType((*MsgContractDepositRentResponse)(nil), "seiprotocol.seichain.dex.MsgContractDepositRentResponse") - proto.RegisterType((*MsgUnregisterContract)(nil), "seiprotocol.seichain.dex.MsgUnregisterContract") - proto.RegisterType((*MsgUnregisterContractResponse)(nil), "seiprotocol.seichain.dex.MsgUnregisterContractResponse") - proto.RegisterType((*MsgRegisterPairs)(nil), "seiprotocol.seichain.dex.MsgRegisterPairs") - proto.RegisterType((*MsgRegisterPairsResponse)(nil), "seiprotocol.seichain.dex.MsgRegisterPairsResponse") - proto.RegisterType((*MsgUpdatePriceTickSize)(nil), "seiprotocol.seichain.dex.MsgUpdatePriceTickSize") - proto.RegisterType((*MsgUpdateQuantityTickSize)(nil), "seiprotocol.seichain.dex.MsgUpdateQuantityTickSize") - proto.RegisterType((*MsgUpdateTickSizeResponse)(nil), "seiprotocol.seichain.dex.MsgUpdateTickSizeResponse") - proto.RegisterType((*MsgUnsuspendContract)(nil), "seiprotocol.seichain.dex.MsgUnsuspendContract") - proto.RegisterType((*MsgUnsuspendContractResponse)(nil), "seiprotocol.seichain.dex.MsgUnsuspendContractResponse") -} - -func init() { proto.RegisterFile("dex/tx.proto", fileDescriptor_463701e671e5a5e0) } - -var fileDescriptor_463701e671e5a5e0 = []byte{ - // 962 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x57, 0x41, 0x6f, 0xe3, 0x44, - 0x14, 0xae, 0x9b, 0x52, 0xba, 0xaf, 0xdd, 0x6e, 0xeb, 0x74, 0x17, 0xd7, 0xcb, 0xda, 0xc1, 0x12, - 0x28, 0x80, 0x6a, 0xd3, 0xac, 0x80, 0x05, 0x89, 0x03, 0xc9, 0x4a, 0x68, 0x25, 0x22, 0x8a, 0x61, - 0x41, 0xe2, 0x12, 0x39, 0xf6, 0xac, 0x3b, 0x34, 0xf5, 0x44, 0x9e, 0x09, 0x9b, 0x2e, 0x08, 0x09, - 0x7e, 0x01, 0x07, 0x4e, 0x1c, 0x39, 0xf2, 0x0b, 0x90, 0x38, 0x72, 0xd9, 0x0b, 0xd2, 0x4a, 0x5c, - 0x38, 0x19, 0xd4, 0xde, 0x72, 0xec, 0x2f, 0x40, 0x1e, 0xdb, 0x43, 0xec, 0x38, 0xc1, 0xd9, 0x03, - 0x12, 0x27, 0x8f, 0x5f, 0xde, 0xf7, 0xbe, 0xf7, 0xbe, 0x37, 0xf3, 0xc6, 0x81, 0x2d, 0x0f, 0x8d, - 0x2d, 0x36, 0x36, 0x87, 0x21, 0x61, 0x44, 0x56, 0x28, 0xc2, 0x7c, 0xe5, 0x92, 0x81, 0x49, 0x11, - 0x76, 0x8f, 0x1d, 0x1c, 0x98, 0x1e, 0x1a, 0xab, 0x9a, 0x4b, 0xe8, 0x29, 0xa1, 0x56, 0xdf, 0xa1, - 0xc8, 0xfa, 0xe2, 0xb0, 0x8f, 0x98, 0x73, 0x68, 0xb9, 0x04, 0x07, 0x09, 0x52, 0xdd, 0xf3, 0x89, - 0x4f, 0xf8, 0xd2, 0x8a, 0x57, 0xa9, 0x55, 0x8e, 0xa3, 0xbb, 0x24, 0x60, 0xa1, 0xe3, 0xb2, 0xd4, - 0x76, 0x2d, 0xb6, 0x91, 0xd0, 0x43, 0x61, 0x6a, 0xd8, 0x8e, 0x0d, 0x43, 0x07, 0x67, 0xef, 0x75, - 0x9e, 0x12, 0x76, 0x4f, 0x7a, 0x14, 0x3f, 0x42, 0x89, 0xd1, 0xf8, 0x71, 0x15, 0xb6, 0xbb, 0xd4, - 0x3f, 0x1a, 0x38, 0x2e, 0xfa, 0x20, 0x06, 0x53, 0xf9, 0x45, 0x78, 0xd6, 0x0d, 0x91, 0xc3, 0x48, - 0xa8, 0x48, 0x0d, 0xa9, 0x79, 0xa5, 0xbd, 0x39, 0x89, 0xf4, 0xcc, 0x64, 0x67, 0x0b, 0xb9, 0x03, - 0xeb, 0x9c, 0x8d, 0x2a, 0xab, 0x8d, 0x5a, 0x73, 0xb3, 0xa5, 0x9b, 0xf3, 0x8a, 0x34, 0x79, 0xe0, - 0x36, 0x4c, 0x22, 0x3d, 0x85, 0xd8, 0xe9, 0x53, 0xbe, 0x03, 0x5b, 0x59, 0x19, 0xef, 0x7a, 0x5e, - 0xa8, 0xd4, 0x38, 0xe1, 0xde, 0x24, 0xd2, 0x77, 0x32, 0x7b, 0xcf, 0xf1, 0xbc, 0x10, 0x51, 0x6a, - 0xe7, 0x3c, 0xe5, 0xcf, 0xe1, 0x99, 0x07, 0xa3, 0xc0, 0xa3, 0xca, 0x1a, 0x67, 0xdf, 0x37, 0x13, - 0x21, 0xcd, 0x58, 0x48, 0x33, 0x15, 0xd2, 0xec, 0x10, 0x1c, 0xb4, 0xdf, 0x7a, 0x1c, 0xe9, 0x2b, - 0x93, 0x48, 0x4f, 0xfc, 0x7f, 0xfa, 0x53, 0x6f, 0xfa, 0x98, 0x1d, 0x8f, 0xfa, 0xa6, 0x4b, 0x4e, - 0xad, 0x54, 0xfe, 0xe4, 0x71, 0x40, 0xbd, 0x13, 0x8b, 0x9d, 0x0d, 0x11, 0xe5, 0x48, 0x6a, 0x27, - 0x10, 0xe3, 0x53, 0xb8, 0x91, 0xd7, 0xc8, 0x46, 0x74, 0x48, 0x02, 0x8a, 0xe4, 0x77, 0x60, 0x83, - 0x57, 0x72, 0xcf, 0xa3, 0x8a, 0xd4, 0xa8, 0x35, 0xd7, 0xda, 0x2f, 0x4c, 0x22, 0xfd, 0x0a, 0xb7, - 0xf5, 0xb0, 0x47, 0x2f, 0x23, 0x7d, 0xe7, 0xcc, 0x39, 0x1d, 0xbc, 0x6d, 0x08, 0x93, 0x61, 0x0b, - 0x88, 0xf1, 0xbb, 0x04, 0xd7, 0xba, 0xd4, 0xef, 0x38, 0x81, 0x8b, 0x06, 0xcb, 0xc9, 0xdf, 0x83, - 0xab, 0x2e, 0x87, 0x0d, 0x1c, 0x86, 0x49, 0x90, 0x75, 0xe1, 0xa5, 0xf9, 0x5d, 0xe8, 0x4c, 0xb9, - 0xb7, 0x77, 0x27, 0x91, 0x9e, 0x0f, 0x60, 0xe7, 0x5f, 0x9f, 0xbe, 0x35, 0xc6, 0x3e, 0x3c, 0x57, - 0x28, 0x2a, 0xd3, 0xcb, 0x18, 0x41, 0xbd, 0x4b, 0x7d, 0x1b, 0xf9, 0x98, 0x32, 0x14, 0x76, 0x52, - 0x94, 0xac, 0x14, 0x6a, 0xfe, 0xa7, 0xcc, 0xbb, 0xb0, 0x91, 0xc5, 0x56, 0x56, 0x1b, 0x52, 0x73, - 0xb3, 0xd5, 0x5c, 0x50, 0x61, 0xea, 0x79, 0x2f, 0x78, 0x40, 0x3e, 0x69, 0xd9, 0x02, 0x69, 0xdc, - 0x82, 0x9b, 0x25, 0xb4, 0x22, 0xab, 0x1f, 0x24, 0xde, 0xe0, 0xcc, 0x7e, 0x17, 0x0d, 0x09, 0xc5, - 0xcc, 0x46, 0x01, 0x9b, 0x51, 0x41, 0xaa, 0xbc, 0x41, 0x0d, 0x58, 0x77, 0x4e, 0xc9, 0x28, 0x48, - 0xf2, 0x5e, 0x4b, 0xb6, 0x7f, 0x62, 0xb1, 0xd3, 0x67, 0xec, 0x43, 0x51, 0xe0, 0xa1, 0x4c, 0x5d, - 0xee, 0x93, 0x58, 0xec, 0xf4, 0x69, 0x34, 0x40, 0x2b, 0xcf, 0x4d, 0xa4, 0x3f, 0x86, 0xeb, 0x5d, - 0xea, 0xdf, 0x0f, 0xc2, 0xa2, 0xac, 0x15, 0xb7, 0x52, 0xb1, 0xc6, 0xd5, 0xca, 0x9d, 0xd6, 0xe1, - 0x56, 0x29, 0xb3, 0x48, 0xed, 0x57, 0x09, 0x76, 0xa6, 0x94, 0x3f, 0x72, 0x70, 0x48, 0x17, 0x74, - 0xfb, 0x7b, 0x09, 0x76, 0xfb, 0x0e, 0x73, 0x8f, 0x33, 0x96, 0x78, 0x7c, 0x29, 0x35, 0xbe, 0xb3, - 0x5f, 0x9d, 0xdf, 0xf7, 0x76, 0x0c, 0xc9, 0xb8, 0x63, 0x0e, 0x71, 0xe6, 0xeb, 0x3c, 0x5a, 0x4f, - 0x94, 0x11, 0xc7, 0xbb, 0x8c, 0x74, 0x35, 0x39, 0x93, 0x25, 0x3f, 0x1a, 0xf6, 0x6c, 0x02, 0x86, - 0x0a, 0x4a, 0xb1, 0x08, 0x51, 0xe1, 0xcf, 0xc9, 0xde, 0xb9, 0x3f, 0xf4, 0x1c, 0x86, 0x8e, 0x42, - 0xec, 0xa2, 0x8f, 0xb1, 0x7b, 0xf2, 0x11, 0x7e, 0x84, 0xaa, 0xca, 0xff, 0x10, 0xb6, 0x58, 0x0a, - 0x79, 0x1f, 0x53, 0x96, 0x1e, 0x64, 0x63, 0x7e, 0xb9, 0x19, 0x41, 0xdb, 0x4a, 0xab, 0xdc, 0x16, - 0x53, 0xbd, 0x37, 0xc0, 0x94, 0x5d, 0x46, 0xfa, 0xf5, 0xa4, 0xc0, 0xbc, 0xdd, 0xb0, 0x73, 0x44, - 0xc6, 0x2f, 0x12, 0xec, 0x8b, 0xd4, 0x3f, 0x1c, 0x39, 0x01, 0xc3, 0xec, 0xec, 0x7f, 0x93, 0xfd, - 0xcd, 0xa9, 0xe4, 0xb3, 0x98, 0xa2, 0x2b, 0x0f, 0x61, 0x8f, 0x6f, 0x4c, 0x3a, 0xa2, 0x43, 0x14, - 0x78, 0xff, 0xdd, 0x89, 0xd0, 0xe0, 0xf9, 0x32, 0xe2, 0x2c, 0xb1, 0xd6, 0x6f, 0x1b, 0x50, 0xeb, - 0x52, 0x5f, 0xc6, 0xb0, 0x39, 0x7d, 0xe7, 0x2e, 0x18, 0x6a, 0xf9, 0x9b, 0x47, 0x7d, 0xad, 0xaa, - 0xa7, 0xb8, 0xa3, 0x06, 0xb0, 0x95, 0xbb, 0x60, 0x5e, 0x5e, 0x18, 0x61, 0xda, 0x55, 0x3d, 0xac, - 0xec, 0x2a, 0xd8, 0xc6, 0xb0, 0x33, 0x33, 0xde, 0x0f, 0x16, 0x86, 0x29, 0xba, 0xab, 0xaf, 0x2f, - 0xe5, 0x2e, 0x98, 0xbf, 0x91, 0xa0, 0x5e, 0x36, 0xc2, 0x17, 0x2b, 0x56, 0x82, 0x50, 0xef, 0x2c, - 0x8b, 0x10, 0x39, 0x7c, 0x0d, 0x72, 0xc9, 0x1c, 0xb6, 0x16, 0xc6, 0x9b, 0x05, 0xa8, 0x6f, 0x2e, - 0x09, 0x10, 0xfc, 0x04, 0xae, 0xe6, 0x67, 0xed, 0x2b, 0x95, 0xb4, 0xe4, 0xbe, 0x6a, 0xab, 0xba, - 0xaf, 0x20, 0xfc, 0x0a, 0xea, 0x65, 0xa3, 0x6f, 0xb1, 0xe6, 0x25, 0x08, 0xf5, 0x76, 0x05, 0x44, - 0xf1, 0x98, 0xcb, 0xdf, 0x4a, 0x70, 0x63, 0xce, 0xf8, 0xaa, 0x12, 0xaf, 0x08, 0x7a, 0xba, 0x24, - 0xbe, 0x84, 0xdd, 0xd9, 0x41, 0x63, 0xfe, 0x4b, 0x07, 0x0b, 0xfe, 0xea, 0x1b, 0xcb, 0xf9, 0x67, - 0xe4, 0xed, 0xf7, 0x1e, 0x9f, 0x6b, 0xd2, 0x93, 0x73, 0x4d, 0xfa, 0xeb, 0x5c, 0x93, 0xbe, 0xbb, - 0xd0, 0x56, 0x9e, 0x5c, 0x68, 0x2b, 0x7f, 0x5c, 0x68, 0x2b, 0x9f, 0x1d, 0x4c, 0x7d, 0xe5, 0x52, - 0x84, 0x0f, 0xb2, 0xe0, 0xfc, 0x85, 0x47, 0xb7, 0xc6, 0x16, 0xff, 0x4b, 0x10, 0x7f, 0xf0, 0xf6, - 0xd7, 0xf9, 0xef, 0xb7, 0xff, 0x0e, 0x00, 0x00, 0xff, 0xff, 0x87, 0xb0, 0xd3, 0x48, 0xb9, 0x0c, - 0x00, 0x00, -} - -// Reference imports to suppress errors if they are not otherwise used. -var _ context.Context -var _ grpc.ClientConn - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion4 - -// MsgClient is the client API for Msg service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. -type MsgClient interface { - PlaceOrders(ctx context.Context, in *MsgPlaceOrders, opts ...grpc.CallOption) (*MsgPlaceOrdersResponse, error) - CancelOrders(ctx context.Context, in *MsgCancelOrders, opts ...grpc.CallOption) (*MsgCancelOrdersResponse, error) - RegisterContract(ctx context.Context, in *MsgRegisterContract, opts ...grpc.CallOption) (*MsgRegisterContractResponse, error) - ContractDepositRent(ctx context.Context, in *MsgContractDepositRent, opts ...grpc.CallOption) (*MsgContractDepositRentResponse, error) - UnregisterContract(ctx context.Context, in *MsgUnregisterContract, opts ...grpc.CallOption) (*MsgUnregisterContractResponse, error) - RegisterPairs(ctx context.Context, in *MsgRegisterPairs, opts ...grpc.CallOption) (*MsgRegisterPairsResponse, error) - UpdatePriceTickSize(ctx context.Context, in *MsgUpdatePriceTickSize, opts ...grpc.CallOption) (*MsgUpdateTickSizeResponse, error) - UpdateQuantityTickSize(ctx context.Context, in *MsgUpdateQuantityTickSize, opts ...grpc.CallOption) (*MsgUpdateTickSizeResponse, error) - UnsuspendContract(ctx context.Context, in *MsgUnsuspendContract, opts ...grpc.CallOption) (*MsgUnsuspendContractResponse, error) -} - -type msgClient struct { - cc grpc1.ClientConn -} - -func NewMsgClient(cc grpc1.ClientConn) MsgClient { - return &msgClient{cc} -} - -func (c *msgClient) PlaceOrders(ctx context.Context, in *MsgPlaceOrders, opts ...grpc.CallOption) (*MsgPlaceOrdersResponse, error) { - out := new(MsgPlaceOrdersResponse) - err := c.cc.Invoke(ctx, "/seiprotocol.seichain.dex.Msg/PlaceOrders", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *msgClient) CancelOrders(ctx context.Context, in *MsgCancelOrders, opts ...grpc.CallOption) (*MsgCancelOrdersResponse, error) { - out := new(MsgCancelOrdersResponse) - err := c.cc.Invoke(ctx, "/seiprotocol.seichain.dex.Msg/CancelOrders", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *msgClient) RegisterContract(ctx context.Context, in *MsgRegisterContract, opts ...grpc.CallOption) (*MsgRegisterContractResponse, error) { - out := new(MsgRegisterContractResponse) - err := c.cc.Invoke(ctx, "/seiprotocol.seichain.dex.Msg/RegisterContract", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *msgClient) ContractDepositRent(ctx context.Context, in *MsgContractDepositRent, opts ...grpc.CallOption) (*MsgContractDepositRentResponse, error) { - out := new(MsgContractDepositRentResponse) - err := c.cc.Invoke(ctx, "/seiprotocol.seichain.dex.Msg/ContractDepositRent", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *msgClient) UnregisterContract(ctx context.Context, in *MsgUnregisterContract, opts ...grpc.CallOption) (*MsgUnregisterContractResponse, error) { - out := new(MsgUnregisterContractResponse) - err := c.cc.Invoke(ctx, "/seiprotocol.seichain.dex.Msg/UnregisterContract", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *msgClient) RegisterPairs(ctx context.Context, in *MsgRegisterPairs, opts ...grpc.CallOption) (*MsgRegisterPairsResponse, error) { - out := new(MsgRegisterPairsResponse) - err := c.cc.Invoke(ctx, "/seiprotocol.seichain.dex.Msg/RegisterPairs", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *msgClient) UpdatePriceTickSize(ctx context.Context, in *MsgUpdatePriceTickSize, opts ...grpc.CallOption) (*MsgUpdateTickSizeResponse, error) { - out := new(MsgUpdateTickSizeResponse) - err := c.cc.Invoke(ctx, "/seiprotocol.seichain.dex.Msg/UpdatePriceTickSize", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *msgClient) UpdateQuantityTickSize(ctx context.Context, in *MsgUpdateQuantityTickSize, opts ...grpc.CallOption) (*MsgUpdateTickSizeResponse, error) { - out := new(MsgUpdateTickSizeResponse) - err := c.cc.Invoke(ctx, "/seiprotocol.seichain.dex.Msg/UpdateQuantityTickSize", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *msgClient) UnsuspendContract(ctx context.Context, in *MsgUnsuspendContract, opts ...grpc.CallOption) (*MsgUnsuspendContractResponse, error) { - out := new(MsgUnsuspendContractResponse) - err := c.cc.Invoke(ctx, "/seiprotocol.seichain.dex.Msg/UnsuspendContract", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// MsgServer is the server API for Msg service. -type MsgServer interface { - PlaceOrders(context.Context, *MsgPlaceOrders) (*MsgPlaceOrdersResponse, error) - CancelOrders(context.Context, *MsgCancelOrders) (*MsgCancelOrdersResponse, error) - RegisterContract(context.Context, *MsgRegisterContract) (*MsgRegisterContractResponse, error) - ContractDepositRent(context.Context, *MsgContractDepositRent) (*MsgContractDepositRentResponse, error) - UnregisterContract(context.Context, *MsgUnregisterContract) (*MsgUnregisterContractResponse, error) - RegisterPairs(context.Context, *MsgRegisterPairs) (*MsgRegisterPairsResponse, error) - UpdatePriceTickSize(context.Context, *MsgUpdatePriceTickSize) (*MsgUpdateTickSizeResponse, error) - UpdateQuantityTickSize(context.Context, *MsgUpdateQuantityTickSize) (*MsgUpdateTickSizeResponse, error) - UnsuspendContract(context.Context, *MsgUnsuspendContract) (*MsgUnsuspendContractResponse, error) -} - -// UnimplementedMsgServer can be embedded to have forward compatible implementations. -type UnimplementedMsgServer struct { -} - -func (*UnimplementedMsgServer) PlaceOrders(ctx context.Context, req *MsgPlaceOrders) (*MsgPlaceOrdersResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method PlaceOrders not implemented") -} -func (*UnimplementedMsgServer) CancelOrders(ctx context.Context, req *MsgCancelOrders) (*MsgCancelOrdersResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method CancelOrders not implemented") -} -func (*UnimplementedMsgServer) RegisterContract(ctx context.Context, req *MsgRegisterContract) (*MsgRegisterContractResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method RegisterContract not implemented") -} -func (*UnimplementedMsgServer) ContractDepositRent(ctx context.Context, req *MsgContractDepositRent) (*MsgContractDepositRentResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method ContractDepositRent not implemented") -} -func (*UnimplementedMsgServer) UnregisterContract(ctx context.Context, req *MsgUnregisterContract) (*MsgUnregisterContractResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method UnregisterContract not implemented") -} -func (*UnimplementedMsgServer) RegisterPairs(ctx context.Context, req *MsgRegisterPairs) (*MsgRegisterPairsResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method RegisterPairs not implemented") -} -func (*UnimplementedMsgServer) UpdatePriceTickSize(ctx context.Context, req *MsgUpdatePriceTickSize) (*MsgUpdateTickSizeResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method UpdatePriceTickSize not implemented") -} -func (*UnimplementedMsgServer) UpdateQuantityTickSize(ctx context.Context, req *MsgUpdateQuantityTickSize) (*MsgUpdateTickSizeResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method UpdateQuantityTickSize not implemented") -} -func (*UnimplementedMsgServer) UnsuspendContract(ctx context.Context, req *MsgUnsuspendContract) (*MsgUnsuspendContractResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method UnsuspendContract not implemented") -} - -func RegisterMsgServer(s grpc1.Server, srv MsgServer) { - s.RegisterService(&_Msg_serviceDesc, srv) -} - -func _Msg_PlaceOrders_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MsgPlaceOrders) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).PlaceOrders(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/seiprotocol.seichain.dex.Msg/PlaceOrders", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).PlaceOrders(ctx, req.(*MsgPlaceOrders)) - } - return interceptor(ctx, in, info, handler) -} - -func _Msg_CancelOrders_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MsgCancelOrders) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).CancelOrders(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/seiprotocol.seichain.dex.Msg/CancelOrders", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).CancelOrders(ctx, req.(*MsgCancelOrders)) - } - return interceptor(ctx, in, info, handler) -} - -func _Msg_RegisterContract_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MsgRegisterContract) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).RegisterContract(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/seiprotocol.seichain.dex.Msg/RegisterContract", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).RegisterContract(ctx, req.(*MsgRegisterContract)) - } - return interceptor(ctx, in, info, handler) -} - -func _Msg_ContractDepositRent_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MsgContractDepositRent) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).ContractDepositRent(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/seiprotocol.seichain.dex.Msg/ContractDepositRent", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).ContractDepositRent(ctx, req.(*MsgContractDepositRent)) - } - return interceptor(ctx, in, info, handler) -} - -func _Msg_UnregisterContract_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MsgUnregisterContract) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).UnregisterContract(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/seiprotocol.seichain.dex.Msg/UnregisterContract", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).UnregisterContract(ctx, req.(*MsgUnregisterContract)) - } - return interceptor(ctx, in, info, handler) -} - -func _Msg_RegisterPairs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MsgRegisterPairs) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).RegisterPairs(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/seiprotocol.seichain.dex.Msg/RegisterPairs", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).RegisterPairs(ctx, req.(*MsgRegisterPairs)) - } - return interceptor(ctx, in, info, handler) -} - -func _Msg_UpdatePriceTickSize_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MsgUpdatePriceTickSize) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).UpdatePriceTickSize(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/seiprotocol.seichain.dex.Msg/UpdatePriceTickSize", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).UpdatePriceTickSize(ctx, req.(*MsgUpdatePriceTickSize)) - } - return interceptor(ctx, in, info, handler) -} - -func _Msg_UpdateQuantityTickSize_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MsgUpdateQuantityTickSize) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).UpdateQuantityTickSize(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/seiprotocol.seichain.dex.Msg/UpdateQuantityTickSize", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).UpdateQuantityTickSize(ctx, req.(*MsgUpdateQuantityTickSize)) - } - return interceptor(ctx, in, info, handler) -} - -func _Msg_UnsuspendContract_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MsgUnsuspendContract) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).UnsuspendContract(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/seiprotocol.seichain.dex.Msg/UnsuspendContract", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).UnsuspendContract(ctx, req.(*MsgUnsuspendContract)) - } - return interceptor(ctx, in, info, handler) -} - -var _Msg_serviceDesc = grpc.ServiceDesc{ - ServiceName: "seiprotocol.seichain.dex.Msg", - HandlerType: (*MsgServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "PlaceOrders", - Handler: _Msg_PlaceOrders_Handler, - }, - { - MethodName: "CancelOrders", - Handler: _Msg_CancelOrders_Handler, - }, - { - MethodName: "RegisterContract", - Handler: _Msg_RegisterContract_Handler, - }, - { - MethodName: "ContractDepositRent", - Handler: _Msg_ContractDepositRent_Handler, - }, - { - MethodName: "UnregisterContract", - Handler: _Msg_UnregisterContract_Handler, - }, - { - MethodName: "RegisterPairs", - Handler: _Msg_RegisterPairs_Handler, - }, - { - MethodName: "UpdatePriceTickSize", - Handler: _Msg_UpdatePriceTickSize_Handler, - }, - { - MethodName: "UpdateQuantityTickSize", - Handler: _Msg_UpdateQuantityTickSize_Handler, - }, - { - MethodName: "UnsuspendContract", - Handler: _Msg_UnsuspendContract_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "dex/tx.proto", -} - -func (m *MsgPlaceOrders) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *MsgPlaceOrders) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgPlaceOrders) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Funds) > 0 { - for iNdEx := len(m.Funds) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Funds[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTx(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x22 - } - } - if len(m.ContractAddr) > 0 { - i -= len(m.ContractAddr) - copy(dAtA[i:], m.ContractAddr) - i = encodeVarintTx(dAtA, i, uint64(len(m.ContractAddr))) - i-- - dAtA[i] = 0x1a - } - if len(m.Orders) > 0 { - for iNdEx := len(m.Orders) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Orders[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTx(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - } - } - if len(m.Creator) > 0 { - i -= len(m.Creator) - copy(dAtA[i:], m.Creator) - i = encodeVarintTx(dAtA, i, uint64(len(m.Creator))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *MsgPlaceOrdersResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *MsgPlaceOrdersResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgPlaceOrdersResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.OrderIds) > 0 { - dAtA2 := make([]byte, len(m.OrderIds)*10) - var j1 int - for _, num := range m.OrderIds { - for num >= 1<<7 { - dAtA2[j1] = uint8(uint64(num)&0x7f | 0x80) - num >>= 7 - j1++ - } - dAtA2[j1] = uint8(num) - j1++ - } - i -= j1 - copy(dAtA[i:], dAtA2[:j1]) - i = encodeVarintTx(dAtA, i, uint64(j1)) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *MsgCancelOrders) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *MsgCancelOrders) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgCancelOrders) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.ContractAddr) > 0 { - i -= len(m.ContractAddr) - copy(dAtA[i:], m.ContractAddr) - i = encodeVarintTx(dAtA, i, uint64(len(m.ContractAddr))) - i-- - dAtA[i] = 0x1a - } - if len(m.Cancellations) > 0 { - for iNdEx := len(m.Cancellations) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Cancellations[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTx(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - } - } - if len(m.Creator) > 0 { - i -= len(m.Creator) - copy(dAtA[i:], m.Creator) - i = encodeVarintTx(dAtA, i, uint64(len(m.Creator))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *MsgCancelOrdersResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *MsgCancelOrdersResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgCancelOrdersResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - return len(dAtA) - i, nil -} - -func (m *MsgRegisterContract) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *MsgRegisterContract) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgRegisterContract) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Contract != nil { - { - size, err := m.Contract.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTx(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - } - if len(m.Creator) > 0 { - i -= len(m.Creator) - copy(dAtA[i:], m.Creator) - i = encodeVarintTx(dAtA, i, uint64(len(m.Creator))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *MsgRegisterContractResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *MsgRegisterContractResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgRegisterContractResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - return len(dAtA) - i, nil -} - -func (m *MsgContractDepositRent) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *MsgContractDepositRent) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgContractDepositRent) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Sender) > 0 { - i -= len(m.Sender) - copy(dAtA[i:], m.Sender) - i = encodeVarintTx(dAtA, i, uint64(len(m.Sender))) - i-- - dAtA[i] = 0x1a - } - if m.Amount != 0 { - i = encodeVarintTx(dAtA, i, uint64(m.Amount)) - i-- - dAtA[i] = 0x10 - } - if len(m.ContractAddr) > 0 { - i -= len(m.ContractAddr) - copy(dAtA[i:], m.ContractAddr) - i = encodeVarintTx(dAtA, i, uint64(len(m.ContractAddr))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *MsgContractDepositRentResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *MsgContractDepositRentResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgContractDepositRentResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - return len(dAtA) - i, nil -} - -func (m *MsgUnregisterContract) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *MsgUnregisterContract) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgUnregisterContract) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.ContractAddr) > 0 { - i -= len(m.ContractAddr) - copy(dAtA[i:], m.ContractAddr) - i = encodeVarintTx(dAtA, i, uint64(len(m.ContractAddr))) - i-- - dAtA[i] = 0x12 - } - if len(m.Creator) > 0 { - i -= len(m.Creator) - copy(dAtA[i:], m.Creator) - i = encodeVarintTx(dAtA, i, uint64(len(m.Creator))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *MsgUnregisterContractResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *MsgUnregisterContractResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgUnregisterContractResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - return len(dAtA) - i, nil -} - -func (m *MsgRegisterPairs) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *MsgRegisterPairs) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgRegisterPairs) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Batchcontractpair) > 0 { - for iNdEx := len(m.Batchcontractpair) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Batchcontractpair[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTx(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x1a - } - } - if len(m.Creator) > 0 { - i -= len(m.Creator) - copy(dAtA[i:], m.Creator) - i = encodeVarintTx(dAtA, i, uint64(len(m.Creator))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *MsgRegisterPairsResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *MsgRegisterPairsResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgRegisterPairsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - return len(dAtA) - i, nil -} - -func (m *MsgUpdatePriceTickSize) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *MsgUpdatePriceTickSize) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgUpdatePriceTickSize) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.TickSizeList) > 0 { - for iNdEx := len(m.TickSizeList) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.TickSizeList[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTx(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - } - } - if len(m.Creator) > 0 { - i -= len(m.Creator) - copy(dAtA[i:], m.Creator) - i = encodeVarintTx(dAtA, i, uint64(len(m.Creator))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *MsgUpdateQuantityTickSize) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *MsgUpdateQuantityTickSize) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgUpdateQuantityTickSize) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.TickSizeList) > 0 { - for iNdEx := len(m.TickSizeList) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.TickSizeList[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTx(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - } - } - if len(m.Creator) > 0 { - i -= len(m.Creator) - copy(dAtA[i:], m.Creator) - i = encodeVarintTx(dAtA, i, uint64(len(m.Creator))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *MsgUpdateTickSizeResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *MsgUpdateTickSizeResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgUpdateTickSizeResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - return len(dAtA) - i, nil -} - -func (m *MsgUnsuspendContract) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *MsgUnsuspendContract) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgUnsuspendContract) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.ContractAddr) > 0 { - i -= len(m.ContractAddr) - copy(dAtA[i:], m.ContractAddr) - i = encodeVarintTx(dAtA, i, uint64(len(m.ContractAddr))) - i-- - dAtA[i] = 0x12 - } - if len(m.Creator) > 0 { - i -= len(m.Creator) - copy(dAtA[i:], m.Creator) - i = encodeVarintTx(dAtA, i, uint64(len(m.Creator))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *MsgUnsuspendContractResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *MsgUnsuspendContractResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgUnsuspendContractResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - return len(dAtA) - i, nil -} - -func encodeVarintTx(dAtA []byte, offset int, v uint64) int { - offset -= sovTx(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *MsgPlaceOrders) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Creator) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - if len(m.Orders) > 0 { - for _, e := range m.Orders { - l = e.Size() - n += 1 + l + sovTx(uint64(l)) - } - } - l = len(m.ContractAddr) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - if len(m.Funds) > 0 { - for _, e := range m.Funds { - l = e.Size() - n += 1 + l + sovTx(uint64(l)) - } - } - return n -} - -func (m *MsgPlaceOrdersResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if len(m.OrderIds) > 0 { - l = 0 - for _, e := range m.OrderIds { - l += sovTx(uint64(e)) - } - n += 1 + sovTx(uint64(l)) + l - } - return n -} - -func (m *MsgCancelOrders) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Creator) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - if len(m.Cancellations) > 0 { - for _, e := range m.Cancellations { - l = e.Size() - n += 1 + l + sovTx(uint64(l)) - } - } - l = len(m.ContractAddr) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - return n -} - -func (m *MsgCancelOrdersResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - return n -} - -func (m *MsgRegisterContract) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Creator) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - if m.Contract != nil { - l = m.Contract.Size() - n += 1 + l + sovTx(uint64(l)) - } - return n -} - -func (m *MsgRegisterContractResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - return n -} - -func (m *MsgContractDepositRent) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.ContractAddr) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - if m.Amount != 0 { - n += 1 + sovTx(uint64(m.Amount)) - } - l = len(m.Sender) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - return n -} - -func (m *MsgContractDepositRentResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - return n -} - -func (m *MsgUnregisterContract) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Creator) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - l = len(m.ContractAddr) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - return n -} - -func (m *MsgUnregisterContractResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - return n -} - -func (m *MsgRegisterPairs) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Creator) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - if len(m.Batchcontractpair) > 0 { - for _, e := range m.Batchcontractpair { - l = e.Size() - n += 1 + l + sovTx(uint64(l)) - } - } - return n -} - -func (m *MsgRegisterPairsResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - return n -} - -func (m *MsgUpdatePriceTickSize) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Creator) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - if len(m.TickSizeList) > 0 { - for _, e := range m.TickSizeList { - l = e.Size() - n += 1 + l + sovTx(uint64(l)) - } - } - return n -} - -func (m *MsgUpdateQuantityTickSize) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Creator) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - if len(m.TickSizeList) > 0 { - for _, e := range m.TickSizeList { - l = e.Size() - n += 1 + l + sovTx(uint64(l)) - } - } - return n -} - -func (m *MsgUpdateTickSizeResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - return n -} - -func (m *MsgUnsuspendContract) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Creator) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - l = len(m.ContractAddr) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - return n -} - -func (m *MsgUnsuspendContractResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - return n -} - -func sovTx(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozTx(x uint64) (n int) { - return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *MsgPlaceOrders) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgPlaceOrders: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgPlaceOrders: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Creator = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Orders", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Orders = append(m.Orders, &Order{}) - if err := m.Orders[len(m.Orders)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractAddr", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ContractAddr = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Funds", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Funds = append(m.Funds, types.Coin{}) - if err := m.Funds[len(m.Funds)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTx - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *MsgPlaceOrdersResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgPlaceOrdersResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgPlaceOrdersResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType == 0 { - var v uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.OrderIds = append(m.OrderIds, v) - } else if wireType == 2 { - var packedLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - packedLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if packedLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + packedLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - var elementCount int - var count int - for _, integer := range dAtA[iNdEx:postIndex] { - if integer < 128 { - count++ - } - } - elementCount = count - if elementCount != 0 && len(m.OrderIds) == 0 { - m.OrderIds = make([]uint64, 0, elementCount) - } - for iNdEx < postIndex { - var v uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.OrderIds = append(m.OrderIds, v) - } - } else { - return fmt.Errorf("proto: wrong wireType = %d for field OrderIds", wireType) - } - default: - iNdEx = preIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTx - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *MsgCancelOrders) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgCancelOrders: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgCancelOrders: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Creator = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Cancellations", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Cancellations = append(m.Cancellations, &Cancellation{}) - if err := m.Cancellations[len(m.Cancellations)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractAddr", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ContractAddr = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTx - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *MsgCancelOrdersResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgCancelOrdersResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgCancelOrdersResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - default: - iNdEx = preIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTx - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *MsgRegisterContract) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgRegisterContract: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgRegisterContract: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Creator = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Contract", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Contract == nil { - m.Contract = &ContractInfoV2{} - } - if err := m.Contract.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTx - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *MsgRegisterContractResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgRegisterContractResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgRegisterContractResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - default: - iNdEx = preIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTx - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *MsgContractDepositRent) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgContractDepositRent: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgContractDepositRent: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractAddr", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ContractAddr = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) - } - m.Amount = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Amount |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Sender = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTx - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *MsgContractDepositRentResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgContractDepositRentResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgContractDepositRentResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - default: - iNdEx = preIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTx - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *MsgUnregisterContract) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgUnregisterContract: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgUnregisterContract: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Creator = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractAddr", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ContractAddr = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTx - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *MsgUnregisterContractResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgUnregisterContractResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgUnregisterContractResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - default: - iNdEx = preIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTx - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *MsgRegisterPairs) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgRegisterPairs: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgRegisterPairs: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Creator = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Batchcontractpair", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Batchcontractpair = append(m.Batchcontractpair, BatchContractPair{}) - if err := m.Batchcontractpair[len(m.Batchcontractpair)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTx - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *MsgRegisterPairsResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgRegisterPairsResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgRegisterPairsResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - default: - iNdEx = preIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTx - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *MsgUpdatePriceTickSize) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgUpdatePriceTickSize: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgUpdatePriceTickSize: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Creator = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field TickSizeList", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.TickSizeList = append(m.TickSizeList, TickSize{}) - if err := m.TickSizeList[len(m.TickSizeList)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTx - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *MsgUpdateQuantityTickSize) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgUpdateQuantityTickSize: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgUpdateQuantityTickSize: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Creator = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field TickSizeList", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.TickSizeList = append(m.TickSizeList, TickSize{}) - if err := m.TickSizeList[len(m.TickSizeList)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTx - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *MsgUpdateTickSizeResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgUpdateTickSizeResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgUpdateTickSizeResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - default: - iNdEx = preIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTx - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *MsgUnsuspendContract) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgUnsuspendContract: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgUnsuspendContract: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Creator = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractAddr", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ContractAddr = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTx - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *MsgUnsuspendContractResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgUnsuspendContractResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgUnsuspendContractResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - default: - iNdEx = preIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTx - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipTx(dAtA []byte) (n int, err error) { - l := len(dAtA) - iNdEx := 0 - depth := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowTx - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowTx - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - iNdEx++ - if dAtA[iNdEx-1] < 0x80 { - break - } - } - case 1: - iNdEx += 8 - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowTx - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if length < 0 { - return 0, ErrInvalidLengthTx - } - iNdEx += length - case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupTx - } - depth-- - case 5: - iNdEx += 4 - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - if iNdEx < 0 { - return 0, ErrInvalidLengthTx - } - if depth == 0 { - return iNdEx, nil - } - } - return 0, io.ErrUnexpectedEOF -} - -var ( - ErrInvalidLengthTx = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowTx = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupTx = fmt.Errorf("proto: unexpected end of group") -) diff --git a/x/dex/types/types.go b/x/dex/types/types.go deleted file mode 100644 index 7cc81e44f..000000000 --- a/x/dex/types/types.go +++ /dev/null @@ -1,6 +0,0 @@ -package types - -var OppositePositionDirection = map[PositionDirection]PositionDirection{ - PositionDirection_LONG: PositionDirection_SHORT, - PositionDirection_SHORT: PositionDirection_LONG, -} diff --git a/x/dex/types/utils.go b/x/dex/types/utils.go deleted file mode 100644 index 2d5587813..000000000 --- a/x/dex/types/utils.go +++ /dev/null @@ -1,14 +0,0 @@ -package types - -import ( - "golang.org/x/text/cases" - "golang.org/x/text/language" -) - -func GetContractPositionDirection(direction PositionDirection) string { - return cases.Title(language.English).String(cases.Lower(language.English).String(PositionDirection_name[int32(direction)])) -} - -func GetContractOrderType(orderType OrderType) string { - return cases.Title(language.English).String(cases.Lower(language.English).String(OrderType_name[int32(orderType)])) -} diff --git a/x/dex/utils/context.go b/x/dex/utils/context.go deleted file mode 100644 index 7c7ca2740..000000000 --- a/x/dex/utils/context.go +++ /dev/null @@ -1,18 +0,0 @@ -package utils - -import ( - "context" - - dexcache "github.com/sei-protocol/sei-chain/x/dex/cache" -) - -type MemStateKeyType string - -const DexMemStateContextKey MemStateKeyType = MemStateKeyType("dex-memstate") - -func GetMemState(ctx context.Context) *dexcache.MemState { - if val := ctx.Value(DexMemStateContextKey); val != nil { - return val.(*dexcache.MemState) - } - return nil -} diff --git a/x/dex/utils/dec.go b/x/dex/utils/dec.go deleted file mode 100644 index b43b70898..000000000 --- a/x/dex/utils/dec.go +++ /dev/null @@ -1,71 +0,0 @@ -package utils - -import ( - "encoding/binary" - "math/big" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - -func DecToBigEndian(d sdk.Dec) (res []byte) { - i := d.BigInt() - words := i.Bits() - // words are little-endian but we want big-endian so we start from the back - for idx := len(words) - 1; idx >= 0; idx-- { - bz := make([]byte, 8) - word := uint64(words[idx]) - if d.IsNegative() { - word = ^word - } - binary.BigEndian.PutUint64(bz, word) - res = append(res, bz...) - } - lastZeroByteIdx := -1 - for i := 0; i < len(res); i++ { - if res[i] != 0 { - break - } - lastZeroByteIdx = i - } - numNonZeroBytes := uint32(len(res) - lastZeroByteIdx - 1) - if d.IsNegative() { - numNonZeroBytes = ^numNonZeroBytes - } - lengthHeaderBz := make([]byte, 4) - binary.BigEndian.PutUint32(lengthHeaderBz, numNonZeroBytes) - res = append(lengthHeaderBz, res[lastZeroByteIdx+1:]...) - if d.IsNegative() { - res = append([]byte{0}, res...) - } else { - res = append([]byte{1}, res...) - } - return res -} - -func BytesToDec(bz []byte) sdk.Dec { - neg := bz[0] == 0 - length := binary.BigEndian.Uint32(bz[1:5]) - if neg { - length = ^length - } - paddingLength := 0 - if length%8 != 0 { - paddingLength = 8 - int(length)%8 - } - padding := make([]byte, paddingLength) - bz = append(padding, bz[5:]...) - words := []big.Word{} - for i := 0; i < len(bz); i += 8 { - word := binary.BigEndian.Uint64(bz[i : i+8]) - if neg { - word = ^word - } - words = append([]big.Word{big.Word(word)}, words...) - } - bi := &big.Int{} - bi.SetBits(words) - if neg { - bi.Neg(bi) - } - return sdk.NewDecFromBigIntWithPrec(bi, sdk.Precision) -} diff --git a/x/dex/utils/dec_test.go b/x/dex/utils/dec_test.go deleted file mode 100644 index 7d170cc42..000000000 --- a/x/dex/utils/dec_test.go +++ /dev/null @@ -1,54 +0,0 @@ -package utils - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/stretchr/testify/require" -) - -var DECS = []sdk.Dec{ - sdk.MustNewDecFromStr("90.0"), - sdk.MustNewDecFromStr("10.01"), - sdk.MustNewDecFromStr("10"), - sdk.MustNewDecFromStr("9.99"), - sdk.MustNewDecFromStr("9.9"), - sdk.MustNewDecFromStr("9.0"), - sdk.MustNewDecFromStr("1"), - sdk.MustNewDecFromStr("0.001"), - sdk.MustNewDecFromStr("0"), - sdk.MustNewDecFromStr("-0.001"), - sdk.MustNewDecFromStr("-1"), - sdk.MustNewDecFromStr("-9.0"), - sdk.MustNewDecFromStr("-9.9"), - sdk.MustNewDecFromStr("-9.99"), - sdk.MustNewDecFromStr("-10"), - sdk.MustNewDecFromStr("-10.01"), - sdk.MustNewDecFromStr("-90.0"), -} - -func TestDecToBigEndian(t *testing.T) { - for i := 1; i < len(DECS); i++ { - require.True(t, compBz(DecToBigEndian(DECS[i-1]), DecToBigEndian(DECS[i]))) - } -} - -func TestBytesToDec(t *testing.T) { - for _, dec := range DECS { - require.Equal(t, dec, BytesToDec(DecToBigEndian(dec))) - } -} - -func compBz(b1 []byte, b2 []byte) bool { - ptr := 0 - for ; ptr < len(b1) && ptr < len(b2); ptr++ { - if b1[ptr] < b2[ptr] { - return false - } - if b1[ptr] > b2[ptr] { - return true - } - } - - return ptr >= len(b2) -} diff --git a/x/dex/utils/errors.go b/x/dex/utils/errors.go deleted file mode 100644 index 6139efd4f..000000000 --- a/x/dex/utils/errors.go +++ /dev/null @@ -1,11 +0,0 @@ -package utils - -const ErrorByteLimit = 50 - -func GetTruncatedErrors(err error) string { - errStr := err.Error() - if len(errStr) <= ErrorByteLimit { - return errStr - } - return errStr[:ErrorByteLimit] -} diff --git a/x/evm/keeper/msg_server_test.go b/x/evm/keeper/msg_server_test.go index f8663da65..79c68ce43 100644 --- a/x/evm/keeper/msg_server_test.go +++ b/x/evm/keeper/msg_server_test.go @@ -2,7 +2,6 @@ package keeper_test import ( "bytes" - "context" "crypto/sha256" "encoding/hex" "math/big" @@ -21,8 +20,6 @@ import ( "github.com/sei-protocol/sei-chain/example/contracts/sendall" "github.com/sei-protocol/sei-chain/example/contracts/simplestorage" testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" - dexcache "github.com/sei-protocol/sei-chain/x/dex/cache" - dexutils "github.com/sei-protocol/sei-chain/x/dex/utils" "github.com/sei-protocol/sei-chain/x/evm/ante" "github.com/sei-protocol/sei-chain/x/evm/artifacts/erc20" "github.com/sei-protocol/sei-chain/x/evm/artifacts/erc721" @@ -741,9 +738,6 @@ func TestAssociateContractAddress(t *testing.T) { func TestAssociate(t *testing.T) { ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithChainID("sei-test").WithBlockHeight(1) - ctx = ctx.WithContext( - context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, &dexcache.MemState{}), - ) privKey := testkeeper.MockPrivateKey() seiAddr, evmAddr := testkeeper.PrivateKeyToAddresses(privKey) acc := testkeeper.EVMTestApp.AccountKeeper.NewAccountWithAddress(ctx, seiAddr) diff --git a/x/mint/keeper/hooks_test.go b/x/mint/keeper/hooks_test.go index 760eea3dd..787bfe504 100644 --- a/x/mint/keeper/hooks_test.go +++ b/x/mint/keeper/hooks_test.go @@ -1,14 +1,10 @@ package keeper_test import ( - "context" "testing" "time" keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - dexcache "github.com/sei-protocol/sei-chain/x/dex/cache" - dextypes "github.com/sei-protocol/sei-chain/x/dex/types" - dexutils "github.com/sei-protocol/sei-chain/x/dex/utils" "github.com/sei-protocol/sei-chain/x/epoch/types" minttypes "github.com/sei-protocol/sei-chain/x/mint/types" "github.com/stretchr/testify/require" @@ -38,7 +34,6 @@ func TestEndOfEpochMintedCoinDistribution(t *testing.T) { t.Run("Initial should be zero", func(t *testing.T) { seiApp := keepertest.TestApp() ctx := seiApp.BaseApp.NewContext(false, tmproto.Header{Time: time.Now()}) - ctx = ctx.WithContext(context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(seiApp.GetMemKey(dextypes.MemStoreKey)))) header := tmproto.Header{ Height: seiApp.LastBlockHeight() + 1, @@ -51,7 +46,6 @@ func TestEndOfEpochMintedCoinDistribution(t *testing.T) { t.Run("even full release", func(t *testing.T) { seiApp := keepertest.TestApp() ctx := seiApp.BaseApp.NewContext(false, tmproto.Header{Time: time.Now()}) - ctx = ctx.WithContext(context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(seiApp.GetMemKey(dextypes.MemStoreKey)))) header := tmproto.Header{ Height: seiApp.LastBlockHeight() + 1, @@ -97,7 +91,6 @@ func TestEndOfEpochMintedCoinDistribution(t *testing.T) { t.Run("uneven full release", func(t *testing.T) { seiApp := keepertest.TestApp() ctx := seiApp.BaseApp.NewContext(false, tmproto.Header{Time: time.Now()}) - ctx = ctx.WithContext(context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(seiApp.GetMemKey(dextypes.MemStoreKey)))) header := tmproto.Header{ Height: seiApp.LastBlockHeight() + 1, @@ -144,7 +137,6 @@ func TestEndOfEpochMintedCoinDistribution(t *testing.T) { t.Run("multiple full releases", func(t *testing.T) { seiApp := keepertest.TestApp() ctx := seiApp.BaseApp.NewContext(false, tmproto.Header{Time: time.Now()}) - ctx = ctx.WithContext(context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(seiApp.GetMemKey(dextypes.MemStoreKey)))) header := tmproto.Header{ Height: seiApp.LastBlockHeight() + 1, @@ -203,7 +195,6 @@ func TestEndOfEpochMintedCoinDistribution(t *testing.T) { t.Run("outage during release", func(t *testing.T) { seiApp := keepertest.TestApp() ctx := seiApp.BaseApp.NewContext(false, tmproto.Header{Time: time.Now()}) - ctx = ctx.WithContext(context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(seiApp.GetMemKey(dextypes.MemStoreKey)))) header := tmproto.Header{ Height: seiApp.LastBlockHeight() + 1, @@ -278,7 +269,6 @@ func TestEndOfEpochMintedCoinDistribution(t *testing.T) { func TestNoEpochPassedNoDistribution(t *testing.T) { seiApp := keepertest.TestApp() ctx := seiApp.BaseApp.NewContext(false, tmproto.Header{Time: time.Now()}) - ctx = ctx.WithContext(context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(seiApp.GetMemKey(dextypes.MemStoreKey)))) header := tmproto.Header{Height: seiApp.LastBlockHeight() + 1} seiApp.BeginBlock(ctx, abci.RequestBeginBlock{Header: header}) diff --git a/x/mint/types/gov.pb.go b/x/mint/types/gov.pb.go index 4ebcd8a7e..32a3d8c9a 100644 --- a/x/mint/types/gov.pb.go +++ b/x/mint/types/gov.pb.go @@ -23,8 +23,6 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// AddAssetMetadataProposal is a gov Content type for adding a new asset -// to the dex module's asset list. type UpdateMinterProposal struct { Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty" yaml:"title"` Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty" yaml:"description"` From 4e175e9260b85b8886f2cd5d1ba2dddc13816a8d Mon Sep 17 00:00:00 2001 From: Jeremy Wei Date: Thu, 22 Aug 2024 22:55:23 -0400 Subject: [PATCH 20/38] Gas mispricing in cw vm patch (#1824) * test * fix loadtest gas price * add to upgrade list * Revert "add to upgrade list" This reverts commit 7adeb92b2bb5b0aca009ddaedd0bfcee134c2d11. --- .github/workflows/golangci.yml | 2 +- go.mod | 4 ++-- go.sum | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/golangci.yml b/.github/workflows/golangci.yml index 9231912e6..a87a8cd54 100644 --- a/.github/workflows/golangci.yml +++ b/.github/workflows/golangci.yml @@ -25,5 +25,5 @@ jobs: uses: golangci/golangci-lint-action@v3 with: # Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version - version: latest + version: v1.60.1 args: --timeout 10m0s diff --git a/go.mod b/go.mod index 2705d6310..4e763cb6c 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.21 require ( github.com/BurntSushi/toml v1.3.2 github.com/CosmWasm/wasmd v0.27.0 - github.com/CosmWasm/wasmvm v1.5.2 + github.com/CosmWasm/wasmvm v1.5.4 github.com/armon/go-metrics v0.4.1 github.com/btcsuite/btcd v0.22.1 github.com/cosmos/cosmos-sdk v0.45.10 @@ -344,7 +344,7 @@ require ( ) replace ( - github.com/CosmWasm/wasmd => github.com/sei-protocol/sei-wasmd v0.2.3 + github.com/CosmWasm/wasmd => github.com/sei-protocol/sei-wasmd v0.2.4-0.20240816184629-eb6d20caf603 github.com/confio/ics23/go => github.com/cosmos/cosmos-sdk/ics23/go v0.8.0 github.com/cosmos/cosmos-sdk => github.com/sei-protocol/sei-cosmos v0.3.33 github.com/cosmos/iavl => github.com/sei-protocol/sei-iavl v0.1.9 diff --git a/go.sum b/go.sum index df2067481..8bdefbce3 100644 --- a/go.sum +++ b/go.sum @@ -96,8 +96,8 @@ github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbi github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw= github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w= -github.com/CosmWasm/wasmvm v1.5.2 h1:+pKB1Mz9GZVt1vadxB+EDdD1FOz3dMNjIKq/58/lrag= -github.com/CosmWasm/wasmvm v1.5.2/go.mod h1:Q0bSEtlktzh7W2hhEaifrFp1Erx11ckQZmjq8FLCyys= +github.com/CosmWasm/wasmvm v1.5.4 h1:Opqy65ubJ8bMsT08dn85VjRdsLJVPIAgIXif92qOMGc= +github.com/CosmWasm/wasmvm v1.5.4/go.mod h1:Q0bSEtlktzh7W2hhEaifrFp1Erx11ckQZmjq8FLCyys= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= @@ -1359,8 +1359,8 @@ github.com/sei-protocol/sei-tendermint v0.3.8 h1:9o+A3tL6q1ki++dLng/J8MHHiT6y3l7 github.com/sei-protocol/sei-tendermint v0.3.8/go.mod h1:4LSlJdhl3nf3OmohliwRNUFLOB1XWlrmSodrIP7fLh4= github.com/sei-protocol/sei-tm-db v0.0.5 h1:3WONKdSXEqdZZeLuWYfK5hP37TJpfaUa13vAyAlvaQY= github.com/sei-protocol/sei-tm-db v0.0.5/go.mod h1:Cpa6rGyczgthq7/0pI31jys2Fw0Nfrc+/jKdP1prVqY= -github.com/sei-protocol/sei-wasmd v0.2.3 h1:txB7LIx4Luh7+fxVN4/PiHEAjYnkutKyrpsuIFW8lmA= -github.com/sei-protocol/sei-wasmd v0.2.3/go.mod h1:EnQkqvUA3tYpdgXjqatHK8ym9LCm1z+lM7XMqR9SA3o= +github.com/sei-protocol/sei-wasmd v0.2.4-0.20240816184629-eb6d20caf603 h1:aOUWB+ABNMdAjghn/PqCKDuz5WTwfoYfre5I/rtOnKo= +github.com/sei-protocol/sei-wasmd v0.2.4-0.20240816184629-eb6d20caf603/go.mod h1:fKHnK3Nms+BZeGvXeIC3SEzUDfkB7/tYOf95kVOhiO4= github.com/sei-protocol/tm-db v0.0.4 h1:7Y4EU62Xzzg6wKAHEotm7SXQR0aPLcGhKHkh3qd0tnk= github.com/sei-protocol/tm-db v0.0.4/go.mod h1:PWsIWOTwdwC7Ow/GUvx8HgUJTO691pBuorIQD8JvwAs= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= From dd7c43db60b4328a2070a90804f0d7bdbe89608e Mon Sep 17 00:00:00 2001 From: codchen Date: Fri, 23 Aug 2024 18:10:20 +0800 Subject: [PATCH 21/38] Fork event manager when creating EVM snapshots (#1831) --- precompiles/pointer/pointer_test.go | 4 +++- x/evm/state/state.go | 2 +- x/evm/state/state_test.go | 4 ++++ x/evm/state/statedb.go | 11 ++++++++++- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/precompiles/pointer/pointer_test.go b/precompiles/pointer/pointer_test.go index e75c09f7f..f5bd4e1c5 100644 --- a/precompiles/pointer/pointer_test.go +++ b/precompiles/pointer/pointer_test.go @@ -52,7 +52,7 @@ func TestAddNative(t *testing.T) { Aliases: []string{"DENOM"}, }}, }) - statedb = state.NewDBImpl(ctx, &testApp.EvmKeeper, true) + statedb = state.NewDBImpl(ctx, &testApp.EvmKeeper, false) evm = vm.NewEVM(*blockCtx, vm.TxContext{}, statedb, cfg, vm.Config{}) ret, g, err := p.RunAndCalculateGas(evm, caller, caller, append(p.GetExecutor().(*pointer.PrecompileExecutor).AddNativePointerID, args...), suppliedGas, nil, nil, false) require.Nil(t, err) @@ -64,6 +64,8 @@ func TestAddNative(t *testing.T) { require.Equal(t, addr, pointerAddr) require.Equal(t, native.CurrentVersion, version) require.True(t, exists) + _, err = statedb.Finalize() + require.Nil(t, err) hasRegisteredEvent := false for _, e := range ctx.EventManager().Events() { if e.Type != types.EventTypePointerRegistered { diff --git a/x/evm/state/state.go b/x/evm/state/state.go index 7d8855176..a6ead6bfa 100644 --- a/x/evm/state/state.go +++ b/x/evm/state/state.go @@ -93,7 +93,7 @@ func (s *DBImpl) HasSelfDestructed(acc common.Address) bool { } func (s *DBImpl) Snapshot() int { - newCtx := s.ctx.WithMultiStore(s.ctx.MultiStore().CacheMultiStore()) + newCtx := s.ctx.WithMultiStore(s.ctx.MultiStore().CacheMultiStore()).WithEventManager(sdk.NewEventManager()) s.snapshottedCtxs = append(s.snapshottedCtxs, s.ctx) s.ctx = newCtx s.tempStatesHist = append(s.tempStatesHist, s.tempStateCurrent) diff --git a/x/evm/state/state_test.go b/x/evm/state/state_test.go index 1b165d63f..28cc4c861 100644 --- a/x/evm/state/state_test.go +++ b/x/evm/state/state_test.go @@ -133,6 +133,7 @@ func TestSnapshot(t *testing.T) { k, ctx := testkeeper.MockEVMKeeper() seiAddr, evmAddr := testkeeper.MockAddressPair() k.SetAddressMapping(ctx, seiAddr, evmAddr) + eventCount := len(ctx.EventManager().Events()) statedb := state.NewDBImpl(ctx, k, false) statedb.CreateAccount(evmAddr) key := common.BytesToHash([]byte("abc")) @@ -141,6 +142,7 @@ func TestSnapshot(t *testing.T) { tval := common.BytesToHash([]byte("mno")) statedb.SetState(evmAddr, key, val) statedb.SetTransientState(evmAddr, tkey, tval) + statedb.Ctx().EventManager().EmitEvent(sdk.Event{}) rev := statedb.Snapshot() @@ -148,6 +150,7 @@ func TestSnapshot(t *testing.T) { newTVal := common.BytesToHash([]byte("y")) statedb.SetState(evmAddr, key, newVal) statedb.SetTransientState(evmAddr, tkey, newTVal) + statedb.Ctx().EventManager().EmitEvent(sdk.Event{}) statedb.RevertToSnapshot(rev) @@ -165,4 +168,5 @@ func TestSnapshot(t *testing.T) { // prev state DB committed except for transient states require.Equal(t, common.Hash{}, newStateDB.GetTransientState(evmAddr, tkey)) require.Equal(t, val, newStateDB.GetState(evmAddr, key)) + require.Equal(t, eventCount+1, len(ctx.EventManager().Events())) } diff --git a/x/evm/state/statedb.go b/x/evm/state/statedb.go index 101735618..9ef3f52eb 100644 --- a/x/evm/state/statedb.go +++ b/x/evm/state/statedb.go @@ -112,6 +112,11 @@ func (s *DBImpl) Finalize() (surplus sdk.Int, err error) { for i := len(s.snapshottedCtxs) - 1; i > 0; i-- { s.flushCtx(s.snapshottedCtxs[i]) } + // write all events in order + for i := 1; i < len(s.snapshottedCtxs); i++ { + s.flushEvents(s.snapshottedCtxs[i]) + } + s.flushEvents(s.ctx) surplus = s.tempStateCurrent.surplus for _, ts := range s.tempStatesHist { @@ -124,6 +129,10 @@ func (s *DBImpl) flushCtx(ctx sdk.Context) { ctx.MultiStore().(sdk.CacheMultiStore).Write() } +func (s *DBImpl) flushEvents(ctx sdk.Context) { + s.snapshottedCtxs[0].EventManager().EmitEvents(ctx.EventManager().Events()) +} + // Backward-compatibility functions func (s *DBImpl) Error() error { return s.Err() @@ -134,7 +143,7 @@ func (s *DBImpl) GetStorageRoot(common.Address) common.Hash { } func (s *DBImpl) Copy() vm.StateDB { - newCtx := s.ctx.WithMultiStore(s.ctx.MultiStore().CacheMultiStore()) + newCtx := s.ctx.WithMultiStore(s.ctx.MultiStore().CacheMultiStore()).WithEventManager(sdk.NewEventManager()) return &DBImpl{ ctx: newCtx, snapshottedCtxs: append(s.snapshottedCtxs, s.ctx), From 83fd512c08eb5153debc4b05d7f5da9b9bd445b1 Mon Sep 17 00:00:00 2001 From: Uday Patil Date: Fri, 23 Aug 2024 08:47:24 -0500 Subject: [PATCH 22/38] Increase timeout for evm hardhat tests (#1827) --- contracts/hardhat.config.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contracts/hardhat.config.js b/contracts/hardhat.config.js index 3088f6320..6a18ac38b 100644 --- a/contracts/hardhat.config.js +++ b/contracts/hardhat.config.js @@ -14,6 +14,9 @@ module.exports = { }, }, }, + mocha: { + timeout: 100000000, + }, paths: { sources: "./src", // contracts are in ./src }, From c2c0f92627b42605ba746c641919e3535357f5d1 Mon Sep 17 00:00:00 2001 From: codchen Date: Tue, 27 Aug 2024 13:26:38 +0800 Subject: [PATCH 23/38] Show CW transactions that have synthetic EVM events in eth_getBlock* response (#1832) --- evmrpc/block.go | 23 +++++++ evmrpc/block_test.go | 69 ++++++++++++++++++++- precompiles/pointer/pointer_test.go | 3 +- x/evm/client/wasm/query_test.go | 66 ++++++++++++-------- x/evm/types/message_evm_transaction_test.go | 3 +- 5 files changed, 134 insertions(+), 30 deletions(-) diff --git a/evmrpc/block.go b/evmrpc/block.go index 1525618dd..4753f00e5 100644 --- a/evmrpc/block.go +++ b/evmrpc/block.go @@ -2,12 +2,14 @@ package evmrpc import ( "context" + "crypto/sha256" "errors" "math/big" "strings" "sync" "time" + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" "github.com/cosmos/cosmos-sdk/client" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" @@ -193,6 +195,27 @@ func EncodeTmBlock( newTx := ethapi.NewRPCTransaction(ethtx, blockhash, number.Uint64(), uint64(blockTime.Second()), uint64(receipt.TransactionIndex), baseFeePerGas, chainConfig) transactions = append(transactions, newTx) } + case *wasmtypes.MsgExecuteContract: + th := sha256.Sum256(block.Block.Txs[i]) + receipt, err := k.GetReceipt(ctx, th) + if err != nil { + continue + } + if !fullTx { + transactions = append(transactions, th) + } else { + ti := uint64(receipt.TransactionIndex) + to := k.GetEVMAddressOrDefault(ctx, sdk.MustAccAddressFromBech32(m.Contract)) + transactions = append(transactions, ðapi.RPCTransaction{ + BlockHash: &blockhash, + BlockNumber: (*hexutil.Big)(number), + From: common.HexToAddress(receipt.From), + To: &to, + Input: m.Msg.Bytes(), + Hash: th, + TransactionIndex: (*hexutil.Uint64)(&ti), + }) + } } } } diff --git a/evmrpc/block_test.go b/evmrpc/block_test.go index 7a50edda8..b12f9fbdf 100644 --- a/evmrpc/block_test.go +++ b/evmrpc/block_test.go @@ -1,14 +1,22 @@ package evmrpc_test import ( - types2 "github.com/tendermint/tendermint/proto/tendermint/types" + "crypto/sha256" + "math/big" "testing" + types2 "github.com/tendermint/tendermint/proto/tendermint/types" + + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" sdk "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/lib/ethapi" "github.com/sei-protocol/sei-chain/evmrpc" testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/types" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/rpc/coretypes" @@ -214,3 +222,62 @@ func TestEncodeBankMsg(t *testing.T) { txs := res["transactions"].([]interface{}) require.Equal(t, 0, len(txs)) } + +func TestEncodeWasmExecuteMsg(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + fromSeiAddr, fromEvmAddr := testkeeper.MockAddressPair() + toSeiAddr, _ := testkeeper.MockAddressPair() + b := TxConfig.NewTxBuilder() + b.SetMsgs(&wasmtypes.MsgExecuteContract{ + Sender: fromSeiAddr.String(), + Contract: toSeiAddr.String(), + Msg: []byte{1, 2, 3}, + }) + tx := b.GetTx() + bz, _ := Encoder(tx) + k.MockReceipt(ctx, sha256.Sum256(bz), &types.Receipt{ + TransactionIndex: 1, + From: fromEvmAddr.Hex(), + }) + resBlock := coretypes.ResultBlock{ + BlockID: MockBlockID, + Block: &tmtypes.Block{ + Header: mockBlockHeader(MockHeight), + Data: tmtypes.Data{ + Txs: []tmtypes.Tx{bz}, + }, + LastCommit: &tmtypes.Commit{ + Height: MockHeight - 1, + }, + }, + } + resBlockRes := coretypes.ResultBlockResults{ + TxsResults: []*abci.ExecTxResult{ + { + Data: bz, + }, + }, + ConsensusParamUpdates: &types2.ConsensusParams{ + Block: &types2.BlockParams{ + MaxBytes: 100000000, + MaxGas: 200000000, + }, + }, + } + res, err := evmrpc.EncodeTmBlock(ctx, &resBlock, &resBlockRes, k, Decoder, true) + require.Nil(t, err) + txs := res["transactions"].([]interface{}) + require.Equal(t, 1, len(txs)) + ti := uint64(1) + bh := common.HexToHash(MockBlockID.Hash.String()) + to := common.Address(toSeiAddr) + require.Equal(t, ðapi.RPCTransaction{ + BlockHash: &bh, + BlockNumber: (*hexutil.Big)(big.NewInt(MockHeight)), + From: fromEvmAddr, + To: &to, + Input: []byte{1, 2, 3}, + Hash: common.Hash(sha256.Sum256(bz)), + TransactionIndex: (*hexutil.Uint64)(&ti), + }, txs[0].(*ethapi.RPCTransaction)) +} diff --git a/precompiles/pointer/pointer_test.go b/precompiles/pointer/pointer_test.go index f5bd4e1c5..c1abc2fb7 100644 --- a/precompiles/pointer/pointer_test.go +++ b/precompiles/pointer/pointer_test.go @@ -8,7 +8,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/vm" - "github.com/sei-protocol/sei-chain/app" "github.com/sei-protocol/sei-chain/precompiles/pointer" testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" "github.com/sei-protocol/sei-chain/x/evm/artifacts/native" @@ -18,7 +17,7 @@ import ( ) func TestAddNative(t *testing.T) { - testApp := app.Setup(false, false) + testApp := testkeeper.EVMTestApp p, err := pointer.NewPrecompile(&testApp.EvmKeeper, testApp.BankKeeper, testApp.WasmKeeper) require.Nil(t, err) ctx := testApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) diff --git a/x/evm/client/wasm/query_test.go b/x/evm/client/wasm/query_test.go index 5b04471e9..e9b68d8dd 100644 --- a/x/evm/client/wasm/query_test.go +++ b/x/evm/client/wasm/query_test.go @@ -11,7 +11,6 @@ import ( "testing" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/tx/signing" ethabi "github.com/ethereum/go-ethereum/accounts/abi" @@ -24,14 +23,14 @@ import ( "github.com/sei-protocol/sei-chain/x/evm/client/wasm" "github.com/sei-protocol/sei-chain/x/evm/client/wasm/bindings" "github.com/sei-protocol/sei-chain/x/evm/keeper" - "github.com/sei-protocol/sei-chain/x/evm/state" evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" "github.com/stretchr/testify/require" ) func TestERC721TransferPayload(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx(nil) addr1, e1 := testkeeper.MockAddressPair() addr2, e2 := testkeeper.MockAddressPair() k.SetAddressMapping(ctx, addr1, e1) @@ -43,7 +42,8 @@ func TestERC721TransferPayload(t *testing.T) { } func TestERC721ApprovePayload(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx(nil) addr1, e1 := testkeeper.MockAddressPair() k.SetAddressMapping(ctx, addr1, e1) h := wasm.NewEVMQueryHandler(k) @@ -53,7 +53,8 @@ func TestERC721ApprovePayload(t *testing.T) { } func TestERC721ApproveAllPayload(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx(nil) addr1, e1 := testkeeper.MockAddressPair() k.SetAddressMapping(ctx, addr1, e1) h := wasm.NewEVMQueryHandler(k) @@ -63,18 +64,20 @@ func TestERC721ApproveAllPayload(t *testing.T) { } func TestERC20TransferPayload(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx(nil) addr1, e1 := testkeeper.MockAddressPair() k.SetAddressMapping(ctx, addr1, e1) h := wasm.NewEVMQueryHandler(k) - value := types.NewInt(500) + value := sdk.NewInt(500) res, err := h.HandleERC20TransferPayload(ctx, addr1.String(), &value) require.Nil(t, err) require.NotEmpty(t, res) } func TestHandleERC20TokenInfo(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx(nil) privKey := testkeeper.MockPrivateKey() res, _ := deployContract(t, ctx, k, "../../../../example/contracts/erc20/ERC20.bin", privKey) addr1, e1 := testkeeper.MockAddressPair() @@ -89,31 +92,34 @@ func TestHandleERC20TokenInfo(t *testing.T) { } func TestERC20TransferFromPayload(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx(nil) addr1, e1 := testkeeper.MockAddressPair() addr2, e2 := testkeeper.MockAddressPair() k.SetAddressMapping(ctx, addr1, e1) k.SetAddressMapping(ctx, addr2, e2) h := wasm.NewEVMQueryHandler(k) - value := types.NewInt(500) + value := sdk.NewInt(500) res, err := h.HandleERC20TransferFromPayload(ctx, addr1.String(), addr2.String(), &value) require.Nil(t, err) require.NotEmpty(t, res) } func TestERC20ApprovePayload(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx(nil) addr1, e1 := testkeeper.MockAddressPair() k.SetAddressMapping(ctx, addr1, e1) h := wasm.NewEVMQueryHandler(k) - value := types.NewInt(500) + value := sdk.NewInt(500) res, err := h.HandleERC20ApprovePayload(ctx, addr1.String(), &value) require.Nil(t, err) require.NotEmpty(t, res) } func TestHandleERC20Balance(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx(nil) privKey := testkeeper.MockPrivateKey() res, _ := deployContract(t, ctx, k, "../../../../example/contracts/erc20/ERC20.bin", privKey) addr1, e1 := testkeeper.MockAddressPair() @@ -129,7 +135,8 @@ func TestHandleERC20Balance(t *testing.T) { } func TestHandleERC721Owner(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx(nil) privKey := testkeeper.MockPrivateKey() res, _ := deployContract(t, ctx, k, "../../../../example/contracts/erc721/DummyERC721.bin", privKey) addr1, e1 := testkeeper.MockAddressPair() @@ -144,7 +151,8 @@ func TestHandleERC721Owner(t *testing.T) { } func TestHandleERC20Allowance(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx(nil) privKey := testkeeper.MockPrivateKey() res, _ := deployContract(t, ctx, k, "../../../../example/contracts/erc20/ERC20.bin", privKey) addr1, e1 := testkeeper.MockAddressPair() @@ -162,7 +170,8 @@ func TestHandleERC20Allowance(t *testing.T) { } func TestHandleERC721Approved(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx(nil) privKey := testkeeper.MockPrivateKey() res, _ := deployContract(t, ctx, k, "../../../../example/contracts/erc721/DummyERC721.bin", privKey) addr1, e1 := testkeeper.MockAddressPair() @@ -179,7 +188,8 @@ func TestHandleERC721Approved(t *testing.T) { } func TestHandleERC721IsApprovedForAll(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx(nil) privKey := testkeeper.MockPrivateKey() res, _ := deployContract(t, ctx, k, "../../../../example/contracts/erc721/DummyERC721.bin", privKey) addr1, e1 := testkeeper.MockAddressPair() @@ -196,7 +206,8 @@ func TestHandleERC721IsApprovedForAll(t *testing.T) { } func TestHandleERC721TotalSupply(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx(nil) privKey := testkeeper.MockPrivateKey() res, _ := deployContract(t, ctx, k, "../../../../example/contracts/erc721/DummyERC721.bin", privKey) addr1, e1 := testkeeper.MockAddressPair() @@ -212,7 +223,8 @@ func TestHandleERC721TotalSupply(t *testing.T) { } func TestHandleERC721NameSymbol(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx(nil) privKey := testkeeper.MockPrivateKey() res, _ := deployContract(t, ctx, k, "../../../../example/contracts/erc721/DummyERC721.bin", privKey) addr1, e1 := testkeeper.MockAddressPair() @@ -228,7 +240,8 @@ func TestHandleERC721NameSymbol(t *testing.T) { } func TestHandleERC721TokenURI(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx(nil) privKey := testkeeper.MockPrivateKey() res, _ := deployContract(t, ctx, k, "../../../../example/contracts/erc721/DummyERC721.bin", privKey) addr1, e1 := testkeeper.MockAddressPair() @@ -243,7 +256,8 @@ func TestHandleERC721TokenURI(t *testing.T) { } func TestHandleERC721RoyaltyInfo(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx(nil) privKey := testkeeper.MockPrivateKey() res, _ := deployContract(t, ctx, k, "../../../../example/contracts/erc721/DummyERC721.bin", privKey) addr1, e1 := testkeeper.MockAddressPair() @@ -252,7 +266,7 @@ func TestHandleERC721RoyaltyInfo(t *testing.T) { require.Nil(t, err) contractAddr := common.HexToAddress(receipt.ContractAddress) h := wasm.NewEVMQueryHandler(k) - value := types.NewInt(100) + value := sdk.NewInt(100) res2, err := h.HandleERC721RoyaltyInfo(ctx, addr1.String(), contractAddr.String(), "1", &value) require.Nil(t, err) require.NotEmpty(t, res2) @@ -261,7 +275,8 @@ func TestHandleERC721RoyaltyInfo(t *testing.T) { } func TestGetAddress(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx(nil) seiAddr1, evmAddr1 := testkeeper.MockAddressPair() k.SetAddressMapping(ctx, seiAddr1, evmAddr1) seiAddr2, evmAddr2 := testkeeper.MockAddressPair() @@ -364,7 +379,8 @@ func createSigner(k *keeper.Keeper, ctx sdk.Context) ethtypes.Signer { } func TestHandleStaticCall(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx(nil) privKey := testkeeper.MockPrivateKey() _, evmAddr := testkeeper.PrivateKeyToAddresses(privKey) testPrivHex := hex.EncodeToString(privKey.Bytes()) @@ -375,8 +391,6 @@ func TestHandleStaticCall(t *testing.T) { require.Empty(t, res.VmError) require.NotEmpty(t, res.ReturnData) require.NotEmpty(t, res.Hash) - require.Equal(t, uint64(100000000)-res.GasUsed, k.BankKeeper().GetBalance(ctx, sdk.AccAddress(evmAddr[:]), "usei").Amount.Uint64()) - require.Equal(t, res.GasUsed, k.BankKeeper().GetBalance(ctx, state.GetCoinbaseAddress(ctx.TxIndex()), k.GetBaseDenom(ctx)).Amount.Uint64()) receipt, err := k.GetReceipt(ctx, common.HexToHash(res.Hash)) require.Nil(t, err) require.NotNil(t, receipt) diff --git a/x/evm/types/message_evm_transaction_test.go b/x/evm/types/message_evm_transaction_test.go index 2c5009610..77a834ffb 100644 --- a/x/evm/types/message_evm_transaction_test.go +++ b/x/evm/types/message_evm_transaction_test.go @@ -35,7 +35,8 @@ func TestIsNotAssociate(t *testing.T) { } func TestAsTransaction(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx(nil) chainID := k.ChainID(ctx) chainCfg := types.DefaultChainConfig() ethCfg := chainCfg.EthereumConfig(chainID) From 871dd2aa78aec93a7bcd185821f9b1192689be0d Mon Sep 17 00:00:00 2001 From: mj Date: Tue, 27 Aug 2024 09:58:08 -0700 Subject: [PATCH 24/38] Add associate with pubkey precompile method (#1798) * Add associate with pubkey precompile method * lint * test bug * slice public key * add comment * string memory * add readonly checks --------- Co-authored-by: _dssei_ Co-authored-by: Denys S <150304777+dssei@users.noreply.github.com> --- contracts/test/EVMPrecompileTest.js | 21 +++- precompiles/addr/Addr.sol | 7 +- precompiles/addr/abi.json | 2 +- precompiles/addr/addr.go | 66 ++++++++++- precompiles/addr/addr_test.go | 177 ++++++++++++++++++++++++++-- utils/helpers/address.go | 4 + 6 files changed, 260 insertions(+), 17 deletions(-) diff --git a/contracts/test/EVMPrecompileTest.js b/contracts/test/EVMPrecompileTest.js index 58e270986..5f9229b93 100755 --- a/contracts/test/EVMPrecompileTest.js +++ b/contracts/test/EVMPrecompileTest.js @@ -29,7 +29,7 @@ describe("EVM Precompile Tester", function () { addr = new ethers.Contract(AddrPrecompileContract, contractABI, signer); }); - it("Assosciates successfully", async function () { + it("Associates successfully", async function () { const unassociatedWallet = hre.ethers.Wallet.createRandom(); try { await addr.getSeiAddr(unassociatedWallet.address); @@ -53,6 +53,25 @@ describe("EVM Precompile Tester", function () { const seiAddr = await addr.getSeiAddr(unassociatedWallet.address); expect(seiAddr).to.not.be.null; }); + + it("Associates with Public Key successfully", async function () { + const unassociatedWallet = hre.ethers.Wallet.createRandom(); + try { + await addr.getSeiAddr(unassociatedWallet.address); + expect.fail("Expected an error here since we look up an unassociated address"); + } catch (error) { + expect(error).to.have.property('message').that.includes('execution reverted'); + } + + // Use the PublicKey without the '0x' prefix. + const associatedAddrs = await addr.associatePubKey(unassociatedWallet.publicKey.slice(2)) + const addrs = await associatedAddrs.wait(); + expect(addrs).to.not.be.null; + + // Verify that addresses are now associated. + const seiAddr = await addr.getSeiAddr(unassociatedWallet.address); + expect(seiAddr).to.not.be.null; + }); }); describe("EVM Gov Precompile Tester", function () { diff --git a/precompiles/addr/Addr.sol b/precompiles/addr/Addr.sol index f24a26659..e83f62da7 100644 --- a/precompiles/addr/Addr.sol +++ b/precompiles/addr/Addr.sol @@ -14,7 +14,12 @@ interface IAddr { string memory r, string memory s, string memory customMessage - ) external returns (string seiAddr, address evmAddr); + ) external returns (string memory seiAddr, address evmAddr); + + // Takes a compressed pubkey in hex format, excluding the '0x' + function associatePubKey( + string memory pubKeyHex + ) external returns (string memory seiAddr, address evmAddr); // Queries function getSeiAddr(address addr) external view returns (string memory response); diff --git a/precompiles/addr/abi.json b/precompiles/addr/abi.json index 211faabec..f0425eaf8 100755 --- a/precompiles/addr/abi.json +++ b/precompiles/addr/abi.json @@ -1 +1 @@ -[{"inputs":[{"internalType":"string","name":"v","type":"string"},{"internalType":"string","name":"r","type":"string"},{"internalType":"string","name":"s","type":"string"},{"internalType":"string","name":"customMessage","type":"string"}],"name":"associate","outputs":[{"internalType":"string","name":"seiAddr","type":"string"},{"internalType":"address","name":"evmAddr","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"getSeiAddr","outputs":[{"internalType":"string","name":"response","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"addr","type":"string"}],"name":"getEvmAddr","outputs":[{"internalType":"address","name":"response","type":"address"}],"stateMutability":"view","type":"function"}] \ No newline at end of file +[{"inputs":[{"internalType":"string","name":"v","type":"string"},{"internalType":"string","name":"r","type":"string"},{"internalType":"string","name":"s","type":"string"},{"internalType":"string","name":"customMessage","type":"string"}],"name":"associate","outputs":[{"internalType":"string","name":"seiAddr","type":"string"},{"internalType":"address","name":"evmAddr","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"pubKeyHex","type":"string"}],"name":"associatePubKey","outputs":[{"internalType":"string","name":"seiAddr","type":"string"},{"internalType":"address","name":"evmAddr","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"getSeiAddr","outputs":[{"internalType":"string","name":"response","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"addr","type":"string"}],"name":"getEvmAddr","outputs":[{"internalType":"address","name":"response","type":"address"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/precompiles/addr/addr.go b/precompiles/addr/addr.go index 506b363af..e0b3c283a 100644 --- a/precompiles/addr/addr.go +++ b/precompiles/addr/addr.go @@ -4,9 +4,12 @@ import ( "bytes" "embed" "encoding/hex" + "errors" "fmt" "strings" + "github.com/btcsuite/btcd/btcec" + "math/big" "github.com/ethereum/go-ethereum/crypto" @@ -18,6 +21,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" pcommon "github.com/sei-protocol/sei-chain/precompiles/common" "github.com/sei-protocol/sei-chain/utils/metrics" "github.com/sei-protocol/sei-chain/x/evm/types" @@ -27,6 +31,7 @@ const ( GetSeiAddressMethod = "getSeiAddr" GetEvmAddressMethod = "getEvmAddr" Associate = "associate" + AssociatePubKey = "associatePubKey" ) const ( @@ -43,9 +48,10 @@ type PrecompileExecutor struct { bankKeeper pcommon.BankKeeper accountKeeper pcommon.AccountKeeper - GetSeiAddressID []byte - GetEvmAddressID []byte - AssociateID []byte + GetSeiAddressID []byte + GetEvmAddressID []byte + AssociateID []byte + AssociatePubKeyID []byte } func NewPrecompile(evmKeeper pcommon.EVMKeeper, bankKeeper pcommon.BankKeeper, accountKeeper pcommon.AccountKeeper) (*pcommon.Precompile, error) { @@ -66,6 +72,8 @@ func NewPrecompile(evmKeeper pcommon.EVMKeeper, bankKeeper pcommon.BankKeeper, a p.GetEvmAddressID = m.ID case Associate: p.AssociateID = m.ID + case AssociatePubKey: + p.AssociatePubKeyID = m.ID } } @@ -74,20 +82,28 @@ func NewPrecompile(evmKeeper pcommon.EVMKeeper, bankKeeper pcommon.BankKeeper, a // RequiredGas returns the required bare minimum gas to execute the precompile. func (p PrecompileExecutor) RequiredGas(input []byte, method *abi.Method) uint64 { - if bytes.Equal(method.ID, p.AssociateID) { + if bytes.Equal(method.ID, p.AssociateID) || bytes.Equal(method.ID, p.AssociatePubKeyID) { return 50000 } return pcommon.DefaultGasCost(input, p.IsTransaction(method.Name)) } -func (p PrecompileExecutor) Execute(ctx sdk.Context, method *abi.Method, _ common.Address, _ common.Address, args []interface{}, value *big.Int, _ bool, _ *vm.EVM) (bz []byte, err error) { +func (p PrecompileExecutor) Execute(ctx sdk.Context, method *abi.Method, _ common.Address, _ common.Address, args []interface{}, value *big.Int, readOnly bool, _ *vm.EVM) (bz []byte, err error) { switch method.Name { case GetSeiAddressMethod: return p.getSeiAddr(ctx, method, args, value) case GetEvmAddressMethod: return p.getEvmAddr(ctx, method, args, value) case Associate: + if readOnly { + return nil, errors.New("cannot call associate precompile from staticcall") + } return p.associate(ctx, method, args, value) + case AssociatePubKey: + if readOnly { + return nil, errors.New("cannot call associate pub key precompile from staticcall") + } + return p.associatePublicKey(ctx, method, args, value) } return } @@ -173,6 +189,44 @@ func (p PrecompileExecutor) associate(ctx sdk.Context, method *abi.Method, args return nil, err } + return p.associateAddresses(ctx, method, evmAddr, seiAddr, pubkey) +} + +func (p PrecompileExecutor) associatePublicKey(ctx sdk.Context, method *abi.Method, args []interface{}, value *big.Int) ([]byte, error) { + if err := pcommon.ValidateNonPayable(value); err != nil { + return nil, err + } + + if err := pcommon.ValidateArgsLength(args, 1); err != nil { + return nil, err + } + + // Takes a single argument, a compressed pubkey in hex format, excluding the '0x' + pubKeyHex := args[0].(string) + + pubKeyBytes, err := hex.DecodeString(pubKeyHex) + if err != nil { + return nil, err + } + + // Parse the compressed public key + pubKey, err := btcec.ParsePubKey(pubKeyBytes, btcec.S256()) + if err != nil { + return nil, err + } + + // Convert to uncompressed public key + uncompressedPubKey := pubKey.SerializeUncompressed() + + evmAddr, seiAddr, pubkey, err := helpers.GetAddressesFromPubkeyBytes(uncompressedPubKey) + if err != nil { + return nil, err + } + + return p.associateAddresses(ctx, method, evmAddr, seiAddr, pubkey) +} + +func (p PrecompileExecutor) associateAddresses(ctx sdk.Context, method *abi.Method, evmAddr common.Address, seiAddr sdk.AccAddress, pubkey cryptotypes.PubKey) ([]byte, error) { // Check that address is not already associated _, found := p.evmKeeper.GetEVMAddress(ctx, seiAddr) if found { @@ -181,7 +235,7 @@ func (p PrecompileExecutor) associate(ctx sdk.Context, method *abi.Method, args // Associate Addresses: associationHelper := helpers.NewAssociationHelper(p.evmKeeper, p.bankKeeper, p.accountKeeper) - err = associationHelper.AssociateAddresses(ctx, seiAddr, evmAddr, pubkey) + err := associationHelper.AssociateAddresses(ctx, seiAddr, evmAddr, pubkey) if err != nil { return nil, err } diff --git a/precompiles/addr/addr_test.go b/precompiles/addr/addr_test.go index 06b84bf19..c43f94834 100644 --- a/precompiles/addr/addr_test.go +++ b/precompiles/addr/addr_test.go @@ -17,6 +17,148 @@ import ( tmtypes "github.com/tendermint/tendermint/proto/tendermint/types" ) +func TestAssociatePubKey(t *testing.T) { + testApp := testkeeper.EVMTestApp + ctx := testApp.NewContext(false, tmtypes.Header{}).WithBlockHeight(2) + k := &testApp.EvmKeeper + + pre, _ := addr.NewPrecompile(k, k.BankKeeper(), k.AccountKeeper()) + associatePubKey, err := pre.ABI.MethodById(pre.GetExecutor().(*addr.PrecompileExecutor).AssociatePubKeyID) + + // Target refers to the address that the caller is trying to associate. + targetPrivKey := testkeeper.MockPrivateKey() + targetPubKey := targetPrivKey.PubKey() + targetPubKeyHex := hex.EncodeToString(targetPubKey.Bytes()) + targetSeiAddress, targetEvmAddress := testkeeper.PrivateKeyToAddresses(targetPrivKey) + + // Caller refers to the party calling the precompile. + callerPrivKey := testkeeper.MockPrivateKey() + callerSeiAddress, callerEvmAddress := testkeeper.PrivateKeyToAddresses(callerPrivKey) + callerPubKey := callerPrivKey.PubKey() + callerPubKeyHex := hex.EncodeToString(callerPubKey.Bytes()) + + // Associate these addresses, so we can use them to test the case where addresses are already associated association. + k.SetAddressMapping(ctx, callerSeiAddress, callerEvmAddress) + + require.Nil(t, err) + + happyPathOutput, _ := associatePubKey.Outputs.Pack(targetSeiAddress.String(), targetEvmAddress) + + type args struct { + evm *vm.EVM + caller common.Address + pubKey string + value *big.Int + readOnly bool + } + tests := []struct { + name string + args args + wantRet []byte + wantErr bool + wantErrMsg string + wrongRet bool + }{ + { + name: "fails if payable", + args: args{ + evm: &vm.EVM{ + StateDB: state.NewDBImpl(ctx, k, true), + TxContext: vm.TxContext{Origin: callerEvmAddress}, + }, + caller: callerEvmAddress, + pubKey: targetPubKeyHex, + value: big.NewInt(10), + }, + wantErr: true, + wantErrMsg: "sending funds to a non-payable function", + }, + { + name: "fails on static call", + args: args{ + evm: &vm.EVM{ + StateDB: state.NewDBImpl(ctx, k, true), + TxContext: vm.TxContext{Origin: callerEvmAddress}, + }, + caller: callerEvmAddress, + pubKey: targetPubKeyHex, + value: big.NewInt(10), + readOnly: true, + }, + wantErr: true, + wantErrMsg: "cannot call associate pub key precompile from staticcall", + }, + { + name: "fails if input is appended with 0x", + args: args{ + evm: &vm.EVM{ + StateDB: state.NewDBImpl(ctx, k, true), + TxContext: vm.TxContext{Origin: callerEvmAddress}, + }, + caller: callerEvmAddress, + pubKey: fmt.Sprintf("0x%v", targetPubKeyHex), + value: big.NewInt(0), + }, + wantErr: true, + wantErrMsg: "encoding/hex: invalid byte: U+0078 'x'", + }, + { + name: "fails if addresses are already associated", + args: args{ + evm: &vm.EVM{ + StateDB: state.NewDBImpl(ctx, k, true), + TxContext: vm.TxContext{Origin: callerEvmAddress}, + }, + caller: callerEvmAddress, + pubKey: callerPubKeyHex, + value: big.NewInt(0), + }, + wantErr: true, + wantErrMsg: fmt.Sprintf("address %s is already associated with evm address %s", callerSeiAddress, callerEvmAddress), + }, + { + name: "happy path - associates addresses if signature is correct", + args: args{ + evm: &vm.EVM{ + StateDB: state.NewDBImpl(ctx, k, true), + TxContext: vm.TxContext{Origin: callerEvmAddress}, + }, + caller: callerEvmAddress, + pubKey: targetPubKeyHex, + value: big.NewInt(0), + }, + wantRet: happyPathOutput, + wantErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create the precompile and inputs + p, _ := addr.NewPrecompile(k, k.BankKeeper(), k.AccountKeeper()) + require.Nil(t, err) + inputs, err := associatePubKey.Inputs.Pack(tt.args.pubKey) + require.Nil(t, err) + + // Make the call to associate. + ret, err := p.Run(tt.args.evm, tt.args.caller, tt.args.caller, append(p.GetExecutor().(*addr.PrecompileExecutor).AssociatePubKeyID, inputs...), tt.args.value, tt.args.readOnly) + if (err != nil) != tt.wantErr { + t.Errorf("Run() error = %v, wantErr %v %v", err, tt.wantErr, string(ret)) + return + } + if err != nil { + require.Equal(t, vm.ErrExecutionReverted, err) + require.Equal(t, tt.wantErrMsg, string(ret)) + } else if tt.wrongRet { + // tt.wrongRet is set if we expect a return value that's different from the happy path. This means that the wrong addresses were associated. + require.NotEqual(t, tt.wantRet, ret) + } else { + require.Equal(t, tt.wantRet, ret) + } + }) + } +} + func TestAssociate(t *testing.T) { testApp := testkeeper.EVMTestApp ctx := testApp.NewContext(false, tmtypes.Header{}).WithBlockHeight(2) @@ -58,13 +200,14 @@ func TestAssociate(t *testing.T) { happyPathOutput, _ := associate.Outputs.Pack(targetSeiAddress.String(), targetEvmAddress) type args struct { - evm *vm.EVM - caller common.Address - v string - r string - s string - msg string - value *big.Int + evm *vm.EVM + caller common.Address + v string + r string + s string + msg string + value *big.Int + readOnly bool } tests := []struct { name string @@ -91,6 +234,24 @@ func TestAssociate(t *testing.T) { wantErr: true, wantErrMsg: "sending funds to a non-payable function", }, + { + name: "fails on static calls", + args: args{ + evm: &vm.EVM{ + StateDB: state.NewDBImpl(ctx, k, true), + TxContext: vm.TxContext{Origin: callerEvmAddress}, + }, + caller: callerEvmAddress, + v: v, + r: r, + s: s, + msg: prefixedMessage, + value: big.NewInt(10), + readOnly: true, + }, + wantErr: true, + wantErrMsg: "cannot call associate precompile from staticcall", + }, { name: "fails if input is not hex", args: args{ @@ -170,7 +331,7 @@ func TestAssociate(t *testing.T) { require.Nil(t, err) // Make the call to associate. - ret, err := p.Run(tt.args.evm, tt.args.caller, tt.args.caller, append(p.GetExecutor().(*addr.PrecompileExecutor).AssociateID, inputs...), tt.args.value, false) + ret, err := p.Run(tt.args.evm, tt.args.caller, tt.args.caller, append(p.GetExecutor().(*addr.PrecompileExecutor).AssociateID, inputs...), tt.args.value, tt.args.readOnly) if (err != nil) != tt.wantErr { t.Errorf("Run() error = %v, wantErr %v %v", err, tt.wantErr, string(ret)) return diff --git a/utils/helpers/address.go b/utils/helpers/address.go index e632a893b..e08e8e8c2 100644 --- a/utils/helpers/address.go +++ b/utils/helpers/address.go @@ -19,6 +19,10 @@ func GetAddresses(V *big.Int, R *big.Int, S *big.Int, data common.Hash) (common. return common.Address{}, sdk.AccAddress{}, nil, err } + return GetAddressesFromPubkeyBytes(pubkey) +} + +func GetAddressesFromPubkeyBytes(pubkey []byte) (common.Address, sdk.AccAddress, cryptotypes.PubKey, error) { evmAddr, err := PubkeyToEVMAddress(pubkey) if err != nil { return common.Address{}, sdk.AccAddress{}, nil, err From c1596737f285dacb22b5d3faf7751b6b9f431c19 Mon Sep 17 00:00:00 2001 From: Kartik Bhat Date: Tue, 27 Aug 2024 13:16:01 -0400 Subject: [PATCH 25/38] [WIP] Add State Store Archive Node Migration (#1772) * Add IAVL migration comman for seid tools * Fix go mod * Add migration command * Make snapshot creation sychrounous * Use latest version instead of given height * New SeiDb Tag * State Store Migration * Add more todo * Bump sei wasmd + add to testing utils * Fix flags * Bump sei-wasmd * Fix SC export and import * Module by Module + logging * remove extra prefix * remove extra prefix * Add more logging * Prefix * Add wasm export/import * Fix wasm export * Fix function name * remove extractPrefix * Update logging * Add verification tool * Update verify command * Update comments * Add error handling * Add dex for sc migration * Fix * Fix * Fix * Fix set latest version * Fix test * Fix lint * Fix lint --------- Co-authored-by: yzang2019 --- app/test_state_store.go | 35 +++++- tools/cmd.go | 7 +- tools/migration/cmd/cmd.go | 99 +++++++++++++++++ tools/migration/sc/migrator.go | 195 ++++++++++++++++++++++++++++++++ tools/migration/ss/migrator.go | 196 +++++++++++++++++++++++++++++++++ tools/migration/wasm/keeper.go | 1 + 6 files changed, 527 insertions(+), 6 deletions(-) create mode 100644 tools/migration/cmd/cmd.go create mode 100644 tools/migration/sc/migrator.go create mode 100644 tools/migration/ss/migrator.go create mode 100644 tools/migration/wasm/keeper.go diff --git a/app/test_state_store.go b/app/test_state_store.go index 7595fd954..15b4d63e1 100644 --- a/app/test_state_store.go +++ b/app/test_state_store.go @@ -213,6 +213,37 @@ func (s *InMemoryStateStore) Import(version int64, ch <-chan types.SnapshotNode) return nil } +func (s *InMemoryStateStore) RawImport(ch <-chan types.RawSnapshotNode) error { + s.mu.Lock() + defer s.mu.Unlock() + + var latestVersion int64 + + for node := range ch { + storeKey := node.StoreKey + key := node.Key + value := node.Value + version := node.Version + + if s.data[storeKey] == nil { + s.data[storeKey] = make(map[int64]map[string][]byte) + } + + if s.data[storeKey][version] == nil { + s.data[storeKey][version] = make(map[string][]byte) + } + + s.data[storeKey][version][string(key)] = value + + if version > latestVersion { + latestVersion = version + } + } + + s.latestVersion = latestVersion + return nil +} + func (s *InMemoryStateStore) Prune(version int64) error { s.mu.Lock() defer s.mu.Unlock() @@ -235,10 +266,6 @@ func (s *InMemoryStateStore) Prune(version int64) error { return nil } -func (db *InMemoryStateStore) RawImport(ch <-chan types.RawSnapshotNode) error { - panic("implement me") -} - func (s *InMemoryStateStore) Close() error { s.mu.Lock() defer s.mu.Unlock() diff --git a/tools/cmd.go b/tools/cmd.go index 9e9de479f..35fc9f177 100644 --- a/tools/cmd.go +++ b/tools/cmd.go @@ -1,7 +1,8 @@ package tools import ( - "github.com/sei-protocol/sei-chain/tools/tx-scanner/cmd" + migration "github.com/sei-protocol/sei-chain/tools/migration/cmd" + scanner "github.com/sei-protocol/sei-chain/tools/tx-scanner/cmd" "github.com/spf13/cobra" ) @@ -10,6 +11,8 @@ func ToolCmd() *cobra.Command { Use: "tools", Short: "A set of useful tools for sei chain", } - toolsCmd.AddCommand(cmd.ScanCmd()) + toolsCmd.AddCommand(scanner.ScanCmd()) + toolsCmd.AddCommand(migration.MigrateCmd()) + toolsCmd.AddCommand(migration.VerifyMigrationCmd()) return toolsCmd } diff --git a/tools/migration/cmd/cmd.go b/tools/migration/cmd/cmd.go new file mode 100644 index 000000000..d1ff27a28 --- /dev/null +++ b/tools/migration/cmd/cmd.go @@ -0,0 +1,99 @@ +package cmd + +import ( + "fmt" + "path/filepath" + + "github.com/cosmos/cosmos-sdk/store/rootmulti" + "github.com/sei-protocol/sei-chain/tools/migration/sc" + "github.com/sei-protocol/sei-chain/tools/migration/ss" + "github.com/spf13/cobra" + dbm "github.com/tendermint/tm-db" +) + +func MigrateCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "migrate-iavl", + Short: "A tool to migrate full IAVL data store to SeiDB. Use this tool to migrate IAVL to SeiDB SC and SS database.", + Run: execute, + } + cmd.PersistentFlags().String("home-dir", "/root/.sei", "Sei home directory") + cmd.PersistentFlags().String("target-db", "", "Available options: [SS, SC]") + return cmd +} + +func execute(cmd *cobra.Command, _ []string) { + homeDir, _ := cmd.Flags().GetString("home-dir") + target, _ := cmd.Flags().GetString("target-db") + dataDir := filepath.Join(homeDir, "data") + db, err := dbm.NewGoLevelDB("application", dataDir) + if err != nil { + panic(err) + } + latestVersion := rootmulti.GetLatestVersion(db) + fmt.Printf("latest version: %d\n", latestVersion) + if target == "SS" { + if err = migrateSS(latestVersion, homeDir, db); err != nil { + panic(err) + } + } else if target == "SC" { + if err = migrateSC(latestVersion, homeDir, db); err != nil { + panic(err) + } + } else { + panic("Invalid target-db, either SS or SC should be provided") + } +} + +func migrateSC(version int64, homeDir string, db dbm.DB) error { + migrator := sc.NewMigrator(homeDir, db) + return migrator.Migrate(version) +} + +func migrateSS(version int64, homeDir string, db dbm.DB) error { + migrator := ss.NewMigrator(homeDir, db) + return migrator.Migrate(version, homeDir) +} + +func verifySS(version int64, homeDir string, db dbm.DB) error { + migrator := ss.NewMigrator(homeDir, db) + return migrator.Verify(version) +} + +func VerifyMigrationCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "verify-migration", + Short: "A tool to verify migration of a IAVL data store to SeiDB at a particular height.", + Run: verify, + } + + cmd.PersistentFlags().Int64("version", -1, "Version to run migration verification on") + cmd.PersistentFlags().String("home-dir", "/root/.sei", "Sei home directory") + + return cmd +} + +func verify(cmd *cobra.Command, _ []string) { + homeDir, _ := cmd.Flags().GetString("home-dir") + version, _ := cmd.Flags().GetInt64("version") + + fmt.Printf("version %d\n", version) + + if version <= 0 { + panic("Must specify version for verification") + } + + dataDir := filepath.Join(homeDir, "data") + db, err := dbm.NewGoLevelDB("application", dataDir) + if err != nil { + panic(err) + } + + err = verifySS(version, homeDir, db) + if err != nil { + fmt.Printf("Verification Failed with err: %s\n", err.Error()) + return + } + + fmt.Println("Verification Succeeded") +} diff --git a/tools/migration/sc/migrator.go b/tools/migration/sc/migrator.go new file mode 100644 index 000000000..5eec43a62 --- /dev/null +++ b/tools/migration/sc/migrator.go @@ -0,0 +1,195 @@ +package sc + +import ( + "fmt" + "io" + "os" + "path/filepath" + + "github.com/CosmWasm/wasmd/x/wasm" + "github.com/CosmWasm/wasmd/x/wasm/keeper" + "github.com/cosmos/cosmos-sdk/snapshots" + "github.com/cosmos/cosmos-sdk/snapshots/types" + "github.com/cosmos/cosmos-sdk/store" + "github.com/cosmos/cosmos-sdk/store/rootmulti" + rootmulti2 "github.com/cosmos/cosmos-sdk/storev2/rootmulti" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + acltypes "github.com/cosmos/cosmos-sdk/x/accesscontrol/types" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" + "github.com/cosmos/cosmos-sdk/x/feegrant" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" + paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" + stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" + ibctransfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" + ibchost "github.com/cosmos/ibc-go/v3/modules/core/24-host" + "github.com/sei-protocol/sei-chain/app/params" + epochmoduletypes "github.com/sei-protocol/sei-chain/x/epoch/types" + evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" + minttypes "github.com/sei-protocol/sei-chain/x/mint/types" + oracletypes "github.com/sei-protocol/sei-chain/x/oracle/types" + tokenfactorytypes "github.com/sei-protocol/sei-chain/x/tokenfactory/types" + "github.com/sei-protocol/sei-db/config" + "github.com/tendermint/tendermint/libs/log" + dbm "github.com/tendermint/tm-db" +) + +type Migrator struct { + homeDir string + logger log.Logger + storeV1 store.CommitMultiStore + storeV2 store.CommitMultiStore +} + +var Keys = sdk.NewKVStoreKeys( + acltypes.StoreKey, authtypes.StoreKey, authzkeeper.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey, + minttypes.StoreKey, distrtypes.StoreKey, slashingtypes.StoreKey, + govtypes.StoreKey, paramstypes.StoreKey, ibchost.StoreKey, upgradetypes.StoreKey, feegrant.StoreKey, + evidencetypes.StoreKey, ibctransfertypes.StoreKey, capabilitytypes.StoreKey, oracletypes.StoreKey, + evmtypes.StoreKey, wasm.StoreKey, epochmoduletypes.StoreKey, tokenfactorytypes.StoreKey, "dex", +) + +func NewMigrator(homeDir string, db dbm.DB) *Migrator { + logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)) + + // Creating CMS for store V1 + cmsV1 := rootmulti.NewStore(db, logger) + for _, key := range Keys { + cmsV1.MountStoreWithDB(key, sdk.StoreTypeIAVL, nil) + } + err := cmsV1.LoadLatestVersion() + if err != nil { + panic(err) + } + + // Creating CMS for store V2 + scConfig := config.DefaultStateCommitConfig() + scConfig.Enable = true + ssConfig := config.DefaultStateStoreConfig() + ssConfig.Enable = false + cmsV2 := rootmulti2.NewStore(homeDir, logger, scConfig, ssConfig) + for _, key := range Keys { + cmsV2.MountStoreWithDB(key, sdk.StoreTypeIAVL, db) + } + err = cmsV2.LoadLatestVersion() + if err != nil { + panic(err) + } + return &Migrator{ + homeDir: homeDir, + logger: logger, + storeV1: cmsV1, + storeV2: cmsV2, + } +} + +func (m *Migrator) Migrate(version int64) error { + // Create a snapshot + chunks := make(chan io.ReadCloser) + go func() { + err := m.createSnapshot(uint64(version), chunks) + if err != nil { + panic(err) + } + }() + streamReader, err := snapshots.NewStreamReader(chunks) + if err != nil { + return err + } + fmt.Printf("Start restoring SC store for height: %d\n", version) + next, _ := m.storeV2.Restore(uint64(version), types.CurrentFormat, streamReader) + for { + if next.Item == nil { + // end of stream + break + } + metadata := next.GetExtension() + if metadata == nil { + return sdkerrors.Wrapf(sdkerrors.ErrLogic, "unknown snapshot item %T", next.Item) + } + wasmSnapshotter := CreateWasmSnapshotter(m.storeV2, m.homeDir) + extension := wasmSnapshotter + fmt.Printf("Start restoring wasm extension for height: %d\n", version) + next, err = extension.Restore(uint64(version), metadata.Format, streamReader) + if err != nil { + return sdkerrors.Wrapf(err, "extension %s restore", metadata.Name) + } + } + fmt.Printf("Finished restoring SC store for height: %d\n", version) + return nil +} + +func (m *Migrator) createSnapshot(height uint64, chunks chan<- io.ReadCloser) error { + streamWriter := snapshots.NewStreamWriter(chunks) + defer streamWriter.Close() + fmt.Printf("Start creating snapshot for height: %d\n", height) + if err := m.storeV1.Snapshot(height, streamWriter); err != nil { + m.logger.Error("Snapshot creation failed", "err", err) + streamWriter.CloseWithError(err) + } + + // Handle wasm snapshot export + wasmSnapshotter := CreateWasmSnapshotter(m.storeV1, m.homeDir) + extension := wasmSnapshotter + // write extension metadata + err := streamWriter.WriteMsg(&types.SnapshotItem{ + Item: &types.SnapshotItem_Extension{ + Extension: &types.SnapshotExtensionMeta{ + Name: wasmSnapshotter.SnapshotName(), + Format: extension.SnapshotFormat(), + }, + }, + }) + fmt.Printf("Finished writing extension metadata for height: %d\n", height) + if err != nil { + streamWriter.CloseWithError(err) + return err + } + fmt.Printf("Start extension snapshot for height: %d\n", height) + if err = extension.Snapshot(height, streamWriter); err != nil { + streamWriter.CloseWithError(err) + return err + } + return nil + +} + +func CreateWasmSnapshotter(cms sdk.MultiStore, homeDir string) *keeper.WasmSnapshotter { + var ( + keyParams = sdk.NewKVStoreKey(paramstypes.StoreKey) + tkeyParams = sdk.NewTransientStoreKey(paramstypes.TStoreKey) + ) + encodingConfig := params.MakeEncodingConfig() + pk := paramskeeper.NewKeeper(encodingConfig.Marshaler, encodingConfig.Amino, keyParams, tkeyParams) + wasmKeeper := keeper.NewKeeper( + encodingConfig.Marshaler, + Keys[wasm.StoreKey], + paramskeeper.Keeper{}, + pk.Subspace("wasm"), + authkeeper.AccountKeeper{}, + nil, + stakingkeeper.Keeper{}, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + filepath.Join(homeDir, "wasm"), + wasm.DefaultWasmConfig(), + "iterator,staking,stargate,sei", + ) + return keeper.NewWasmSnapshotter(cms, &wasmKeeper) + +} diff --git a/tools/migration/ss/migrator.go b/tools/migration/ss/migrator.go new file mode 100644 index 000000000..cb4e42bfc --- /dev/null +++ b/tools/migration/ss/migrator.go @@ -0,0 +1,196 @@ +package ss + +import ( + "bytes" + "fmt" + + "github.com/cosmos/iavl" + "github.com/sei-protocol/sei-db/config" + "github.com/sei-protocol/sei-db/ss" + "github.com/sei-protocol/sei-db/ss/types" + "github.com/tendermint/tendermint/libs/log" + dbm "github.com/tendermint/tm-db" +) + +type Migrator struct { + iavlDB dbm.DB + stateStore types.StateStore +} + +// TODO: make this configurable? +const ( + DefaultCacheSize int = 10000 +) + +var modules = []string{ + "wasm", "aclaccesscontrol", "oracle", "epoch", "mint", "acc", "bank", "feegrant", "staking", "distribution", "slashing", "gov", "params", "ibc", "upgrade", "evidence", "transfer", "tokenfactory", +} + +func NewMigrator(homeDir string, db dbm.DB) *Migrator { + // TODO: Pass in more configs outside default, in particular ImportNumWorkers + ssConfig := config.DefaultStateStoreConfig() + ssConfig.Enable = true + + stateStore, err := ss.NewStateStore(log.NewNopLogger(), homeDir, ssConfig) + if err != nil { + panic(err) + } + + return &Migrator{ + iavlDB: db, + stateStore: stateStore, + } +} + +func (m *Migrator) Migrate(version int64, homeDir string) error { + // TODO: Read in capacity of this buffered channel as param + ch := make(chan types.RawSnapshotNode, 1000) + errCh := make(chan error, 2) + + fmt.Println("Beginning Migration...") + + // Goroutine to iterate through iavl and export leaf nodes + go func() { + defer close(ch) + errCh <- ExportLeafNodes(m.iavlDB, ch) + }() + + go func() { + errCh <- m.stateStore.RawImport(ch) + }() + + // Block on completion of both goroutines + for i := 0; i < 2; i++ { + if err := <-errCh; err != nil { + return err + } + } + + // Set latest version + err := m.stateStore.SetLatestVersion(version) + if err != nil { + return err + } + + return nil +} + +func (m *Migrator) Verify(version int64) error { + var verifyErr error + for _, module := range modules { + tree, err := ReadTree(m.iavlDB, version, []byte(buildTreePrefix(module))) + if err != nil { + fmt.Printf("Error reading tree %s: %s\n", module, err.Error()) + return err + } + var count int + _, err = tree.Iterate(func(key []byte, value []byte) bool { + // Run Get() against PebbleDB and verify values match + val, err := m.stateStore.Get(module, version, key) + if err != nil { + verifyErr = fmt.Errorf("verification error: error retrieving key %s with err %w", string(key), err) + return true + } + if val == nil { + verifyErr = fmt.Errorf("verification error: Key %s does not exist in state store", string(key)) + return true + } + if !bytes.Equal(val, value) { + verifyErr = fmt.Errorf("verification error: value doesn't match for key %s", string(key)) + } + count++ + if count%10000 == 0 { + fmt.Printf("Verified %d keys in for module %s\n", count, module) + } + return false + }) + if err != nil { + fmt.Printf("Failed to iterate the tree %s: %s\n", module, err.Error()) + return err + } + fmt.Printf("Finished verifying module %s, total scanned: %d keys\n", module, count) + } + return verifyErr +} + +// Export leaf nodes of iavl +func ExportLeafNodes(db dbm.DB, ch chan<- types.RawSnapshotNode) error { + // Module by module, TODO: Potentially parallelize + count := 0 + leafNodeCount := 0 + fmt.Println("Scanning database and exporting leaf nodes...") + + for _, module := range modules { + fmt.Printf("Iterating through %s module...\n", module) + + // Can't use the previous, have to create an inner + prefixDB := dbm.NewPrefixDB(db, []byte(buildRawPrefix(module))) + itr, err := prefixDB.Iterator(nil, nil) + if err != nil { + fmt.Printf("error Export Leaf Nodes %+v\n", err) + return fmt.Errorf("failed to create iterator: %w", err) + } + defer itr.Close() + + for ; itr.Valid(); itr.Next() { + value := bytes.Clone(itr.Value()) + + node, err := iavl.MakeNode(value) + + if err != nil { + fmt.Printf("failed to make node err: %+v\n", err) + return fmt.Errorf("failed to make node: %w", err) + } + + // leaf node + if node.GetHeight() == 0 { + leafNodeCount++ + ch <- types.RawSnapshotNode{ + // TODO: Likely need to clone + StoreKey: module, + Key: node.GetNodeKey(), + Value: node.GetValue(), + Version: node.GetVersion(), + } + } + + count++ + if count%10000 == 0 { + fmt.Printf("Total scanned: %d, leaf nodes exported: %d\n", count, leafNodeCount) + } + } + + fmt.Printf("Finished scanning module %s Total scanned: %d, leaf nodes exported: %d\n", module, count, leafNodeCount) + + if err := itr.Error(); err != nil { + fmt.Printf("iterator error: %+v\n", err) + return fmt.Errorf("iterator error: %w", err) + } + + } + + fmt.Printf("DB contains %d entries, exported %d leaf nodes\n", count, leafNodeCount) + return nil +} + +func buildRawPrefix(moduleName string) string { + return fmt.Sprintf("s/k:%s/n", moduleName) +} + +func buildTreePrefix(moduleName string) string { + return fmt.Sprintf("s/k:%s/", moduleName) +} + +func ReadTree(db dbm.DB, version int64, prefix []byte) (*iavl.MutableTree, error) { + // TODO: Verify if we need a prefix here (or can just iterate through all modules) + if len(prefix) != 0 { + db = dbm.NewPrefixDB(db, prefix) + } + + tree, err := iavl.NewMutableTree(db, DefaultCacheSize, true) + if err != nil { + return nil, err + } + _, err = tree.LoadVersion(version) + return tree, err +} diff --git a/tools/migration/wasm/keeper.go b/tools/migration/wasm/keeper.go new file mode 100644 index 000000000..955e5a9a8 --- /dev/null +++ b/tools/migration/wasm/keeper.go @@ -0,0 +1 @@ +package wasm From 0e39c3803a0c1a0ac7a4b7d49ec010b4d04b642b Mon Sep 17 00:00:00 2001 From: yirenz Date: Tue, 27 Aug 2024 18:21:56 -0400 Subject: [PATCH 26/38] feat: limit MsgExec nested level to prevent excessive nesting (#1826) - introduces a limit on the nested level of MsgExec to prevent potential attacks. Co-authored-by: blindchaser --- app/antedecorators/authz_nested_message.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/app/antedecorators/authz_nested_message.go b/app/antedecorators/authz_nested_message.go index a7d4957e9..08064fc0f 100644 --- a/app/antedecorators/authz_nested_message.go +++ b/app/antedecorators/authz_nested_message.go @@ -8,6 +8,9 @@ import ( evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" ) +// maxNestedMsgs defines a cap for the number of nested messages on a MsgExec message +const maxNestedMsgs = 5 + type AuthzNestedMessageDecorator struct{} func NewAuthzNestedMessageDecorator() AuthzNestedMessageDecorator { @@ -19,7 +22,7 @@ func (ad AuthzNestedMessageDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, sim switch m := msg.(type) { case *authz.MsgExec: // find nested evm messages - containsEvm, err := ad.CheckAuthzContainsEvm(ctx, m) + containsEvm, err := ad.CheckAuthzContainsEvm(ctx, m, 0) if err != nil { return ctx, err } @@ -34,7 +37,10 @@ func (ad AuthzNestedMessageDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, sim return next(ctx, tx, simulate) } -func (ad AuthzNestedMessageDecorator) CheckAuthzContainsEvm(ctx sdk.Context, authzMsg *authz.MsgExec) (bool, error) { +func (ad AuthzNestedMessageDecorator) CheckAuthzContainsEvm(ctx sdk.Context, authzMsg *authz.MsgExec, nestedLvl int) (bool, error) { + if nestedLvl >= maxNestedMsgs { + return false, errors.New("permission denied, more nested msgs than permitted") + } msgs, err := authzMsg.GetMessages() if err != nil { return false, err @@ -46,12 +52,10 @@ func (ad AuthzNestedMessageDecorator) CheckAuthzContainsEvm(ctx sdk.Context, aut return true, nil case *authz.MsgExec: // find nested to check for evm - valid, err := ad.CheckAuthzContainsEvm(ctx, m) - + valid, err := ad.CheckAuthzContainsEvm(ctx, m, nestedLvl+1) if err != nil { return false, err } - if valid { return true, nil } From 1e6db8bdb8dca79bcfa8fad580ceecd1031c59c3 Mon Sep 17 00:00:00 2001 From: codchen Date: Wed, 28 Aug 2024 12:28:03 +0800 Subject: [PATCH 27/38] Prevent ddos against associate msgs (#1818) * Prevent ddos against associate msgs * fix unit tests --- app/antedecorators/gasless.go | 2 + evmrpc/block_test.go | 10 ++- precompiles/bank/bank_test.go | 18 ++-- precompiles/common/precompiles_test.go | 9 +- precompiles/pointerview/pointerview_test.go | 4 +- x/evm/ante/basic_test.go | 4 +- x/evm/ante/fee_test.go | 7 +- x/evm/ante/gas_test.go | 4 +- x/evm/ante/preprocess_test.go | 26 ++++-- x/evm/ante/sig_test.go | 7 +- x/evm/genesis_test.go | 3 +- x/evm/gov_test.go | 3 +- x/evm/integration_test.go | 99 +++++++++++++++++++++ x/evm/keeper/address_test.go | 9 +- x/evm/keeper/code_test.go | 6 +- x/evm/keeper/coinbase_test.go | 5 +- x/evm/keeper/genesis.go | 22 ++--- x/evm/keeper/genesis_test.go | 5 +- x/evm/keeper/grpc_query_test.go | 4 +- x/evm/keeper/nonce_test.go | 7 +- x/evm/keeper/params_test.go | 4 +- x/evm/keeper/pointer_test.go | 9 +- x/evm/keeper/pointer_upgrade_test.go | 13 ++- x/evm/keeper/receipt_test.go | 5 +- x/evm/keeper/state_test.go | 4 +- x/evm/keeper/tx_test.go | 5 +- x/evm/migrations/fix_total_supply_test.go | 4 +- x/evm/state/accesslist_test.go | 13 ++- x/evm/state/balance_test.go | 13 ++- x/evm/state/check_test.go | 7 +- x/evm/state/code_test.go | 4 +- x/evm/state/log_test.go | 7 +- x/evm/state/nonce_test.go | 7 +- x/evm/state/refund_test.go | 4 +- x/evm/state/state_test.go | 13 ++- x/evm/state/transfer_test.go | 4 +- x/evm/types/constants.go | 3 + x/evm/types/message_associate.go | 3 + x/evm/types/message_evm_transaction.go | 14 ++- 39 files changed, 293 insertions(+), 97 deletions(-) create mode 100644 x/evm/types/constants.go diff --git a/app/antedecorators/gasless.go b/app/antedecorators/gasless.go index 2835b93ba..2208c8154 100644 --- a/app/antedecorators/gasless.go +++ b/app/antedecorators/gasless.go @@ -125,6 +125,8 @@ func IsTxGasless(tx sdk.Tx, ctx sdk.Context, oracleKeeper oraclekeeper.Keeper, e if !evmAssociateIsGasless(m, ctx, evmKeeper) { return false, nil } + // ddos prevention + return len(tx.GetMsgs()) == 1, nil default: return false, nil } diff --git a/evmrpc/block_test.go b/evmrpc/block_test.go index b12f9fbdf..37b5090df 100644 --- a/evmrpc/block_test.go +++ b/evmrpc/block_test.go @@ -4,6 +4,7 @@ import ( "crypto/sha256" "math/big" "testing" + "time" types2 "github.com/tendermint/tendermint/proto/tendermint/types" @@ -150,7 +151,8 @@ func verifyBlockResult(t *testing.T, resObj map[string]interface{}) { } func TestEncodeTmBlock_EmptyTransactions(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) block := &coretypes.ResultBlock{ BlockID: MockBlockID, Block: &tmtypes.Block{ @@ -180,7 +182,8 @@ func TestEncodeTmBlock_EmptyTransactions(t *testing.T) { } func TestEncodeBankMsg(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) fromSeiAddr, _ := testkeeper.MockAddressPair() toSeiAddr, _ := testkeeper.MockAddressPair() b := TxConfig.NewTxBuilder() @@ -224,7 +227,8 @@ func TestEncodeBankMsg(t *testing.T) { } func TestEncodeWasmExecuteMsg(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx(nil) fromSeiAddr, fromEvmAddr := testkeeper.MockAddressPair() toSeiAddr, _ := testkeeper.MockAddressPair() b := TxConfig.NewTxBuilder() diff --git a/precompiles/bank/bank_test.go b/precompiles/bank/bank_test.go index 107cbc69e..931898452 100644 --- a/precompiles/bank/bank_test.go +++ b/precompiles/bank/bank_test.go @@ -7,6 +7,7 @@ import ( "math/big" "strings" "testing" + "time" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -338,7 +339,8 @@ func TestSendForUnlinkedReceiver(t *testing.T) { } func TestMetadata(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) k.BankKeeper().SetDenomMetaData(ctx, banktypes.Metadata{Name: "SEI", Symbol: "usei", Base: "usei"}) p, err := bank.NewPrecompile(k.BankKeeper(), k, k.AccountKeeper()) require.Nil(t, err) @@ -375,20 +377,10 @@ func TestMetadata(t *testing.T) { outputs, err = decimal.Outputs.Unpack(res) require.Nil(t, err) require.Equal(t, uint8(0), outputs[0]) - - supply, err := p.ABI.MethodById(p.GetExecutor().(*bank.PrecompileExecutor).SupplyID) - require.Nil(t, err) - args, err = supply.Inputs.Pack("usei") - require.Nil(t, err) - res, err = p.Run(&evm, common.Address{}, common.Address{}, append(p.GetExecutor().(*bank.PrecompileExecutor).SupplyID, args...), nil, false) - require.Nil(t, err) - outputs, err = supply.Outputs.Unpack(res) - require.Nil(t, err) - require.Equal(t, big.NewInt(10), outputs[0]) } func TestRequiredGas(t *testing.T) { - k, _ := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper p, err := bank.NewPrecompile(k.BankKeeper(), k, k.AccountKeeper()) require.Nil(t, err) balanceRequiredGas := p.RequiredGas(p.GetExecutor().(*bank.PrecompileExecutor).BalanceID) @@ -398,7 +390,7 @@ func TestRequiredGas(t *testing.T) { } func TestAddress(t *testing.T) { - k, _ := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper p, err := bank.NewPrecompile(k.BankKeeper(), k, k.AccountKeeper()) require.Nil(t, err) require.Equal(t, common.HexToAddress(bank.BankAddress), p.Address()) diff --git a/precompiles/common/precompiles_test.go b/precompiles/common/precompiles_test.go index fab3d849f..eae5ad7ab 100644 --- a/precompiles/common/precompiles_test.go +++ b/precompiles/common/precompiles_test.go @@ -39,7 +39,8 @@ func TestValidteNonPayable(t *testing.T) { func TestHandlePrecompileError(t *testing.T) { _, evmAddr := testkeeper.MockAddressPair() - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx(nil) stateDB := state.NewDBImpl(ctx, k, false) evm := &vm.EVM{StateDB: stateDB} @@ -66,7 +67,8 @@ func (e *MockPrecompileExecutor) Execute(ctx sdk.Context, method *abi.Method, ca } func TestPrecompileRun(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx(nil) abiBz, err := os.ReadFile("erc20_abi.json") require.Nil(t, err) newAbi, err := abi.JSON(bytes.NewReader(abiBz)) @@ -106,7 +108,8 @@ func (e *MockDynamicGasPrecompileExecutor) EVMKeeper() common.EVMKeeper { } func TestDynamicGasPrecompileRun(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx(nil) abiBz, err := os.ReadFile("erc20_abi.json") require.Nil(t, err) newAbi, err := abi.JSON(bytes.NewReader(abiBz)) diff --git a/precompiles/pointerview/pointerview_test.go b/precompiles/pointerview/pointerview_test.go index 19054bb9a..e338a9c43 100644 --- a/precompiles/pointerview/pointerview_test.go +++ b/precompiles/pointerview/pointerview_test.go @@ -2,6 +2,7 @@ package pointerview_test import ( "testing" + "time" "github.com/ethereum/go-ethereum/common" "github.com/sei-protocol/sei-chain/precompiles/pointerview" @@ -13,7 +14,8 @@ import ( ) func TestPointerView(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) p, err := pointerview.NewPrecompile(k) require.Nil(t, err) _, pointer := testkeeper.MockAddressPair() diff --git a/x/evm/ante/basic_test.go b/x/evm/ante/basic_test.go index d1976c87e..6f6ceb5cd 100644 --- a/x/evm/ante/basic_test.go +++ b/x/evm/ante/basic_test.go @@ -2,6 +2,7 @@ package ante_test import ( "testing" + "time" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -14,7 +15,8 @@ import ( ) func TestBasicDecorator(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) a := ante.NewBasicDecorator(k) msg, _ := types.NewMsgEVMTransaction(ðtx.LegacyTx{}) ctx, err := a.AnteHandle(ctx, &mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { diff --git a/x/evm/ante/fee_test.go b/x/evm/ante/fee_test.go index 8b47c980e..138d22dbd 100644 --- a/x/evm/ante/fee_test.go +++ b/x/evm/ante/fee_test.go @@ -5,6 +5,7 @@ import ( "math" "math/big" "testing" + "time" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" @@ -20,7 +21,8 @@ import ( ) func TestEVMFeeCheckDecorator(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) handler := ante.NewEVMFeeCheckDecorator(k) privKey := testkeeper.MockPrivateKey() testPrivHex := hex.EncodeToString(privKey.Bytes()) @@ -113,7 +115,8 @@ func TestEVMFeeCheckDecorator(t *testing.T) { } func TestCalculatePriorityScenarios(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) decorator := ante.NewEVMFeeCheckDecorator(k) _1gwei := big.NewInt(100000000000) diff --git a/x/evm/ante/gas_test.go b/x/evm/ante/gas_test.go index 53a57155c..d1cac2b93 100644 --- a/x/evm/ante/gas_test.go +++ b/x/evm/ante/gas_test.go @@ -2,6 +2,7 @@ package ante_test import ( "testing" + "time" sdk "github.com/cosmos/cosmos-sdk/types" testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" @@ -12,7 +13,8 @@ import ( ) func TestGasLimitDecorator(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) a := ante.NewGasLimitDecorator(k) limitMsg, _ := types.NewMsgEVMTransaction(ðtx.LegacyTx{GasLimit: 100}) ctx, err := a.AnteHandle(ctx, &mockTx{msgs: []sdk.Msg{limitMsg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { diff --git a/x/evm/ante/preprocess_test.go b/x/evm/ante/preprocess_test.go index 0c20790f4..b503f07f5 100644 --- a/x/evm/ante/preprocess_test.go +++ b/x/evm/ante/preprocess_test.go @@ -29,7 +29,8 @@ import ( ) func TestPreprocessAnteHandler(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx(nil) handler := ante.NewEVMPreprocessDecorator(k, k.AccountKeeper()) privKey := testkeeper.MockPrivateKey() seiAddr, evmAddr := testkeeper.PrivateKeyToAddresses(privKey) @@ -70,7 +71,8 @@ func TestPreprocessAnteHandler(t *testing.T) { } func TestPreprocessAnteHandlerUnprotected(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx(nil) handler := ante.NewEVMPreprocessDecorator(k, k.AccountKeeper()) gasPrice := sdk.NewInt(73141930316) amt := sdk.NewInt(270000000000000000) @@ -98,7 +100,8 @@ func TestPreprocessAnteHandlerUnprotected(t *testing.T) { } func TestPreprocessAssociateTx(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx(nil) handler := ante.NewEVMPreprocessDecorator(k, k.AccountKeeper()) privKey := testkeeper.MockPrivateKey() testPrivHex := hex.EncodeToString(privKey.Bytes()) @@ -141,7 +144,8 @@ func TestPreprocessAssociateTx(t *testing.T) { } func TestPreprocessAssociateTxWithWeiBalance(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx(nil) handler := ante.NewEVMPreprocessDecorator(k, k.AccountKeeper()) privKey := testkeeper.MockPrivateKey() testPrivHex := hex.EncodeToString(privKey.Bytes()) @@ -188,7 +192,7 @@ func TestGetVersion(t *testing.T) { } func TestAnteDeps(t *testing.T) { - k, _ := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper handler := ante.NewEVMPreprocessDecorator(k, k.AccountKeeper()) msg, _ := types.NewMsgEVMTransaction(ðtx.LegacyTx{GasLimit: 100}) msg.Derived = &derived.Derived{ @@ -204,7 +208,8 @@ func TestAnteDeps(t *testing.T) { } func TestEVMAddressDecorator(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx(nil) privKey := testkeeper.MockPrivateKey() sender, evmAddr := testkeeper.PrivateKeyToAddresses(privKey) recipient, _ := testkeeper.MockAddressPair() @@ -221,7 +226,8 @@ func TestEVMAddressDecorator(t *testing.T) { } func TestIsAccountBalancePositive(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx(nil) s1, e1 := testkeeper.MockAddressPair() s2, e2 := testkeeper.MockAddressPair() s3, e3 := testkeeper.MockAddressPair() @@ -253,7 +259,8 @@ func (m MockTxIncompatible) ValidateBasic() error { } func TestEVMAddressDecoratorContinueDespiteErrors(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx(nil) handler := ante.NewEVMAddressDecorator(k, k.AccountKeeper()) _, err := handler.AnteHandle(ctx, MockTxIncompatible{}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { @@ -294,7 +301,8 @@ func TestEVMAddressDecoratorContinueDespiteErrors(t *testing.T) { } func TestMigrateBalance(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx(nil) admin, _ := testkeeper.MockAddressPair() seiAddr, evmAddr := testkeeper.MockAddressPair() k.BankKeeper().AddCoins(ctx, sdk.AccAddress(evmAddr[:]), sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(2))), false) diff --git a/x/evm/ante/sig_test.go b/x/evm/ante/sig_test.go index 22bae527a..a4ccd8895 100644 --- a/x/evm/ante/sig_test.go +++ b/x/evm/ante/sig_test.go @@ -4,6 +4,7 @@ import ( "encoding/hex" "math/big" "testing" + "time" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" @@ -18,7 +19,8 @@ import ( ) func TestEVMSigVerifyDecorator(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) handler := ante.NewEVMSigVerifyDecorator(k, func() sdk.Context { return ctx }) privKey := testkeeper.MockPrivateKey() testPrivHex := hex.EncodeToString(privKey.Bytes()) @@ -99,7 +101,8 @@ func TestEVMSigVerifyDecorator(t *testing.T) { } func TestSigVerifyPendingTransaction(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) ctx = ctx.WithIsCheckTx(true) handler := ante.NewEVMSigVerifyDecorator(k, func() sdk.Context { return ctx }) privKey := testkeeper.MockPrivateKey() diff --git a/x/evm/genesis_test.go b/x/evm/genesis_test.go index bcb78c0cb..2ad13e0f4 100644 --- a/x/evm/genesis_test.go +++ b/x/evm/genesis_test.go @@ -13,7 +13,8 @@ import ( ) func TestExportImportGenesis(t *testing.T) { - keeper, origctx := testkeeper.MockEVMKeeper() + keeper := &testkeeper.EVMTestApp.EvmKeeper + origctx := testkeeper.EVMTestApp.GetContextForDeliverTx(nil) ctx := origctx.WithMultiStore(origctx.MultiStore().CacheMultiStore()) seiAddr, evmAddr := testkeeper.MockAddressPair() keeper.SetAddressMapping(ctx, seiAddr, evmAddr) diff --git a/x/evm/gov_test.go b/x/evm/gov_test.go index 8b6769394..402bf4f5c 100644 --- a/x/evm/gov_test.go +++ b/x/evm/gov_test.go @@ -11,7 +11,8 @@ import ( ) func TestAddERCNativePointerProposalsV2(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx(nil) require.Nil(t, evm.HandleAddERCNativePointerProposalV2(ctx, k, &types.AddERCNativePointerProposalV2{ Token: "test", Name: "NAME", diff --git a/x/evm/integration_test.go b/x/evm/integration_test.go index 29eb74ab2..9ed2990fa 100644 --- a/x/evm/integration_test.go +++ b/x/evm/integration_test.go @@ -9,10 +9,17 @@ import ( "fmt" "math/big" "os" + "strings" "testing" "time" + "github.com/cosmos/cosmos-sdk/client" + clienttx "github.com/cosmos/cosmos-sdk/client/tx" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/tx/signing" + xauthsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" ethabi "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" @@ -282,3 +289,95 @@ func TestNonceIncrementsForInsufficientFunds(t *testing.T) { require.Equal(t, uint32(5), res.Code) // insufficient funds has error code 5 require.Equal(t, uint64(1), k.GetNonce(ctx, evmAddr)) // make sure nonce is incremented regardless } + +func TestInvalidAssociateMsg(t *testing.T) { + // EVM associate tx + k := testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()).WithChainID("sei-test").WithBlockHeight(1) + privKey := testkeeper.MockPrivateKey() + seiAddr, _ := testkeeper.PrivateKeyToAddresses(privKey) + amt := sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(1000000))) + k.BankKeeper().MintCoins(ctx, "evm", amt) + k.BankKeeper().SendCoinsFromModuleToAccount(ctx, "evm", seiAddr, amt) + testPrivHex := hex.EncodeToString(privKey.Bytes()) + key, _ := crypto.HexToECDSA(testPrivHex) + customMsg := strings.Repeat("a", 65) + hash := crypto.Keccak256Hash([]byte(customMsg)) + sig, err := crypto.Sign(hash[:], key) + require.Nil(t, err) + R, S, _, err := ethtx.DecodeSignature(sig) + require.Nil(t, err) + V := big.NewInt(int64(sig[64])) + require.Nil(t, err) + typedTx := ðtx.AssociateTx{ + V: V.Bytes(), R: R.Bytes(), S: S.Bytes(), CustomMessage: customMsg, + } + msg, err := types.NewMsgEVMTransaction(typedTx) + require.Nil(t, err) + txBuilder := testkeeper.EVMTestApp.GetTxConfig().NewTxBuilder() + txBuilder.SetMsgs(msg) + cosmosTx := txBuilder.GetTx() + txbz, err := testkeeper.EVMTestApp.GetTxConfig().TxEncoder()(cosmosTx) + require.Nil(t, err) + res := testkeeper.EVMTestApp.DeliverTx(ctx, abci.RequestDeliverTx{Tx: txbz}, cosmosTx, sha256.Sum256(txbz)) + require.Equal(t, uint32(21), res.Code) // tx too large + + // cosmos associate tx + amsg := &types.MsgAssociate{ + Sender: seiAddr.String(), CustomMessage: customMsg, + } + txBuilder = testkeeper.EVMTestApp.GetTxConfig().NewTxBuilder() + txBuilder.SetMsgs(amsg) + signedTx := signTx(txBuilder, privKey, k.AccountKeeper().GetAccount(ctx, seiAddr)) + txbz, err = testkeeper.EVMTestApp.GetTxConfig().TxEncoder()(signedTx) + require.Nil(t, err) + res = testkeeper.EVMTestApp.DeliverTx(ctx, abci.RequestDeliverTx{Tx: txbz}, signedTx, sha256.Sum256(txbz)) + require.Equal(t, uint32(21), res.Code) + + // multiple associate msgs should charge gas (and run out of gas in this test case) + amsg = &types.MsgAssociate{ + Sender: seiAddr.String(), CustomMessage: "", + } + txBuilder = testkeeper.EVMTestApp.GetTxConfig().NewTxBuilder() + msgs := []sdk.Msg{} + for i := 1; i <= 1000; i++ { + msgs = append(msgs, amsg) + } + txBuilder.SetMsgs(msgs...) + signedTx = signTx(txBuilder, privKey, k.AccountKeeper().GetAccount(ctx, seiAddr)) + txbz, err = testkeeper.EVMTestApp.GetTxConfig().TxEncoder()(signedTx) + require.Nil(t, err) + res = testkeeper.EVMTestApp.DeliverTx(ctx, abci.RequestDeliverTx{Tx: txbz}, signedTx, sha256.Sum256(txbz)) + require.Equal(t, uint32(11), res.Code) // out of gas +} + +func signTx(txBuilder client.TxBuilder, privKey cryptotypes.PrivKey, acc authtypes.AccountI) sdk.Tx { + var sigsV2 []signing.SignatureV2 + sigV2 := signing.SignatureV2{ + PubKey: privKey.PubKey(), + Data: &signing.SingleSignatureData{ + SignMode: testkeeper.EVMTestApp.GetTxConfig().SignModeHandler().DefaultMode(), + Signature: nil, + }, + Sequence: acc.GetSequence(), + } + sigsV2 = append(sigsV2, sigV2) + _ = txBuilder.SetSignatures(sigsV2...) + sigsV2 = []signing.SignatureV2{} + signerData := xauthsigning.SignerData{ + ChainID: "sei-test", + AccountNumber: acc.GetAccountNumber(), + Sequence: acc.GetSequence(), + } + sigV2, _ = clienttx.SignWithPrivKey( + testkeeper.EVMTestApp.GetTxConfig().SignModeHandler().DefaultMode(), + signerData, + txBuilder, + privKey, + testkeeper.EVMTestApp.GetTxConfig(), + acc.GetSequence(), + ) + sigsV2 = append(sigsV2, sigV2) + _ = txBuilder.SetSignatures(sigsV2...) + return txBuilder.GetTx() +} diff --git a/x/evm/keeper/address_test.go b/x/evm/keeper/address_test.go index 25f341cfa..8a66da57f 100644 --- a/x/evm/keeper/address_test.go +++ b/x/evm/keeper/address_test.go @@ -10,7 +10,8 @@ import ( ) func TestSetGetAddressMapping(t *testing.T) { - k, ctx := keeper.MockEVMKeeper() + k := &keeper.EVMTestApp.EvmKeeper + ctx := keeper.EVMTestApp.GetContextForDeliverTx([]byte{}) seiAddr, evmAddr := keeper.MockAddressPair() _, ok := k.GetEVMAddress(ctx, seiAddr) require.False(t, ok) @@ -27,7 +28,8 @@ func TestSetGetAddressMapping(t *testing.T) { } func TestDeleteAddressMapping(t *testing.T) { - k, ctx := keeper.MockEVMKeeper() + k := &keeper.EVMTestApp.EvmKeeper + ctx := keeper.EVMTestApp.GetContextForDeliverTx([]byte{}) seiAddr, evmAddr := keeper.MockAddressPair() k.SetAddressMapping(ctx, seiAddr, evmAddr) foundEVM, ok := k.GetEVMAddress(ctx, seiAddr) @@ -44,7 +46,8 @@ func TestDeleteAddressMapping(t *testing.T) { } func TestGetAddressOrDefault(t *testing.T) { - k, ctx := keeper.MockEVMKeeper() + k := &keeper.EVMTestApp.EvmKeeper + ctx := keeper.EVMTestApp.GetContextForDeliverTx([]byte{}) seiAddr, evmAddr := keeper.MockAddressPair() defaultEvmAddr := k.GetEVMAddressOrDefault(ctx, seiAddr) require.True(t, bytes.Equal(seiAddr, defaultEvmAddr[:])) diff --git a/x/evm/keeper/code_test.go b/x/evm/keeper/code_test.go index 57ea70577..1a9a7f9a9 100644 --- a/x/evm/keeper/code_test.go +++ b/x/evm/keeper/code_test.go @@ -12,7 +12,8 @@ import ( ) func TestCode(t *testing.T) { - k, ctx := keeper.MockEVMKeeper() + k := &keeper.EVMTestApp.EvmKeeper + ctx := keeper.EVMTestApp.GetContextForDeliverTx([]byte{}) _, addr := keeper.MockAddressPair() require.Equal(t, common.Hash{}, k.GetCodeHash(ctx, addr)) @@ -32,7 +33,8 @@ func TestCode(t *testing.T) { } func TestNilCode(t *testing.T) { - k, ctx := keeper.MockEVMKeeper() + k := &keeper.EVMTestApp.EvmKeeper + ctx := keeper.EVMTestApp.GetContextForDeliverTx([]byte{}) _, addr := keeper.MockAddressPair() k.SetCode(ctx, addr, nil) diff --git a/x/evm/keeper/coinbase_test.go b/x/evm/keeper/coinbase_test.go index 1b61929db..9b2579f71 100644 --- a/x/evm/keeper/coinbase_test.go +++ b/x/evm/keeper/coinbase_test.go @@ -3,13 +3,14 @@ package keeper_test import ( "testing" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" "github.com/sei-protocol/sei-chain/x/evm/keeper" "github.com/stretchr/testify/require" ) func TestGetFeeCollectorAddress(t *testing.T) { - k, ctx := keepertest.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}) addr, err := k.GetFeeCollectorAddress(ctx) require.Nil(t, err) expected := k.GetEVMAddressOrDefault(ctx, k.AccountKeeper().GetModuleAddress("fee_collector")) diff --git a/x/evm/keeper/genesis.go b/x/evm/keeper/genesis.go index a1a8606fc..2d1e1ee99 100644 --- a/x/evm/keeper/genesis.go +++ b/x/evm/keeper/genesis.go @@ -37,21 +37,23 @@ func (k *Keeper) InitGenesis(ctx sdk.Context, genState types.GenesisState) { erc20CodeID, err := k.wasmKeeper.Create(ctx, k.accountKeeper.GetModuleAddress(types.ModuleName), erc20.GetBin(), nil) if err != nil { - panic(err) + ctx.Logger().Error(fmt.Sprintf("error creating CWERC20 pointer code due to %s", err)) + } else { + prefix.NewStore(k.PrefixStore(ctx, types.PointerCWCodePrefix), types.PointerCW20ERC20Prefix).Set( + artifactsutils.GetVersionBz(erc20.CurrentVersion), + artifactsutils.GetCodeIDBz(erc20CodeID), + ) } - prefix.NewStore(k.PrefixStore(ctx, types.PointerCWCodePrefix), types.PointerCW20ERC20Prefix).Set( - artifactsutils.GetVersionBz(erc20.CurrentVersion), - artifactsutils.GetCodeIDBz(erc20CodeID), - ) erc721CodeID, err := k.wasmKeeper.Create(ctx, k.accountKeeper.GetModuleAddress(types.ModuleName), erc721.GetBin(), nil) if err != nil { - panic(err) + ctx.Logger().Error(fmt.Sprintf("error creating CWERC721 pointer code due to %s", err)) + } else { + prefix.NewStore(k.PrefixStore(ctx, types.PointerCWCodePrefix), types.PointerCW721ERC721Prefix).Set( + artifactsutils.GetVersionBz(erc721.CurrentVersion), + artifactsutils.GetCodeIDBz(erc721CodeID), + ) } - prefix.NewStore(k.PrefixStore(ctx, types.PointerCWCodePrefix), types.PointerCW721ERC721Prefix).Set( - artifactsutils.GetVersionBz(erc721.CurrentVersion), - artifactsutils.GetCodeIDBz(erc721CodeID), - ) if k.EthReplayConfig.Enabled && !ethReplayInitialied { header := k.OpenEthDatabase() diff --git a/x/evm/keeper/genesis_test.go b/x/evm/keeper/genesis_test.go index 7567a5777..a6ba1b054 100644 --- a/x/evm/keeper/genesis_test.go +++ b/x/evm/keeper/genesis_test.go @@ -4,13 +4,14 @@ import ( "bytes" "testing" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" "github.com/sei-protocol/sei-chain/x/evm/keeper" "github.com/stretchr/testify/require" ) func TestInitGenesis(t *testing.T) { - k, ctx := keepertest.MockEVMKeeper() // this would call `InitGenesis` + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}) // coinbase address must be associated coinbaseSeiAddr, associated := k.GetSeiAddress(ctx, keeper.GetCoinbaseAddress()) require.True(t, associated) diff --git a/x/evm/keeper/grpc_query_test.go b/x/evm/keeper/grpc_query_test.go index 30c26af00..e8b08a267 100644 --- a/x/evm/keeper/grpc_query_test.go +++ b/x/evm/keeper/grpc_query_test.go @@ -2,6 +2,7 @@ package keeper_test import ( "testing" + "time" sdk "github.com/cosmos/cosmos-sdk/types" testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" @@ -16,7 +17,8 @@ import ( ) func TestQueryPointer(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) seiAddr1, evmAddr1 := testkeeper.MockAddressPair() seiAddr2, evmAddr2 := testkeeper.MockAddressPair() seiAddr3, evmAddr3 := testkeeper.MockAddressPair() diff --git a/x/evm/keeper/nonce_test.go b/x/evm/keeper/nonce_test.go index 32c87ba5f..6a6294dff 100644 --- a/x/evm/keeper/nonce_test.go +++ b/x/evm/keeper/nonce_test.go @@ -3,13 +3,14 @@ package keeper_test import ( "testing" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" "github.com/stretchr/testify/require" ) func TestNonce(t *testing.T) { - k, ctx := keepertest.MockEVMKeeper() - _, evmAddr := keepertest.MockAddressPair() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}) + _, evmAddr := testkeeper.MockAddressPair() require.Equal(t, uint64(0), k.GetNonce(ctx, evmAddr)) k.SetNonce(ctx, evmAddr, 1) require.Equal(t, uint64(1), k.GetNonce(ctx, evmAddr)) diff --git a/x/evm/keeper/params_test.go b/x/evm/keeper/params_test.go index 39bcc9f75..9a25e26d7 100644 --- a/x/evm/keeper/params_test.go +++ b/x/evm/keeper/params_test.go @@ -2,6 +2,7 @@ package keeper_test import ( "testing" + "time" testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" "github.com/sei-protocol/sei-chain/x/evm/types" @@ -9,7 +10,8 @@ import ( ) func TestParams(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) require.Equal(t, "usei", k.GetBaseDenom(ctx)) require.Equal(t, types.DefaultPriorityNormalizer, k.GetPriorityNormalizer(ctx)) require.Equal(t, types.DefaultBaseFeePerGas, k.GetBaseFeePerGas(ctx)) diff --git a/x/evm/keeper/pointer_test.go b/x/evm/keeper/pointer_test.go index b34724c88..da245ee39 100644 --- a/x/evm/keeper/pointer_test.go +++ b/x/evm/keeper/pointer_test.go @@ -2,6 +2,7 @@ package keeper_test import ( "testing" + "time" "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" @@ -31,7 +32,7 @@ type seiPointerTest struct { } func TestEVMtoCWPointers(t *testing.T) { - _, ctx := testkeeper.MockEVMKeeper() + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}) tests := []seiPointerTest{ { @@ -115,7 +116,8 @@ func TestEVMtoCWPointers(t *testing.T) { } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) handlers := test.getHandlers(k) cwAddress, evmAddress := testkeeper.MockAddressPair() @@ -219,7 +221,8 @@ func TestCWtoEVMPointers(t *testing.T) { } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) handlers := test.getHandlers(k) cwAddress, evmAddress := testkeeper.MockAddressPair() diff --git a/x/evm/keeper/pointer_upgrade_test.go b/x/evm/keeper/pointer_upgrade_test.go index cc4db4d93..f7a1d2e09 100644 --- a/x/evm/keeper/pointer_upgrade_test.go +++ b/x/evm/keeper/pointer_upgrade_test.go @@ -4,6 +4,7 @@ import ( "errors" "math" "testing" + "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" @@ -13,7 +14,8 @@ import ( ) func TestRunWithOneOffEVMInstance(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) errLog := "" errRunner := func(*vm.EVM) error { return errors.New("test") } errLogger := func(a string, b string) { errLog = a + " " + b } @@ -27,7 +29,8 @@ func TestRunWithOneOffEVMInstance(t *testing.T) { } func TestUpsertERCNativePointer(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) var addr common.Address err := k.RunWithOneOffEVMInstance(ctx, func(e *vm.EVM) error { a, _, err := k.UpsertERCNativePointer(ctx, e, math.MaxUint64, "test", utils.ERCMetadata{ @@ -65,7 +68,8 @@ func TestUpsertERCNativePointer(t *testing.T) { } func TestUpsertERC20Pointer(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) var addr common.Address err := k.RunWithOneOffEVMInstance(ctx, func(e *vm.EVM) error { a, _, err := k.UpsertERCCW20Pointer(ctx, e, math.MaxUint64, "test", utils.ERCMetadata{ @@ -90,7 +94,8 @@ func TestUpsertERC20Pointer(t *testing.T) { } func TestUpsertERC721Pointer(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) var addr common.Address err := k.RunWithOneOffEVMInstance(ctx, func(e *vm.EVM) error { a, _, err := k.UpsertERCCW721Pointer(ctx, e, math.MaxUint64, "test", utils.ERCMetadata{ diff --git a/x/evm/keeper/receipt_test.go b/x/evm/keeper/receipt_test.go index 5111e4081..7f96e66cd 100644 --- a/x/evm/keeper/receipt_test.go +++ b/x/evm/keeper/receipt_test.go @@ -4,13 +4,14 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" "github.com/sei-protocol/sei-chain/x/evm/types" "github.com/stretchr/testify/require" ) func TestReceipt(t *testing.T) { - k, ctx := keepertest.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}) txHash := common.HexToHash("0x0750333eac0be1203864220893d8080dd8a8fd7a2ed098dfd92a718c99d437f2") _, err := k.GetReceipt(ctx, txHash) require.NotNil(t, err) diff --git a/x/evm/keeper/state_test.go b/x/evm/keeper/state_test.go index f8d0be2cf..6edc70805 100644 --- a/x/evm/keeper/state_test.go +++ b/x/evm/keeper/state_test.go @@ -2,6 +2,7 @@ package keeper_test import ( "testing" + "time" "github.com/ethereum/go-ethereum/common" testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" @@ -9,7 +10,8 @@ import ( ) func TestState(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) _, addr := testkeeper.MockAddressPair() initialState := k.GetState(ctx, addr, common.HexToHash("0xabc")) diff --git a/x/evm/keeper/tx_test.go b/x/evm/keeper/tx_test.go index 5c96fd45d..af8f25c81 100644 --- a/x/evm/keeper/tx_test.go +++ b/x/evm/keeper/tx_test.go @@ -4,12 +4,13 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" "github.com/stretchr/testify/require" ) func TestTxHashesOnHeight(t *testing.T) { - k, ctx := keepertest.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}) require.Empty(t, k.GetTxHashesOnHeight(ctx, 1234)) hashes := []common.Hash{ common.HexToHash("0x0750333eac0be1203864220893d8080dd8a8fd7a2ed098dfd92a718c99d437f2"), diff --git a/x/evm/migrations/fix_total_supply_test.go b/x/evm/migrations/fix_total_supply_test.go index a932098af..da0bb5bbe 100644 --- a/x/evm/migrations/fix_total_supply_test.go +++ b/x/evm/migrations/fix_total_supply_test.go @@ -2,6 +2,7 @@ package migrations_test import ( "testing" + "time" sdk "github.com/cosmos/cosmos-sdk/types" testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" @@ -10,7 +11,8 @@ import ( ) func TestFixTotalSupply(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) addr, _ := testkeeper.MockAddressPair() balance := sdk.NewCoins(sdk.NewCoin(sdk.MustGetBaseDenom(), sdk.OneInt())) k.BankKeeper().MintCoins(ctx, "evm", balance) diff --git a/x/evm/state/accesslist_test.go b/x/evm/state/accesslist_test.go index 9b6fe1e47..7ccdd8b86 100644 --- a/x/evm/state/accesslist_test.go +++ b/x/evm/state/accesslist_test.go @@ -2,6 +2,7 @@ package state_test import ( "testing" + "time" "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" @@ -12,7 +13,8 @@ import ( ) func TestAddAddressToAccessList(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) statedb := state.NewDBImpl(ctx, k, false) _, addr := testkeeper.MockAddressPair() @@ -28,7 +30,8 @@ func TestAddAddressToAccessList(t *testing.T) { } func TestAddSlotToAccessList(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) statedb := state.NewDBImpl(ctx, k, false) _, addr := testkeeper.MockAddressPair() @@ -45,7 +48,8 @@ func TestAddSlotToAccessList(t *testing.T) { } func TestAddSlotToAccessListWithNonExistentAddress(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) statedb := state.NewDBImpl(ctx, k, false) _, addr := testkeeper.MockAddressPair() @@ -55,7 +59,8 @@ func TestAddSlotToAccessListWithNonExistentAddress(t *testing.T) { } func TestPrepare(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) statedb := state.NewDBImpl(ctx, k, false) _, sender := testkeeper.MockAddressPair() diff --git a/x/evm/state/balance_test.go b/x/evm/state/balance_test.go index abe7d5b70..c676af2ef 100644 --- a/x/evm/state/balance_test.go +++ b/x/evm/state/balance_test.go @@ -3,6 +3,7 @@ package state_test import ( "math/big" "testing" + "time" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/core/tracing" @@ -13,7 +14,8 @@ import ( ) func TestAddBalance(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) db := state.NewDBImpl(ctx, k, false) seiAddr, evmAddr := testkeeper.MockAddressPair() require.Equal(t, big.NewInt(0), db.GetBalance(evmAddr)) @@ -40,7 +42,8 @@ func TestAddBalance(t *testing.T) { } func TestSubBalance(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) db := state.NewDBImpl(ctx, k, false) seiAddr, evmAddr := testkeeper.MockAddressPair() require.Equal(t, big.NewInt(0), db.GetBalance(evmAddr)) @@ -78,7 +81,8 @@ func TestSubBalance(t *testing.T) { } func TestSetBalance(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) db := state.NewDBImpl(ctx, k, true) _, evmAddr := testkeeper.MockAddressPair() db.SetBalance(evmAddr, big.NewInt(10000000000000), tracing.BalanceChangeUnspecified) @@ -91,7 +95,8 @@ func TestSetBalance(t *testing.T) { } func TestSurplus(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) _, evmAddr := testkeeper.MockAddressPair() // test negative usei surplus negative wei surplus diff --git a/x/evm/state/check_test.go b/x/evm/state/check_test.go index 6c631bd1b..2707b9547 100644 --- a/x/evm/state/check_test.go +++ b/x/evm/state/check_test.go @@ -3,6 +3,7 @@ package state_test import ( "math/big" "testing" + "time" "github.com/ethereum/go-ethereum/core/tracing" testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" @@ -12,7 +13,8 @@ import ( func TestExist(t *testing.T) { // not exist - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) _, addr := testkeeper.MockAddressPair() statedb := state.NewDBImpl(ctx, k, false) require.False(t, statedb.Exist(addr)) @@ -35,7 +37,8 @@ func TestExist(t *testing.T) { func TestEmpty(t *testing.T) { // empty - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) _, addr := testkeeper.MockAddressPair() statedb := state.NewDBImpl(ctx, k, false) require.True(t, statedb.Empty(addr)) diff --git a/x/evm/state/code_test.go b/x/evm/state/code_test.go index e6491a0b2..fedb6dd9e 100644 --- a/x/evm/state/code_test.go +++ b/x/evm/state/code_test.go @@ -2,6 +2,7 @@ package state_test import ( "testing" + "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" @@ -11,7 +12,8 @@ import ( ) func TestCode(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) _, addr := testkeeper.MockAddressPair() statedb := state.NewDBImpl(ctx, k, false) diff --git a/x/evm/state/log_test.go b/x/evm/state/log_test.go index afbbf83a8..87d3f1186 100644 --- a/x/evm/state/log_test.go +++ b/x/evm/state/log_test.go @@ -2,6 +2,7 @@ package state_test import ( "testing" + "time" "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" @@ -11,7 +12,8 @@ import ( ) func TestAddLog(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) statedb := state.NewDBImpl(ctx, k, false) logs := statedb.GetAllLogs() @@ -37,7 +39,8 @@ func TestAddLog(t *testing.T) { } func TestLogIndex(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) statedb := state.NewDBImpl(ctx, k, false) statedb.AddLog(ðtypes.Log{}) statedb.Snapshot() diff --git a/x/evm/state/nonce_test.go b/x/evm/state/nonce_test.go index ed8b579f0..298231119 100644 --- a/x/evm/state/nonce_test.go +++ b/x/evm/state/nonce_test.go @@ -1,15 +1,18 @@ package state_test import ( - "github.com/stretchr/testify/require" "testing" + "time" + + "github.com/stretchr/testify/require" testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" "github.com/sei-protocol/sei-chain/x/evm/state" ) func TestNonce(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) stateDB := state.NewDBImpl(ctx, k, false) _, addr := testkeeper.MockAddressPair() stateDB.SetNonce(addr, 1) diff --git a/x/evm/state/refund_test.go b/x/evm/state/refund_test.go index a2810f3e6..89c59cd19 100644 --- a/x/evm/state/refund_test.go +++ b/x/evm/state/refund_test.go @@ -2,6 +2,7 @@ package state_test import ( "testing" + "time" testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" "github.com/sei-protocol/sei-chain/x/evm/state" @@ -9,7 +10,8 @@ import ( ) func TestGasRefund(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) statedb := state.NewDBImpl(ctx, k, false) require.Equal(t, uint64(0), statedb.GetRefund()) diff --git a/x/evm/state/state_test.go b/x/evm/state/state_test.go index 28cc4c861..ff2a8671a 100644 --- a/x/evm/state/state_test.go +++ b/x/evm/state/state_test.go @@ -3,6 +3,7 @@ package state_test import ( "math/big" "testing" + "time" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" @@ -14,7 +15,8 @@ import ( ) func TestState(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) _, evmAddr := testkeeper.MockAddressPair() statedb := state.NewDBImpl(ctx, k, false) statedb.CreateAccount(evmAddr) @@ -53,7 +55,8 @@ func TestState(t *testing.T) { } func TestCreate(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) _, evmAddr := testkeeper.MockAddressPair() statedb := state.NewDBImpl(ctx, k, false) statedb.CreateAccount(evmAddr) @@ -86,7 +89,8 @@ func TestCreate(t *testing.T) { } func TestSelfDestructAssociated(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) seiAddr, evmAddr := testkeeper.MockAddressPair() k.SetAddressMapping(ctx, seiAddr, evmAddr) statedb := state.NewDBImpl(ctx, k, false) @@ -130,7 +134,8 @@ func TestSelfDestructAssociated(t *testing.T) { } func TestSnapshot(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) seiAddr, evmAddr := testkeeper.MockAddressPair() k.SetAddressMapping(ctx, seiAddr, evmAddr) eventCount := len(ctx.EventManager().Events()) diff --git a/x/evm/state/transfer_test.go b/x/evm/state/transfer_test.go index f633dc879..e45a38396 100644 --- a/x/evm/state/transfer_test.go +++ b/x/evm/state/transfer_test.go @@ -3,6 +3,7 @@ package state_test import ( "math/big" "testing" + "time" testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" "github.com/sei-protocol/sei-chain/x/evm/state" @@ -10,7 +11,8 @@ import ( ) func TestEventlessTransfer(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) db := state.NewDBImpl(ctx, k, false) _, fromAddr := testkeeper.MockAddressPair() _, toAddr := testkeeper.MockAddressPair() diff --git a/x/evm/types/constants.go b/x/evm/types/constants.go new file mode 100644 index 000000000..7b5acfc58 --- /dev/null +++ b/x/evm/types/constants.go @@ -0,0 +1,3 @@ +package types + +const MaxAssociateCustomMessageLength = 64 diff --git a/x/evm/types/message_associate.go b/x/evm/types/message_associate.go index 2107487dd..11427d70d 100644 --- a/x/evm/types/message_associate.go +++ b/x/evm/types/message_associate.go @@ -40,6 +40,9 @@ func (msg *MsgAssociate) ValidateBasic() error { if err != nil { return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "Invalid sender address (%s)", err) } + if len(msg.CustomMessage) > MaxAssociateCustomMessageLength { + return sdkerrors.Wrapf(sdkerrors.ErrTxTooLarge, "custom message can have at most 64 characters") + } return nil } diff --git a/x/evm/types/message_evm_transaction.go b/x/evm/types/message_evm_transaction.go index affcc3701..c408b0757 100644 --- a/x/evm/types/message_evm_transaction.go +++ b/x/evm/types/message_evm_transaction.go @@ -3,6 +3,7 @@ package types import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/gogo/protobuf/proto" "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" @@ -41,6 +42,10 @@ func (msg *MsgEVMTransaction) GetSignBytes() []byte { } func (msg *MsgEVMTransaction) ValidateBasic() error { + amsg, isAssociate := msg.GetAssociateTx() + if isAssociate && len(amsg.CustomMessage) > MaxAssociateCustomMessageLength { + return sdkerrors.Wrapf(sdkerrors.ErrTxTooLarge, "custom message can have at most 64 characters") + } return nil } @@ -59,13 +64,18 @@ func (msg *MsgEVMTransaction) UnpackInterfaces(unpacker codectypes.AnyUnpacker) } func (msg *MsgEVMTransaction) IsAssociateTx() bool { + _, ok := msg.GetAssociateTx() + return ok +} + +func (msg *MsgEVMTransaction) GetAssociateTx() (*ethtx.AssociateTx, bool) { txData, err := UnpackTxData(msg.Data) if err != nil { // should never happen panic(err) } - _, ok := txData.(*ethtx.AssociateTx) - return ok + amsg, ok := txData.(*ethtx.AssociateTx) + return amsg, ok } func MustGetEVMTransactionMessage(tx sdk.Tx) *MsgEVMTransaction { From a8ea0f988de814e1f62938c4b9dcfcbefa1282c8 Mon Sep 17 00:00:00 2001 From: codchen Date: Wed, 28 Aug 2024 13:03:06 +0800 Subject: [PATCH 28/38] Check TX nonce before registering hook to bump nonce for failed tx (#1835) --- x/evm/ante/basic.go | 3 ++- x/evm/ante/fee.go | 2 +- x/evm/integration_test.go | 5 +++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/x/evm/ante/basic.go b/x/evm/ante/basic.go index 7185a1566..18954258d 100644 --- a/x/evm/ante/basic.go +++ b/x/evm/ante/basic.go @@ -28,7 +28,8 @@ func (gl BasicDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, n if msg.Derived != nil && !gl.k.EthReplayConfig.Enabled && !gl.k.EthBlockTestConfig.Enabled { startingNonce := gl.k.GetNonce(ctx, msg.Derived.SenderEVMAddr) - if !ctx.IsCheckTx() && !ctx.IsReCheckTx() { + txNonce := etx.Nonce() + if !ctx.IsCheckTx() && !ctx.IsReCheckTx() && startingNonce == txNonce { ctx = ctx.WithDeliverTxCallback(func(callCtx sdk.Context) { // bump nonce if it is for some reason not incremented (e.g. ante failure) if gl.k.GetNonce(callCtx, msg.Derived.SenderEVMAddr) == startingNonce { diff --git a/x/evm/ante/fee.go b/x/evm/ante/fee.go index 9c161d187..262a88fe8 100644 --- a/x/evm/ante/fee.go +++ b/x/evm/ante/fee.go @@ -76,7 +76,7 @@ func (fc EVMFeeCheckDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate b // we don't want to run nonce check here for CheckTx because we have special // logic for pending nonce during CheckTx in sig.go if err := st.StatelessChecks(); err != nil { - return ctx, err + return ctx, sdkerrors.Wrap(sdkerrors.ErrWrongSequence, err.Error()) } } if err := st.BuyGas(); err != nil { diff --git a/x/evm/integration_test.go b/x/evm/integration_test.go index 9ed2990fa..d27fe98b0 100644 --- a/x/evm/integration_test.go +++ b/x/evm/integration_test.go @@ -288,6 +288,11 @@ func TestNonceIncrementsForInsufficientFunds(t *testing.T) { res := testkeeper.EVMTestApp.DeliverTx(ctx, abci.RequestDeliverTx{Tx: txbz}, cosmosTx, sha256.Sum256(txbz)) require.Equal(t, uint32(5), res.Code) // insufficient funds has error code 5 require.Equal(t, uint64(1), k.GetNonce(ctx, evmAddr)) // make sure nonce is incremented regardless + + // ensure that old txs cannot be used by malicious party to bump nonces + res = testkeeper.EVMTestApp.DeliverTx(ctx, abci.RequestDeliverTx{Tx: txbz}, cosmosTx, sha256.Sum256(txbz)) + require.Equal(t, uint32(32), res.Code) // wrong nonce has error code 32 + require.Equal(t, uint64(1), k.GetNonce(ctx, evmAddr)) // nonce should not be incremented this time because the tx is an old one } func TestInvalidAssociateMsg(t *testing.T) { From 0ebeaebd05cf5818f2fc73ec66706354d4949621 Mon Sep 17 00:00:00 2001 From: yirenz Date: Wed, 28 Aug 2024 10:13:39 -0400 Subject: [PATCH 29/38] feat: add wasm contract query gas limit (#1830) * feat: add wasm contract query gas limit add a wasm contract query gas limit to prevent infinite gas attacks * test: update unit tests - add and update unit tests * fix: assign new queryCtx instead of overwriting current tx --------- Co-authored-by: blindchaser --- app/receipt.go | 19 +++- go.mod | 22 ++-- go.sum | 40 +++---- precompiles/distribution/distribution_test.go | 8 +- precompiles/ibc/ibc_test.go | 6 +- proto/evm/params.proto | 1 + x/evm/keeper/params.go | 4 + x/evm/keeper/params_test.go | 1 + x/evm/module_test.go | 2 +- x/evm/types/params.go | 24 ++++- x/evm/types/params.pb.go | 100 ++++++++++++------ x/evm/types/params_test.go | 21 ++++ 12 files changed, 171 insertions(+), 77 deletions(-) diff --git a/app/receipt.go b/app/receipt.go index b9ddef9fc..41c8e4ec9 100644 --- a/app/receipt.go +++ b/app/receipt.go @@ -37,16 +37,21 @@ func (app *App) AddCosmosEventsToEVMReceiptIfApplicable(ctx sdk.Context, tx sdk. return } wasmEvents := GetEventsOfType(response, wasmtypes.WasmModuleEventType) + if len(wasmEvents) == 0 { + return + } logs := []*ethtypes.Log{} + wasmGasLimit := app.EvmKeeper.GetDeliverTxHookWasmGasLimit(ctx) + queryCtx := ctx.WithGasMeter(sdk.NewGasMeterWithMultiplier(ctx, wasmGasLimit)) for _, wasmEvent := range wasmEvents { contractAddr, found := GetAttributeValue(wasmEvent, wasmtypes.AttributeKeyContractAddr) if !found { continue } // check if there is a ERC20 pointer to contractAddr - pointerAddr, _, exists := app.EvmKeeper.GetERC20CW20Pointer(ctx, contractAddr) + pointerAddr, _, exists := app.EvmKeeper.GetERC20CW20Pointer(queryCtx, contractAddr) if exists { - log, eligible := app.translateCW20Event(ctx, wasmEvent, pointerAddr, contractAddr) + log, eligible := app.translateCW20Event(queryCtx, wasmEvent, pointerAddr, contractAddr) if eligible { log.Index = uint(len(logs)) logs = append(logs, log) @@ -54,9 +59,9 @@ func (app *App) AddCosmosEventsToEVMReceiptIfApplicable(ctx sdk.Context, tx sdk. continue } // check if there is a ERC721 pointer to contract Addr - pointerAddr, _, exists = app.EvmKeeper.GetERC721CW721Pointer(ctx, contractAddr) + pointerAddr, _, exists = app.EvmKeeper.GetERC721CW721Pointer(queryCtx, contractAddr) if exists { - log, eligible := app.translateCW721Event(ctx, wasmEvent, pointerAddr, contractAddr) + log, eligible := app.translateCW721Event(queryCtx, wasmEvent, pointerAddr, contractAddr) if eligible { log.Index = uint(len(logs)) logs = append(logs, log) @@ -107,6 +112,12 @@ func (app *App) AddCosmosEventsToEVMReceiptIfApplicable(ctx sdk.Context, tx sdk. } func (app *App) translateCW20Event(ctx sdk.Context, wasmEvent abci.Event, pointerAddr common.Address, contractAddr string) (*ethtypes.Log, bool) { + defer func() { + if r := recover(); r != nil { + fmt.Printf("[Error] Panic caught during translateCW20Event: type=%T, value=%+v\n", r, r) + } + }() + action, found := GetAttributeValue(wasmEvent, "action") if !found { return nil, false diff --git a/go.mod b/go.mod index 4e763cb6c..014d9679d 100644 --- a/go.mod +++ b/go.mod @@ -41,11 +41,11 @@ require ( go.opentelemetry.io/otel v1.9.0 go.opentelemetry.io/otel/trace v1.9.0 golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa - golang.org/x/sync v0.7.0 + golang.org/x/sync v0.8.0 golang.org/x/time v0.3.0 - google.golang.org/genproto/googleapis/api v0.0.0-20240513163218-0867130af1f8 - google.golang.org/grpc v1.64.0 - google.golang.org/protobuf v1.34.1 + google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 + google.golang.org/grpc v1.64.1 + google.golang.org/protobuf v1.34.2 gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 ) @@ -312,16 +312,16 @@ require ( go.opencensus.io v0.23.0 // indirect go.opentelemetry.io/otel/exporters/jaeger v1.9.0 // indirect go.opentelemetry.io/otel/sdk v1.9.0 // indirect - golang.org/x/crypto v0.23.0 // indirect + golang.org/x/crypto v0.24.0 // indirect golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e // indirect golang.org/x/mod v0.17.0 // indirect - golang.org/x/net v0.25.0 // indirect - golang.org/x/sys v0.20.0 // indirect - golang.org/x/term v0.20.0 // indirect - golang.org/x/text v0.15.0 // indirect - golang.org/x/tools v0.21.0 // indirect + golang.org/x/net v0.26.0 // indirect + golang.org/x/sys v0.21.0 // indirect + golang.org/x/term v0.21.0 // indirect + golang.org/x/text v0.17.0 // indirect + golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240513163218-0867130af1f8 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect honnef.co/go/tools v0.3.1 // indirect diff --git a/go.sum b/go.sum index 8bdefbce3..1413d1f77 100644 --- a/go.sum +++ b/go.sum @@ -1647,8 +1647,8 @@ golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98y golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= -golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= -golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= +golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1788,8 +1788,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= -golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/oauth2 v0.0.0-20170207211851-4464e7848382/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1828,8 +1828,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1956,8 +1956,8 @@ golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1970,8 +1970,8 @@ golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= -golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= -golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= +golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= +golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1990,8 +1990,8 @@ golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= -golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -2109,8 +2109,8 @@ golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= -golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw= -golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -2255,10 +2255,10 @@ google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2I google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac h1:ZL/Teoy/ZGnzyrqK/Optxxp2pmVh+fmJ97slxSRyzUg= google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:+Rvu7ElI+aLzyDQhpHMFMMltsD6m7nqpuWDd2CwJw3k= -google.golang.org/genproto/googleapis/api v0.0.0-20240513163218-0867130af1f8 h1:W5Xj/70xIA4x60O/IFyXivR5MGqblAb8R3w26pnD6No= -google.golang.org/genproto/googleapis/api v0.0.0-20240513163218-0867130af1f8/go.mod h1:vPrPUTsDCYxXWjP7clS81mZ6/803D8K4iM9Ma27VKas= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240513163218-0867130af1f8 h1:mxSlqyb8ZAHsYDCfiXN1EDdNTdvjUJSLY+OnAUtYNYA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240513163218-0867130af1f8/go.mod h1:I7Y+G38R2bu5j1aLzfFmQfTcU/WnFuqDwLZAbvKTKpM= +google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 h1:wKguEg1hsxI2/L3hUYrpo1RVi48K+uTyzKqprwLXsb8= +google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/grpc v1.33.2 h1:EQyQC3sa8M+p6Ulc8yy9SWSS2GVwyRc83gAbG8lrl4o= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= @@ -2276,8 +2276,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= -google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/precompiles/distribution/distribution_test.go b/precompiles/distribution/distribution_test.go index 1a7e071d3..19bab661c 100644 --- a/precompiles/distribution/distribution_test.go +++ b/precompiles/distribution/distribution_test.go @@ -148,7 +148,7 @@ func TestWithdraw(t *testing.T) { res, err = msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), req) require.Nil(t, err) require.Empty(t, res.VmError) - require.Equal(t, uint64(68688), res.GasUsed) + require.Equal(t, uint64(69808), res.GasUsed) // reinitialized d, found = testApp.StakingKeeper.GetDelegation(ctx, seiAddr, val) @@ -301,7 +301,7 @@ func setWithdrawAddressAndWithdraw( res, err = msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), r) require.Nil(t, err) require.Empty(t, res.VmError) - require.Equal(t, uint64(152854), res.GasUsed) + require.Equal(t, uint64(153974), res.GasUsed) // reinitialized for _, val := range vals { @@ -1051,7 +1051,7 @@ func TestPrecompile_RunAndCalculateGas_Rewards(t *testing.T) { suppliedGas: uint64(1000000), }, wantRet: emptyCasePackedOutput, - wantRemainingGas: 994313, + wantRemainingGas: 993193, wantErr: false, }, { @@ -1067,7 +1067,7 @@ func TestPrecompile_RunAndCalculateGas_Rewards(t *testing.T) { suppliedGas: uint64(1000000), }, wantRet: happyPathPackedOutput, - wantRemainingGas: 994313, + wantRemainingGas: 993193, wantErr: false, }, } diff --git a/precompiles/ibc/ibc_test.go b/precompiles/ibc/ibc_test.go index feccfb150..b651af746 100644 --- a/precompiles/ibc/ibc_test.go +++ b/precompiles/ibc/ibc_test.go @@ -106,7 +106,7 @@ func TestPrecompile_Run(t *testing.T) { fields: fields{transferKeeper: &MockTransferKeeper{}}, args: commonArgs, wantBz: packedTrue, - wantRemainingGas: 994313, + wantRemainingGas: 993193, wantErr: false, }, { @@ -235,7 +235,7 @@ func TestPrecompile_Run(t *testing.T) { value: nil, }, wantBz: packedTrue, - wantRemainingGas: 994313, + wantRemainingGas: 993193, wantErr: false, }, { @@ -255,7 +255,7 @@ func TestPrecompile_Run(t *testing.T) { value: nil, }, wantBz: packedTrue, - wantRemainingGas: 994313, + wantRemainingGas: 993193, wantErr: false, }, } diff --git a/proto/evm/params.proto b/proto/evm/params.proto index 3f07c1a07..d2497e4b3 100644 --- a/proto/evm/params.proto +++ b/proto/evm/params.proto @@ -32,6 +32,7 @@ string minimum_fee_per_gas = 4 [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "minimum_fee_per_gas" ]; +uint64 deliver_tx_hook_wasm_gas_limit = 5; // ChainConfig chain_config = 5 [(gogoproto.moretags) = "yaml:\"chain_config\"", (gogoproto.nullable) = false]; // string chain_id = 6 [ // (gogoproto.moretags) = "yaml:\"chain_id\"", diff --git a/x/evm/keeper/params.go b/x/evm/keeper/params.go index a70a52d86..951f82d20 100644 --- a/x/evm/keeper/params.go +++ b/x/evm/keeper/params.go @@ -37,6 +37,10 @@ func (k *Keeper) GetMinimumFeePerGas(ctx sdk.Context) sdk.Dec { return k.GetParams(ctx).MinimumFeePerGas } +func (k *Keeper) GetDeliverTxHookWasmGasLimit(ctx sdk.Context) uint64 { + return k.GetParams(ctx).DeliverTxHookWasmGasLimit +} + func (k *Keeper) ChainID(ctx sdk.Context) *big.Int { if k.EthReplayConfig.Enabled || k.EthBlockTestConfig.Enabled { // replay is for eth mainnet so always return 1 diff --git a/x/evm/keeper/params_test.go b/x/evm/keeper/params_test.go index 9a25e26d7..e508d99b0 100644 --- a/x/evm/keeper/params_test.go +++ b/x/evm/keeper/params_test.go @@ -16,6 +16,7 @@ func TestParams(t *testing.T) { require.Equal(t, types.DefaultPriorityNormalizer, k.GetPriorityNormalizer(ctx)) require.Equal(t, types.DefaultBaseFeePerGas, k.GetBaseFeePerGas(ctx)) require.Equal(t, types.DefaultMinFeePerGas, k.GetMinimumFeePerGas(ctx)) + require.Equal(t, types.DefaultDeliverTxHookWasmGasLimit, k.GetDeliverTxHookWasmGasLimit(ctx)) require.Nil(t, k.GetParams(ctx).Validate()) } diff --git a/x/evm/module_test.go b/x/evm/module_test.go index b5bda72dd..181cd0377 100644 --- a/x/evm/module_test.go +++ b/x/evm/module_test.go @@ -53,7 +53,7 @@ func TestModuleExportGenesis(t *testing.T) { module := evm.NewAppModule(nil, k) jsonMsg := module.ExportGenesis(ctx, types.ModuleCdc) jsonStr := string(jsonMsg) - assert.Equal(t, "{\"params\":{\"priority_normalizer\":\"1.000000000000000000\",\"base_fee_per_gas\":\"0.000000000000000000\",\"minimum_fee_per_gas\":\"100000000000.000000000000000000\",\"whitelisted_cw_code_hashes_for_delegate_call\":[]},\"address_associations\":[{\"sei_address\":\"sei17xpfvakm2amg962yls6f84z3kell8c5la4jkdu\",\"eth_address\":\"0x27F7B8B8B5A4e71E8E9aA671f4e4031E3773303F\"}],\"codes\":[],\"states\":[],\"nonces\":[],\"serialized\":[{\"prefix\":\"Fg==\",\"key\":\"AwAC\",\"value\":\"AAAAAAAAAAM=\"},{\"prefix\":\"Fg==\",\"key\":\"BAAG\",\"value\":\"AAAAAAAAAAQ=\"}]}", jsonStr) + assert.Equal(t, "{\"params\":{\"priority_normalizer\":\"1.000000000000000000\",\"base_fee_per_gas\":\"0.000000000000000000\",\"minimum_fee_per_gas\":\"100000000000.000000000000000000\",\"deliver_tx_hook_wasm_gas_limit\":\"300000\",\"whitelisted_cw_code_hashes_for_delegate_call\":[]},\"address_associations\":[{\"sei_address\":\"sei17xpfvakm2amg962yls6f84z3kell8c5la4jkdu\",\"eth_address\":\"0x27F7B8B8B5A4e71E8E9aA671f4e4031E3773303F\"}],\"codes\":[],\"states\":[],\"nonces\":[],\"serialized\":[{\"prefix\":\"Fg==\",\"key\":\"AwAC\",\"value\":\"AAAAAAAAAAM=\"},{\"prefix\":\"Fg==\",\"key\":\"BAAG\",\"value\":\"AAAAAAAAAAQ=\"}]}", jsonStr) } func TestConsensusVersion(t *testing.T) { diff --git a/x/evm/types/params.go b/x/evm/types/params.go index 6e98e3ead..ffb78606d 100644 --- a/x/evm/types/params.go +++ b/x/evm/types/params.go @@ -10,9 +10,10 @@ import ( ) var ( - KeyPriorityNormalizer = []byte("KeyPriorityNormalizer") - KeyBaseFeePerGas = []byte("KeyBaseFeePerGas") - KeyMinFeePerGas = []byte("KeyMinFeePerGas") + KeyPriorityNormalizer = []byte("KeyPriorityNormalizer") + KeyBaseFeePerGas = []byte("KeyBaseFeePerGas") + KeyMinFeePerGas = []byte("KeyMinFeePerGas") + KeyDeliverTxHookWasmGasLimit = []byte("KeyDeliverTxHookWasmGasLimit") // deprecated KeyWhitelistedCwCodeHashesForDelegateCall = []byte("KeyWhitelistedCwCodeHashesForDelegateCall") ) @@ -24,6 +25,7 @@ var DefaultPriorityNormalizer = sdk.NewDec(1) // Ethereum). var DefaultBaseFeePerGas = sdk.NewDec(0) var DefaultMinFeePerGas = sdk.NewDec(100000000000) +var DefaultDeliverTxHookWasmGasLimit = uint64(300000) var DefaultWhitelistedCwCodeHashesForDelegateCall = generateDefaultWhitelistedCwCodeHashesForDelegateCall() @@ -38,6 +40,7 @@ func DefaultParams() Params { PriorityNormalizer: DefaultPriorityNormalizer, BaseFeePerGas: DefaultBaseFeePerGas, MinimumFeePerGas: DefaultMinFeePerGas, + DeliverTxHookWasmGasLimit: DefaultDeliverTxHookWasmGasLimit, WhitelistedCwCodeHashesForDelegateCall: DefaultWhitelistedCwCodeHashesForDelegateCall, } } @@ -47,6 +50,7 @@ func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { paramtypes.NewParamSetPair(KeyPriorityNormalizer, &p.PriorityNormalizer, validatePriorityNormalizer), paramtypes.NewParamSetPair(KeyBaseFeePerGas, &p.BaseFeePerGas, validateBaseFeePerGas), paramtypes.NewParamSetPair(KeyMinFeePerGas, &p.MinimumFeePerGas, validateMinFeePerGas), + paramtypes.NewParamSetPair(KeyDeliverTxHookWasmGasLimit, &p.DeliverTxHookWasmGasLimit, validateDeliverTxHookWasmGasLimit), paramtypes.NewParamSetPair(KeyWhitelistedCwCodeHashesForDelegateCall, &p.WhitelistedCwCodeHashesForDelegateCall, validateWhitelistedCwHashesForDelegateCall), } } @@ -61,6 +65,9 @@ func (p Params) Validate() error { if err := validateMinFeePerGas(p.MinimumFeePerGas); err != nil { return err } + if err := validateDeliverTxHookWasmGasLimit(p.DeliverTxHookWasmGasLimit); err != nil { + return err + } if p.MinimumFeePerGas.LT(p.BaseFeePerGas) { return errors.New("minimum fee cannot be lower than base fee") } @@ -111,6 +118,17 @@ func validateMinFeePerGas(i interface{}) error { return nil } +func validateDeliverTxHookWasmGasLimit(i interface{}) error { + v, ok := i.(uint64) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + if v == 0 { + return fmt.Errorf("invalid deliver_tx_hook_wasm_gas_limit: must be greater than 0, got %d", v) + } + return nil +} + func validateWhitelistedCwHashesForDelegateCall(i interface{}) error { _, ok := i.([][]byte) if !ok { diff --git a/x/evm/types/params.pb.go b/x/evm/types/params.pb.go index 3f16118ba..8303ff5af 100644 --- a/x/evm/types/params.pb.go +++ b/x/evm/types/params.pb.go @@ -30,9 +30,10 @@ type Params struct { // (gogoproto.moretags) = "yaml:\"base_denom\"", // (gogoproto.jsontag) = "base_denom" // ]; - PriorityNormalizer github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,2,opt,name=priority_normalizer,json=priorityNormalizer,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"priority_normalizer" yaml:"priority_normalizer"` - BaseFeePerGas github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,3,opt,name=base_fee_per_gas,json=baseFeePerGas,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"base_fee_per_gas" yaml:"base_fee_per_gas"` - MinimumFeePerGas github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,4,opt,name=minimum_fee_per_gas,json=minimumFeePerGas,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"minimum_fee_per_gas" yaml:"minimum_fee_per_gas"` + PriorityNormalizer github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,2,opt,name=priority_normalizer,json=priorityNormalizer,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"priority_normalizer" yaml:"priority_normalizer"` + BaseFeePerGas github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,3,opt,name=base_fee_per_gas,json=baseFeePerGas,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"base_fee_per_gas" yaml:"base_fee_per_gas"` + MinimumFeePerGas github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,4,opt,name=minimum_fee_per_gas,json=minimumFeePerGas,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"minimum_fee_per_gas" yaml:"minimum_fee_per_gas"` + DeliverTxHookWasmGasLimit uint64 `protobuf:"varint,5,opt,name=deliver_tx_hook_wasm_gas_limit,json=deliverTxHookWasmGasLimit,proto3" json:"deliver_tx_hook_wasm_gas_limit,omitempty"` // ChainConfig chain_config = 5 [(gogoproto.moretags) = "yaml:\"chain_config\"", (gogoproto.nullable) = false]; // string chain_id = 6 [ // (gogoproto.moretags) = "yaml:\"chain_id\"", @@ -79,6 +80,13 @@ func (m *Params) XXX_DiscardUnknown() { var xxx_messageInfo_Params proto.InternalMessageInfo +func (m *Params) GetDeliverTxHookWasmGasLimit() uint64 { + if m != nil { + return m.DeliverTxHookWasmGasLimit + } + return 0 +} + func (m *Params) GetWhitelistedCwCodeHashesForDelegateCall() [][]byte { if m != nil { return m.WhitelistedCwCodeHashesForDelegateCall @@ -93,34 +101,37 @@ func init() { func init() { proto.RegisterFile("evm/params.proto", fileDescriptor_9272f3679901ea94) } var fileDescriptor_9272f3679901ea94 = []byte{ - // 423 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x52, 0x31, 0x6f, 0xd3, 0x40, - 0x18, 0xf5, 0xd1, 0x52, 0x81, 0x05, 0x52, 0xe4, 0x22, 0x61, 0x65, 0xf0, 0x55, 0x1e, 0xaa, 0x0e, - 0xc4, 0x1e, 0xba, 0x75, 0x4c, 0xaa, 0x96, 0x09, 0x55, 0x1e, 0x91, 0xd0, 0xe9, 0x72, 0xfe, 0x62, - 0x9f, 0xb8, 0xf3, 0x59, 0x77, 0x6e, 0x43, 0xf8, 0x01, 0x2c, 0x2c, 0x08, 0x31, 0x30, 0xf2, 0x67, - 0x90, 0x3a, 0x76, 0x44, 0x0c, 0x16, 0x4a, 0xb6, 0x8e, 0xf9, 0x05, 0xc8, 0xe7, 0x94, 0x04, 0xf0, - 0x92, 0x4e, 0xf7, 0xdd, 0x7b, 0xef, 0x7b, 0x7a, 0x7a, 0xfa, 0xdc, 0x1e, 0x5c, 0xc9, 0xb8, 0xa4, - 0x9a, 0x4a, 0x13, 0x95, 0x5a, 0x55, 0xca, 0xf3, 0x0d, 0x70, 0x3b, 0x31, 0x25, 0x22, 0x03, 0x9c, - 0xe5, 0x94, 0x17, 0x11, 0x5c, 0xc9, 0xfe, 0xb3, 0x4c, 0x65, 0xca, 0x52, 0x71, 0x33, 0xb5, 0xfa, - 0xbe, 0x75, 0x60, 0xaa, 0x98, 0xf0, 0xac, 0x45, 0xc2, 0x8f, 0x0f, 0xdd, 0xbd, 0x0b, 0x6b, 0xe9, - 0x7d, 0x41, 0xee, 0x7e, 0xa9, 0xb9, 0xd2, 0xbc, 0x9a, 0x91, 0x42, 0x69, 0x49, 0x05, 0x7f, 0x0f, - 0xda, 0x7f, 0x70, 0x80, 0x8e, 0x1e, 0x0f, 0xd9, 0x75, 0x8d, 0x9d, 0x9f, 0x35, 0x3e, 0xcc, 0x78, - 0x95, 0x5f, 0x8e, 0x23, 0xa6, 0x1a, 0x27, 0x23, 0x95, 0x59, 0x3d, 0x03, 0x93, 0xbe, 0x8d, 0xab, - 0x59, 0x09, 0x26, 0x3a, 0x05, 0x76, 0x5b, 0xe3, 0x2e, 0xb3, 0x65, 0x8d, 0xfb, 0x33, 0x2a, 0xc5, - 0x49, 0xd8, 0x41, 0x86, 0x89, 0x77, 0x87, 0xbe, 0xfa, 0x03, 0x7a, 0x1f, 0x90, 0xdb, 0x1b, 0x53, - 0x03, 0x64, 0x02, 0x40, 0x4a, 0xd0, 0x24, 0xa3, 0xc6, 0xdf, 0xb1, 0x99, 0xde, 0x6c, 0x9d, 0xe9, - 0x3f, 0xa7, 0x65, 0x8d, 0x9f, 0xb7, 0x81, 0xfe, 0x65, 0xc2, 0xe4, 0x69, 0x03, 0x9d, 0x01, 0x5c, - 0x80, 0x3e, 0xa7, 0xc6, 0xfb, 0x8c, 0xdc, 0x7d, 0xc9, 0x0b, 0x2e, 0x2f, 0xe5, 0x5f, 0x59, 0x76, - 0xef, 0xdb, 0x4f, 0x87, 0xd9, 0xba, 0x9f, 0x0e, 0x32, 0x4c, 0x7a, 0x2b, 0x74, 0x1d, 0xea, 0x3b, - 0x72, 0x5f, 0x4c, 0x73, 0x5e, 0x81, 0xe0, 0xa6, 0x82, 0x94, 0xb0, 0x29, 0x61, 0x2a, 0x05, 0x92, - 0x53, 0x93, 0x83, 0x21, 0x13, 0xa5, 0x49, 0x0a, 0x02, 0x32, 0x5a, 0x01, 0x61, 0x54, 0x08, 0xff, - 0xd1, 0xc1, 0xce, 0xd1, 0x93, 0x61, 0x76, 0x5b, 0xe3, 0xad, 0xf6, 0x96, 0x35, 0x3e, 0x6e, 0x83, - 0x6d, 0xb3, 0x15, 0x26, 0x87, 0x1b, 0xf2, 0xd1, 0x74, 0xa4, 0x52, 0x78, 0x69, 0xb5, 0x67, 0x4a, - 0x9f, 0xae, 0x94, 0x23, 0x2a, 0xc4, 0xc9, 0xee, 0xd7, 0x6f, 0xd8, 0x19, 0x9e, 0x5f, 0xcf, 0x03, - 0x74, 0x33, 0x0f, 0xd0, 0xaf, 0x79, 0x80, 0x3e, 0x2d, 0x02, 0xe7, 0x66, 0x11, 0x38, 0x3f, 0x16, - 0x81, 0xf3, 0x7a, 0xb0, 0x51, 0xab, 0x01, 0x3e, 0xb8, 0xbb, 0x7a, 0xfb, 0xb1, 0x67, 0x1f, 0xbf, - 0x8b, 0x9b, 0xeb, 0xb6, 0x0d, 0x8f, 0xf7, 0x2c, 0x7f, 0xfc, 0x3b, 0x00, 0x00, 0xff, 0xff, 0x53, - 0xce, 0xd1, 0xa6, 0x33, 0x03, 0x00, 0x00, + // 472 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x53, 0xcf, 0x8b, 0xd3, 0x40, + 0x14, 0x4e, 0xdc, 0xee, 0xa2, 0x41, 0xa1, 0x64, 0x05, 0x63, 0x0f, 0x49, 0xc9, 0x61, 0xe9, 0xc1, + 0x26, 0x87, 0xbd, 0xed, 0xcd, 0x76, 0xd9, 0xee, 0x41, 0x64, 0x09, 0x82, 0x20, 0xc8, 0x30, 0x4d, + 0x5e, 0x93, 0xa1, 0x33, 0x7d, 0x61, 0x26, 0xdb, 0x1f, 0xfe, 0x01, 0x9e, 0x45, 0x3c, 0x78, 0xf4, + 0x9f, 0x11, 0xf6, 0x24, 0x7b, 0x14, 0x0f, 0x41, 0xda, 0xdb, 0x1e, 0xfb, 0x17, 0x48, 0xa6, 0x5d, + 0xb7, 0x6a, 0x2f, 0xf5, 0x94, 0x97, 0xef, 0xfb, 0xde, 0xc7, 0x37, 0xef, 0xf1, 0xac, 0x3a, 0x8c, + 0x45, 0x98, 0x53, 0x49, 0x85, 0x0a, 0x72, 0x89, 0x05, 0xda, 0x8e, 0x02, 0xa6, 0xab, 0x18, 0x79, + 0xa0, 0x80, 0xc5, 0x19, 0x65, 0xa3, 0x00, 0xc6, 0xa2, 0xf1, 0x38, 0xc5, 0x14, 0x35, 0x15, 0x56, + 0xd5, 0x4a, 0xdf, 0xd0, 0x0e, 0x31, 0x8e, 0x06, 0x2c, 0x5d, 0x21, 0xfe, 0xb7, 0x7d, 0xeb, 0xe0, + 0x42, 0x5b, 0xda, 0x9f, 0x4c, 0xeb, 0x30, 0x97, 0x0c, 0x25, 0x2b, 0x66, 0x64, 0x84, 0x52, 0x50, + 0xce, 0xde, 0x81, 0x74, 0xee, 0x35, 0xcd, 0xd6, 0x83, 0x4e, 0x7c, 0x55, 0x7a, 0xc6, 0x8f, 0xd2, + 0x3b, 0x4a, 0x59, 0x91, 0x5d, 0xf6, 0x83, 0x18, 0x2b, 0x27, 0x25, 0x50, 0xad, 0x3f, 0x6d, 0x95, + 0x0c, 0xc3, 0x62, 0x96, 0x83, 0x0a, 0x4e, 0x21, 0xbe, 0x29, 0xbd, 0x6d, 0x66, 0xcb, 0xd2, 0x6b, + 0xcc, 0xa8, 0xe0, 0x27, 0xfe, 0x16, 0xd2, 0x8f, 0xec, 0x5b, 0xf4, 0xe5, 0x6f, 0xd0, 0x7e, 0x6f, + 0x5a, 0xf5, 0x3e, 0x55, 0x40, 0x06, 0x00, 0x24, 0x07, 0x49, 0x52, 0xaa, 0x9c, 0x3d, 0x9d, 0xe9, + 0xed, 0xce, 0x99, 0xfe, 0x71, 0x5a, 0x96, 0xde, 0x93, 0x55, 0xa0, 0xbf, 0x19, 0x3f, 0x7a, 0x54, + 0x41, 0x67, 0x00, 0x17, 0x20, 0x7b, 0x54, 0xd9, 0x1f, 0x4d, 0xeb, 0x50, 0xb0, 0x11, 0x13, 0x97, + 0xe2, 0x8f, 0x2c, 0xb5, 0xff, 0x9d, 0xcf, 0x16, 0xb3, 0xbb, 0xf9, 0x6c, 0x21, 0xfd, 0xa8, 0xbe, + 0x46, 0xef, 0x42, 0x3d, 0xb7, 0xdc, 0x04, 0x38, 0x1b, 0x83, 0x24, 0xc5, 0x94, 0x64, 0x88, 0x43, + 0x32, 0xa1, 0x4a, 0x54, 0x72, 0xc2, 0x99, 0x60, 0x85, 0xb3, 0xdf, 0x34, 0x5b, 0xb5, 0xe8, 0xe9, + 0x5a, 0xf5, 0x6a, 0x7a, 0x8e, 0x38, 0x7c, 0x4d, 0x95, 0xe8, 0x51, 0xf5, 0xa2, 0x12, 0xd8, 0x5f, + 0x4d, 0xeb, 0xd9, 0x24, 0x63, 0x05, 0x70, 0xa6, 0x0a, 0x48, 0x48, 0x3c, 0x21, 0x31, 0x26, 0x40, + 0x32, 0xaa, 0x32, 0x50, 0x64, 0x80, 0x92, 0x24, 0xc0, 0x21, 0xa5, 0x05, 0x90, 0x98, 0x72, 0xee, + 0xdc, 0x6f, 0xee, 0xb5, 0x1e, 0x76, 0xd2, 0x9b, 0xd2, 0xdb, 0xa9, 0x6f, 0x59, 0x7a, 0xc7, 0xab, + 0xb7, 0xed, 0xd2, 0xe5, 0x47, 0x47, 0x1b, 0xf2, 0xee, 0xa4, 0x8b, 0x09, 0x9c, 0x6b, 0xed, 0x19, + 0xca, 0xd3, 0xb5, 0xb2, 0x4b, 0x39, 0x3f, 0xa9, 0x7d, 0xfe, 0xe2, 0x19, 0x9d, 0xde, 0xd5, 0xdc, + 0x35, 0xaf, 0xe7, 0xae, 0xf9, 0x73, 0xee, 0x9a, 0x1f, 0x16, 0xae, 0x71, 0xbd, 0x70, 0x8d, 0xef, + 0x0b, 0xd7, 0x78, 0xd3, 0xde, 0xd8, 0x8c, 0x02, 0xd6, 0xbe, 0x3d, 0x1c, 0xfd, 0xa3, 0x2f, 0x27, + 0x9c, 0x86, 0xd5, 0x81, 0xe8, 0x25, 0xf5, 0x0f, 0x34, 0x7f, 0xfc, 0x2b, 0x00, 0x00, 0xff, 0xff, + 0x70, 0xe7, 0xb6, 0xa2, 0x76, 0x03, 0x00, 0x00, } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -152,6 +163,11 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0x42 } } + if m.DeliverTxHookWasmGasLimit != 0 { + i = encodeVarintParams(dAtA, i, uint64(m.DeliverTxHookWasmGasLimit)) + i-- + dAtA[i] = 0x28 + } { size := m.MinimumFeePerGas.Size() i -= size @@ -208,6 +224,9 @@ func (m *Params) Size() (n int) { n += 1 + l + sovParams(uint64(l)) l = m.MinimumFeePerGas.Size() n += 1 + l + sovParams(uint64(l)) + if m.DeliverTxHookWasmGasLimit != 0 { + n += 1 + sovParams(uint64(m.DeliverTxHookWasmGasLimit)) + } if len(m.WhitelistedCwCodeHashesForDelegateCall) > 0 { for _, b := range m.WhitelistedCwCodeHashesForDelegateCall { l = len(b) @@ -354,6 +373,25 @@ func (m *Params) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DeliverTxHookWasmGasLimit", wireType) + } + m.DeliverTxHookWasmGasLimit = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.DeliverTxHookWasmGasLimit |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } case 8: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field WhitelistedCwCodeHashesForDelegateCall", wireType) diff --git a/x/evm/types/params_test.go b/x/evm/types/params_test.go index 342e2a2e8..40b7dc911 100644 --- a/x/evm/types/params_test.go +++ b/x/evm/types/params_test.go @@ -14,6 +14,7 @@ func TestDefaultParams(t *testing.T) { PriorityNormalizer: types.DefaultPriorityNormalizer, BaseFeePerGas: types.DefaultBaseFeePerGas, MinimumFeePerGas: types.DefaultMinFeePerGas, + DeliverTxHookWasmGasLimit: types.DefaultDeliverTxHookWasmGasLimit, WhitelistedCwCodeHashesForDelegateCall: types.DefaultWhitelistedCwCodeHashesForDelegateCall, }, types.DefaultParams()) @@ -46,3 +47,23 @@ func TestBaseFeeMinimumFee(t *testing.T) { require.Error(t, err) require.Contains(t, err.Error(), "minimum fee cannot be lower than base fee") } + +func TestValidateParamsInvalidDeliverTxHookWasmGasLimit(t *testing.T) { + params := types.DefaultParams() + params.DeliverTxHookWasmGasLimit = 0 // Set to invalid value (0) + + err := params.Validate() + require.Error(t, err) + require.Contains(t, err.Error(), "invalid deliver_tx_hook_wasm_gas_limit: must be greater than 0") +} + +func TestValidateParamsValidDeliverTxHookWasmGasLimit(t *testing.T) { + params := types.DefaultParams() + + require.Equal(t, params.DeliverTxHookWasmGasLimit, types.DefaultDeliverTxHookWasmGasLimit) + + params.DeliverTxHookWasmGasLimit = 100000 // Set to valid value + + err := params.Validate() + require.NoError(t, err) +} From 18c3e2d37f709dbf8ab90e098c2cec0d37a276ed Mon Sep 17 00:00:00 2001 From: Jeremy Wei Date: Thu, 29 Aug 2024 09:42:43 -0400 Subject: [PATCH 30/38] Move token id from Data to Topic in ERC721 Event (#1837) fix --- app/receipt.go | 44 ++++++++++++++++++++++++-------------------- app/receipt_test.go | 13 +++++++++---- 2 files changed, 33 insertions(+), 24 deletions(-) diff --git a/app/receipt.go b/app/receipt.go index 41c8e4ec9..9ad3b5301 100644 --- a/app/receipt.go +++ b/app/receipt.go @@ -182,64 +182,68 @@ func (app *App) translateCW721Event(ctx sdk.Context, wasmEvent abci.Event, point var topics []common.Hash switch action { case "transfer_nft", "send_nft", "burn": + tokenID := GetTokenIDAttribute(wasmEvent) + if tokenID == nil { + return nil, false + } topics = []common.Hash{ ERC721TransferTopic, app.GetEvmAddressAttribute(ctx, wasmEvent, "sender"), app.GetEvmAddressAttribute(ctx, wasmEvent, "recipient"), - } - tokenID := GetTokenIDAttribute(wasmEvent) - if tokenID == nil { - return nil, false + common.BigToHash(tokenID), } return ðtypes.Log{ Address: pointerAddr, Topics: topics, - Data: common.BigToHash(tokenID).Bytes(), + Data: EmptyHash.Bytes(), }, true case "mint": + tokenID := GetTokenIDAttribute(wasmEvent) + if tokenID == nil { + return nil, false + } topics = []common.Hash{ ERC721TransferTopic, EmptyHash, app.GetEvmAddressAttribute(ctx, wasmEvent, "owner"), - } - tokenID := GetTokenIDAttribute(wasmEvent) - if tokenID == nil { - return nil, false + common.BigToHash(tokenID), } return ðtypes.Log{ Address: pointerAddr, Topics: topics, - Data: common.BigToHash(tokenID).Bytes(), + Data: EmptyHash.Bytes(), }, true case "approve": + tokenID := GetTokenIDAttribute(wasmEvent) + if tokenID == nil { + return nil, false + } topics = []common.Hash{ ERC721ApprovalTopic, app.GetEvmAddressAttribute(ctx, wasmEvent, "sender"), app.GetEvmAddressAttribute(ctx, wasmEvent, "spender"), - } - tokenID := GetTokenIDAttribute(wasmEvent) - if tokenID == nil { - return nil, false + common.BigToHash(tokenID), } return ðtypes.Log{ Address: pointerAddr, Topics: topics, - Data: common.BigToHash(tokenID).Bytes(), + Data: EmptyHash.Bytes(), }, true case "revoke": + tokenID := GetTokenIDAttribute(wasmEvent) + if tokenID == nil { + return nil, false + } topics = []common.Hash{ ERC721ApprovalTopic, app.GetEvmAddressAttribute(ctx, wasmEvent, "sender"), EmptyHash, - } - tokenID := GetTokenIDAttribute(wasmEvent) - if tokenID == nil { - return nil, false + common.BigToHash(tokenID), } return ðtypes.Log{ Address: pointerAddr, Topics: topics, - Data: common.BigToHash(tokenID).Bytes(), + Data: EmptyHash.Bytes(), }, true case "approve_all": topics = []common.Hash{ diff --git a/app/receipt_test.go b/app/receipt_test.go index 625818286..bfdff291b 100644 --- a/app/receipt_test.go +++ b/app/receipt_test.go @@ -115,7 +115,6 @@ func TestEvmEventsForCw20(t *testing.T) { require.Equal(t, uint32(0), res.Code) receipt, err = testkeeper.EVMTestApp.EvmKeeper.GetTransientReceipt(ctx, signedTx.Hash()) require.Nil(t, err) - fmt.Println(receipt.Logs) require.Equal(t, 1, len(receipt.Logs)) require.NotEmpty(t, receipt.LogsBloom) require.Equal(t, mockPointerAddr.Hex(), receipt.Logs[0].Address) @@ -261,9 +260,11 @@ func TestEvmEventsForCw721(t *testing.T) { require.NotEmpty(t, receipt.LogsBloom) require.Equal(t, mockPointerAddr.Hex(), receipt.Logs[0].Address) require.Equal(t, uint32(0), receipt.Logs[0].Index) + tokenIdHash := receipt.Logs[0].Topics[3] + require.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000002", tokenIdHash) _, found = testkeeper.EVMTestApp.EvmKeeper.GetEVMTxDeferredInfo(ctx) require.True(t, found) - require.Equal(t, common.HexToHash("0x2").Bytes(), receipt.Logs[0].Data) + require.Equal(t, common.HexToHash("0x0").Bytes(), receipt.Logs[0].Data) // revoke payload = []byte(fmt.Sprintf("{\"revoke\":{\"spender\":\"%s\",\"token_id\":\"2\"}}", recipient.String())) @@ -289,7 +290,9 @@ func TestEvmEventsForCw721(t *testing.T) { require.Equal(t, mockPointerAddr.Hex(), receipt.Logs[0].Address) _, found = testkeeper.EVMTestApp.EvmKeeper.GetEVMTxDeferredInfo(ctx) require.True(t, found) - require.Equal(t, common.HexToHash("0x2").Bytes(), receipt.Logs[0].Data) + tokenIdHash = receipt.Logs[0].Topics[3] + require.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000002", tokenIdHash) + require.Equal(t, common.HexToHash("0x0").Bytes(), receipt.Logs[0].Data) // approve all payload = []byte(fmt.Sprintf("{\"approve_all\":{\"operator\":\"%s\"}}", recipient.String())) @@ -367,7 +370,9 @@ func TestEvmEventsForCw721(t *testing.T) { require.Equal(t, mockPointerAddr.Hex(), receipt.Logs[0].Address) _, found = testkeeper.EVMTestApp.EvmKeeper.GetEVMTxDeferredInfo(ctx) require.True(t, found) - require.Equal(t, common.HexToHash("0x2").Bytes(), receipt.Logs[0].Data) + tokenIdHash = receipt.Logs[0].Topics[3] + require.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000002", tokenIdHash) + require.Equal(t, common.HexToHash("0x0").Bytes(), receipt.Logs[0].Data) } func signTx(txBuilder client.TxBuilder, privKey cryptotypes.PrivKey, acc authtypes.AccountI) sdk.Tx { From 7aeb9d128bc9d98aa80caead1f9d06ca1354819e Mon Sep 17 00:00:00 2001 From: codchen Date: Fri, 30 Aug 2024 00:08:42 +0800 Subject: [PATCH 31/38] Properly handle gas in pointer precompile (#1836) --- precompiles/common/expected_keepers.go | 14 ++++++----- precompiles/common/precompiles.go | 12 ++------- precompiles/distribution/distribution_test.go | 8 +++--- precompiles/ibc/ibc_test.go | 6 ++--- precompiles/pointer/pointer.go | 21 +++++++++------- precompiles/pointer/pointer_test.go | 4 ++- x/evm/gov.go | 2 +- x/evm/keeper/params.go | 18 +++++++++++++ x/evm/keeper/pointer_upgrade.go | 25 +++++++++++-------- x/evm/keeper/pointer_upgrade_test.go | 17 +++++++------ x/evm/migrations/migrate_all_pointers.go | 7 +++--- x/evm/migrations/migrate_all_pointers_test.go | 7 +++--- 12 files changed, 81 insertions(+), 60 deletions(-) diff --git a/precompiles/common/expected_keepers.go b/precompiles/common/expected_keepers.go index 95c9657f3..bb98ffbef 100644 --- a/precompiles/common/expected_keepers.go +++ b/precompiles/common/expected_keepers.go @@ -48,14 +48,16 @@ type EVMKeeper interface { GetERC721CW721Pointer(ctx sdk.Context, cw721Address string) (addr common.Address, version uint16, exists bool) SetCode(ctx sdk.Context, addr common.Address, code []byte) UpsertERCNativePointer( - ctx sdk.Context, evm *vm.EVM, suppliedGas uint64, token string, metadata utils.ERCMetadata, - ) (contractAddr common.Address, remainingGas uint64, err error) + ctx sdk.Context, evm *vm.EVM, token string, metadata utils.ERCMetadata, + ) (contractAddr common.Address, err error) UpsertERCCW20Pointer( - ctx sdk.Context, evm *vm.EVM, suppliedGas uint64, cw20Addr string, metadata utils.ERCMetadata, - ) (contractAddr common.Address, remainingGas uint64, err error) + ctx sdk.Context, evm *vm.EVM, cw20Addr string, metadata utils.ERCMetadata, + ) (contractAddr common.Address, err error) UpsertERCCW721Pointer( - ctx sdk.Context, evm *vm.EVM, suppliedGas uint64, cw721Addr string, metadata utils.ERCMetadata, - ) (contractAddr common.Address, remainingGas uint64, err error) + ctx sdk.Context, evm *vm.EVM, cw721Addr string, metadata utils.ERCMetadata, + ) (contractAddr common.Address, err error) + GetEVMGasLimitFromCtx(ctx sdk.Context) uint64 + GetCosmosGasLimitFromEVMGas(ctx sdk.Context, evmGas uint64) uint64 } type AccountKeeper interface { diff --git a/precompiles/common/precompiles.go b/precompiles/common/precompiles.go index 1354e54db..006d90074 100644 --- a/precompiles/common/precompiles.go +++ b/precompiles/common/precompiles.go @@ -13,7 +13,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/vm" - "github.com/sei-protocol/sei-chain/utils" "github.com/sei-protocol/sei-chain/utils/metrics" "github.com/sei-protocol/sei-chain/x/evm/state" "github.com/sei-protocol/sei-chain/x/evm/types" @@ -160,12 +159,7 @@ func (d DynamicGasPrecompile) RunAndCalculateGas(evm *vm.EVM, caller common.Addr if err != nil { return nil, 0, err } - gasMultipler := d.executor.EVMKeeper().GetPriorityNormalizer(ctx) - gasLimitBigInt := sdk.NewDecFromInt(sdk.NewIntFromUint64(suppliedGas)).Mul(gasMultipler).TruncateInt().BigInt() - if gasLimitBigInt.Cmp(utils.BigMaxU64) > 0 { - gasLimitBigInt = utils.BigMaxU64 - } - ctx = ctx.WithGasMeter(sdk.NewGasMeterWithMultiplier(ctx, gasLimitBigInt.Uint64())) + ctx = ctx.WithGasMeter(sdk.NewGasMeterWithMultiplier(ctx, d.executor.EVMKeeper().GetCosmosGasLimitFromEVMGas(ctx, suppliedGas))) operation = method.Name em := ctx.EventManager() @@ -231,9 +225,7 @@ sei gas = evm gas * multiplier sei gas price = fee / sei gas = fee / (evm gas * multiplier) = evm gas / multiplier */ func GetRemainingGas(ctx sdk.Context, evmKeeper EVMKeeper) uint64 { - gasMultipler := evmKeeper.GetPriorityNormalizer(ctx) - seiGasRemaining := ctx.GasMeter().Limit() - ctx.GasMeter().GasConsumedToLimit() - return sdk.NewDecFromInt(sdk.NewIntFromUint64(seiGasRemaining)).Quo(gasMultipler).TruncateInt().Uint64() + return evmKeeper.GetEVMGasLimitFromCtx(ctx) } func ExtractMethodID(input []byte) ([]byte, error) { diff --git a/precompiles/distribution/distribution_test.go b/precompiles/distribution/distribution_test.go index 19bab661c..f45919ebb 100644 --- a/precompiles/distribution/distribution_test.go +++ b/precompiles/distribution/distribution_test.go @@ -148,7 +148,7 @@ func TestWithdraw(t *testing.T) { res, err = msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), req) require.Nil(t, err) require.Empty(t, res.VmError) - require.Equal(t, uint64(69808), res.GasUsed) + require.Equal(t, uint64(64124), res.GasUsed) // reinitialized d, found = testApp.StakingKeeper.GetDelegation(ctx, seiAddr, val) @@ -301,7 +301,7 @@ func setWithdrawAddressAndWithdraw( res, err = msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), r) require.Nil(t, err) require.Empty(t, res.VmError) - require.Equal(t, uint64(153974), res.GasUsed) + require.Equal(t, uint64(148290), res.GasUsed) // reinitialized for _, val := range vals { @@ -1051,7 +1051,7 @@ func TestPrecompile_RunAndCalculateGas_Rewards(t *testing.T) { suppliedGas: uint64(1000000), }, wantRet: emptyCasePackedOutput, - wantRemainingGas: 993193, + wantRemainingGas: 998877, wantErr: false, }, { @@ -1067,7 +1067,7 @@ func TestPrecompile_RunAndCalculateGas_Rewards(t *testing.T) { suppliedGas: uint64(1000000), }, wantRet: happyPathPackedOutput, - wantRemainingGas: 993193, + wantRemainingGas: 998877, wantErr: false, }, } diff --git a/precompiles/ibc/ibc_test.go b/precompiles/ibc/ibc_test.go index b651af746..7b5e735a4 100644 --- a/precompiles/ibc/ibc_test.go +++ b/precompiles/ibc/ibc_test.go @@ -106,7 +106,7 @@ func TestPrecompile_Run(t *testing.T) { fields: fields{transferKeeper: &MockTransferKeeper{}}, args: commonArgs, wantBz: packedTrue, - wantRemainingGas: 993193, + wantRemainingGas: 998877, wantErr: false, }, { @@ -235,7 +235,7 @@ func TestPrecompile_Run(t *testing.T) { value: nil, }, wantBz: packedTrue, - wantRemainingGas: 993193, + wantRemainingGas: 998877, wantErr: false, }, { @@ -255,7 +255,7 @@ func TestPrecompile_Run(t *testing.T) { value: nil, }, wantBz: packedTrue, - wantRemainingGas: 993193, + wantRemainingGas: 998877, wantErr: false, }, } diff --git a/precompiles/pointer/pointer.go b/precompiles/pointer/pointer.go index 8efe8386f..c939a47b4 100644 --- a/precompiles/pointer/pointer.go +++ b/precompiles/pointer/pointer.go @@ -73,11 +73,11 @@ func (p PrecompileExecutor) Execute(ctx sdk.Context, method *ethabi.Method, call switch method.Name { case AddNativePointer: - return p.AddNative(ctx, method, caller, args, value, evm, suppliedGas) + return p.AddNative(ctx, method, caller, args, value, evm) case AddCW20Pointer: - return p.AddCW20(ctx, method, caller, args, value, evm, suppliedGas) + return p.AddCW20(ctx, method, caller, args, value, evm) case AddCW721Pointer: - return p.AddCW721(ctx, method, caller, args, value, evm, suppliedGas) + return p.AddCW721(ctx, method, caller, args, value, evm) default: err = fmt.Errorf("unknown method %s", method.Name) } @@ -88,7 +88,7 @@ func (p PrecompileExecutor) EVMKeeper() pcommon.EVMKeeper { return p.evmKeeper } -func (p PrecompileExecutor) AddNative(ctx sdk.Context, method *ethabi.Method, caller common.Address, args []interface{}, value *big.Int, evm *vm.EVM, suppliedGas uint64) (ret []byte, remainingGas uint64, err error) { +func (p PrecompileExecutor) AddNative(ctx sdk.Context, method *ethabi.Method, caller common.Address, args []interface{}, value *big.Int, evm *vm.EVM) (ret []byte, remainingGas uint64, err error) { if err := pcommon.ValidateNonPayable(value); err != nil { return nil, 0, err } @@ -113,15 +113,16 @@ func (p PrecompileExecutor) AddNative(ctx sdk.Context, method *ethabi.Method, ca } } } - contractAddr, remainingGas, err := p.evmKeeper.UpsertERCNativePointer(ctx, evm, suppliedGas, token, utils.ERCMetadata{Name: name, Symbol: symbol, Decimals: decimals}) + contractAddr, err := p.evmKeeper.UpsertERCNativePointer(ctx, evm, token, utils.ERCMetadata{Name: name, Symbol: symbol, Decimals: decimals}) if err != nil { return nil, 0, err } ret, err = method.Outputs.Pack(contractAddr) + remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) return } -func (p PrecompileExecutor) AddCW20(ctx sdk.Context, method *ethabi.Method, caller common.Address, args []interface{}, value *big.Int, evm *vm.EVM, suppliedGas uint64) (ret []byte, remainingGas uint64, err error) { +func (p PrecompileExecutor) AddCW20(ctx sdk.Context, method *ethabi.Method, caller common.Address, args []interface{}, value *big.Int, evm *vm.EVM) (ret []byte, remainingGas uint64, err error) { if err := pcommon.ValidateNonPayable(value); err != nil { return nil, 0, err } @@ -143,15 +144,16 @@ func (p PrecompileExecutor) AddCW20(ctx sdk.Context, method *ethabi.Method, call } name := formattedRes["name"].(string) symbol := formattedRes["symbol"].(string) - contractAddr, remainingGas, err := p.evmKeeper.UpsertERCCW20Pointer(ctx, evm, suppliedGas, cwAddr, utils.ERCMetadata{Name: name, Symbol: symbol}) + contractAddr, err := p.evmKeeper.UpsertERCCW20Pointer(ctx, evm, cwAddr, utils.ERCMetadata{Name: name, Symbol: symbol}) if err != nil { return nil, 0, err } ret, err = method.Outputs.Pack(contractAddr) + remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) return } -func (p PrecompileExecutor) AddCW721(ctx sdk.Context, method *ethabi.Method, caller common.Address, args []interface{}, value *big.Int, evm *vm.EVM, suppliedGas uint64) (ret []byte, remainingGas uint64, err error) { +func (p PrecompileExecutor) AddCW721(ctx sdk.Context, method *ethabi.Method, caller common.Address, args []interface{}, value *big.Int, evm *vm.EVM) (ret []byte, remainingGas uint64, err error) { if err := pcommon.ValidateNonPayable(value); err != nil { return nil, 0, err } @@ -173,10 +175,11 @@ func (p PrecompileExecutor) AddCW721(ctx sdk.Context, method *ethabi.Method, cal } name := formattedRes["name"].(string) symbol := formattedRes["symbol"].(string) - contractAddr, remainingGas, err := p.evmKeeper.UpsertERCCW721Pointer(ctx, evm, suppliedGas, cwAddr, utils.ERCMetadata{Name: name, Symbol: symbol}) + contractAddr, err := p.evmKeeper.UpsertERCCW721Pointer(ctx, evm, cwAddr, utils.ERCMetadata{Name: name, Symbol: symbol}) if err != nil { return nil, 0, err } ret, err = method.Outputs.Pack(contractAddr) + remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) return } diff --git a/precompiles/pointer/pointer_test.go b/precompiles/pointer/pointer_test.go index c1abc2fb7..be5f10b46 100644 --- a/precompiles/pointer/pointer_test.go +++ b/precompiles/pointer/pointer_test.go @@ -4,6 +4,7 @@ import ( "testing" "time" + sdk "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" @@ -21,6 +22,7 @@ func TestAddNative(t *testing.T) { p, err := pointer.NewPrecompile(&testApp.EvmKeeper, testApp.BankKeeper, testApp.WasmKeeper) require.Nil(t, err) ctx := testApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) + ctx = ctx.WithGasMeter(sdk.NewInfiniteGasMeterWithMultiplier(ctx)) _, caller := testkeeper.MockAddressPair() suppliedGas := uint64(10000000) cfg := types.DefaultChainConfig().EthereumConfig(testApp.EvmKeeper.ChainID(ctx)) @@ -55,7 +57,7 @@ func TestAddNative(t *testing.T) { evm = vm.NewEVM(*blockCtx, vm.TxContext{}, statedb, cfg, vm.Config{}) ret, g, err := p.RunAndCalculateGas(evm, caller, caller, append(p.GetExecutor().(*pointer.PrecompileExecutor).AddNativePointerID, args...), suppliedGas, nil, nil, false) require.Nil(t, err) - require.Equal(t, uint64(8907806), g) + require.Equal(t, uint64(8888494), g) outputs, err := m.Outputs.Unpack(ret) require.Nil(t, err) addr := outputs[0].(common.Address) diff --git a/x/evm/gov.go b/x/evm/gov.go index a527b0278..db4638458 100644 --- a/x/evm/gov.go +++ b/x/evm/gov.go @@ -20,7 +20,7 @@ func HandleAddERCNativePointerProposalV2(ctx sdk.Context, k *keeper.Keeper, p *t } return k.RunWithOneOffEVMInstance( ctx, func(e *vm.EVM) error { - _, _, err := k.UpsertERCNativePointer(ctx, e, math.MaxUint64, p.Token, utils.ERCMetadata{Name: p.Name, Symbol: p.Symbol, Decimals: decimals}) + _, err := k.UpsertERCNativePointer(ctx, e, p.Token, utils.ERCMetadata{Name: p.Name, Symbol: p.Symbol, Decimals: decimals}) return err }, func(s1, s2 string) { logNativeV2Error(ctx, p, s1, s2) diff --git a/x/evm/keeper/params.go b/x/evm/keeper/params.go index 951f82d20..04d8be61c 100644 --- a/x/evm/keeper/params.go +++ b/x/evm/keeper/params.go @@ -50,3 +50,21 @@ func (k *Keeper) ChainID(ctx sdk.Context) *big.Int { return config.GetEVMChainID(ctx.ChainID()) } + +/* +* +sei gas = evm gas * multiplier +sei gas price = fee / sei gas = fee / (evm gas * multiplier) = evm gas / multiplier +*/ +func (k *Keeper) GetEVMGasLimitFromCtx(ctx sdk.Context) uint64 { + return k.getEvmGasLimitFromCtx(ctx) +} + +func (k *Keeper) GetCosmosGasLimitFromEVMGas(ctx sdk.Context, evmGas uint64) uint64 { + gasMultipler := k.GetPriorityNormalizer(ctx) + gasLimitBigInt := sdk.NewDecFromInt(sdk.NewIntFromUint64(evmGas)).Mul(gasMultipler).TruncateInt().BigInt() + if gasLimitBigInt.Cmp(utils.BigMaxU64) > 0 { + gasLimitBigInt = utils.BigMaxU64 + } + return gasLimitBigInt.Uint64() +} diff --git a/x/evm/keeper/pointer_upgrade.go b/x/evm/keeper/pointer_upgrade.go index 04d6aebcf..378570a88 100644 --- a/x/evm/keeper/pointer_upgrade.go +++ b/x/evm/keeper/pointer_upgrade.go @@ -44,38 +44,38 @@ func (k *Keeper) RunWithOneOffEVMInstance( } func (k *Keeper) UpsertERCNativePointer( - ctx sdk.Context, evm *vm.EVM, suppliedGas uint64, token string, metadata utils.ERCMetadata, -) (contractAddr common.Address, remainingGas uint64, err error) { + ctx sdk.Context, evm *vm.EVM, token string, metadata utils.ERCMetadata, +) (contractAddr common.Address, err error) { return k.UpsertERCPointer( - ctx, evm, suppliedGas, "native", []interface{}{ + ctx, evm, "native", []interface{}{ token, metadata.Name, metadata.Symbol, metadata.Decimals, }, k.GetERC20NativePointer, k.SetERC20NativePointer, ) } func (k *Keeper) UpsertERCCW20Pointer( - ctx sdk.Context, evm *vm.EVM, suppliedGas uint64, cw20Addr string, metadata utils.ERCMetadata, -) (contractAddr common.Address, remainingGas uint64, err error) { + ctx sdk.Context, evm *vm.EVM, cw20Addr string, metadata utils.ERCMetadata, +) (contractAddr common.Address, err error) { return k.UpsertERCPointer( - ctx, evm, suppliedGas, "cw20", []interface{}{ + ctx, evm, "cw20", []interface{}{ cw20Addr, metadata.Name, metadata.Symbol, }, k.GetERC20CW20Pointer, k.SetERC20CW20Pointer, ) } func (k *Keeper) UpsertERCCW721Pointer( - ctx sdk.Context, evm *vm.EVM, suppliedGas uint64, cw721Addr string, metadata utils.ERCMetadata, -) (contractAddr common.Address, remainingGas uint64, err error) { + ctx sdk.Context, evm *vm.EVM, cw721Addr string, metadata utils.ERCMetadata, +) (contractAddr common.Address, err error) { return k.UpsertERCPointer( - ctx, evm, suppliedGas, "cw721", []interface{}{ + ctx, evm, "cw721", []interface{}{ cw721Addr, metadata.Name, metadata.Symbol, }, k.GetERC721CW721Pointer, k.SetERC721CW721Pointer, ) } func (k *Keeper) UpsertERCPointer( - ctx sdk.Context, evm *vm.EVM, suppliedGas uint64, typ string, args []interface{}, getter PointerGetter, setter PointerSetter, -) (contractAddr common.Address, remainingGas uint64, err error) { + ctx sdk.Context, evm *vm.EVM, typ string, args []interface{}, getter PointerGetter, setter PointerSetter, +) (contractAddr common.Address, err error) { pointee := args[0].(string) evmModuleAddress := k.GetEVMAddressOrDefault(ctx, k.AccountKeeper().GetModuleAddress(types.ModuleName)) @@ -86,6 +86,8 @@ func (k *Keeper) UpsertERCPointer( } bin = append(artifacts.GetBin(typ), bin...) existingAddr, _, exists := getter(ctx, pointee) + suppliedGas := k.getEvmGasLimitFromCtx(ctx) + var remainingGas uint64 if exists { var ret []byte contractAddr = existingAddr @@ -97,6 +99,7 @@ func (k *Keeper) UpsertERCPointer( if err != nil { return } + ctx.GasMeter().ConsumeGas(k.GetCosmosGasLimitFromEVMGas(ctx, suppliedGas-remainingGas), "ERC pointer deployment") if err = setter(ctx, pointee, contractAddr); err != nil { return } diff --git a/x/evm/keeper/pointer_upgrade_test.go b/x/evm/keeper/pointer_upgrade_test.go index f7a1d2e09..14d61675f 100644 --- a/x/evm/keeper/pointer_upgrade_test.go +++ b/x/evm/keeper/pointer_upgrade_test.go @@ -2,10 +2,10 @@ package keeper_test import ( "errors" - "math" "testing" "time" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" @@ -31,9 +31,10 @@ func TestRunWithOneOffEVMInstance(t *testing.T) { func TestUpsertERCNativePointer(t *testing.T) { k := &testkeeper.EVMTestApp.EvmKeeper ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) + ctx = ctx.WithGasMeter(sdk.NewInfiniteGasMeterWithMultiplier(ctx)) var addr common.Address err := k.RunWithOneOffEVMInstance(ctx, func(e *vm.EVM) error { - a, _, err := k.UpsertERCNativePointer(ctx, e, math.MaxUint64, "test", utils.ERCMetadata{ + a, err := k.UpsertERCNativePointer(ctx, e, "test", utils.ERCMetadata{ Name: "test", Symbol: "test", Decimals: 6, @@ -44,7 +45,7 @@ func TestUpsertERCNativePointer(t *testing.T) { require.Nil(t, err) var newAddr common.Address err = k.RunWithOneOffEVMInstance(ctx, func(e *vm.EVM) error { - a, _, err := k.UpsertERCNativePointer(ctx, e, math.MaxUint64, "test", utils.ERCMetadata{ + a, err := k.UpsertERCNativePointer(ctx, e, "test", utils.ERCMetadata{ Name: "test2", Symbol: "test2", Decimals: 12, @@ -70,9 +71,10 @@ func TestUpsertERCNativePointer(t *testing.T) { func TestUpsertERC20Pointer(t *testing.T) { k := &testkeeper.EVMTestApp.EvmKeeper ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) + ctx = ctx.WithGasMeter(sdk.NewInfiniteGasMeterWithMultiplier(ctx)) var addr common.Address err := k.RunWithOneOffEVMInstance(ctx, func(e *vm.EVM) error { - a, _, err := k.UpsertERCCW20Pointer(ctx, e, math.MaxUint64, "test", utils.ERCMetadata{ + a, err := k.UpsertERCCW20Pointer(ctx, e, "test", utils.ERCMetadata{ Name: "test", Symbol: "test", }) @@ -82,7 +84,7 @@ func TestUpsertERC20Pointer(t *testing.T) { require.Nil(t, err) var newAddr common.Address err = k.RunWithOneOffEVMInstance(ctx, func(e *vm.EVM) error { - a, _, err := k.UpsertERCCW20Pointer(ctx, e, math.MaxUint64, "test", utils.ERCMetadata{ + a, err := k.UpsertERCCW20Pointer(ctx, e, "test", utils.ERCMetadata{ Name: "test2", Symbol: "test2", }) @@ -96,9 +98,10 @@ func TestUpsertERC20Pointer(t *testing.T) { func TestUpsertERC721Pointer(t *testing.T) { k := &testkeeper.EVMTestApp.EvmKeeper ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) + ctx = ctx.WithGasMeter(sdk.NewInfiniteGasMeterWithMultiplier(ctx)) var addr common.Address err := k.RunWithOneOffEVMInstance(ctx, func(e *vm.EVM) error { - a, _, err := k.UpsertERCCW721Pointer(ctx, e, math.MaxUint64, "test", utils.ERCMetadata{ + a, err := k.UpsertERCCW721Pointer(ctx, e, "test", utils.ERCMetadata{ Name: "test", Symbol: "test", }) @@ -108,7 +111,7 @@ func TestUpsertERC721Pointer(t *testing.T) { require.Nil(t, err) var newAddr common.Address err = k.RunWithOneOffEVMInstance(ctx, func(e *vm.EVM) error { - a, _, err := k.UpsertERCCW721Pointer(ctx, e, math.MaxUint64, "test", utils.ERCMetadata{ + a, err := k.UpsertERCCW721Pointer(ctx, e, "test", utils.ERCMetadata{ Name: "test2", Symbol: "test2", }) diff --git a/x/evm/migrations/migrate_all_pointers.go b/x/evm/migrations/migrate_all_pointers.go index 31d650101..05d7f7e59 100644 --- a/x/evm/migrations/migrate_all_pointers.go +++ b/x/evm/migrations/migrate_all_pointers.go @@ -3,7 +3,6 @@ package migrations import ( "encoding/json" "fmt" - "math" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" @@ -41,7 +40,7 @@ func MigrateERCNativePointers(ctx sdk.Context, k *keeper.Keeper) error { continue } _ = k.RunWithOneOffEVMInstance(ctx, func(e *vm.EVM) error { - _, _, err := k.UpsertERCNativePointer(ctx, e, math.MaxUint64, token, utils.ERCMetadata{ + _, err := k.UpsertERCNativePointer(ctx.WithGasMeter(sdk.NewInfiniteGasMeterWithMultiplier(ctx)), e, token, utils.ERCMetadata{ Name: oName.(string), Symbol: oSymbol.(string), Decimals: oDecimals.(uint8), @@ -76,7 +75,7 @@ func MigrateERCCW20Pointers(ctx sdk.Context, k *keeper.Keeper) error { continue } _ = k.RunWithOneOffEVMInstance(ctx, func(e *vm.EVM) error { - _, _, err := k.UpsertERCCW20Pointer(ctx, e, math.MaxUint64, cwAddr, utils.ERCMetadata{ + _, err := k.UpsertERCCW20Pointer(ctx.WithGasMeter(sdk.NewInfiniteGasMeterWithMultiplier(ctx)), e, cwAddr, utils.ERCMetadata{ Name: oName.(string), Symbol: oSymbol.(string), }) @@ -110,7 +109,7 @@ func MigrateERCCW721Pointers(ctx sdk.Context, k *keeper.Keeper) error { continue } _ = k.RunWithOneOffEVMInstance(ctx, func(e *vm.EVM) error { - _, _, err := k.UpsertERCCW721Pointer(ctx, e, math.MaxUint64, cwAddr, utils.ERCMetadata{ + _, err := k.UpsertERCCW721Pointer(ctx.WithGasMeter(sdk.NewInfiniteGasMeterWithMultiplier(ctx)), e, cwAddr, utils.ERCMetadata{ Name: oName.(string), Symbol: oSymbol.(string), }) diff --git a/x/evm/migrations/migrate_all_pointers_test.go b/x/evm/migrations/migrate_all_pointers_test.go index a6f6420e8..fee2e4732 100644 --- a/x/evm/migrations/migrate_all_pointers_test.go +++ b/x/evm/migrations/migrate_all_pointers_test.go @@ -1,7 +1,6 @@ package migrations_test import ( - "math" "testing" "time" @@ -21,7 +20,7 @@ func TestMigrateERCNativePointers(t *testing.T) { ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) var pointerAddr common.Address require.Nil(t, k.RunWithOneOffEVMInstance(ctx, func(e *vm.EVM) error { - a, _, err := k.UpsertERCNativePointer(ctx, e, math.MaxUint64, "test", utils.ERCMetadata{Name: "name", Symbol: "symbol", Decimals: 6}) + a, err := k.UpsertERCNativePointer(ctx, e, "test", utils.ERCMetadata{Name: "name", Symbol: "symbol", Decimals: 6}) pointerAddr = a return err }, func(s1, s2 string) {})) @@ -36,7 +35,7 @@ func TestMigrateERCCW20Pointers(t *testing.T) { ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) var pointerAddr common.Address require.Nil(t, k.RunWithOneOffEVMInstance(ctx, func(e *vm.EVM) error { - a, _, err := k.UpsertERCCW20Pointer(ctx, e, math.MaxUint64, "test", utils.ERCMetadata{Name: "name", Symbol: "symbol"}) + a, err := k.UpsertERCCW20Pointer(ctx, e, "test", utils.ERCMetadata{Name: "name", Symbol: "symbol"}) pointerAddr = a return err }, func(s1, s2 string) {})) @@ -51,7 +50,7 @@ func TestMigrateERCCW721Pointers(t *testing.T) { ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) var pointerAddr common.Address require.Nil(t, k.RunWithOneOffEVMInstance(ctx, func(e *vm.EVM) error { - a, _, err := k.UpsertERCCW721Pointer(ctx, e, math.MaxUint64, "test", utils.ERCMetadata{Name: "name", Symbol: "symbol"}) + a, err := k.UpsertERCCW721Pointer(ctx, e, "test", utils.ERCMetadata{Name: "name", Symbol: "symbol"}) pointerAddr = a return err }, func(s1, s2 string) {})) From f50837ec08bc154c30b4c168bdda5693073e8344 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Ma=C5=82ota-W=C3=B3jcik?= Date: Fri, 30 Aug 2024 14:21:36 +0200 Subject: [PATCH 32/38] Return evm logs from cosmos interface (#1825) --- proto/evm/tx.proto | 4 +- x/evm/keeper/evm.go | 1 + x/evm/keeper/msg_server.go | 35 ++++--- x/evm/keeper/msg_server_test.go | 6 +- x/evm/types/logs.go | 25 +++++ x/evm/types/tx.pb.go | 173 ++++++++++++++++++++++---------- 6 files changed, 170 insertions(+), 74 deletions(-) create mode 100644 x/evm/types/logs.go diff --git a/proto/evm/tx.proto b/proto/evm/tx.proto index 0d32c7c45..de27ea8a7 100644 --- a/proto/evm/tx.proto +++ b/proto/evm/tx.proto @@ -5,6 +5,7 @@ import "google/protobuf/any.proto"; import "gogoproto/gogo.proto"; import "cosmos/base/v1beta1/coin.proto"; import "evm/enums.proto"; +import "evm/receipt.proto"; option go_package = "github.com/sei-protocol/sei-chain/x/evm/types"; @@ -26,6 +27,7 @@ message MsgEVMTransactionResponse { string vm_error = 2; bytes return_data = 3; string hash = 4; + repeated Log logs = 5; } message MsgInternalEVMCall { @@ -80,4 +82,4 @@ message MsgAssociate { string custom_message = 2; } -message MsgAssociateResponse {} \ No newline at end of file +message MsgAssociateResponse {} diff --git a/x/evm/keeper/evm.go b/x/evm/keeper/evm.go index 147912140..1ec7f039d 100644 --- a/x/evm/keeper/evm.go +++ b/x/evm/keeper/evm.go @@ -13,6 +13,7 @@ import ( ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/params" + "github.com/sei-protocol/sei-chain/utils" "github.com/sei-protocol/sei-chain/utils/metrics" "github.com/sei-protocol/sei-chain/x/evm/state" diff --git a/x/evm/keeper/msg_server.go b/x/evm/keeper/msg_server.go index 358a9f001..0402ff48a 100644 --- a/x/evm/keeper/msg_server.go +++ b/x/evm/keeper/msg_server.go @@ -21,6 +21,7 @@ import ( "github.com/ethereum/go-ethereum/core" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" + "github.com/sei-protocol/sei-chain/precompiles/wasmd" "github.com/sei-protocol/sei-chain/utils" "github.com/sei-protocol/sei-chain/x/evm/artifacts/erc20" @@ -176,23 +177,26 @@ func (server msgServer) EVMTransaction(goCtx context.Context, msg *types.MsgEVMT }, ) - } else { - // if applyErr is nil then res must be non-nil - if res.Err != nil { - serverRes.VmError = res.Err.Error() + return + } - telemetry.IncrCounterWithLabels( - []string{types.ModuleName, "errors", "vm_execution"}, - 1, - []metrics.Label{ - telemetry.NewLabel("type", serverRes.VmError), - }, - ) - } - serverRes.GasUsed = res.UsedGas - serverRes.ReturnData = res.ReturnData + // if applyErr is nil then res must be non-nil + if res.Err != nil { + serverRes.VmError = res.Err.Error() + + telemetry.IncrCounterWithLabels( + []string{types.ModuleName, "errors", "vm_execution"}, + 1, + []metrics.Label{ + telemetry.NewLabel("type", serverRes.VmError), + }, + ) } + serverRes.GasUsed = res.UsedGas + serverRes.ReturnData = res.ReturnData + serverRes.Logs = types.NewLogsFromEth(stateDB.GetAllLogs()) + return } @@ -233,8 +237,7 @@ func (k Keeper) applyEVMMessage(ctx sdk.Context, msg *core.Message, stateDB *sta txCtx := core.NewEVMTxContext(msg) evmInstance := vm.NewEVM(*blockCtx, txCtx, stateDB, cfg, vm.Config{}) st := core.NewStateTransition(evmInstance, msg, &gp, true) // fee already charged in ante handler - res, err := st.TransitionDb() - return res, err + return st.TransitionDb() } func (server msgServer) Send(goCtx context.Context, msg *types.MsgSend) (*types.MsgSendResponse, error) { diff --git a/x/evm/keeper/msg_server_test.go b/x/evm/keeper/msg_server_test.go index 79c68ce43..deb333287 100644 --- a/x/evm/keeper/msg_server_test.go +++ b/x/evm/keeper/msg_server_test.go @@ -16,6 +16,9 @@ import ( "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/sei-protocol/sei-chain/example/contracts/echo" "github.com/sei-protocol/sei-chain/example/contracts/sendall" "github.com/sei-protocol/sei-chain/example/contracts/simplestorage" @@ -27,8 +30,6 @@ import ( "github.com/sei-protocol/sei-chain/x/evm/state" "github.com/sei-protocol/sei-chain/x/evm/types" "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" - "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" ) type mockTx struct { @@ -125,6 +126,7 @@ func TestEVMTransaction(t *testing.T) { require.Nil(t, err) res, err = msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), req) require.Nil(t, err) + require.NotEmpty(t, res.Logs) require.LessOrEqual(t, res.GasUsed, uint64(200000)) require.Empty(t, res.VmError) require.NoError(t, k.FlushTransientReceipts(ctx)) diff --git a/x/evm/types/logs.go b/x/evm/types/logs.go new file mode 100644 index 000000000..aff53a053 --- /dev/null +++ b/x/evm/types/logs.go @@ -0,0 +1,25 @@ +package types + +import ethtypes "github.com/ethereum/go-ethereum/core/types" + +func NewLogsFromEth(ethlogs []*ethtypes.Log) []*Log { + logs := make([]*Log, 0, len(ethlogs)) + for _, ethlog := range ethlogs { + logs = append(logs, newLogFromEth(ethlog)) + } + return logs +} + +func newLogFromEth(log *ethtypes.Log) *Log { + topics := make([]string, len(log.Topics)) + for i, topic := range log.Topics { + topics[i] = topic.String() + } + + return &Log{ + Address: log.Address.String(), + Topics: topics, + Data: log.Data, + Index: uint32(log.Index), + } +} diff --git a/x/evm/types/tx.pb.go b/x/evm/types/tx.pb.go index 42a5057e9..1f1beb9d0 100644 --- a/x/evm/types/tx.pb.go +++ b/x/evm/types/tx.pb.go @@ -82,6 +82,7 @@ type MsgEVMTransactionResponse struct { VmError string `protobuf:"bytes,2,opt,name=vm_error,json=vmError,proto3" json:"vm_error,omitempty"` ReturnData []byte `protobuf:"bytes,3,opt,name=return_data,json=returnData,proto3" json:"return_data,omitempty"` Hash string `protobuf:"bytes,4,opt,name=hash,proto3" json:"hash,omitempty"` + Logs []*Log `protobuf:"bytes,5,rep,name=logs,proto3" json:"logs,omitempty"` } func (m *MsgEVMTransactionResponse) Reset() { *m = MsgEVMTransactionResponse{} } @@ -145,6 +146,13 @@ func (m *MsgEVMTransactionResponse) GetHash() string { return "" } +func (m *MsgEVMTransactionResponse) GetLogs() []*Log { + if m != nil { + return m.Logs + } + return nil +} + type MsgInternalEVMCall struct { Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty"` Value *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,2,opt,name=value,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"value,omitempty"` @@ -750,61 +758,62 @@ func init() { func init() { proto.RegisterFile("evm/tx.proto", fileDescriptor_d72e73a3d1d93781) } var fileDescriptor_d72e73a3d1d93781 = []byte{ - // 849 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x55, 0xcd, 0x6e, 0xdb, 0x46, - 0x10, 0x36, 0x6d, 0xc5, 0x8a, 0x46, 0xaa, 0x8c, 0x10, 0x46, 0x20, 0xb3, 0xad, 0xe4, 0xb2, 0x75, - 0xaa, 0xfe, 0x98, 0x6c, 0x9c, 0x16, 0x3d, 0x14, 0x05, 0xea, 0x3f, 0x34, 0x39, 0x10, 0x2d, 0x58, - 0x27, 0x87, 0x5e, 0x84, 0x15, 0x39, 0xa1, 0x89, 0x8a, 0xbb, 0xc2, 0xee, 0x52, 0x88, 0x5e, 0xa0, - 0xe7, 0xa0, 0x28, 0xd0, 0x3e, 0x43, 0x4f, 0x7d, 0x82, 0x9e, 0x73, 0xcc, 0xb1, 0xc8, 0xc1, 0x2d, - 0xec, 0x17, 0x29, 0x76, 0x97, 0x64, 0x6c, 0x19, 0x52, 0xe5, 0x9c, 0xb8, 0x33, 0xf3, 0xcd, 0xcc, - 0x37, 0x3f, 0xbb, 0x84, 0x16, 0x4e, 0x32, 0x5f, 0x3e, 0xf3, 0xc6, 0x9c, 0x49, 0x66, 0x77, 0x04, - 0xa6, 0xfa, 0x14, 0xb1, 0x91, 0x27, 0x30, 0x8d, 0x4e, 0x49, 0x4a, 0x3d, 0x9c, 0x64, 0xce, 0x56, - 0xc2, 0x58, 0x32, 0x42, 0x5f, 0x5b, 0x87, 0xf9, 0x53, 0x9f, 0xd0, 0xa9, 0x71, 0x72, 0x36, 0x13, - 0x96, 0x30, 0x7d, 0xf4, 0xd5, 0xa9, 0xd0, 0x76, 0x23, 0x26, 0x32, 0x26, 0xfc, 0x21, 0x11, 0xe8, - 0x4f, 0xee, 0x0f, 0x51, 0x92, 0xfb, 0x7e, 0xc4, 0x52, 0x5a, 0xd8, 0x37, 0x54, 0x62, 0xa4, 0x79, - 0x26, 0x8c, 0xc2, 0xfd, 0xd5, 0x82, 0x3b, 0x81, 0x48, 0x8e, 0x9f, 0x04, 0x27, 0x9c, 0x50, 0x41, - 0x22, 0x99, 0x32, 0x6a, 0xf7, 0xa1, 0x16, 0x13, 0x49, 0x3a, 0xd6, 0xb6, 0xd5, 0x6f, 0xee, 0x6d, - 0x7a, 0x86, 0x86, 0x57, 0xd2, 0xf0, 0xf6, 0xe9, 0x34, 0xd4, 0x08, 0xfb, 0x31, 0xd4, 0x63, 0xe4, - 0xe9, 0x04, 0xe3, 0xce, 0xea, 0xb6, 0xd5, 0x6f, 0x1d, 0x7c, 0xf5, 0xea, 0xac, 0xf7, 0x65, 0x92, - 0xca, 0xd3, 0x7c, 0xe8, 0x45, 0x2c, 0xf3, 0x05, 0xa6, 0xbb, 0x65, 0x71, 0x5a, 0xd0, 0xd5, 0xf9, - 0xcf, 0x7c, 0xc5, 0xa4, 0x70, 0xf5, 0x8e, 0xcc, 0x37, 0x2c, 0x63, 0xb9, 0x3f, 0x5b, 0xb0, 0x75, - 0x8d, 0x56, 0x88, 0x62, 0xcc, 0xa8, 0x40, 0x7b, 0x0b, 0x6e, 0x27, 0x44, 0x0c, 0x72, 0x81, 0xb1, - 0xa6, 0x58, 0x0b, 0xeb, 0x09, 0x11, 0x8f, 0x05, 0xc6, 0xca, 0x34, 0xc9, 0x06, 0xc8, 0x39, 0xe3, - 0x9a, 0x50, 0x23, 0xac, 0x4f, 0xb2, 0x63, 0x25, 0xda, 0x3d, 0x68, 0x72, 0x94, 0x39, 0xa7, 0x03, - 0x5d, 0xdb, 0x9a, 0xa2, 0x1b, 0x82, 0x51, 0x1d, 0xa9, 0x5a, 0x6c, 0xa8, 0x9d, 0x12, 0x71, 0xda, - 0xa9, 0x69, 0x3f, 0x7d, 0x76, 0x7f, 0xb1, 0xc0, 0x0e, 0x44, 0xf2, 0x88, 0x4a, 0xe4, 0x94, 0x8c, - 0x8e, 0x9f, 0x04, 0x87, 0x64, 0x34, 0xb2, 0xef, 0xc2, 0xba, 0x40, 0x1a, 0x23, 0xd7, 0xf9, 0x1b, - 0x61, 0x21, 0xd9, 0xdf, 0xc0, 0xad, 0x09, 0x19, 0xe5, 0x68, 0x72, 0x1f, 0x7c, 0xfc, 0xea, 0xac, - 0x77, 0xef, 0x52, 0x33, 0x8a, 0xe9, 0x98, 0xcf, 0xae, 0x88, 0x7f, 0xf2, 0xe5, 0x74, 0x8c, 0xc2, - 0x7b, 0x44, 0x65, 0x68, 0x1c, 0xed, 0x36, 0xac, 0x4a, 0xa6, 0xc9, 0x35, 0xc2, 0x55, 0xc9, 0x14, - 0x29, 0x4d, 0xb7, 0xa6, 0xe9, 0xea, 0xb3, 0xfb, 0x0e, 0x38, 0xd7, 0x39, 0x95, 0xdd, 0x71, 0x7f, - 0xb7, 0x66, 0xcd, 0x47, 0x38, 0xc2, 0x84, 0x48, 0x5c, 0x48, 0xdd, 0x81, 0xdb, 0x11, 0x8b, 0xf1, - 0xa1, 0xea, 0x80, 0x1e, 0x65, 0x58, 0xc9, 0xcb, 0x90, 0xb2, 0x5d, 0x68, 0x3d, 0xe5, 0x2c, 0x3b, - 0x64, 0x54, 0x72, 0x12, 0xc9, 0xce, 0x2d, 0x8d, 0xbe, 0xa2, 0x73, 0x3f, 0x00, 0x77, 0x3e, 0xb3, - 0xaa, 0x80, 0x3f, 0x2d, 0xa8, 0x07, 0x22, 0xf9, 0x01, 0x69, 0x6c, 0xbf, 0x67, 0xa2, 0x0e, 0x48, - 0x1c, 0x73, 0x14, 0xa2, 0xe0, 0xdc, 0x54, 0xba, 0x7d, 0xa3, 0xb2, 0xdf, 0x05, 0x90, 0xac, 0x02, - 0x98, 0xa1, 0x37, 0x24, 0x2b, 0xcd, 0x11, 0xac, 0x93, 0x8c, 0xe5, 0x54, 0x76, 0xd6, 0xb6, 0xd7, - 0xfa, 0xcd, 0xbd, 0x2d, 0xcf, 0xb4, 0xdf, 0x53, 0x77, 0xc4, 0x2b, 0xee, 0x88, 0x77, 0xc8, 0x52, - 0x7a, 0xf0, 0xd9, 0x8b, 0xb3, 0xde, 0xca, 0x1f, 0xff, 0xf4, 0xfa, 0x4b, 0x8c, 0x4c, 0x39, 0x88, - 0xb0, 0x08, 0xed, 0xde, 0x81, 0x8d, 0x82, 0x71, 0x55, 0xc5, 0x6f, 0x66, 0x73, 0x42, 0x4c, 0x52, - 0x21, 0x91, 0x7f, 0xcf, 0x52, 0x55, 0xf6, 0xdc, 0xf6, 0x3f, 0x84, 0xd6, 0xd8, 0x40, 0x06, 0x2a, - 0x81, 0xae, 0xa3, 0xbd, 0xb7, 0xe3, 0xcd, 0x7b, 0x1b, 0xbc, 0x22, 0xe0, 0xc9, 0x74, 0x8c, 0x61, - 0x73, 0xfc, 0x5a, 0x50, 0x7b, 0x8e, 0x3c, 0xaa, 0x1a, 0x62, 0xa6, 0x06, 0xc8, 0xa3, 0xa2, 0x23, - 0xee, 0xb1, 0xde, 0x8f, 0x19, 0x62, 0xd5, 0xe5, 0xfa, 0x10, 0x36, 0x4a, 0x22, 0x57, 0x9b, 0xde, - 0x2e, 0xd4, 0x65, 0x98, 0xef, 0xe0, 0xed, 0x40, 0x24, 0xfb, 0x42, 0xb0, 0x28, 0x55, 0x23, 0x2c, - 0x86, 0x5c, 0xf6, 0x7d, 0x5e, 0xa1, 0x1d, 0xa8, 0x5f, 0x9d, 0x55, 0x29, 0xba, 0x3b, 0xf0, 0xfe, - 0x82, 0x80, 0x55, 0x63, 0x03, 0x68, 0x5d, 0x86, 0xcd, 0x4d, 0xb4, 0x03, 0xed, 0x28, 0x17, 0x92, - 0x65, 0x83, 0x0c, 0x85, 0x20, 0x49, 0x71, 0x29, 0xc3, 0xb7, 0x8c, 0x36, 0x30, 0x4a, 0xf7, 0x2e, - 0x6c, 0x5e, 0x0e, 0x57, 0xa6, 0xd9, 0xfb, 0xab, 0x06, 0x6b, 0x81, 0x48, 0x6c, 0x0e, 0xed, 0x99, - 0xd7, 0xf1, 0x93, 0xf9, 0x43, 0xb9, 0xf6, 0x66, 0x39, 0x0f, 0x6e, 0x00, 0xae, 0x66, 0x70, 0x02, - 0x35, 0xb3, 0xfd, 0x0b, 0x9d, 0x15, 0xc4, 0xf9, 0xe8, 0x7f, 0x21, 0x55, 0xd4, 0x1c, 0x36, 0x66, - 0xb7, 0xf1, 0xd3, 0x85, 0xde, 0x33, 0x68, 0xe7, 0xf3, 0x9b, 0xa0, 0xab, 0xb4, 0xcf, 0x2d, 0xe8, - 0xcc, 0xdd, 0x92, 0x2f, 0x16, 0x86, 0x9c, 0xe7, 0xe6, 0x7c, 0xfd, 0x46, 0x6e, 0x15, 0xa5, 0x08, - 0x1a, 0xaf, 0xf7, 0xe7, 0xde, 0x72, 0xb1, 0x1c, 0x6f, 0x39, 0x5c, 0x99, 0xe4, 0xe0, 0xdb, 0x17, - 0xe7, 0x5d, 0xeb, 0xe5, 0x79, 0xd7, 0xfa, 0xf7, 0xbc, 0x6b, 0x3d, 0xbf, 0xe8, 0xae, 0xbc, 0xbc, - 0xe8, 0xae, 0xfc, 0x7d, 0xd1, 0x5d, 0xf9, 0x71, 0x77, 0xd9, 0xff, 0xa3, 0x7e, 0x6a, 0x86, 0xeb, - 0xda, 0xfe, 0xe0, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0a, 0x08, 0xef, 0xf5, 0x36, 0x08, 0x00, - 0x00, + // 878 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x55, 0x4d, 0x6f, 0xdb, 0x46, + 0x13, 0x36, 0x6d, 0xd9, 0x8a, 0x46, 0x7a, 0x65, 0x98, 0x30, 0x02, 0x9a, 0x6f, 0x23, 0xb9, 0x6c, + 0x9d, 0xaa, 0x1f, 0x26, 0x6b, 0xa7, 0x45, 0x0f, 0x45, 0x81, 0xfa, 0x0b, 0x4d, 0x80, 0x12, 0x2d, + 0x58, 0x27, 0x87, 0x5e, 0x84, 0x15, 0x39, 0xa1, 0x89, 0x8a, 0x5c, 0x61, 0x77, 0x29, 0xc4, 0xff, + 0x22, 0x28, 0x0a, 0xb4, 0xbf, 0xa1, 0xa7, 0x5e, 0x7b, 0xe9, 0x39, 0xc7, 0x1c, 0x8b, 0x1c, 0xdc, + 0xc2, 0xfe, 0x23, 0xc5, 0xee, 0x92, 0x8c, 0x2d, 0x83, 0xaa, 0xd2, 0x93, 0x76, 0x67, 0x9e, 0x99, + 0x79, 0x9e, 0x99, 0x59, 0x0a, 0x3a, 0x38, 0x4d, 0x3d, 0xf1, 0xcc, 0x9d, 0x30, 0x2a, 0xa8, 0x69, + 0x71, 0x4c, 0xd4, 0x29, 0xa4, 0x63, 0x97, 0x63, 0x12, 0x9e, 0x91, 0x24, 0x73, 0x71, 0x9a, 0xda, + 0x5b, 0x31, 0xa5, 0xf1, 0x18, 0x3d, 0xe5, 0x1d, 0xe5, 0x4f, 0x3d, 0x92, 0x9d, 0xeb, 0x20, 0x7b, + 0x33, 0xa6, 0x31, 0x55, 0x47, 0x4f, 0x9e, 0x0a, 0x6b, 0x2f, 0xa4, 0x3c, 0xa5, 0xdc, 0x1b, 0x11, + 0x8e, 0xde, 0x74, 0x6f, 0x84, 0x82, 0xec, 0x79, 0x21, 0x4d, 0xb2, 0xc2, 0xbf, 0x2e, 0x0b, 0x63, + 0x96, 0xa7, 0xbc, 0x30, 0x6c, 0x48, 0x03, 0xc3, 0x10, 0x93, 0x89, 0xd0, 0x26, 0xe7, 0x27, 0x03, + 0x36, 0x7c, 0x1e, 0x9f, 0x3c, 0xf1, 0x4f, 0x19, 0xc9, 0x38, 0x09, 0x45, 0x42, 0x33, 0x73, 0x00, + 0x8d, 0x88, 0x08, 0x62, 0x19, 0xdb, 0xc6, 0xa0, 0xbd, 0xbf, 0xe9, 0x6a, 0x66, 0x6e, 0xc9, 0xcc, + 0x3d, 0xc8, 0xce, 0x03, 0x85, 0x30, 0x1f, 0x43, 0x33, 0x42, 0x96, 0x4c, 0x31, 0xb2, 0x96, 0xb7, + 0x8d, 0x41, 0xe7, 0xf0, 0xf3, 0x57, 0x17, 0xfd, 0xcf, 0xe2, 0x44, 0x9c, 0xe5, 0x23, 0x37, 0xa4, + 0xa9, 0xc7, 0x31, 0xd9, 0x2d, 0xf5, 0xaa, 0x8b, 0x12, 0xec, 0x3d, 0xf3, 0x24, 0x97, 0x22, 0xd4, + 0x3d, 0xd6, 0xbf, 0x41, 0x99, 0xcb, 0xf9, 0xdd, 0x80, 0xad, 0x5b, 0xb4, 0x02, 0xe4, 0x13, 0x9a, + 0x71, 0x34, 0xb7, 0xe0, 0x4e, 0x4c, 0xf8, 0x30, 0xe7, 0x18, 0x29, 0x8a, 0x8d, 0xa0, 0x19, 0x13, + 0xfe, 0x98, 0x63, 0x24, 0x5d, 0xd3, 0x74, 0x88, 0x8c, 0x51, 0xa6, 0x08, 0xb5, 0x82, 0xe6, 0x34, + 0x3d, 0x91, 0x57, 0xb3, 0x0f, 0x6d, 0x86, 0x22, 0x67, 0xd9, 0x50, 0x69, 0x5b, 0x91, 0x74, 0x03, + 0xd0, 0xa6, 0x63, 0xa9, 0xc5, 0x84, 0xc6, 0x19, 0xe1, 0x67, 0x56, 0x43, 0xc5, 0xa9, 0xb3, 0xb9, + 0x07, 0x8d, 0x31, 0x8d, 0xb9, 0xb5, 0xba, 0xbd, 0x32, 0x68, 0xef, 0xdf, 0x73, 0xeb, 0xa6, 0xe7, + 0x7e, 0x4d, 0xe3, 0x40, 0x41, 0x9d, 0x1f, 0x0d, 0x30, 0x7d, 0x1e, 0x3f, 0xca, 0x04, 0xb2, 0x8c, + 0x8c, 0x4f, 0x9e, 0xf8, 0x47, 0x64, 0x3c, 0x36, 0xef, 0xc2, 0x1a, 0xc7, 0x2c, 0x42, 0xa6, 0x28, + 0xb7, 0x82, 0xe2, 0x66, 0x7e, 0x09, 0xab, 0x53, 0x32, 0xce, 0x51, 0xd3, 0x3d, 0xfc, 0xe0, 0xd5, + 0x45, 0xff, 0xfe, 0xb5, 0xfe, 0x15, 0x33, 0xd6, 0x3f, 0xbb, 0x3c, 0xfa, 0xc1, 0x13, 0xe7, 0x13, + 0xe4, 0xee, 0xa3, 0x4c, 0x04, 0x3a, 0xd0, 0xec, 0xc2, 0xb2, 0xa0, 0x4a, 0x4f, 0x2b, 0x58, 0x16, + 0x54, 0xea, 0x50, 0x0a, 0x1b, 0x4a, 0xa1, 0x3a, 0x3b, 0x6f, 0x81, 0x7d, 0x9b, 0x53, 0xd9, 0x50, + 0xe7, 0x17, 0x63, 0xd6, 0x7d, 0x8c, 0x63, 0x8c, 0x89, 0xc0, 0xb9, 0xd4, 0x6d, 0xb8, 0x13, 0xd2, + 0x08, 0x1f, 0xca, 0xa6, 0xa9, 0xe9, 0x07, 0xd5, 0x7d, 0x11, 0x52, 0xa6, 0x03, 0x9d, 0xa7, 0x8c, + 0xa6, 0x47, 0x34, 0x13, 0x8c, 0x84, 0xc2, 0x5a, 0x55, 0xe8, 0x1b, 0x36, 0xe7, 0x5d, 0x70, 0xea, + 0x99, 0x55, 0x02, 0x7e, 0x33, 0xa0, 0xe9, 0xf3, 0xf8, 0x3b, 0xcc, 0x22, 0xf3, 0x6d, 0x9d, 0x75, + 0x48, 0xa2, 0x88, 0x21, 0xe7, 0x05, 0xe7, 0xb6, 0xb4, 0x1d, 0x68, 0x93, 0x79, 0x0f, 0x40, 0xd0, + 0x0a, 0xa0, 0xf7, 0xa4, 0x25, 0x68, 0xe9, 0x0e, 0x61, 0x8d, 0xa4, 0x34, 0xcf, 0x84, 0xb5, 0xa2, + 0xc6, 0xbe, 0xe5, 0xea, 0xf6, 0xbb, 0xf2, 0xa5, 0xb9, 0xc5, 0x4b, 0x73, 0x8f, 0x68, 0x92, 0x1d, + 0x7e, 0xfc, 0xe2, 0xa2, 0xbf, 0xf4, 0xeb, 0x5f, 0xfd, 0xc1, 0x02, 0x23, 0x93, 0x01, 0x3c, 0x28, + 0x52, 0x3b, 0x1b, 0xb0, 0x5e, 0x30, 0xae, 0x54, 0xfc, 0xac, 0x37, 0x27, 0xc0, 0x38, 0xe1, 0x02, + 0xd9, 0xb7, 0x34, 0x91, 0xb2, 0x6b, 0xdb, 0xff, 0x10, 0x3a, 0x13, 0x0d, 0x19, 0xca, 0x02, 0x4a, + 0x47, 0x77, 0x7f, 0xa7, 0x7e, 0x47, 0x8b, 0x84, 0xa7, 0xe7, 0x13, 0x0c, 0xda, 0x93, 0xd7, 0x17, + 0xf9, 0x34, 0x90, 0x85, 0x55, 0x43, 0xf4, 0xd4, 0x00, 0x59, 0x58, 0x74, 0xc4, 0x39, 0x51, 0xfb, + 0x31, 0x43, 0xac, 0x7a, 0x8f, 0xef, 0xc1, 0x7a, 0x49, 0xe4, 0x66, 0xd3, 0xbb, 0x85, 0xb9, 0x4c, + 0xf3, 0x0d, 0xfc, 0xdf, 0xe7, 0xf1, 0x01, 0xe7, 0x34, 0x4c, 0xe4, 0x08, 0x8b, 0x21, 0x97, 0x7d, + 0xaf, 0x13, 0x6a, 0x41, 0xf3, 0xe6, 0xac, 0xca, 0xab, 0xb3, 0x03, 0xef, 0xcc, 0x49, 0x58, 0x35, + 0xd6, 0x87, 0xce, 0x75, 0x58, 0x6d, 0xa1, 0x1d, 0xe8, 0x86, 0x39, 0x17, 0x34, 0x1d, 0xa6, 0xc8, + 0x39, 0x89, 0x8b, 0x47, 0x19, 0xfc, 0x4f, 0x5b, 0x7d, 0x6d, 0x74, 0xee, 0xc2, 0xe6, 0xf5, 0x74, + 0x65, 0x99, 0xfd, 0x3f, 0x1a, 0xb0, 0xe2, 0xf3, 0xd8, 0x64, 0xd0, 0x9d, 0xf9, 0xa0, 0x7e, 0x58, + 0x3f, 0x94, 0x5b, 0x9f, 0x39, 0xfb, 0xc1, 0x1b, 0x80, 0xab, 0x19, 0x9c, 0x42, 0x43, 0x6f, 0xff, + 0xdc, 0x60, 0x09, 0xb1, 0xdf, 0xff, 0x57, 0x48, 0x95, 0x35, 0x87, 0xf5, 0xd9, 0x6d, 0xfc, 0x68, + 0x6e, 0xf4, 0x0c, 0xda, 0xfe, 0xe4, 0x4d, 0xd0, 0x55, 0xd9, 0xe7, 0x06, 0x58, 0xb5, 0x5b, 0xf2, + 0xe9, 0xdc, 0x94, 0x75, 0x61, 0xf6, 0x17, 0xff, 0x29, 0xac, 0xa2, 0x14, 0x42, 0xeb, 0xf5, 0xfe, + 0xdc, 0x5f, 0x2c, 0x97, 0xed, 0x2e, 0x86, 0x2b, 0x8b, 0x1c, 0x7e, 0xf5, 0xe2, 0xb2, 0x67, 0xbc, + 0xbc, 0xec, 0x19, 0x7f, 0x5f, 0xf6, 0x8c, 0xe7, 0x57, 0xbd, 0xa5, 0x97, 0x57, 0xbd, 0xa5, 0x3f, + 0xaf, 0x7a, 0x4b, 0xdf, 0xef, 0x2e, 0xfa, 0x97, 0xaa, 0x3e, 0x35, 0xa3, 0x35, 0xe5, 0x7f, 0xf0, + 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x66, 0x4a, 0xcb, 0x49, 0x7c, 0x08, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1098,6 +1107,20 @@ func (m *MsgEVMTransactionResponse) MarshalToSizedBuffer(dAtA []byte) (int, erro _ = i var l int _ = l + if len(m.Logs) > 0 { + for iNdEx := len(m.Logs) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Logs[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + } if len(m.Hash) > 0 { i -= len(m.Hash) copy(dAtA[i:], m.Hash) @@ -1602,6 +1625,12 @@ func (m *MsgEVMTransactionResponse) Size() (n int) { if l > 0 { n += 1 + l + sovTx(uint64(l)) } + if len(m.Logs) > 0 { + for _, e := range m.Logs { + l = e.Size() + n += 1 + l + sovTx(uint64(l)) + } + } return n } @@ -2067,6 +2096,40 @@ func (m *MsgEVMTransactionResponse) Unmarshal(dAtA []byte) error { } m.Hash = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Logs", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Logs = append(m.Logs, &Log{}) + if err := m.Logs[len(m.Logs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) From 942e73dec66d19c1b89e87615c802f2427620530 Mon Sep 17 00:00:00 2001 From: Yiming Zang <50607998+yzang2019@users.noreply.github.com> Date: Fri, 30 Aug 2024 14:48:54 -0700 Subject: [PATCH 33/38] Add antehandler for EVM to check gas exceed limit or not (#1821) * Add antehandler for EVM to check gas exceed limit or not * Separate the check for EVM message * Fix lint * Fix some test * Fix gas * Enable log * Add log * Add log * Add stdout * Fix docker * Fix associate tx causing chain halt issue * fix go mod * Fix lint * Removel og * Fix gas * Fix gas * Fix go mod * Fix unit test * fix docker --- app/app.go | 92 ++++++------ contracts/test/AssociateTest.js | 8 +- docker/docker-compose.yml | 2 - docker/localnode/Dockerfile | 3 +- go.mod | 2 +- go.sum | 4 +- integration_test/dapp_tests/steak/utils.js | 154 +++++++++++++++++++++ x/evm/ante/basic.go | 9 ++ x/evm/integration_test.go | 10 +- 9 files changed, 227 insertions(+), 57 deletions(-) create mode 100644 integration_test/dapp_tests/steak/utils.js diff --git a/app/app.go b/app/app.go index be0a2801d..cd13480a2 100644 --- a/app/app.go +++ b/app/app.go @@ -15,20 +15,6 @@ import ( "sync" "time" - "github.com/cosmos/cosmos-sdk/server" - "github.com/gorilla/mux" - "github.com/rakyll/statik/fs" - "github.com/sei-protocol/sei-db/ss" - - "github.com/ethereum/go-ethereum/ethclient" - ethrpc "github.com/ethereum/go-ethereum/rpc" - "github.com/sei-protocol/sei-chain/app/antedecorators" - "github.com/sei-protocol/sei-chain/evmrpc" - "github.com/sei-protocol/sei-chain/precompiles" - "go.opentelemetry.io/otel/trace" - - storetypes "github.com/cosmos/cosmos-sdk/store/types" - wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" @@ -36,17 +22,18 @@ import ( "github.com/cosmos/cosmos-sdk/client/rpc" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/server" "github.com/cosmos/cosmos-sdk/server/api" "github.com/cosmos/cosmos-sdk/server/config" servertypes "github.com/cosmos/cosmos-sdk/server/types" "github.com/cosmos/cosmos-sdk/simapp" + storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkacltypes "github.com/cosmos/cosmos-sdk/types/accesscontrol" - "github.com/cosmos/cosmos-sdk/types/module" - "github.com/cosmos/cosmos-sdk/version" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" genesistypes "github.com/cosmos/cosmos-sdk/types/genesis" + "github.com/cosmos/cosmos-sdk/types/module" + "github.com/cosmos/cosmos-sdk/version" aclmodule "github.com/cosmos/cosmos-sdk/x/accesscontrol" aclclient "github.com/cosmos/cosmos-sdk/x/accesscontrol/client" aclconstants "github.com/cosmos/cosmos-sdk/x/accesscontrol/constants" @@ -114,13 +101,24 @@ import ( ibcporttypes "github.com/cosmos/ibc-go/v3/modules/core/05-port/types" ibchost "github.com/cosmos/ibc-go/v3/modules/core/24-host" ibckeeper "github.com/cosmos/ibc-go/v3/modules/core/keeper" + "github.com/ethereum/go-ethereum/ethclient" + ethrpc "github.com/ethereum/go-ethereum/rpc" + "github.com/gorilla/mux" + "github.com/rakyll/statik/fs" "github.com/sei-protocol/sei-chain/aclmapping" aclutils "github.com/sei-protocol/sei-chain/aclmapping/utils" + "github.com/sei-protocol/sei-chain/app/antedecorators" appparams "github.com/sei-protocol/sei-chain/app/params" "github.com/sei-protocol/sei-chain/app/upgrades" v0upgrade "github.com/sei-protocol/sei-chain/app/upgrades/v0" + "github.com/sei-protocol/sei-chain/evmrpc" + "github.com/sei-protocol/sei-chain/precompiles" "github.com/sei-protocol/sei-chain/utils" + "github.com/sei-protocol/sei-chain/utils/metrics" "github.com/sei-protocol/sei-chain/wasmbinding" + epochmodule "github.com/sei-protocol/sei-chain/x/epoch" + epochmodulekeeper "github.com/sei-protocol/sei-chain/x/epoch/keeper" + epochmoduletypes "github.com/sei-protocol/sei-chain/x/epoch/types" "github.com/sei-protocol/sei-chain/x/evm" evmante "github.com/sei-protocol/sei-chain/x/evm/ante" "github.com/sei-protocol/sei-chain/x/evm/blocktest" @@ -132,6 +130,13 @@ import ( mintclient "github.com/sei-protocol/sei-chain/x/mint/client/cli" mintkeeper "github.com/sei-protocol/sei-chain/x/mint/keeper" minttypes "github.com/sei-protocol/sei-chain/x/mint/types" + oraclemodule "github.com/sei-protocol/sei-chain/x/oracle" + oraclekeeper "github.com/sei-protocol/sei-chain/x/oracle/keeper" + oracletypes "github.com/sei-protocol/sei-chain/x/oracle/types" + tokenfactorymodule "github.com/sei-protocol/sei-chain/x/tokenfactory" + tokenfactorykeeper "github.com/sei-protocol/sei-chain/x/tokenfactory/keeper" + tokenfactorytypes "github.com/sei-protocol/sei-chain/x/tokenfactory/types" + "github.com/sei-protocol/sei-db/ss" seidb "github.com/sei-protocol/sei-db/ss/types" "github.com/spf13/cast" abci "github.com/tendermint/tendermint/abci/types" @@ -140,20 +145,7 @@ import ( tmos "github.com/tendermint/tendermint/libs/os" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" dbm "github.com/tendermint/tm-db" - - "github.com/sei-protocol/sei-chain/utils/metrics" - - oraclemodule "github.com/sei-protocol/sei-chain/x/oracle" - oraclekeeper "github.com/sei-protocol/sei-chain/x/oracle/keeper" - oracletypes "github.com/sei-protocol/sei-chain/x/oracle/types" - - epochmodule "github.com/sei-protocol/sei-chain/x/epoch" - epochmodulekeeper "github.com/sei-protocol/sei-chain/x/epoch/keeper" - epochmoduletypes "github.com/sei-protocol/sei-chain/x/epoch/types" - - tokenfactorymodule "github.com/sei-protocol/sei-chain/x/tokenfactory" - tokenfactorykeeper "github.com/sei-protocol/sei-chain/x/tokenfactory/keeper" - tokenfactorytypes "github.com/sei-protocol/sei-chain/x/tokenfactory/types" + "go.opentelemetry.io/otel/trace" // this line is used by starport scaffolding # stargate/app/moduleImport @@ -163,7 +155,6 @@ import ( // unnamed import of statik for openapi/swagger UI support _ "github.com/sei-protocol/sei-chain/docs/swagger" - ssconfig "github.com/sei-protocol/sei-db/config" ) @@ -1859,17 +1850,13 @@ func RegisterSwaggerAPI(rtr *mux.Router) { func (app *App) checkTotalBlockGasWanted(ctx sdk.Context, txs [][]byte) bool { totalGasWanted := uint64(0) for _, tx := range txs { - decoded, err := app.txDecoder(tx) + decodedTx, err := app.txDecoder(tx) if err != nil { // such tx will not be processed and thus won't consume gas. Skipping continue } - feeTx, ok := decoded.(sdk.FeeTx) - if !ok { - // such tx will not be processed and thus won't consume gas. Skipping - continue - } - isGasless, err := antedecorators.IsTxGasless(decoded, ctx, app.OracleKeeper, &app.EvmKeeper) + // check gasless first (this has to happen before other checks to avoid panics) + isGasless, err := antedecorators.IsTxGasless(decodedTx, ctx, app.OracleKeeper, &app.EvmKeeper) if err != nil { ctx.Logger().Error("error checking if tx is gasless", "error", err) continue @@ -1877,8 +1864,31 @@ func (app *App) checkTotalBlockGasWanted(ctx sdk.Context, txs [][]byte) bool { if isGasless { continue } - // Check for overflow before adding - gasWanted := feeTx.GetGas() + // Check whether it's associate tx + gasWanted := uint64(0) + // Check whether it's an EVM or Cosmos tx + isEVM, err := evmante.IsEVMMessage(decodedTx) + if err != nil { + continue + } + if isEVM { + msg := evmtypes.MustGetEVMTransactionMessage(decodedTx) + if msg.IsAssociateTx() { + continue + } + etx, _ := msg.AsTransaction() + gasWanted = etx.Gas() + } else { + feeTx, ok := decodedTx.(sdk.FeeTx) + if !ok { + // such tx will not be processed and thus won't consume gas. Skipping + continue + } + + // Check for overflow before adding + gasWanted = feeTx.GetGas() + } + if int64(gasWanted) < 0 || int64(totalGasWanted) > math.MaxInt64-int64(gasWanted) { return false } diff --git a/contracts/test/AssociateTest.js b/contracts/test/AssociateTest.js index 40c4af735..dda941987 100644 --- a/contracts/test/AssociateTest.js +++ b/contracts/test/AssociateTest.js @@ -35,10 +35,10 @@ describe("Associate Balances", function () { const afterSei = BigInt(await getSeiBalance(seiAddr)) const afterEvm = await ethers.provider.getBalance(evmAddr) - // console.log(`SEI Balance (before): ${beforeSei}`) - // console.log(`EVM Balance (before): ${beforeEvm}`) - // console.log(`SEI Balance (after): ${afterSei}`) - // console.log(`EVM Balance (after): ${afterEvm}`) + console.log(`SEI Balance (before): ${beforeSei}`) + console.log(`EVM Balance (before): ${beforeEvm}`) + console.log(`SEI Balance (after): ${afterSei}`) + console.log(`EVM Balance (after): ${afterEvm}`) const multiplier = BigInt(1000000000000) expect(afterEvm).to.equal((beforeSei * multiplier) + beforeEvm - (gas * multiplier)) diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index bc3cc123e..7e197935d 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -1,5 +1,3 @@ -version: '3.3' - services: node0: platform: linux/amd64 diff --git a/docker/localnode/Dockerfile b/docker/localnode/Dockerfile index 8b3c978e2..08f0d5838 100644 --- a/docker/localnode/Dockerfile +++ b/docker/localnode/Dockerfile @@ -1,7 +1,6 @@ FROM ubuntu:latest ENV HOME="/root" PATH="/root/go/bin:/sei-protocol/sei-chain/integration_test/upgrade_module/scripts/:$PATH" -RUN apt-get update && \ - apt-get install -y make git build-essential jq python3 curl vim uuid-runtime nodejs +RUN apt-get update && apt-get install -y make build-essential git jq python3 curl vim uuid-runtime RUN curl -L https://go.dev/dl/go1.22.4.linux-amd64.tar.gz | tar xvzf - -C /usr/local/ RUN curl -L https://foundry.paradigm.xyz | bash RUN curl -sL https://deb.nodesource.com/setup_16.x | bash diff --git a/go.mod b/go.mod index 014d9679d..edb3e5ae0 100644 --- a/go.mod +++ b/go.mod @@ -346,7 +346,7 @@ require ( replace ( github.com/CosmWasm/wasmd => github.com/sei-protocol/sei-wasmd v0.2.4-0.20240816184629-eb6d20caf603 github.com/confio/ics23/go => github.com/cosmos/cosmos-sdk/ics23/go v0.8.0 - github.com/cosmos/cosmos-sdk => github.com/sei-protocol/sei-cosmos v0.3.33 + github.com/cosmos/cosmos-sdk => github.com/sei-protocol/sei-cosmos v0.3.34 github.com/cosmos/iavl => github.com/sei-protocol/sei-iavl v0.1.9 github.com/cosmos/ibc-go/v3 => github.com/sei-protocol/sei-ibc-go/v3 v3.3.2 github.com/ethereum/go-ethereum => github.com/sei-protocol/go-ethereum v1.13.5-sei-22 diff --git a/go.sum b/go.sum index 1413d1f77..bfd59e249 100644 --- a/go.sum +++ b/go.sum @@ -1347,8 +1347,8 @@ github.com/sei-protocol/go-ethereum v1.13.5-sei-22 h1:t/m1qXER+DEMrcpqgoYmUxifkA github.com/sei-protocol/go-ethereum v1.13.5-sei-22/go.mod h1:kcRZmuzRn1lVejiFNTz4l4W7imnpq1bDAnuKS/RyhbQ= github.com/sei-protocol/goutils v0.0.2 h1:Bfa7Sv+4CVLNM20QcpvGb81B8C5HkQC/kW1CQpIbXDA= github.com/sei-protocol/goutils v0.0.2/go.mod h1:iYE2DuJfEnM+APPehr2gOUXfuLuPsVxorcDO+Tzq9q8= -github.com/sei-protocol/sei-cosmos v0.3.33 h1:6BmEmNOqotT0OqwLFQiCyRcZTxJfG/x/CNQadljAKok= -github.com/sei-protocol/sei-cosmos v0.3.33/go.mod h1:og/KbejR/zSQ8otapODEDU9zYNhFSUDbq9+tgeYePyU= +github.com/sei-protocol/sei-cosmos v0.3.34 h1:U2TqBEMJC9ztDqSxi7ET+HEEx0CyyAs6D+Y5VOfYTAc= +github.com/sei-protocol/sei-cosmos v0.3.34/go.mod h1:og/KbejR/zSQ8otapODEDU9zYNhFSUDbq9+tgeYePyU= github.com/sei-protocol/sei-db v0.0.43 h1:m9kIWqSBCvKRLPGbAttlqCytIlPxVZbKchAEbVKSHHk= github.com/sei-protocol/sei-db v0.0.43/go.mod h1:F/ZKZA8HJPcUzSZPA8yt6pfwlGriJ4RDR4eHKSGLStI= github.com/sei-protocol/sei-iavl v0.1.9 h1:y4mVYftxLNRs6533zl7N0/Ch+CzRQc04JDfHolIxgBE= diff --git a/integration_test/dapp_tests/steak/utils.js b/integration_test/dapp_tests/steak/utils.js new file mode 100644 index 000000000..78188be73 --- /dev/null +++ b/integration_test/dapp_tests/steak/utils.js @@ -0,0 +1,154 @@ +const { execute } = require("../../../contracts/test/lib"); + +const encodeBase64 = (obj) => { + return Buffer.from(JSON.stringify(obj)).toString("base64"); +}; + +const getValidators = async () => { + const command = `seid q staking validators --output json`; + const output = await execute(command); + const response = JSON.parse(output); + return response.validators.map((v) => v.operator_address); +}; + +const getCodeIdFromContractAddress = async (contractAddress) => { + const command = `seid q wasm contract ${contractAddress} --output json`; + const output = await execute(command); + const response = JSON.parse(output); + return response.contract_info.code_id; +}; + +// Note: Not using the `deployWasm` function because we need to retrieve the +// hub and token contract addresses from the event logs +const instantiateHubContract = async ( + codeId, + adminAddress, + instantiateMsg, + label +) => { + const jsonString = JSON.stringify(instantiateMsg).replace(/"/g, '\\"'); + const command = `seid tx wasm instantiate ${codeId} "${jsonString}" --label ${label} --admin ${adminAddress} --from admin --gas=5000000 --fees=1000000usei -y --broadcast-mode block -o json`; + const output = await execute(command); + const response = JSON.parse(output); + // Get all attributes with _contractAddress + if (!response.logs || response.logs.length === 0) { + throw new Error("logs not returned"); + } + const addresses = []; + for (let event of response.logs[0].events) { + if (event.type === "instantiate") { + for (let attribute of event.attributes) { + if (attribute.key === "_contract_address") { + addresses.push(attribute.value); + } + } + } + } + + // Return hub and token contracts + const contracts = {}; + for (let address of addresses) { + const contractCodeId = await getCodeIdFromContractAddress(address); + if (contractCodeId === `${codeId}`) { + contracts.hubContract = address; + } else { + contracts.tokenContract = address; + } + } + return contracts; +}; + +const bond = async (contractAddress, address, amount) => { + const msg = { + 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 output = await execute(command); + const response = JSON.parse(output); + if (response.code !== 0) { + throw new Error(response.raw_log); + } + return response; +}; + +const unbond = async (hubAddress, tokenAddress, address, amount) => { + const msg = { + send: { + contract: hubAddress, + amount: `${amount}`, + msg: encodeBase64({ + queue_unbond: {}, + }), + }, + }; + const jsonString = JSON.stringify(msg).replace(/"/g, '\\"'); + const command = `seid tx wasm execute ${tokenAddress} "${jsonString}" --from=${address} --gas=500000 --gas-prices=0.1usei --broadcast-mode=block -y --output=json`; + const output = await execute(command); + const response = JSON.parse(output); + if (response.code !== 0) { + throw new Error(response.raw_log); + } + return response; +}; + +const harvest = async (contractAddress, address) => { + const msg = { + harvest: {}, + }; + const jsonString = JSON.stringify(msg).replace(/"/g, '\\"'); + const command = `seid tx wasm execute ${contractAddress} "${jsonString}" --from=${address} --gas=500000 --gas-prices=0.1usei --broadcast-mode=block -y --output=json`; + const output = await execute(command); + const response = JSON.parse(output); + if (response.code !== 0) { + throw new Error(response.raw_log); + } + return response; +}; + +const queryTokenBalance = async (contractAddress, address) => { + const msg = { + balance: { + address, + }, + }; + const jsonString = JSON.stringify(msg).replace(/"/g, '\\"'); + const command = `seid q wasm contract-state smart ${contractAddress} "${jsonString}" --output=json`; + const output = await execute(command); + const response = JSON.parse(output); + return response.data.balance; +}; + +const addAccount = async (accountName) => { + const command = `seid keys add ${accountName}-${Date.now()} --output=json`; + const output = await execute(command); + return JSON.parse(output); +}; + +const transferTokens = async (tokenAddress, sender, destination, amount) => { + const msg = { + transfer: { + recipient: destination, + amount: `${amount}`, + }, + }; + const jsonString = JSON.stringify(msg).replace(/"/g, '\\"'); + const command = `seid tx wasm execute ${tokenAddress} "${jsonString}" --from=${sender} --gas=200000 --gas-prices=0.1usei --broadcast-mode=block -y --output=json`; + const output = await execute(command); + const response = JSON.parse(output); + if (response.code !== 0) { + throw new Error(response.raw_log); + } + return response; +}; + +module.exports = { + getValidators, + instantiateHubContract, + bond, + unbond, + harvest, + queryTokenBalance, + addAccount, + transferTokens, +}; diff --git a/x/evm/ante/basic.go b/x/evm/ante/basic.go index 18954258d..f4e3497fe 100644 --- a/x/evm/ante/basic.go +++ b/x/evm/ante/basic.go @@ -59,6 +59,15 @@ func (gl BasicDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, n return ctx, sdkerrors.ErrUnsupportedTxType } + // Check if gas exceed the limit + if cp := ctx.ConsensusParams(); cp != nil && cp.Block != nil { + // If there exists a maximum block gas limit, we must ensure that the tx + // does not exceed it. + if cp.Block.MaxGas > 0 && etx.Gas() > uint64(cp.Block.MaxGas) { + return ctx, sdkerrors.Wrapf(sdkerrors.ErrOutOfGas, "tx gas limit %d exceeds block max gas %d", etx.Gas(), cp.Block.MaxGas) + } + } + //TODO: support blobs (leaving this commented out) // Ensure blob transactions have valid commitments //if etx.Type() == ethtypes.BlobTxType { diff --git a/x/evm/integration_test.go b/x/evm/integration_test.go index d27fe98b0..6c312f5a8 100644 --- a/x/evm/integration_test.go +++ b/x/evm/integration_test.go @@ -83,7 +83,7 @@ func TestERC2981PointerToCW2981(t *testing.T) { txData := ethtypes.LegacyTx{ Nonce: 0, GasPrice: big.NewInt(100000000000), - Gas: 5000000, + Gas: 6000000, To: &to, Data: data, } @@ -116,7 +116,7 @@ func TestERC2981PointerToCW2981(t *testing.T) { txData = ethtypes.LegacyTx{ Nonce: 1, GasPrice: big.NewInt(100000000000), - Gas: 1000000, + Gas: 300000, To: &pointerAddr, Data: data, } @@ -166,7 +166,7 @@ func TestCW2981PointerToERC2981(t *testing.T) { txData := ethtypes.LegacyTx{ Nonce: 0, GasPrice: big.NewInt(100000000000), - Gas: 5000000, + Gas: 6000000, To: nil, Data: append(bz, data...), } @@ -201,7 +201,7 @@ func TestCW2981PointerToERC2981(t *testing.T) { txData = ethtypes.LegacyTx{ Nonce: 1, GasPrice: big.NewInt(100000000000), - Gas: 1000000, + Gas: 300000, To: &to, Data: data, } @@ -265,7 +265,7 @@ func TestNonceIncrementsForInsufficientFunds(t *testing.T) { txData := ethtypes.LegacyTx{ Nonce: 0, GasPrice: big.NewInt(100000000000), - Gas: 5000000, + Gas: 6000000, To: nil, Data: []byte{}, } From c2a0d85449bd744db9e7c0e9d7723a9dc3e92f59 Mon Sep 17 00:00:00 2001 From: yirenz Date: Fri, 30 Aug 2024 19:16:14 -0400 Subject: [PATCH 34/38] Add migration for new params (#1840) * Add migration function for DeliverTxHookWasmGasLimitParam --------- Co-authored-by: blindchaser --- .../migrate_deliver_tx_gas_limit.go | 20 ++++++++++ .../migrate_deliver_tx_gas_limit_test.go | 37 +++++++++++++++++++ x/evm/module.go | 6 ++- x/evm/module_test.go | 2 +- 4 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 x/evm/migrations/migrate_deliver_tx_gas_limit.go create mode 100644 x/evm/migrations/migrate_deliver_tx_gas_limit_test.go diff --git a/x/evm/migrations/migrate_deliver_tx_gas_limit.go b/x/evm/migrations/migrate_deliver_tx_gas_limit.go new file mode 100644 index 000000000..d8802005b --- /dev/null +++ b/x/evm/migrations/migrate_deliver_tx_gas_limit.go @@ -0,0 +1,20 @@ +package migrations + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/sei-protocol/sei-chain/x/evm/keeper" + "github.com/sei-protocol/sei-chain/x/evm/types" +) + +func MigrateDeliverTxHookWasmGasLimitParam(ctx sdk.Context, k *keeper.Keeper) error { + // Fetch the current parameters + keeperParams := k.GetParams(ctx) + + // Update DeliverTxHookWasmGasLimit to the default value + keeperParams.DeliverTxHookWasmGasLimit = types.DefaultParams().DeliverTxHookWasmGasLimit + + // Set the updated parameters back in the keeper + k.SetParams(ctx, keeperParams) + + return nil +} diff --git a/x/evm/migrations/migrate_deliver_tx_gas_limit_test.go b/x/evm/migrations/migrate_deliver_tx_gas_limit_test.go new file mode 100644 index 000000000..5d88fb200 --- /dev/null +++ b/x/evm/migrations/migrate_deliver_tx_gas_limit_test.go @@ -0,0 +1,37 @@ +package migrations_test + +import ( + "testing" + + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/migrations" + "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/stretchr/testify/require" + tmtypes "github.com/tendermint/tendermint/proto/tendermint/types" +) + +func TestMigrateDeliverTxHookWasmGasLimitParam(t *testing.T) { + k := testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.NewContext(false, tmtypes.Header{}) + + currParams := k.GetParams(ctx) + + // Keep a copy of the other parameters to compare later + priorityNormalizer := currParams.PriorityNormalizer + baseFeePerGas := currParams.BaseFeePerGas + minimumFeePerGas := currParams.MinimumFeePerGas + + // Perform the migration + err := migrations.MigrateDeliverTxHookWasmGasLimitParam(ctx, &k) + require.NoError(t, err) + + keeperParams := k.GetParams(ctx) + + // Ensure that the DeliverTxHookWasmGasLimit was migrated to the default value + require.Equal(t, keeperParams.GetDeliverTxHookWasmGasLimit(), types.DefaultParams().DeliverTxHookWasmGasLimit) + + // Verify that the other parameters were not changed by the migration + require.True(t, keeperParams.PriorityNormalizer.Equal(priorityNormalizer)) + require.True(t, keeperParams.BaseFeePerGas.Equal(baseFeePerGas)) + require.True(t, keeperParams.MinimumFeePerGas.Equal(minimumFeePerGas)) +} diff --git a/x/evm/module.go b/x/evm/module.go index b5db176a4..fbbd882a3 100644 --- a/x/evm/module.go +++ b/x/evm/module.go @@ -208,6 +208,10 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { _ = cfg.RegisterMigration(types.ModuleName, 10, func(ctx sdk.Context) error { return migrations.MigrateCastAddressBalances(ctx, am.keeper) }) + + _ = cfg.RegisterMigration(types.ModuleName, 11, func(ctx sdk.Context) error { + return migrations.MigrateDeliverTxHookWasmGasLimitParam(ctx, am.keeper) + }) } // RegisterInvariants registers the capability module's invariants. @@ -245,7 +249,7 @@ func (am AppModule) ExportGenesisStream(ctx sdk.Context, cdc codec.JSONCodec) <- } // ConsensusVersion implements ConsensusVersion. -func (AppModule) ConsensusVersion() uint64 { return 11 } +func (AppModule) ConsensusVersion() uint64 { return 12 } // BeginBlock executes all ABCI BeginBlock logic respective to the capability module. func (am AppModule) BeginBlock(ctx sdk.Context, _ abci.RequestBeginBlock) { diff --git a/x/evm/module_test.go b/x/evm/module_test.go index 181cd0377..d9ad4a0dd 100644 --- a/x/evm/module_test.go +++ b/x/evm/module_test.go @@ -59,7 +59,7 @@ func TestModuleExportGenesis(t *testing.T) { func TestConsensusVersion(t *testing.T) { k, _ := testkeeper.MockEVMKeeper() module := evm.NewAppModule(nil, k) - assert.Equal(t, uint64(11), module.ConsensusVersion()) + assert.Equal(t, uint64(12), module.ConsensusVersion()) } func TestABCI(t *testing.T) { From 7e7951042023e6eff69f659dbbfdd61f2e4d970d Mon Sep 17 00:00:00 2001 From: yirenz Date: Tue, 3 Sep 2024 08:41:16 -0400 Subject: [PATCH 35/38] fix: use GetParamsIfExists() to fetch old params (#1842) Co-authored-by: blindchaser --- x/evm/keeper/params.go | 6 +++++ x/evm/keeper/params_test.go | 26 +++++++++++++++++++ .../migrate_deliver_tx_gas_limit.go | 6 ++--- 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/x/evm/keeper/params.go b/x/evm/keeper/params.go index 04d8be61c..fbd885e11 100644 --- a/x/evm/keeper/params.go +++ b/x/evm/keeper/params.go @@ -21,6 +21,12 @@ func (k *Keeper) GetParams(ctx sdk.Context) types.Params { return params } +func (k *Keeper) GetParamsIfExists(ctx sdk.Context) types.Params { + params := types.Params{} + k.Paramstore.GetParamSetIfExists(ctx, ¶ms) + return params +} + func (k *Keeper) GetBaseDenom(ctx sdk.Context) string { return BaseDenom } diff --git a/x/evm/keeper/params_test.go b/x/evm/keeper/params_test.go index e508d99b0..2f157ad68 100644 --- a/x/evm/keeper/params_test.go +++ b/x/evm/keeper/params_test.go @@ -4,6 +4,7 @@ import ( "testing" "time" + sdk "github.com/cosmos/cosmos-sdk/types" testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" "github.com/sei-protocol/sei-chain/x/evm/types" "github.com/stretchr/testify/require" @@ -20,3 +21,28 @@ func TestParams(t *testing.T) { require.Nil(t, k.GetParams(ctx).Validate()) } + +func TestGetParamsIfExists(t *testing.T) { + k := &testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) + + // Define the expected parameters + expectedParams := types.Params{ + PriorityNormalizer: sdk.NewDec(1), + BaseFeePerGas: sdk.NewDec(1), + } + + // Set only a subset of the parameters in the keeper + k.Paramstore.Set(ctx, types.KeyPriorityNormalizer, expectedParams.PriorityNormalizer) + k.Paramstore.Set(ctx, types.KeyBaseFeePerGas, expectedParams.BaseFeePerGas) + + // Retrieve the parameters using GetParamsIfExists + params := k.GetParamsIfExists(ctx) + + // Assert that the retrieved parameters match the expected parameters + require.Equal(t, expectedParams.PriorityNormalizer, params.PriorityNormalizer) + require.Equal(t, expectedParams.BaseFeePerGas, params.BaseFeePerGas) + + // Assert that the missing parameter has its default value + require.Equal(t, types.DefaultParams().DeliverTxHookWasmGasLimit, params.DeliverTxHookWasmGasLimit) +} diff --git a/x/evm/migrations/migrate_deliver_tx_gas_limit.go b/x/evm/migrations/migrate_deliver_tx_gas_limit.go index d8802005b..3c082f973 100644 --- a/x/evm/migrations/migrate_deliver_tx_gas_limit.go +++ b/x/evm/migrations/migrate_deliver_tx_gas_limit.go @@ -7,10 +7,10 @@ import ( ) func MigrateDeliverTxHookWasmGasLimitParam(ctx sdk.Context, k *keeper.Keeper) error { - // Fetch the current parameters - keeperParams := k.GetParams(ctx) + // Fetch the v11 parameters + keeperParams := k.GetParamsIfExists(ctx) - // Update DeliverTxHookWasmGasLimit to the default value + // Add DeliverTxHookWasmGasLimit to with default value keeperParams.DeliverTxHookWasmGasLimit = types.DefaultParams().DeliverTxHookWasmGasLimit // Set the updated parameters back in the keeper From c58e08ea8b9436dc3c2188ec588853f22891e982 Mon Sep 17 00:00:00 2001 From: yirenz Date: Wed, 4 Sep 2024 09:04:37 -0400 Subject: [PATCH 36/38] feat: add CLI and RPC endpoint from Pointee to Pointer mapping (#1834) * feat: add CLI and RPC endpoint from Pointee to Pointer mapping --------- Co-authored-by: blindchaser --- proto/evm/query.proto | 15 + x/evm/client/cli/query.go | 30 ++ x/evm/keeper/grpc_query.go | 43 +++ x/evm/keeper/grpc_query_test.go | 116 +++++++ x/evm/keeper/pointer.go | 42 +++ x/evm/types/query.pb.go | 571 +++++++++++++++++++++++++++++--- x/evm/types/query.pb.gw.go | 83 +++++ 7 files changed, 859 insertions(+), 41 deletions(-) diff --git a/proto/evm/query.proto b/proto/evm/query.proto index f92d02df0..33888c4aa 100644 --- a/proto/evm/query.proto +++ b/proto/evm/query.proto @@ -27,6 +27,10 @@ service Query { rpc PointerVersion(QueryPointerVersionRequest) returns (QueryPointerVersionResponse) { option (google.api.http).get = "/sei-protocol/seichain/evm/pointer_version"; } + + rpc Pointee(QueryPointeeRequest) returns (QueryPointeeResponse) { + option (google.api.http).get = "/sei-protocol/seichain/evm/pointee"; + } } message QuerySeiAddressByEVMAddressRequest { @@ -75,3 +79,14 @@ message QueryPointerVersionResponse { uint32 version = 1; uint64 cw_code_id = 2; } + +message QueryPointeeRequest { + PointerType pointer_type = 1; + string pointer = 2; +} + +message QueryPointeeResponse { + string pointee = 1; + uint32 version = 2; + bool exists = 3; +} \ No newline at end of file diff --git a/x/evm/client/cli/query.go b/x/evm/client/cli/query.go index ad8806f81..091e0e4af 100644 --- a/x/evm/client/cli/query.go +++ b/x/evm/client/cli/query.go @@ -44,6 +44,7 @@ func GetQueryCmd(_ string) *cobra.Command { cmd.AddCommand(CmdQueryPayload()) cmd.AddCommand(CmdQueryPointer()) cmd.AddCommand(CmdQueryPointerVersion()) + cmd.AddCommand(CmdQueryPointee()) return cmd } @@ -348,3 +349,32 @@ func CmdQueryPointerVersion() *cobra.Command { return cmd } + +func CmdQueryPointee() *cobra.Command { + cmd := &cobra.Command{ + Use: "pointee [type] [pointer]", + Short: "Get pointee address of the specified type (one of [NATIVE, CW20, CW721, ERC20, ERC721]) and pointer", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + ctx := cmd.Context() + + res, err := queryClient.Pointee(ctx, &types.QueryPointeeRequest{ + PointerType: types.PointerType(types.PointerType_value[args[0]]), Pointer: args[1], + }) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/x/evm/keeper/grpc_query.go b/x/evm/keeper/grpc_query.go index 095f2c3c1..16bd0b000 100644 --- a/x/evm/keeper/grpc_query.go +++ b/x/evm/keeper/grpc_query.go @@ -146,3 +146,46 @@ func (q Querier) PointerVersion(c context.Context, req *types.QueryPointerVersio return nil, errors.ErrUnsupported } } + +func (q Querier) Pointee(c context.Context, req *types.QueryPointeeRequest) (*types.QueryPointeeResponse, error) { + ctx := sdk.UnwrapSDKContext(c) + switch req.PointerType { + case types.PointerType_NATIVE: + p, v, e := q.Keeper.GetNativePointee(ctx, req.Pointer) + return &types.QueryPointeeResponse{ + Pointee: p, + Version: uint32(v), + Exists: e, + }, nil + case types.PointerType_CW20: + p, v, e := q.Keeper.GetCW20Pointee(ctx, common.HexToAddress(req.Pointer)) + return &types.QueryPointeeResponse{ + Pointee: p, + Version: uint32(v), + Exists: e, + }, nil + case types.PointerType_CW721: + p, v, e := q.Keeper.GetCW721Pointee(ctx, common.HexToAddress(req.Pointer)) + return &types.QueryPointeeResponse{ + Pointee: p, + Version: uint32(v), + Exists: e, + }, nil + case types.PointerType_ERC20: + p, v, e := q.Keeper.GetERC20Pointee(ctx, req.Pointer) + return &types.QueryPointeeResponse{ + Pointee: p.Hex(), + Version: uint32(v), + Exists: e, + }, nil + case types.PointerType_ERC721: + p, v, e := q.Keeper.GetERC721Pointee(ctx, req.Pointer) + return &types.QueryPointeeResponse{ + Pointee: p.Hex(), + Version: uint32(v), + Exists: e, + }, nil + default: + return nil, errors.ErrUnsupported + } +} diff --git a/x/evm/keeper/grpc_query_test.go b/x/evm/keeper/grpc_query_test.go index e8b08a267..11d57b1c8 100644 --- a/x/evm/keeper/grpc_query_test.go +++ b/x/evm/keeper/grpc_query_test.go @@ -1,6 +1,7 @@ package keeper_test import ( + "errors" "testing" "time" @@ -47,3 +48,118 @@ func TestQueryPointer(t *testing.T) { require.Nil(t, err) require.Equal(t, types.QueryPointerResponse{Pointer: seiAddr5.String(), Version: uint32(erc721.CurrentVersion), Exists: true}, *res) } + +func TestQueryPointee(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + _, pointerAddr1 := testkeeper.MockAddressPair() + seiAddr2, evmAddr2 := testkeeper.MockAddressPair() + seiAddr3, evmAddr3 := testkeeper.MockAddressPair() + seiAddr4, evmAddr4 := testkeeper.MockAddressPair() + seiAddr5, evmAddr5 := testkeeper.MockAddressPair() + goCtx := sdk.WrapSDKContext(ctx) + + // Set up pointers for each type + k.SetERC20NativePointer(ctx, "ufoo", pointerAddr1) + k.SetERC20CW20Pointer(ctx, seiAddr2.String(), evmAddr2) + k.SetERC721CW721Pointer(ctx, seiAddr3.String(), evmAddr3) + k.SetCW20ERC20Pointer(ctx, evmAddr4, seiAddr4.String()) + k.SetCW721ERC721Pointer(ctx, evmAddr5, seiAddr5.String()) + + q := keeper.Querier{k} + + // Test for Native Pointee + res, err := q.Pointee(goCtx, &types.QueryPointeeRequest{PointerType: types.PointerType_NATIVE, Pointer: pointerAddr1.Hex()}) + require.Nil(t, err) + require.Equal(t, types.QueryPointeeResponse{Pointee: "ufoo", Version: uint32(native.CurrentVersion), Exists: true}, *res) + + // Test for CW20 Pointee + res, err = q.Pointee(goCtx, &types.QueryPointeeRequest{PointerType: types.PointerType_CW20, Pointer: evmAddr2.Hex()}) + require.Nil(t, err) + require.Equal(t, types.QueryPointeeResponse{Pointee: seiAddr2.String(), Version: uint32(cw20.CurrentVersion(ctx)), Exists: true}, *res) + + // Test for CW721 Pointee + res, err = q.Pointee(goCtx, &types.QueryPointeeRequest{PointerType: types.PointerType_CW721, Pointer: evmAddr3.Hex()}) + require.Nil(t, err) + require.Equal(t, types.QueryPointeeResponse{Pointee: seiAddr3.String(), Version: uint32(cw721.CurrentVersion), Exists: true}, *res) + + // Test for ERC20 Pointee + res, err = q.Pointee(goCtx, &types.QueryPointeeRequest{PointerType: types.PointerType_ERC20, Pointer: seiAddr4.String()}) + require.Nil(t, err) + require.Equal(t, types.QueryPointeeResponse{Pointee: evmAddr4.Hex(), Version: uint32(erc20.CurrentVersion), Exists: true}, *res) + + // Test for ERC721 Pointee + res, err = q.Pointee(goCtx, &types.QueryPointeeRequest{PointerType: types.PointerType_ERC721, Pointer: seiAddr5.String()}) + require.Nil(t, err) + require.Equal(t, types.QueryPointeeResponse{Pointee: evmAddr5.Hex(), Version: uint32(erc721.CurrentVersion), Exists: true}, *res) + + // Test for not registered Native Pointee + res, err = q.Pointee(goCtx, &types.QueryPointeeRequest{PointerType: types.PointerType_NATIVE, Pointer: "0x1234567890123456789012345678901234567890"}) + require.Nil(t, err) + require.Equal(t, types.QueryPointeeResponse{Pointee: "", Version: 0, Exists: false}, *res) + + // Test for not registered CW20 Pointee + res, err = q.Pointee(goCtx, &types.QueryPointeeRequest{PointerType: types.PointerType_CW20, Pointer: "0x1234567890123456789012345678901234567890"}) + require.Nil(t, err) + require.Equal(t, types.QueryPointeeResponse{Pointee: "", Version: 0, Exists: false}, *res) + + // Test for not registered CW721 Pointee + res, err = q.Pointee(goCtx, &types.QueryPointeeRequest{PointerType: types.PointerType_CW721, Pointer: "0x1234567890123456789012345678901234567890"}) + require.Nil(t, err) + require.Equal(t, types.QueryPointeeResponse{Pointee: "", Version: 0, Exists: false}, *res) + + // Test for not registered ERC20 Pointee + res, err = q.Pointee(goCtx, &types.QueryPointeeRequest{PointerType: types.PointerType_ERC20, Pointer: "sei1notregistered"}) + require.Nil(t, err) + require.Equal(t, types.QueryPointeeResponse{Pointee: "0x0000000000000000000000000000000000000000", Version: 0, Exists: false}, *res) + + // Test for not registered ERC721 Pointee + res, err = q.Pointee(goCtx, &types.QueryPointeeRequest{PointerType: types.PointerType_ERC721, Pointer: "sei1notregistered"}) + require.Nil(t, err) + require.Equal(t, types.QueryPointeeResponse{Pointee: "0x0000000000000000000000000000000000000000", Version: 0, Exists: false}, *res) + + // Test cases for invalid inputs + testCases := []struct { + name string + req *types.QueryPointeeRequest + expectedRes *types.QueryPointeeResponse + expectedErr error + }{ + { + name: "Invalid pointer type", + req: &types.QueryPointeeRequest{PointerType: 999, Pointer: pointerAddr1.Hex()}, + expectedRes: nil, + expectedErr: errors.ErrUnsupported, + }, + { + name: "Empty pointer", + req: &types.QueryPointeeRequest{PointerType: types.PointerType_NATIVE, Pointer: ""}, + expectedRes: &types.QueryPointeeResponse{Pointee: "", Version: 0, Exists: false}, + expectedErr: nil, + }, + { + name: "Invalid hex address for EVM-based pointer types", + req: &types.QueryPointeeRequest{PointerType: types.PointerType_CW20, Pointer: "not-a-hex-address"}, + expectedRes: &types.QueryPointeeResponse{Pointee: "", Version: 0, Exists: false}, + expectedErr: nil, + }, + { + name: "Invalid bech32 address for Cosmos-based pointer types", + req: &types.QueryPointeeRequest{PointerType: types.PointerType_ERC20, Pointer: "not-a-bech32-address"}, + expectedRes: &types.QueryPointeeResponse{Pointee: "0x0000000000000000000000000000000000000000", Version: 0, Exists: false}, + expectedErr: nil, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + res, err := q.Pointee(goCtx, tc.req) + if tc.expectedErr != nil { + require.ErrorIs(t, err, tc.expectedErr) + require.Nil(t, res) + } else { + require.NoError(t, err) + require.Equal(t, tc.expectedRes, res) + } + }) + } +} diff --git a/x/evm/keeper/pointer.go b/x/evm/keeper/pointer.go index 8c80c64a8..467cd8861 100644 --- a/x/evm/keeper/pointer.go +++ b/x/evm/keeper/pointer.go @@ -254,3 +254,45 @@ func (k *Keeper) GetStoredPointerCodeID(ctx sdk.Context, pointerType types.Point } return binary.BigEndian.Uint64(bz) } + +func (k *Keeper) GetCW20Pointee(ctx sdk.Context, erc20Address common.Address) (cw20Address string, version uint16, exists bool) { + addrBz, version, exists := k.GetPointerInfo(ctx, types.PointerReverseRegistryKey(erc20Address)) + if exists { + cw20Address = string(addrBz) + } + return +} + +func (k *Keeper) GetCW721Pointee(ctx sdk.Context, erc721Address common.Address) (cw721Address string, version uint16, exists bool) { + addrBz, version, exists := k.GetPointerInfo(ctx, types.PointerReverseRegistryKey(erc721Address)) + if exists { + cw721Address = string(addrBz) + } + return +} + +func (k *Keeper) GetERC20Pointee(ctx sdk.Context, cw20Address string) (erc20Address common.Address, version uint16, exists bool) { + addrBz, version, exists := k.GetPointerInfo(ctx, types.PointerReverseRegistryKey(common.BytesToAddress([]byte(cw20Address)))) + if exists { + erc20Address = common.BytesToAddress(addrBz) + } + return +} + +func (k *Keeper) GetERC721Pointee(ctx sdk.Context, cw721Address string) (erc721Address common.Address, version uint16, exists bool) { + addrBz, version, exists := k.GetPointerInfo(ctx, types.PointerReverseRegistryKey(common.BytesToAddress([]byte(cw721Address)))) + if exists { + erc721Address = common.BytesToAddress(addrBz) + } + return +} + +func (k *Keeper) GetNativePointee(ctx sdk.Context, erc20Address string) (token string, version uint16, exists bool) { + // Ensure the key matches how it was set in SetERC20NativePointer + key := types.PointerReverseRegistryKey(common.HexToAddress(erc20Address)) + addrBz, version, exists := k.GetPointerInfo(ctx, key) + if exists { + token = string(addrBz) + } + return +} diff --git a/x/evm/types/query.pb.go b/x/evm/types/query.pb.go index a13d53789..138f54fed 100644 --- a/x/evm/types/query.pb.go +++ b/x/evm/types/query.pb.go @@ -524,6 +524,118 @@ func (m *QueryPointerVersionResponse) GetCwCodeId() uint64 { return 0 } +type QueryPointeeRequest struct { + PointerType PointerType `protobuf:"varint,1,opt,name=pointer_type,json=pointerType,proto3,enum=seiprotocol.seichain.evm.PointerType" json:"pointer_type,omitempty"` + Pointer string `protobuf:"bytes,2,opt,name=pointer,proto3" json:"pointer,omitempty"` +} + +func (m *QueryPointeeRequest) Reset() { *m = QueryPointeeRequest{} } +func (m *QueryPointeeRequest) String() string { return proto.CompactTextString(m) } +func (*QueryPointeeRequest) ProtoMessage() {} +func (*QueryPointeeRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_11c0d37eed5339f7, []int{10} +} +func (m *QueryPointeeRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryPointeeRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryPointeeRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryPointeeRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryPointeeRequest.Merge(m, src) +} +func (m *QueryPointeeRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryPointeeRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryPointeeRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryPointeeRequest proto.InternalMessageInfo + +func (m *QueryPointeeRequest) GetPointerType() PointerType { + if m != nil { + return m.PointerType + } + return PointerType_ERC20 +} + +func (m *QueryPointeeRequest) GetPointer() string { + if m != nil { + return m.Pointer + } + return "" +} + +type QueryPointeeResponse struct { + Pointee string `protobuf:"bytes,1,opt,name=pointee,proto3" json:"pointee,omitempty"` + Version uint32 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"` + Exists bool `protobuf:"varint,3,opt,name=exists,proto3" json:"exists,omitempty"` +} + +func (m *QueryPointeeResponse) Reset() { *m = QueryPointeeResponse{} } +func (m *QueryPointeeResponse) String() string { return proto.CompactTextString(m) } +func (*QueryPointeeResponse) ProtoMessage() {} +func (*QueryPointeeResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_11c0d37eed5339f7, []int{11} +} +func (m *QueryPointeeResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryPointeeResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryPointeeResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryPointeeResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryPointeeResponse.Merge(m, src) +} +func (m *QueryPointeeResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryPointeeResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryPointeeResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryPointeeResponse proto.InternalMessageInfo + +func (m *QueryPointeeResponse) GetPointee() string { + if m != nil { + return m.Pointee + } + return "" +} + +func (m *QueryPointeeResponse) GetVersion() uint32 { + if m != nil { + return m.Version + } + return 0 +} + +func (m *QueryPointeeResponse) GetExists() bool { + if m != nil { + return m.Exists + } + return false +} + func init() { proto.RegisterType((*QuerySeiAddressByEVMAddressRequest)(nil), "seiprotocol.seichain.evm.QuerySeiAddressByEVMAddressRequest") proto.RegisterType((*QuerySeiAddressByEVMAddressResponse)(nil), "seiprotocol.seichain.evm.QuerySeiAddressByEVMAddressResponse") @@ -535,52 +647,56 @@ func init() { proto.RegisterType((*QueryPointerResponse)(nil), "seiprotocol.seichain.evm.QueryPointerResponse") proto.RegisterType((*QueryPointerVersionRequest)(nil), "seiprotocol.seichain.evm.QueryPointerVersionRequest") proto.RegisterType((*QueryPointerVersionResponse)(nil), "seiprotocol.seichain.evm.QueryPointerVersionResponse") + proto.RegisterType((*QueryPointeeRequest)(nil), "seiprotocol.seichain.evm.QueryPointeeRequest") + proto.RegisterType((*QueryPointeeResponse)(nil), "seiprotocol.seichain.evm.QueryPointeeResponse") } func init() { proto.RegisterFile("evm/query.proto", fileDescriptor_11c0d37eed5339f7) } var fileDescriptor_11c0d37eed5339f7 = []byte{ - // 627 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x94, 0xcd, 0x6e, 0xd3, 0x4e, - 0x14, 0xc5, 0xeb, 0xfc, 0xfb, 0xef, 0xc7, 0x6d, 0x29, 0xd2, 0x80, 0x4a, 0x64, 0x2a, 0x53, 0x99, - 0x0f, 0x55, 0x15, 0xb1, 0xa1, 0xc0, 0xae, 0x2c, 0x68, 0x55, 0x01, 0x0b, 0x24, 0x30, 0xd0, 0x05, - 0x1b, 0xcb, 0xb5, 0x6f, 0xdb, 0x91, 0x62, 0x8f, 0xeb, 0x99, 0xa4, 0xcd, 0x96, 0x05, 0x6b, 0x24, - 0x78, 0x01, 0x1e, 0x81, 0x87, 0x40, 0x62, 0x59, 0x89, 0x0d, 0x4b, 0xd4, 0xf0, 0x20, 0xc8, 0xe3, - 0x71, 0xe2, 0xb4, 0x89, 0x9d, 0x20, 0x76, 0x73, 0x27, 0x73, 0xce, 0xfd, 0xdd, 0xc9, 0x1c, 0xc3, - 0x65, 0x6c, 0x87, 0xf6, 0x51, 0x0b, 0x93, 0x8e, 0x15, 0x27, 0x4c, 0x30, 0x52, 0xe7, 0x48, 0xe5, - 0xca, 0x67, 0x4d, 0x8b, 0x23, 0xf5, 0x0f, 0x3d, 0x1a, 0x59, 0xd8, 0x0e, 0xf5, 0x95, 0x03, 0xc6, - 0x0e, 0x9a, 0x68, 0x7b, 0x31, 0xb5, 0xbd, 0x28, 0x62, 0xc2, 0x13, 0x94, 0x45, 0x3c, 0xd3, 0xe9, - 0xd2, 0x08, 0xa3, 0x56, 0xa8, 0x36, 0xcc, 0x1d, 0x30, 0x5f, 0xa5, 0xbe, 0xaf, 0x91, 0x3e, 0x09, - 0x82, 0x04, 0x39, 0xdf, 0xea, 0xec, 0xec, 0xbe, 0x50, 0x6b, 0x07, 0x8f, 0x5a, 0xc8, 0x05, 0xb9, - 0x01, 0x0b, 0xd8, 0x0e, 0x5d, 0x2f, 0xdb, 0xad, 0x6b, 0xab, 0xda, 0xda, 0xbc, 0x03, 0xd8, 0x0e, - 0xd5, 0x39, 0x73, 0x1f, 0x6e, 0x96, 0xda, 0xf0, 0x98, 0x45, 0x1c, 0x53, 0x1f, 0x8e, 0xf4, 0xbc, - 0x0f, 0xef, 0x89, 0x88, 0x01, 0xe0, 0x71, 0xce, 0x7c, 0xea, 0x09, 0x0c, 0xea, 0xb5, 0x55, 0x6d, - 0x6d, 0xce, 0x29, 0xec, 0xf4, 0x70, 0xfb, 0xde, 0x5b, 0x85, 0x9e, 0x05, 0xdc, 0xd2, 0x36, 0x3d, - 0xdc, 0x51, 0x36, 0x7d, 0xdc, 0xd2, 0xb1, 0x2b, 0x71, 0x37, 0x61, 0x39, 0xbb, 0x96, 0xf4, 0x5f, - 0xf0, 0xb7, 0xbd, 0x66, 0x33, 0x47, 0x24, 0x30, 0x1d, 0x78, 0xc2, 0x93, 0x9e, 0x8b, 0x8e, 0x5c, - 0x93, 0x25, 0xa8, 0x09, 0x26, 0x5d, 0xe6, 0x9d, 0x9a, 0x60, 0x66, 0x03, 0xae, 0x5d, 0x50, 0x2b, - 0xb2, 0x21, 0x72, 0xb3, 0x03, 0x57, 0xe4, 0xf1, 0x97, 0x8c, 0x46, 0x02, 0x93, 0xbc, 0xd3, 0x33, - 0x58, 0x8c, 0xb3, 0x1d, 0x57, 0x74, 0x62, 0x94, 0x92, 0xa5, 0x8d, 0xdb, 0xd6, 0xa8, 0x17, 0x64, - 0x29, 0xfd, 0x9b, 0x4e, 0x8c, 0xce, 0x42, 0xdc, 0x2f, 0x48, 0x1d, 0x66, 0xb3, 0x12, 0x15, 0x64, - 0x5e, 0x9a, 0x7b, 0x70, 0x75, 0xb0, 0xb5, 0xc2, 0xec, 0x29, 0x12, 0x75, 0x79, 0x79, 0x99, 0xfe, - 0xd2, 0xc6, 0x84, 0x53, 0x16, 0x49, 0xaf, 0x4b, 0x4e, 0x5e, 0x92, 0x65, 0x98, 0xc1, 0x13, 0xca, - 0x05, 0xaf, 0xff, 0x27, 0xef, 0x53, 0x55, 0xe6, 0x3e, 0xe8, 0xc5, 0x1e, 0xbb, 0xd9, 0xf1, 0x7f, - 0x3e, 0xa5, 0xf9, 0x16, 0xae, 0x0f, 0xed, 0xd3, 0x1f, 0x29, 0x07, 0xd7, 0x06, 0xc1, 0x57, 0x00, - 0xfc, 0x63, 0xd7, 0x67, 0x01, 0xba, 0x34, 0x7b, 0x0c, 0xd3, 0xce, 0x9c, 0x7f, 0xbc, 0xcd, 0x02, - 0x7c, 0x1e, 0x6c, 0x7c, 0x98, 0x85, 0xff, 0xa5, 0x2f, 0xf9, 0xa6, 0xc1, 0xf2, 0xf0, 0x9c, 0x90, - 0xcd, 0xd1, 0xbc, 0xd5, 0x29, 0xd5, 0x1f, 0xff, 0xa5, 0x3a, 0x9b, 0xcc, 0xb4, 0xde, 0xff, 0xf8, - 0xfd, 0xa9, 0xb6, 0x46, 0xee, 0xd8, 0x1c, 0x69, 0x23, 0xf7, 0xb1, 0x73, 0x1f, 0x3b, 0xfd, 0x74, - 0x14, 0x62, 0x25, 0xe7, 0x18, 0x1e, 0xa0, 0xca, 0x39, 0x4a, 0xe3, 0x5b, 0x39, 0x47, 0x79, 0x6a, - 0xc7, 0x9a, 0xa3, 0x10, 0x6b, 0xf2, 0x45, 0x03, 0xe8, 0x47, 0x8c, 0xdc, 0xab, 0xba, 0xc5, 0xf3, - 0x59, 0xd6, 0xef, 0x4f, 0xa0, 0x98, 0xe4, 0xae, 0xa5, 0xcc, 0xf5, 0x53, 0xa8, 0xcf, 0x1a, 0xcc, - 0xaa, 0x07, 0x49, 0x1a, 0x15, 0xed, 0x06, 0xf3, 0xaf, 0x5b, 0xe3, 0x1e, 0x57, 0x68, 0xeb, 0x12, - 0xed, 0x16, 0x31, 0x4b, 0xd0, 0xf2, 0x14, 0x7f, 0xd5, 0x60, 0x69, 0x30, 0x27, 0xe4, 0xe1, 0x78, - 0xed, 0x06, 0xe3, 0xab, 0x3f, 0x9a, 0x50, 0xa5, 0x58, 0x37, 0x24, 0xeb, 0x5d, 0xb2, 0x5e, 0xcd, - 0xea, 0xaa, 0x98, 0x6e, 0x3d, 0xfd, 0x7e, 0x66, 0x68, 0xa7, 0x67, 0x86, 0xf6, 0xeb, 0xcc, 0xd0, - 0x3e, 0x76, 0x8d, 0xa9, 0xd3, 0xae, 0x31, 0xf5, 0xb3, 0x6b, 0x4c, 0xbd, 0x6b, 0x1c, 0x50, 0x71, - 0xd8, 0xda, 0xb3, 0x7c, 0x16, 0x5e, 0xf0, 0x6b, 0x64, 0x86, 0x27, 0xd2, 0x32, 0xfd, 0xc2, 0xf0, - 0xbd, 0x19, 0xf9, 0xfb, 0x83, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x5d, 0xbe, 0x8f, 0x9b, 0x9d, - 0x07, 0x00, 0x00, + // 662 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x54, 0xcf, 0x6e, 0xd3, 0x4e, + 0x10, 0xae, 0xf3, 0xeb, 0xaf, 0x7f, 0xa6, 0xa5, 0x48, 0x0b, 0x2a, 0x91, 0xa9, 0x4c, 0x65, 0xfe, + 0xa8, 0xaa, 0x88, 0x03, 0x05, 0x6e, 0xe5, 0x40, 0xab, 0x0a, 0x38, 0x20, 0x81, 0x81, 0x1e, 0xb8, + 0x44, 0xae, 0x3d, 0x6d, 0x57, 0x8a, 0xbd, 0xae, 0x77, 0x93, 0x36, 0x57, 0x9e, 0x00, 0x09, 0xae, + 0x1c, 0x78, 0x04, 0x1e, 0x02, 0x89, 0x63, 0x25, 0x2e, 0x1c, 0x51, 0xcb, 0x83, 0x20, 0xaf, 0xd7, + 0xb1, 0x9d, 0xa6, 0x76, 0x52, 0xc1, 0x6d, 0x67, 0x3d, 0xdf, 0x37, 0xdf, 0xcc, 0xac, 0x3f, 0xb8, + 0x8c, 0x5d, 0xbf, 0x79, 0xd0, 0xc1, 0xa8, 0x67, 0x85, 0x11, 0x13, 0x8c, 0xd4, 0x39, 0x52, 0x79, + 0x72, 0x59, 0xdb, 0xe2, 0x48, 0xdd, 0x7d, 0x87, 0x06, 0x16, 0x76, 0x7d, 0x7d, 0x69, 0x8f, 0xb1, + 0xbd, 0x36, 0x36, 0x9d, 0x90, 0x36, 0x9d, 0x20, 0x60, 0xc2, 0x11, 0x94, 0x05, 0x3c, 0xc1, 0xe9, + 0x92, 0x08, 0x83, 0x8e, 0xaf, 0x2e, 0xcc, 0x2d, 0x30, 0x5f, 0xc5, 0xbc, 0xaf, 0x91, 0x3e, 0xf1, + 0xbc, 0x08, 0x39, 0xdf, 0xe8, 0x6d, 0x6d, 0xbf, 0x50, 0x67, 0x1b, 0x0f, 0x3a, 0xc8, 0x05, 0xb9, + 0x01, 0x73, 0xd8, 0xf5, 0x5b, 0x4e, 0x72, 0x5b, 0xd7, 0x96, 0xb5, 0x95, 0x59, 0x1b, 0xb0, 0xeb, + 0xab, 0x3c, 0x73, 0x17, 0x6e, 0x96, 0xd2, 0xf0, 0x90, 0x05, 0x1c, 0x63, 0x1e, 0x8e, 0x74, 0x90, + 0x87, 0xf7, 0x41, 0xc4, 0x00, 0x70, 0x38, 0x67, 0x2e, 0x75, 0x04, 0x7a, 0xf5, 0xda, 0xb2, 0xb6, + 0x32, 0x63, 0xe7, 0x6e, 0xfa, 0x72, 0x33, 0xee, 0x8d, 0x5c, 0xcd, 0x9c, 0xdc, 0xd2, 0x32, 0x7d, + 0xb9, 0xe7, 0xd1, 0x64, 0x72, 0x4b, 0xdb, 0xae, 0x94, 0xbb, 0x0e, 0x8b, 0xc9, 0x58, 0xe2, 0x2d, + 0xb8, 0x9b, 0x4e, 0xbb, 0x9d, 0x4a, 0x24, 0x30, 0xe9, 0x39, 0xc2, 0x91, 0x9c, 0xf3, 0xb6, 0x3c, + 0x93, 0x05, 0xa8, 0x09, 0x26, 0x59, 0x66, 0xed, 0x9a, 0x60, 0x66, 0x03, 0xae, 0x9d, 0x41, 0x2b, + 0x65, 0x43, 0xe0, 0x66, 0x0f, 0xae, 0xc8, 0xf4, 0x97, 0x8c, 0x06, 0x02, 0xa3, 0xb4, 0xd2, 0x33, + 0x98, 0x0f, 0x93, 0x9b, 0x96, 0xe8, 0x85, 0x28, 0x21, 0x0b, 0x6b, 0xb7, 0xad, 0xf3, 0x5e, 0x90, + 0xa5, 0xf0, 0x6f, 0x7a, 0x21, 0xda, 0x73, 0x61, 0x16, 0x90, 0x3a, 0x4c, 0x27, 0x21, 0x2a, 0x91, + 0x69, 0x68, 0xee, 0xc0, 0xd5, 0x62, 0x69, 0x25, 0xb3, 0x8f, 0x88, 0xd4, 0xf0, 0xd2, 0x30, 0xfe, + 0xd2, 0xc5, 0x88, 0x53, 0x16, 0x48, 0xae, 0x4b, 0x76, 0x1a, 0x92, 0x45, 0x98, 0xc2, 0x23, 0xca, + 0x05, 0xaf, 0xff, 0x27, 0xe7, 0xa9, 0x22, 0x73, 0x17, 0xf4, 0x7c, 0x8d, 0xed, 0x24, 0xfd, 0xaf, + 0x77, 0x69, 0xbe, 0x85, 0xeb, 0x43, 0xeb, 0x64, 0x2d, 0xa5, 0xc2, 0xb5, 0xa2, 0xf0, 0x25, 0x00, + 0xf7, 0xb0, 0xe5, 0x32, 0x0f, 0x5b, 0x34, 0x79, 0x0c, 0x93, 0xf6, 0x8c, 0x7b, 0xb8, 0xc9, 0x3c, + 0x7c, 0xee, 0x0d, 0x6c, 0x07, 0xff, 0xe1, 0x76, 0xa2, 0xe2, 0x76, 0xa2, 0x81, 0xed, 0xe0, 0xd9, + 0xed, 0x60, 0x71, 0x3b, 0x38, 0xfe, 0x76, 0xd6, 0x3e, 0xcf, 0xc0, 0xff, 0xb2, 0x08, 0xf9, 0xa6, + 0xc1, 0xe2, 0x70, 0x1b, 0x20, 0xeb, 0xe7, 0xb7, 0x55, 0x6d, 0x42, 0xfa, 0xe3, 0x0b, 0xa2, 0x93, + 0x6e, 0x4d, 0xeb, 0xfd, 0x8f, 0xdf, 0x1f, 0x6b, 0x2b, 0xe4, 0x4e, 0x93, 0x23, 0x6d, 0xa4, 0x3c, + 0xcd, 0x94, 0xa7, 0x19, 0x3b, 0x63, 0xce, 0x35, 0x64, 0x1f, 0xc3, 0xfd, 0xa1, 0xb2, 0x8f, 0x52, + 0x77, 0xaa, 0xec, 0xa3, 0xdc, 0x94, 0x46, 0xea, 0x23, 0xe7, 0x5a, 0xe4, 0x8b, 0x06, 0x90, 0x39, + 0x08, 0xb9, 0x57, 0x35, 0xc5, 0x41, 0xab, 0xd2, 0xef, 0x8f, 0x81, 0x18, 0x67, 0xd6, 0x12, 0xd6, + 0x72, 0x63, 0x51, 0x9f, 0x34, 0x98, 0x56, 0x0f, 0x9b, 0x34, 0x2a, 0xca, 0x15, 0xed, 0x4d, 0xb7, + 0x46, 0x4d, 0x57, 0xd2, 0x56, 0xa5, 0xb4, 0x5b, 0xc4, 0x2c, 0x91, 0x96, 0x9a, 0xd4, 0x57, 0x0d, + 0x16, 0x8a, 0x36, 0x40, 0x1e, 0x8e, 0x56, 0xae, 0xe8, 0x4e, 0xfa, 0xa3, 0x31, 0x51, 0x4a, 0xeb, + 0x9a, 0xd4, 0x7a, 0x97, 0xac, 0x56, 0x6b, 0x6d, 0xa5, 0x3f, 0x68, 0x36, 0x4a, 0x1c, 0x71, 0x94, + 0x38, 0xde, 0x28, 0xf1, 0x02, 0xa3, 0xc4, 0x8d, 0xa7, 0xdf, 0x4f, 0x0c, 0xed, 0xf8, 0xc4, 0xd0, + 0x7e, 0x9d, 0x18, 0xda, 0x87, 0x53, 0x63, 0xe2, 0xf8, 0xd4, 0x98, 0xf8, 0x79, 0x6a, 0x4c, 0xbc, + 0x6b, 0xec, 0x51, 0xb1, 0xdf, 0xd9, 0xb1, 0x5c, 0xe6, 0x9f, 0xe1, 0x69, 0x24, 0x44, 0x47, 0x92, + 0x2a, 0xf6, 0x47, 0xbe, 0x33, 0x25, 0xbf, 0x3f, 0xf8, 0x13, 0x00, 0x00, 0xff, 0xff, 0x2b, 0xa9, + 0x46, 0xf3, 0x13, 0x09, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -600,6 +716,7 @@ type QueryClient interface { StaticCall(ctx context.Context, in *QueryStaticCallRequest, opts ...grpc.CallOption) (*QueryStaticCallResponse, error) Pointer(ctx context.Context, in *QueryPointerRequest, opts ...grpc.CallOption) (*QueryPointerResponse, error) PointerVersion(ctx context.Context, in *QueryPointerVersionRequest, opts ...grpc.CallOption) (*QueryPointerVersionResponse, error) + Pointee(ctx context.Context, in *QueryPointeeRequest, opts ...grpc.CallOption) (*QueryPointeeResponse, error) } type queryClient struct { @@ -655,6 +772,15 @@ func (c *queryClient) PointerVersion(ctx context.Context, in *QueryPointerVersio return out, nil } +func (c *queryClient) Pointee(ctx context.Context, in *QueryPointeeRequest, opts ...grpc.CallOption) (*QueryPointeeResponse, error) { + out := new(QueryPointeeResponse) + err := c.cc.Invoke(ctx, "/seiprotocol.seichain.evm.Query/Pointee", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // QueryServer is the server API for Query service. type QueryServer interface { SeiAddressByEVMAddress(context.Context, *QuerySeiAddressByEVMAddressRequest) (*QuerySeiAddressByEVMAddressResponse, error) @@ -662,6 +788,7 @@ type QueryServer interface { StaticCall(context.Context, *QueryStaticCallRequest) (*QueryStaticCallResponse, error) Pointer(context.Context, *QueryPointerRequest) (*QueryPointerResponse, error) PointerVersion(context.Context, *QueryPointerVersionRequest) (*QueryPointerVersionResponse, error) + Pointee(context.Context, *QueryPointeeRequest) (*QueryPointeeResponse, error) } // UnimplementedQueryServer can be embedded to have forward compatible implementations. @@ -683,6 +810,9 @@ func (*UnimplementedQueryServer) Pointer(ctx context.Context, req *QueryPointerR func (*UnimplementedQueryServer) PointerVersion(ctx context.Context, req *QueryPointerVersionRequest) (*QueryPointerVersionResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method PointerVersion not implemented") } +func (*UnimplementedQueryServer) Pointee(ctx context.Context, req *QueryPointeeRequest) (*QueryPointeeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Pointee not implemented") +} func RegisterQueryServer(s grpc1.Server, srv QueryServer) { s.RegisterService(&_Query_serviceDesc, srv) @@ -778,6 +908,24 @@ func _Query_PointerVersion_Handler(srv interface{}, ctx context.Context, dec fun return interceptor(ctx, in, info, handler) } +func _Query_Pointee_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryPointeeRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).Pointee(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/seiprotocol.seichain.evm.Query/Pointee", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).Pointee(ctx, req.(*QueryPointeeRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _Query_serviceDesc = grpc.ServiceDesc{ ServiceName: "seiprotocol.seichain.evm.Query", HandlerType: (*QueryServer)(nil), @@ -802,6 +950,10 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "PointerVersion", Handler: _Query_PointerVersion_Handler, }, + { + MethodName: "Pointee", + Handler: _Query_Pointee_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "evm/query.proto", @@ -1155,6 +1307,86 @@ func (m *QueryPointerVersionResponse) MarshalToSizedBuffer(dAtA []byte) (int, er return len(dAtA) - i, nil } +func (m *QueryPointeeRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryPointeeRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryPointeeRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Pointer) > 0 { + i -= len(m.Pointer) + copy(dAtA[i:], m.Pointer) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Pointer))) + i-- + dAtA[i] = 0x12 + } + if m.PointerType != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.PointerType)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *QueryPointeeResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryPointeeResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryPointeeResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Exists { + i-- + if m.Exists { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x18 + } + if m.Version != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.Version)) + i-- + dAtA[i] = 0x10 + } + if len(m.Pointee) > 0 { + i -= len(m.Pointee) + copy(dAtA[i:], m.Pointee) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Pointee))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { offset -= sovQuery(v) base := offset @@ -1316,6 +1548,41 @@ func (m *QueryPointerVersionResponse) Size() (n int) { return n } +func (m *QueryPointeeRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PointerType != 0 { + n += 1 + sovQuery(uint64(m.PointerType)) + } + l = len(m.Pointer) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryPointeeResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Pointee) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + if m.Version != 0 { + n += 1 + sovQuery(uint64(m.Version)) + } + if m.Exists { + n += 2 + } + return n +} + func sovQuery(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -2269,6 +2536,228 @@ func (m *QueryPointerVersionResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *QueryPointeeRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryPointeeRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryPointeeRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PointerType", wireType) + } + m.PointerType = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PointerType |= PointerType(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pointer", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Pointer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryPointeeResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryPointeeResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryPointeeResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pointee", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Pointee = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) + } + m.Version = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Version |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Exists", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Exists = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipQuery(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/evm/types/query.pb.gw.go b/x/evm/types/query.pb.gw.go index 72c5e53f0..21a2750cb 100644 --- a/x/evm/types/query.pb.gw.go +++ b/x/evm/types/query.pb.gw.go @@ -213,6 +213,42 @@ func local_request_Query_PointerVersion_0(ctx context.Context, marshaler runtime } +var ( + filter_Query_Pointee_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_Pointee_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryPointeeRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_Pointee_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.Pointee(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_Pointee_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryPointeeRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_Pointee_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.Pointee(ctx, &protoReq) + return msg, metadata, err + +} + // RegisterQueryHandlerServer registers the http handlers for service Query to "mux". // UnaryRPC :call QueryServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -334,6 +370,29 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) + mux.Handle("GET", pattern_Query_Pointee_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_Pointee_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Pointee_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -475,6 +534,26 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) + mux.Handle("GET", pattern_Query_Pointee_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_Pointee_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Pointee_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -488,6 +567,8 @@ var ( pattern_Query_Pointer_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"sei-protocol", "seichain", "evm", "pointer"}, "", runtime.AssumeColonVerbOpt(true))) pattern_Query_PointerVersion_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"sei-protocol", "seichain", "evm", "pointer_version"}, "", runtime.AssumeColonVerbOpt(true))) + + pattern_Query_Pointee_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"sei-protocol", "seichain", "evm", "pointee"}, "", runtime.AssumeColonVerbOpt(true))) ) var ( @@ -500,4 +581,6 @@ var ( forward_Query_Pointer_0 = runtime.ForwardResponseMessage forward_Query_PointerVersion_0 = runtime.ForwardResponseMessage + + forward_Query_Pointee_0 = runtime.ForwardResponseMessage ) From 7ebd2c40cc7d493b0f28f77a7c2e8e7f5401800c Mon Sep 17 00:00:00 2001 From: mj Date: Wed, 4 Sep 2024 11:34:51 -0700 Subject: [PATCH 37/38] Add NFT Marketplace Tests (#1829) * test * test * add more setup * add to path * githubpath * seid path * dapp tests * try artifacts * ditch setup step * deps * test workflow * set keyring * without * keys add * add to sh * nobackend * no script * test * keyring * no sh * test * fix flakiness * cleanup * move seid config command * only if docker * test without * if isdocker * printf mnemonic * try escape path * try single quotes * try modifying execute * no path * backend * try without keyring * move keyring * path * basedir * try pwd * config reset * seid config * redeclare * print * docker path * dynamic path * config for all * full * lint issue * backend * cleanup * seaport starter * working locally * working on all chains * add readme * keyring * stray argument in unit test * cleanup * reduce costs * scripts --- contracts/test/CW721toERC721PointerTest.js | 2 +- contracts/test/lib.js | 7 +- integration_test/dapp_tests/README.md | 48 +++++ .../dapp_tests/contracts/MockERC20.sol | 2 +- .../dapp_tests/contracts/MockERC721.sol | 54 ++++++ .../dapp_tests/contracts/NftMarketplace.sol | 163 ++++++++++++++++ integration_test/dapp_tests/dapp_tests.sh | 35 +++- .../dapp_tests/nftMarketplace/cw721_base.wasm | Bin 0 -> 377539 bytes .../nftMarketplace/nftMarketplaceTests.js | 178 ++++++++++++++++++ integration_test/dapp_tests/package-lock.json | 46 ++--- integration_test/dapp_tests/package.json | 2 +- .../dapp_tests/uniswap/uniswapTest.js | 65 +++---- integration_test/dapp_tests/utils.js | 124 +++++++----- 13 files changed, 599 insertions(+), 127 deletions(-) create mode 100644 integration_test/dapp_tests/README.md create mode 100644 integration_test/dapp_tests/contracts/MockERC721.sol create mode 100644 integration_test/dapp_tests/contracts/NftMarketplace.sol create mode 100755 integration_test/dapp_tests/nftMarketplace/cw721_base.wasm create mode 100644 integration_test/dapp_tests/nftMarketplace/nftMarketplaceTests.js diff --git a/contracts/test/CW721toERC721PointerTest.js b/contracts/test/CW721toERC721PointerTest.js index 3bfa394f1..999eb8d06 100644 --- a/contracts/test/CW721toERC721PointerTest.js +++ b/contracts/test/CW721toERC721PointerTest.js @@ -27,7 +27,7 @@ describe("CW721 to ERC721 Pointer", function () { describe("validation", function(){ it("should not allow a pointer to the pointer", async function(){ try { - await deployErc721PointerForCw721(hre.ethers.provider, pointer, 5) + await deployErc721PointerForCw721(hre.ethers.provider, pointer) expect.fail(`Expected to be prevented from creating a pointer`); } catch(e){ expect(e.message).to.include("contract deployment failed"); diff --git a/contracts/test/lib.js b/contracts/test/lib.js index 3c5fbf633..f69d2dcff 100644 --- a/contracts/test/lib.js +++ b/contracts/test/lib.js @@ -252,8 +252,11 @@ async function deployErc20PointerNative(provider, name, from=adminKeyName, evmRp throw new Error("contract deployment failed") } -async function deployErc721PointerForCw721(provider, cw721Address) { - const command = `seid tx evm register-evm-pointer CW721 ${cw721Address} --from=admin -b block` +async function deployErc721PointerForCw721(provider, cw721Address, from=adminKeyName, evmRpc="") { + let command = `seid tx evm register-evm-pointer CW721 ${cw721Address} --from=${from} -b block` + if (evmRpc) { + command = command + ` --evm-rpc=${evmRpc}` + } const output = await execute(command); const txHash = output.replace(/.*0x/, "0x").trim() let attempt = 0; diff --git a/integration_test/dapp_tests/README.md b/integration_test/dapp_tests/README.md new file mode 100644 index 000000000..65fa2c439 --- /dev/null +++ b/integration_test/dapp_tests/README.md @@ -0,0 +1,48 @@ +# dApp Tests + +This directory contains integration tests that simulate simple use cases on the chain by deploying and running common dApp contracts. +The focus here is mainly on testing common interop scenarios (interactions with associated/unassociated accounts, pointer contracts etc.) +In each test scenario, we deploy the dapp contracts, fund wallets, then go through common end to end scenarios. + +## Setup +To run the dapp tests, simply run the script at `/integration_test/dapp_tests/dapp_tests.sh ` + +3 chain types are supported, `seilocal`, `devnet` (arctic-1) and `testnet` (atlantic-2). The configs for each chain are stored in `./hardhat.config.js`. + +If running on `seilocal`, the script assumes that a local instance of the chain is running by running `/scripts/initialize_local_chain.sh`. +A well funded `admin` account must be available on the local keyring. + +If running on the live chains, the tests rely on a `deployer` account, which has to have sufficient funds on the chain the test is running on. +The deployer mnemonic must be stored as an environment variable: DAPP_TESTS_MNEMONIC. +On the test pipelines, the account used is: +- Deployer Sei address: `sei1rtpakm7w9egh0n7xngzm6vrln0szv6yeva6hhn` +- Deployer EVM address: `0x4D952b770C3a0B096e739399B40263D0b516d406` + +## Tests + +### Uniswap (EVM DEX) +This test deploys a small set of UniswapV3 contracts to the EVM and tests swapping and creation of uniswap pools. +- Test that associated accounts are able to swap erc20 tokens +- Test that associated accounts are able to swap native tokens via pointer +- Test that associated accounts are able to swap cw20 tokens via pointer +- Test that unassociated accounts are able to receive erc20 tokens +- Test that unassociated accounts are able to receive native tokens via pointer +- Unassociated EVM accounts are not able to receive cw20 tokens via pointer +- Test that unassociated accounts can still deploy and supply erc20-erc20pointer liquidity pools. + +### Steak (CW Liquid Staking) +This test deploys a set of WASM liquid staking contracts, then tests bonding and unbonding. +- Test that associated accounts are able to bond, then unbond tokens. +- Test that unassociated accounts are able to bond, then unbond tokens. + +### NFT Marketplace (EVM NFT Marketplace) +This test deploys a simple NFT Marketplace contract, then tests listing and buying NFTs. +- Test that associated accounts are able to list and buy erc721 tokens +- Test that unassociated accounts are able to list and buy erc721 tokens +- Test that associated accounts are able to buy cw721 tokens via pointers +- Unassociated EVM accounts are currently unable to own or receive cw721 tokens via pointers + +### To Be Added +The following is a list of testcases/scenarios that we should add to verify completeness +- CosmWasm DEX tests - test that ERC20 tokens are tradeable via pointer contracts. +- CosmWasm NFT Marketplace tests - test that ERC721 tokens are tradeable via pointer contracts. \ No newline at end of file diff --git a/integration_test/dapp_tests/contracts/MockERC20.sol b/integration_test/dapp_tests/contracts/MockERC20.sol index 58989ad89..e089db9e3 100644 --- a/integration_test/dapp_tests/contracts/MockERC20.sol +++ b/integration_test/dapp_tests/contracts/MockERC20.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; diff --git a/integration_test/dapp_tests/contracts/MockERC721.sol b/integration_test/dapp_tests/contracts/MockERC721.sol new file mode 100644 index 000000000..50ea9b905 --- /dev/null +++ b/integration_test/dapp_tests/contracts/MockERC721.sol @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import "@openzeppelin/contracts/access/Ownable.sol"; +import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; + +contract MockERC721 is ERC721, ERC721Enumerable, Ownable { + uint256 private _currentTokenId = 0; + + constructor(string memory name, string memory symbol) ERC721(name, symbol) Ownable(msg.sender) {} + + function mint(address to) public onlyOwner { + _currentTokenId++; + _mint(to, _currentTokenId); + } + + function batchMint(address to, uint256 amount) public onlyOwner { + for (uint256 i = 0; i < amount; i++) { + _currentTokenId++; + _mint(to, _currentTokenId); + } + } + + function burn(uint256 tokenId) public { + _burn(tokenId); + } + + // The following functions are overrides required by Solidity. + + function _update(address to, uint256 tokenId, address auth) + internal + override(ERC721, ERC721Enumerable) + returns (address) + { + return super._update(to, tokenId, auth); + } + + function _increaseBalance(address account, uint128 value) + internal + override(ERC721, ERC721Enumerable) + { + super._increaseBalance(account, value); + } + + function supportsInterface(bytes4 interfaceId) + public + view + override(ERC721, ERC721Enumerable) + returns (bool) + { + return super.supportsInterface(interfaceId); + } +} \ No newline at end of file diff --git a/integration_test/dapp_tests/contracts/NftMarketplace.sol b/integration_test/dapp_tests/contracts/NftMarketplace.sol new file mode 100644 index 000000000..a23e6042f --- /dev/null +++ b/integration_test/dapp_tests/contracts/NftMarketplace.sol @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.20; + +import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; + +/* + * @title NftMarketplace + * @auth Patrick Collins + * @notice This contract allows users to list NFTs for sale + * @notice This is the reference + */ +contract NftMarketplace { + error NftMarketplace__PriceNotMet(address nftAddress, uint256 tokenId, uint256 price); + error NftMarketplace__NotListed(address nftAddress, uint256 tokenId); + error NftMarketplace__NoProceeds(); + error NftMarketplace__NotOwner(); + error NftMarketplace__PriceMustBeAboveZero(); + error NftMarketplace__TransferFailed(); + + event ItemListed(address indexed seller, address indexed nftAddress, uint256 indexed tokenId, uint256 price); + event ItemUpdated(address indexed seller, address indexed nftAddress, uint256 indexed tokenId, uint256 price); + event ItemCanceled(address indexed seller, address indexed nftAddress, uint256 indexed tokenId); + event ItemBought(address indexed buyer, address indexed nftAddress, uint256 indexed tokenId, uint256 price); + + mapping(address nftAddress => mapping(uint256 tokenId => Listing)) private s_listings; + mapping(address seller => uint256 proceedAmount) private s_proceeds; + + struct Listing { + uint256 price; + address seller; + } + + /*////////////////////////////////////////////////////////////// + FUNCTIONS + //////////////////////////////////////////////////////////////*/ + /* + * @notice Method for listing NFT + * @param nftAddress Address of NFT contract + * @param tokenId Token ID of NFT + * @param price sale price for each item + */ + function listItem(address nftAddress, uint256 tokenId, uint256 price) external { + // Checks + if (price <= 0) { + revert NftMarketplace__PriceMustBeAboveZero(); + } + + // Effects (Internal) + s_listings[nftAddress][tokenId] = Listing(price, msg.sender); + emit ItemListed(msg.sender, nftAddress, tokenId, price); + + // Interactions (External) + IERC721(nftAddress).safeTransferFrom(msg.sender, address(this), tokenId); + } + + /* + * @notice Method for cancelling listing + * @param nftAddress Address of NFT contract + * @param tokenId Token ID of NFT + * + * @audit-known seller can front-run a bought NFT and cancel the listing + */ + function cancelListing(address nftAddress, uint256 tokenId) external { + // Checks + if (msg.sender != s_listings[nftAddress][tokenId].seller) { + revert NftMarketplace__NotOwner(); + } + + // Effects (Internal) + delete s_listings[nftAddress][tokenId]; + emit ItemCanceled(msg.sender, nftAddress, tokenId); + + // Interactions (External) + IERC721(nftAddress).safeTransferFrom(address(this), msg.sender, tokenId); + } + + /* + * @notice Method for buying listing + * @notice The owner of an NFT could unapprove the marketplace, + * @param nftAddress Address of NFT contract + * @param tokenId Token ID of NFT + */ + function buyItem(address nftAddress, uint256 tokenId) external payable { + Listing memory listedItem = s_listings[nftAddress][tokenId]; + // Checks + if (listedItem.seller == address(0)) { + revert NftMarketplace__NotListed(nftAddress, tokenId); + } + if (msg.value < listedItem.price) { + revert NftMarketplace__PriceNotMet(nftAddress, tokenId, listedItem.price); + } + + // Effects (Internal) + s_proceeds[listedItem.seller] += msg.value; + delete s_listings[nftAddress][tokenId]; + emit ItemBought(msg.sender, nftAddress, tokenId, listedItem.price); + + // Interactions (External) + IERC721(nftAddress).safeTransferFrom(address(this), msg.sender, tokenId); + } + + /* + * @notice Method for updating listing + * @param nftAddress Address of NFT contract + * @param tokenId Token ID of NFT + * @param newPrice Price in Wei of the item + * + * @audit-known seller can front-run a bought NFT and update the listing + */ + function updateListing(address nftAddress, uint256 tokenId, uint256 newPrice) external { + // Checks + if (newPrice <= 0) { + revert NftMarketplace__PriceMustBeAboveZero(); + } + if (msg.sender != s_listings[nftAddress][tokenId].seller) { + revert NftMarketplace__NotOwner(); + } + + // Effects (Internal) + s_listings[nftAddress][tokenId].price = newPrice; + emit ItemUpdated(msg.sender, nftAddress, tokenId, newPrice); + } + + /* + * @notice Method for withdrawing proceeds from sales + * + * @audit-known, we should emit an event for withdrawing proceeds + */ + function withdrawProceeds() external { + uint256 proceeds = s_proceeds[msg.sender]; + // Checks + if (proceeds <= 0) { + revert NftMarketplace__NoProceeds(); + } + // Effects (Internal) + s_proceeds[msg.sender] = 0; + + // Interactions (External) + (bool success,) = payable(msg.sender).call{value: proceeds}(""); + if (!success) { + revert NftMarketplace__TransferFailed(); + } + } + + function onERC721Received(address, /*operator*/ address, /*from*/ uint256, /*tokenId*/ bytes calldata /*data*/ ) + external + pure + returns (bytes4) + { + return this.onERC721Received.selector; + } + + /*////////////////////////////////////////////////////////////// + VIEW/PURE FUNCTIONS + //////////////////////////////////////////////////////////////*/ + function getListing(address nftAddress, uint256 tokenId) external view returns (Listing memory) { + return s_listings[nftAddress][tokenId]; + } + + function getProceeds(address seller) external view returns (uint256) { + return s_proceeds[seller]; + } +} \ No newline at end of file diff --git a/integration_test/dapp_tests/dapp_tests.sh b/integration_test/dapp_tests/dapp_tests.sh index a889b3d2b..0549381e4 100755 --- a/integration_test/dapp_tests/dapp_tests.sh +++ b/integration_test/dapp_tests/dapp_tests.sh @@ -8,7 +8,12 @@ fi set -e -# Build contacts repo first since we rely on that for lib.js +# Define the paths to the test files +uniswap_test="uniswap/uniswapTest.js" +steak_test="steak/SteakTests.js" +nft_test="nftMarketplace/nftMarketplaceTests.js" + +# Build contracts repo first since we rely on that for lib.js cd contracts npm ci @@ -20,5 +25,29 @@ npx hardhat compile # Set the CONFIG environment variable export DAPP_TEST_ENV=$1 -npx hardhat test --network $1 uniswap/uniswapTest.js -npx hardhat test --network $1 steak/SteakTests.js +# Determine which tests to run +if [ -z "$2" ]; then + tests=("$uniswap_test" "$steak_test" "$nft_test") +else + case $2 in + uniswap) + tests=("$uniswap_test") + ;; + steak) + tests=("$steak_test") + ;; + nft) + tests=("$nft_test") + ;; + *) + echo "Invalid test specified. Please choose either 'uniswap', 'steak', or 'nft'." + exit 1 + ;; + esac +fi + +# Run the selected tests +for test in "${tests[@]}"; do + npx hardhat test --network $1 $test +done + diff --git a/integration_test/dapp_tests/nftMarketplace/cw721_base.wasm b/integration_test/dapp_tests/nftMarketplace/cw721_base.wasm new file mode 100755 index 0000000000000000000000000000000000000000..09c700df88f5cd62d3727d16ce98ad2ec58bdc6e GIT binary patch literal 377539 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

      k>-QUQ-^w>vmoWI!t-kDg#_Yx2CNn2_{e&^Y)Yn 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ν;Yr)`^ssx0Wzjpa1QbYy1n}jC$?OM0t%`An| zl<(vNq5Wn)5bSRPaZtS8Xf?2SJr}RskFMDtvm5VrK3<}o!^SPT13war2;60Z-|uBs zai$dG`95|Xvu0l{gK?1j4%x32&y>pj)lLc&aX!zM!91QSSFeo)zdg!2aql)}+kzTb z-Wd1Nnsedx&tutn{0;THUeCLxm!I2js&Bt}vv#eO8{VY-HktQIn2DWHp$>n`e0tvIlg?+Z_eEU`<_YloI)@Jd__Qx-t#e4faw>yB zAJ$Yml|j~2YhM&}XA$`NdRG*tldLI~8#y(d$WSZ#v8b|pWa8PLwLPipEqhY!ZBOcY z%bwJA+mpIp+mkb!i&7?a?23Z@C#%^8w4R$bF>l+PefZKXV+MNnW)oAJ#aii_$a^^f z<@b?PQBw1mLnUX8Os8>s*q4X7*?8nUy_jch9vTz@llt0>84kb7d!o=N)1D|jQd{-j zL>|DHwlYalPI-s&6~z>1Vg{FPO9FoNT1O0S8t#`%(HY#u?ea>b-AP&*R}~CNa9!4= z<0vP$Bhfo7=Qzm8*8m*KvUhjMGbv0WyRefRts{T8 zJZ<8X8qp2f@q0rP;tRavT8(_sjuk4~h^lt1kjeqn$gXP)w`?Jx-+|i7ro6gcYX@=K z2B88QwLeeScw!5Gp0_}-N5f}o=ijalg!Z9nG0%~a9 z)0mcg&eqA9O{OkpDQTadVT3JIlZLK4!UP*hLd?cU@^zkQwW8 z4P?|rrTo2^Vl8~t6l`0z@Kx91Kr&;b@m1GaI9%r#w{Y0*K?I=u>-&UxT8|dgCzOWH zzW!ObbNt%2ke?`>J;6S~3N5+zZ{s<%0u~FEqXY4ap*MP0CM)1dF=q_Y3=ne;e(~&1 zA!wd;90@0)gp9pc-FL3fNMZB@ZZTURv@OcoUbnHBQPviCq|R@RvU26NfY$O&@}3W3zP*W->MhQiBKej@M_>&hzwE?zy^9*&+L-xNc6Qse~)PMa)h#HV%8Ducu6kbcrjYvaf^)e#8YuqG*n z5)1?064xvUb*oeHE&lBnKWQ&}9VOYO zT)}IXZ;?pv$iXn?gNW>v@oU5f+NZ0opiXF?L}$2`wQO-Kkq#<^NkN)2q_f2ia(V1R z1Z4d^Sd2EUM~nyxrI0)1%@_L7mr(K~Q+ags<5KX3uTV|XxQ}BeKeHvn7-gWadMIyO!CP<2SX-?0m@ z9nUhm&*(_vmG`DFc)Wp2&);3+veeZT;jXEgtqmaA%Xlk%1=q_b?gKfRoV}kNEb z$;3irbyqdUM_xO0#sSDI*CvZ8W+6=0=#%8pnXt%V?dVSg!89jD8@DJ7uq2Yr_le5q z4gSJ)dSdTsCSn?ih((XOm-l(^9D92=D8_oIqrjJDSF|r6{+j*NY61I~jT7$`|dYQdixbJD)>bx1u9KXC-eNmPys8SQFLGPUd1{-Ahy8h*|h zaq0GIrFMFv-5kZXROJTQnwlAZWv@U1W_1cCzus6l`B9w@MO zg?>@LHhbg}hXVOpTVF4b=&-Xc8bt}CpuT$Yv3?0l@`_nM(Ym(KKCM%4Ul~rp>3byTG!OZ%1tuMA$Az^gY_%Y#IFHcb0*LmQFfs_20h4|KS{mM|& z(6Y-eqhbqc7xdljZ22-1+&p;lGU~AhWx%#I_7_sQ$$R6^@3$LXm$}0YawFYPvm}!x zeD%fas*=GlEBV8SU@1Y!qz$BEcPBDKa}nJwm^7Bhb79j#t-KG~WDWTnJ|L)d^rTdT zFcrhYwBA#p|L{794F)}%25Ytz>iz%9YejpP-2NrY%1^4eQD?~&{_=O(v-$h!4{jXlR5!6;BDJGO_3LT<9i2%} zsw`t}Er(YA-tMK{Mmq8(wi%1g!%Lr}f|Jk0vb9HQd8s<}qw0ONx^LUw zTT>W6pTG_}Oxt~>1a)ioQ;{8O>sO1mBhFpxC`~GSlXjpKE~WE{1rSJ=2f+hOo-wF@ zQx<$vI;nAg>-0h!O$mm)T>Qj~a>4g^w|KwxP>1NIeRMGGt>52Us-*MhHGFR9-dcS| zp2~z~*8WVJwF}$^Fu7L%jM{W%lrZD1Uq!Q^GvnL z(M*#TCsSetJYc(oOx>-%8D1I<>Y{u!PC8kd&N$)Ozsu5;I<}h_v$EeHsX!1>S&Nqh zaY$rF2v05XfrB5|$EL;xKN?a@m;w?g+yp6Xi61JdzMIUet4ZFuW_2fF17(2Wa*|b3 z$EoZ%cfOw^P&$D$`b-{3$<$ESLDm#L23g6rR6F=WN=HJnlQU+dB(=FiVrre*EJWRu z0R2rsUI5=@YDen9Y^pX8GAGp`tmd1DCBR3GLZTJmCK-vUCKx-7#*37*+|!I;{zR@&}V3P_ZHhLy7Bd(; zU5hzeEG>VT1TMX_GDbF6(KTtwKJJiPZ;l)Ks1$r(v)UT^Yr58wNFma7-Hsf=&?>O5 zw`>w!hsc6#x3cEdzHz=JYrY+AXl9pR7J^_Vp9Tym#`9Zj+0Y0=BgGX9$Rivhn|x`s zVcP`UB%g-Ur}#oX%~BNc5~brWovP(!x>j623SHW@m?(TLV^T~ebAo_aOx)KDq<~fi zDsQ}Gw_>n@J+%#m0~{^vK^c~oaWDP?xC5VBX(Y*|!Lxg#u$RGLgO#RY&H&J%9;;X` z^=wu;&DVpl*x4q)AT`+B)&Pd{EVfgQ0jKje+Z8qg#DBM|3?t5fLEGdhk_z>joUO-r*5vbZ}vI7LC=`vZ7 z-0=+@Cp*$DM@lBtGflVbLyM#@iR3FLG(52J>)3VjQsZ{9h=)@d+T=vy{@7XS+u&=dNy1IC9u zUda{r90kAgnD)@Bg~z-ZK7P%3K~;43#MJOw2y!43zk%Fmg`q8Ap!sV_ctGi676aDJ z7us0>2$KaymE>;-lBBdSc4wWbG&` z#TZSR6NB_zy$;D_V@hGI>oEH~W1T~lQN4bV_@GZK@)|+D3)M4tcvyp29ut5@cL<^q z)bG@|ZUAfoPFP|Y+FScd(vVQ_(trhhSt`?TnH~tNBLEiANvLwOu0F-^7<8aW3@?r7 z`g%m?hYp=5D7NrHBFPl)lnzsPBScJWPVQ=vvFT8xS3A-2L)J%V$$Q?!fKiPDq=b5-D*9;K!X1Hb(Ne1M7D#wm@zcPHt(Ep<5p5RhOg{=pnFT_yZOqM zEBV;*s?Mtck!3!$9FoXccD=Oa8U|Bd zZ0@yIF?e~bLx7$I0`x*faowF_x$z4Yve^8BwJdFB*h6vnw+6!=?k(=D8Fs^?d9dN$ zvkW`lR5NUjMh5tYy5tq{c{g=Bv=*ye6?6;{$u53f$0EiBi)%_Y07hXzQQd9C@3Ysj z7dRk&mrZn>9dSVAK&pdo0EHvcb=C`)679-Imbiir&Eh=T9rP)6dXG5u&{AV4)kNGl zpzo1RfHqLv%P6%UojEhcchs!dP~Dmp8^pE_6L`&vS@Ip@k+!8Vj<;|Es;10{=H8JM z6tLfADmYKCp18F!6vx)Y$9ptsF|k@}?$UFu&Wq<4G@5(ITX--hlI#$Lke6de$PP3B zo)6stmazkBrLAf|k8h@@kzUkV6O1maC+X@a?))C35J9X3B|C3TgCPc%x;!i=1_R^t-wM zJL~1g_jRu1{AoC3Z?y!Y@mrU13((>@xN0(R#fBd`u+r;wI$eW&Q2pQmUtPebfW#~% zp$63*2Oe7gTK69O0NL|W&5Q|pN;YC>x_KpHKW|u**RHIXT0c!*WuS1RNwUj ze9Yna?5r=YcSb+OrbyQY0VZ5<2uH`AU<3cbB(iuQ=;eN zhJ0B*?J2K(L4k?Tsql65)3+r_SJj=s=2&c$E4K~d;y_Q@kuA{;VXO`gj2RUy z^w9&cQ$lsKRPjw~cq@u*ss@vuGa6$|f(EfkhuUbNe74k6KUo@%j2Bs(n+cf)(YQHX(Y9@TWc`DpUO!Dy5tdeg_CVky2Ws&Ynq)LkvQqG@?EKPd7pe zTGI5zCHvJAAp|XQJl5Ath9)oVC~^-Lf=Tot1d}+FtPUwo=MqjJ8`4jBXmpXgTAlOv zh|k)qC#BOKUnA^nssrLZLC8y~OcTFD%BIWiyauebf(gWKkJn7SIt?*d(c^l2z#@$~ zW3LFCcW(VI-n+MWVcsPs6#iu7Fak=n4{Rc$BQkOpAy-#Rs9SW-)LsM9#zNciCwk4X zRS?IB*_+17Go1rDTq+En3YWg2l?+JUwbHL|HMr9|a;Wsf?-Nq(*_7?i`?|c1xL!Nk zztpd(Y=2NISfQf&#xtfRzUg16Z>_yj*Qwl`z+Bo@#GF;xLHpi&t&D#rsYQl@?ex;x zd(})FwPI+@SKtc63KaSiG!6I|`0Hyd zRBK~Hnwj_y;H93rm%$6pYb4q5wtnygriAn4#yYrxO3gX zqpRAPk=K~-2*Dm@i^Dln=;upj4W*te?bSw2d$J_|&M}R->MRMMIDn#y+5r^TL2@5P z2olBxP|P{Ix-g!5W#`R0Yn2V>G#N<@GJofg2<1`qX}#|0Vq%{nUzv50`JXgH z4<_z97U30mRwnmMFv7KrJ0*l)()+6zbjOnJ(W8E-w5Hayeda4P!R zR#0iwSNLNA($BBcgVpEbu-H7GQ}FD%0k_iuwcLKS=61GqTUBubnm{cdT3LfP=XPhD z2;iM}4A!c731et9YY#GwA~#?ZO#{YDRjOMU3ckHq*jQl*PK&1{*Bu6#N2@zh@PwQs zWl`Abrt)t1WFvgRe6&Smn{-D)H9}m%x>m$7xx7^>a~$y=3%1O0U_s(II3H@p^P=H6 z2@<_f;!O~W!Qkz`8}Mw+j}}ma8-65)kqAp%$HqYP11ukh>xdDo6>uGVQ+vye5+#S< zkCw1tKH)-(G8N%LUGbnBwLCDgt$2{G!(~M!=?%ehewH_g9>qe&G=}(F< zY^Hw~8GoV#l@UBZoxXzTA)dKlDL6APOJAuDh>>R=%T-mK4Ct*cfZWn5o`e&r)ol zKVD4o$f~kzy81V~aS=MIe?vHnF`6J5x_?x!rTde1FpPJ(NAu)lEuje_mI5C@onQ%o4gIC%d)af>s(vA9s&7 zV(q?Sb7j0}bg=H>?&%Jk20A}(>foyV`NhlfgFtZjpolFC8pNV$W1SjA>|QaMSX~fi zOI;9mN$P@VX=rR}h^{Mo$8qiZ0cIUE7(+e=9=u#FKyEhArX-Q%6A)0;B zs;CRNe`}Fo=I)xgF!x;TlEk6@wjl}X~BCOc}ehARkGC09^+T3idJ2}d#0 zd|aO}%?*8`!J4bV-4a(5=Vk$F{|`gW49#CRyonelk{Fsd*XBb2M35Acgby-5xS81t zUwLiDa2Kfi`%qTh5x&%x-+SOc5=t01)bjI6P!5iU3b&M}-T~2*+twSjk1mP@>NKMTh=GkjVN12 zKt0IX!Mur2iG%NcXmtpq?!rY?J$Sc52qqQ0xCk>87mwsh{kTd$!04f$ly=#pwKo&7C6cGFk)5R;M1;mE#o;=mG=ajqL$2o+akj zk`x#v;#)J4LIrXp8)`|>ZA*%H=lP{EAjw7Q;cMD9)~Wembm6RSJEygd&tG4p(vnNQs{ zlbc7A9)M=JS@YNbp^b4`u|PSkuyAJv=Y+eLkF}JlxXr#90Pu1dIe8$%mp4Woj4biE zMZP(`0S1;tG#}T%Da`6z8D2FL&Eqf%#N1HLbVvyV_{|sQn|T~e0--yA0o?Vf&Vw3c zC`nATW!Hs$SSw!mL!;s7t5TJwnBl?{Gn^nyPXzA?t=H`EV|tIYW+L?f9cO7iTqSW- zcQO{s3OClt=mNiwmA8%jJiSmv|CfK5LFh>sLAEgU0OpCUAd&(+^w148zbq=8}`2Klm?%?=52q))%$A9s6wBG0~F%XFcPMMcUm)1vIKiSl`OH_)migYl{ewN3&e2u zJu^;1D79AXs(9KamQrls?$P4D)-U7 zxN-|Jyy8>x3id%pPE%iA3hsc%pUQgc*MJiGpmRz&v?#Nno%#w*x-jM~)CbFu^(xXRbOF zx>$A{p2N{}heq&hfx^q@GX>A_`E;?m8^{{JWYa)+LXAuE0grcR^nIwVm7EgGc76@w zNMp|*o^eyhETfZ0n`Us@DMf>soM`TTY-^{0b*#%<`jxuPhR2qg2bn2y+c zCKmTF?mnYLnCxvNzavhQ6KJ;^uI|NPSM@apyDCOmOLeVH^A?Gu+U+G_WAEj|Fecfi zv7Q?`noTb)(KqmIm?7j1=;E&VyHunLea{=#=c?n(bgTLd7jA*?O6Fll;!O@|*t1d_ zVAh;0AU2{52Usw{MWw?jhvW)z@XmM_f(>5S8UBw1{8p{wNx2(dE1+P10Vi`!J|j#k zQj+$P47;eyU$C}_TKq`zxoKS2wr=MjsSED?H7Ui4P)Xfl0Iv;3Rjn^%IC)s%VnNI>-(G z$LmLrXgGTHS!keZzoxaTc1Io6Xo@G>%#aYLDmiK3ollqhJ71BApeLD^ysWF2Jz-bZ zv7{5Zu|gR)0p@5Bo_+_wp0xwJ9`n<1t-E7}aLkZ_=JGYA=mjDVs8LvupOmbz5+ZZ` z=Z*BbYlAUvc+WFKWJr4%Oe9H0`cnW=59b{~!`;!a+`zR5E`(53i<&YWz7FlV z7Kjd<$F(dBhg56GcsyJAa2AvQs9EBT7A8Mqt*d_dCN!1;q$$bXM0yIHw?Jd?SHzd% zMn+>M8H3GXBBZCoZXyU1hGf6Yc%T0${2do2u0T-T`BkA)tZaP|<~E2#9ZRrS(u}ks z4&pSDpILJbECG$0P$m+@US);>m9~7!H3AIU2mpdL81RhKcD|h#FrsM;aJ_KR?(<() zGAlB+ADY5rN17kISWH7@e(f?PF7>A^6F9x0v;F}P!W&+MSY)2SdPW(YYUCMxp)q%Y z#dx7SN!%>1jTHuzHACT%GX_$q(Zp}(wT{&CzCAj{~9tP#?c5Sv-?SJM5xZj3WYK2fecY4#Nl1orX>b6MlP zIa%QmGblQq$1^%7Jzn3zYd(7Nyom^o`ju|P77nS7p+!0diE_ThvrIwiJkkZgT^m>v zQGNip+XgUA0W^a8Ks9l}K{SR0ZJyObijFNS{3SwL8GWc(oaR}ATDZr4ObDSs%Ao4o zUv?~C@T0Z_=C$Nu@Tp_R)pWPmy5s5>o{j2}YJ#Q7<8(k^K&KZ6G8S!a8rUhGT8!=$ zg(p*SBLw57W!MIGfS6Hs8nJ(l=MB}+W-W*hPcbl-2lIi!f$s-vIefRkS^Ex@T{3@QOAbdl0NLH6-fQxCRo`k&ZH09#t~cF=?zL+x)l zUANjXZnYY+3nZxiUbao_s-a4pKOu|9)q{SbwTr19WC)oJNKrFRZ zLL&jhT2xEv;#KzMkvBuS)dUB)JBGfosX`-$VW^e7WKYJ|MaDf>J>?&vx1*^`ZzpL% zdOKRYbOtC^8ZbJ8G~g&6;ehb>6r&JGFr^tTE;e=Sgm6G-(aq?fr*s^%!3AZwn% zpn&X?n(5#~(10`spFCCJwS=jfkLNDJQzD6T9^UzA8Je)DiPz~>`*=e`6jDwSPnzv2 zvo~Eo4}1HxhaXenb*8Y;g;C!Cd#$UI1j2liE^L;$oi21vJdfd$)|GW381)5pArjph zUFcV=3q4eWTQMWD}& zzK4=3ejm9ic6@7Vm;r0oxUvq>DZwg`x;77bZwJX(%h9I}!&CVVjY*BYLlXs{=-R!Z=pS9;!JvW})Ba$}zIg*mMyg$C5=DYlzPngg*x=fMf z#;m+tvLXJBnG;VyduL@~ff43PMfL9gS$shh(NDfqG98er+A>g#j%i1WcJM^}mH1v} z9-0xoDM3-6&ddQo@<}V1{Hz5tHw-at+9HZHUUXOwnx>Hmq2<=ST?~cl&)Q{DO*wXz zhJaUAf9#draW(FhV#d$QE9K`krztXEiaO7qq9r4xH~+*S-Y8=(S0q@Q_Jk^IrJ4T3vx#UgzaL>#)%U{QjCECl0xq+5Gr zADi;XZX{2Hfhxa-T0c7DkwwF{4E<~CTQoq4)`7KSv@^h+YCmc>5TgpMBu`P#;kE@E zyMTH~5<)a-4_~jmLz^W@gfaxPzpLd3GnJ(4YEOLJ3$0iQ?`k~wd4Uaod1j{;2QRRTqiLp|8!mu6ovGYFA$E*(jWy^(d&ZZd>v1I^c≤p@ekjV_$L%2 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 literal 0 HcmV?d00001 diff --git a/integration_test/dapp_tests/nftMarketplace/nftMarketplaceTests.js b/integration_test/dapp_tests/nftMarketplace/nftMarketplaceTests.js new file mode 100644 index 000000000..3b1fde0df --- /dev/null +++ b/integration_test/dapp_tests/nftMarketplace/nftMarketplaceTests.js @@ -0,0 +1,178 @@ +const { expect } = require("chai"); +const hre = require("hardhat"); + +const {sendFunds, deployEthersContract, estimateAndCall, deployCw721WithPointer, setupAccountWithMnemonic, + mintCw721 +} = require("../utils"); +const { fundAddress, getSeiAddress, execute } = require("../../../contracts/test/lib.js"); +const {evmRpcUrls, chainIds, rpcUrls} = require("../constants"); + +const testChain = process.env.DAPP_TEST_ENV; +console.log("testChain", testChain); +describe("NFT Marketplace", function () { + + let marketplace, deployer, erc721token, erc721PointerToken, cw721Address, originalSeidConfig; + + 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); + + 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`) + + 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); + 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) + }) + + describe("Orders", function () { + 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) { + const nftOwner = await nftContract.ownerOf(nftId); + expect(nftOwner).to.equal(deployer.address); + tokenId = nftId; + } else { + // Refers to the first token owned by the deployer. + tokenId = await nftContract.tokenOfOwnerByIndex(deployer.address, 0); + } + + if (seller.address !== deployer.address) { + if (expectTransferFail) { + // Transfer to unassociated address should fail if seller is not associated. + expect(nftContract.transferFrom(deployer.address, seller.address, tokenId)).to.be.reverted; + + // Associate the seller from here. + await sendFunds("0.01", seller.address, seller); + } + + // Send one NFT to the seller so they can list it. + await estimateAndCall(nftContract, "transferFrom", [deployer.address, seller.address, tokenId]); + + let nftOwner = await nftContract.ownerOf(tokenId); + + // Seller should have the token here + expect(nftOwner).to.equal(seller.address, "NFT should have been transferred to the seller"); + } + + const sellerNftbalance = await nftContract.balanceOf(seller.address); + // Deployer should have at least one token here. + expect(Number(sellerNftbalance)).to.be.greaterThanOrEqual(1, "Seller must have at least 1 NFT remaining") + + // List the NFT on the marketplace contract. + const nftPrice = hre.ethers.utils.parseEther("0.1"); + await estimateAndCall(nftContract.connect(seller), "setApprovalForAll", [marketplace.address, true]) + await estimateAndCall(marketplace.connect(seller), "listItem", [nftContract.address, tokenId, nftPrice]) + + // Confirm that the NFT was listed. + const listing = await marketplace.getListing(nftContract.address, tokenId); + expect(listing.price).to.equal(nftPrice, "Listing price should be correct"); + expect(listing.seller).to.equal(seller.address, "Listing seller should be correct"); + + // Buyer purchases the NFT from the marketplace contract. + if (expectTransferFail) { + // We expect a revert here if the buyer address is not associated, since pointer tokens cant be transferred to buyer. + expect(marketplace.connect(buyer).buyItem(nftContract.address, tokenId, {value: nftPrice})).to.be.reverted; + + // Associate buyer here. + await sendFunds('0.01', buyer.address, buyer); + } + await estimateAndCall(marketplace.connect(buyer), "buyItem", [nftContract.address, tokenId], nftPrice); + + 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); + expect(nftOwner).to.equal(buyer.address, "NFT should have been transferred to the buyer."); + } + + it("Should allow listing and buying erc721 by associated users", async function () { + // Create and fund buyer account + const buyerWallet = hre.ethers.Wallet.createRandom(); + const buyer = buyerWallet.connect(hre.ethers.provider); + await sendFunds("0.5", buyer.address, deployer) + + await testNFTMarketplaceOrder(buyer, deployer, erc721token) + }); + + it("Should allow listing and buying erc721 by unassociated users", async function () { + // Create and fund seller account + const sellerWallet = hre.ethers.Wallet.createRandom(); + const seller = sellerWallet.connect(hre.ethers.provider); + await sendFunds("0.5", seller.address, deployer) + + // Create and fund buyer account + const buyerWallet = hre.ethers.Wallet.createRandom(); + const buyer = buyerWallet.connect(hre.ethers.provider); + await sendFunds("0.5", buyer.address, deployer) + + await testNFTMarketplaceOrder(buyer, seller, erc721token); + }); + + it("Should allow listing and buying erc721 pointer by associated users", async function () { + // Create and fund buyer account + const buyerWallet = hre.ethers.Wallet.createRandom(); + 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'); + }); + + it("Currently does not allow listing or buying erc721 pointer by unassociated users", async function () { + // Create and fund seller account + const sellerWallet = hre.ethers.Wallet.createRandom(); + const seller = sellerWallet.connect(hre.ethers.provider); + await sendFunds("0.5", seller.address, deployer) + + // Create and fund buyer account + const buyerWallet = hre.ethers.Wallet.createRandom(); + const buyer = buyerWallet.connect(hre.ethers.provider); + await sendFunds("0.5", buyer.address, deployer) + + await testNFTMarketplaceOrder(buyer, seller, erc721PointerToken, '2', true); + }); + }) + + after(async function () { + // Set the chain back to regular state + 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 c1617b5c5..5aa2af6c1 100644 --- a/integration_test/dapp_tests/package-lock.json +++ b/integration_test/dapp_tests/package-lock.json @@ -288,6 +288,23 @@ "typechain": "^8.0.0" } }, + "node_modules/@ethereum-waffle/compiler/node_modules/@typechain/ethers-v5": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/@typechain/ethers-v5/-/ethers-v5-10.2.1.tgz", + "integrity": "sha512-n3tQmCZjRE6IU4h6lqUGiQ1j866n5MTCBJreNEHHVWXa2u9GJTaeYyU1/k+1qLutkyw+sS6VAN+AbeiTqsxd/A==", + "peer": true, + "dependencies": { + "lodash": "^4.17.15", + "ts-essentials": "^7.0.1" + }, + "peerDependencies": { + "@ethersproject/abi": "^5.0.0", + "@ethersproject/providers": "^5.0.0", + "ethers": "^5.1.3", + "typechain": "^8.1.1", + "typescript": ">=4.3.0" + } + }, "node_modules/@ethereum-waffle/ens": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/@ethereum-waffle/ens/-/ens-4.0.3.tgz", @@ -886,7 +903,6 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "license": "MIT", "dependencies": { "@ethersproject/abi": "^5.7.0", "@ethersproject/abstract-provider": "^5.7.0", @@ -941,7 +957,6 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "license": "MIT", "dependencies": { "@ethersproject/abstract-signer": "^5.7.0", "@ethersproject/basex": "^5.7.0", @@ -971,7 +986,6 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "license": "MIT", "dependencies": { "@ethersproject/abstract-signer": "^5.7.0", "@ethersproject/address": "^5.7.0", @@ -1057,7 +1071,6 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "license": "MIT", "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/sha2": "^5.7.0" @@ -1267,7 +1280,6 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "license": "MIT", "dependencies": { "@ethersproject/bignumber": "^5.7.0", "@ethersproject/bytes": "^5.7.0", @@ -1339,7 +1351,6 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "license": "MIT", "dependencies": { "@ethersproject/bignumber": "^5.7.0", "@ethersproject/constants": "^5.7.0", @@ -1360,7 +1371,6 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "license": "MIT", "dependencies": { "@ethersproject/abstract-provider": "^5.7.0", "@ethersproject/abstract-signer": "^5.7.0", @@ -1416,7 +1426,6 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "license": "MIT", "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/hash": "^5.7.0", @@ -1965,8 +1974,7 @@ "node_modules/@openzeppelin/contracts": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-5.0.2.tgz", - "integrity": "sha512-ytPc6eLGcHHnapAZ9S+5qsdomhjo6QBHTDRRBFfTxXIpsicMhVPouPgmUPebZZZGX7vt9USA+Z+0M0dSVtSUEA==", - "license": "MIT" + "integrity": "sha512-ytPc6eLGcHHnapAZ9S+5qsdomhjo6QBHTDRRBFfTxXIpsicMhVPouPgmUPebZZZGX7vt9USA+Z+0M0dSVtSUEA==" }, "node_modules/@openzeppelin/test-helpers": { "version": "0.5.16", @@ -3512,23 +3520,6 @@ "node": ">=4" } }, - "node_modules/@typechain/ethers-v5": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/@typechain/ethers-v5/-/ethers-v5-10.2.1.tgz", - "integrity": "sha512-n3tQmCZjRE6IU4h6lqUGiQ1j866n5MTCBJreNEHHVWXa2u9GJTaeYyU1/k+1qLutkyw+sS6VAN+AbeiTqsxd/A==", - "peer": true, - "dependencies": { - "lodash": "^4.17.15", - "ts-essentials": "^7.0.1" - }, - "peerDependencies": { - "@ethersproject/abi": "^5.0.0", - "@ethersproject/providers": "^5.0.0", - "ethers": "^5.1.3", - "typechain": "^8.1.1", - "typescript": ">=4.3.0" - } - }, "node_modules/@types/abstract-leveldown": { "version": "7.2.5", "resolved": "https://registry.npmjs.org/@types/abstract-leveldown/-/abstract-leveldown-7.2.5.tgz", @@ -5731,7 +5722,6 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "license": "MIT", "dependencies": { "@ethersproject/abi": "5.7.0", "@ethersproject/abstract-provider": "5.7.0", diff --git a/integration_test/dapp_tests/package.json b/integration_test/dapp_tests/package.json index bd6d8ef52..d58091898 100644 --- a/integration_test/dapp_tests/package.json +++ b/integration_test/dapp_tests/package.json @@ -17,8 +17,8 @@ "ethers": "^5.7.2" }, "devDependencies": { - "it-each": "^0.5.0", "hardhat": "^2.22.6", + "it-each": "^0.5.0", "uuid": "^10.0.0" } } diff --git a/integration_test/dapp_tests/uniswap/uniswapTest.js b/integration_test/dapp_tests/uniswap/uniswapTest.js index 9347abe07..347bb62f0 100755 --- a/integration_test/dapp_tests/uniswap/uniswapTest.js +++ b/integration_test/dapp_tests/uniswap/uniswapTest.js @@ -7,7 +7,7 @@ const { abi: MANAGER_ABI, bytecode: MANAGER_BYTECODE } = require("@uniswap/v3-pe 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 } = require("../utils.js") +const { deployTokenPool, supplyLiquidity, deployCw20WithPointer, deployEthersContract, sendFunds, pollBalance, setupAccountWithMnemonic, estimateAndCall } = require("../utils") const { rpcUrls, chainIds, evmRpcUrls} = require("../constants") const { expect } = require("chai"); @@ -53,7 +53,7 @@ describe("Uniswap Test", function () { const userWallet = hre.ethers.Wallet.createRandom(); user = userWallet.connect(hre.ethers.provider); - await sendFunds("5", user.address, deployer) + await sendFunds("1", user.address, deployer) const deployerSeiAddr = await getSeiAddress(deployer.address); @@ -94,7 +94,7 @@ describe("Uniswap Test", function () { // Deploy SwapRouter router = await deployEthersContract("SwapRouter", SWAP_ROUTER_ABI, SWAP_ROUTER_BYTECODE, deployer, deployParams=[factory.address, weth9.address]); - const amountETH = hre.ethers.utils.parseEther("30") + 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 }) @@ -109,9 +109,9 @@ describe("Uniswap Test", function () { await deployTokenPool(manager, weth9.address, erc20cw20.address) // Add Liquidity to pools - await supplyLiquidity(manager, deployer.address, weth9, token, hre.ethers.utils.parseEther("10"), hre.ethers.utils.parseEther("10")) - await supplyLiquidity(manager, deployer.address, weth9, erc20TokenFactory, hre.ethers.utils.parseEther("10"), hre.ethers.utils.parseEther("10")) - await supplyLiquidity(manager, deployer.address, weth9, erc20cw20, hre.ethers.utils.parseEther("10"), hre.ethers.utils.parseEther("10")) + 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 () { @@ -120,20 +120,18 @@ describe("Uniswap Test", function () { const fee = 3000; // Fee tier (0.3%) // Perform a Swap - const amountIn = hre.ethers.utils.parseEther("1"); + 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(); + // const gasLimit = hre.ethers.utils.hexlify(1000000); // Example gas limit + // const gasPrice = await hre.ethers.provider.getGasPrice(); - const deposit = await token1.connect(user).deposit({ value: amountIn, gasLimit, gasPrice }); - await deposit.wait(); + await estimateAndCall(token1.connect(user), "deposit", [], amountIn) const token1balance = await token1.connect(user).balanceOf(user.address); expect(token1balance).to.equal(amountIn.toString(), "token1 balance should be equal to value passed in") - const approval = await token1.connect(user).approve(router.address, amountIn, {gasLimit, gasPrice}); - await approval.wait(); + await estimateAndCall(token1.connect(user), "approve", [router.address, amountIn]) const allowance = await token1.allowance(user.address, router.address); // Change to expect @@ -151,7 +149,7 @@ describe("Uniswap Test", function () { sqrtPriceLimitX96: 0 }, {gasLimit, gasPrice})).to.be.reverted; } else { - const tx = await router.connect(user).exactInputSingle({ + await estimateAndCall(router.connect(user), "exactInputSingle", [{ tokenIn: token1.address, tokenOut: token2.address, fee, @@ -160,12 +158,10 @@ describe("Uniswap Test", function () { amountIn, amountOutMinimum: amountOutMin, sqrtPriceLimitX96: 0 - }, {gasLimit, gasPrice}); - - await tx.wait(); + }]) // Check User's MockToken Balance - const balance = BigInt(await token2.balanceOf(user.address)); + const balance = await token2.balanceOf(user.address); // Check that it's more than 0 (no specified amount since there might be slippage) expect(Number(balance)).to.greaterThan(0, "Token2 should have been swapped successfully.") } @@ -181,22 +177,17 @@ describe("Uniswap Test", function () { const fee = 3000; // Fee tier (0.3%) // Perform a Swap - const amountIn = hre.ethers.utils.parseEther("1"); + const amountIn = hre.ethers.utils.parseEther("0.1"); const amountOutMin = hre.ethers.utils.parseEther("0"); // Minimum amount of MockToken expected - let gasPrice = await deployer.getGasPrice(); - let gasLimit = token1.estimateGas.deposit({ value: amountIn }); - const deposit = await token1.deposit({ value: amountIn, gasPrice, gasLimit }); - await deposit.wait(); + await estimateAndCall(token1, "deposit", [], amountIn) const token1balance = await token1.balanceOf(deployer.address); // Check that deployer has amountIn amount of token1 expect(Number(token1balance)).to.greaterThanOrEqual(Number(amountIn), "token1 balance should be received by user") - gasLimit = token1.estimateGas.approve(router.address, amountIn); - const approval = await token1.approve(router.address, amountIn, {gasPrice, gasLimit}); - await approval.wait(); + await estimateAndCall(token1, "approve", [router.address, amountIn]) const allowance = await token1.allowance(deployer.address, router.address); // Check that deployer has approved amountIn amount of token1 to be used by router @@ -212,15 +203,12 @@ describe("Uniswap Test", function () { amountOutMinimum: amountOutMin, sqrtPriceLimitX96: 0 } - gasLimit = router.estimateGas.exactInputSingle(txParams); if (expectSwapFail) { - expect(router.exactInputSingle(txParams, {gasPrice, gasLimit})).to.be.reverted; + expect(router.exactInputSingle(txParams)).to.be.reverted; } else { // Perform the swap, with recipient being the unassociated account. - const tx = await router.exactInputSingle(txParams, {gasPrice, gasLimit}); - - await tx.wait(); + await estimateAndCall(router, "exactInputSingle", [txParams]) // Check User's MockToken Balance const balance = await pollBalance(token2, unassocUser.address, function(bal) {return bal === 0}); @@ -281,7 +269,7 @@ describe("Uniswap Test", function () { 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("5", unassocUser.address, deployer) + await sendFunds("0.5", unassocUser.address, deployer) await deployTokenPool(manager.connect(unassocUser), erc20TokenFactory.address, token.address) }) @@ -291,18 +279,15 @@ describe("Uniswap Test", function () { const unassocUser = unassocUserWallet.connect(hre.ethers.provider); // Fund the user account - await sendFunds("2", unassocUser.address, deployer) + await sendFunds("0.5", unassocUser.address, deployer) const erc20TokenFactoryAmount = "100000" - let gasPrice = deployer.getGasPrice(); - let gasLimit = erc20TokenFactory.estimateGas.transfer(unassocUser.address, erc20TokenFactoryAmount); - const tx = await erc20TokenFactory.transfer(unassocUser.address, erc20TokenFactoryAmount, {gasPrice, gasLimit}); - await tx.wait(); + + await estimateAndCall(erc20TokenFactory, "transfer", [unassocUser.address, erc20TokenFactoryAmount]) const mockTokenAmount = "100000" - gasLimit = token.estimateGas.transfer(unassocUser.address, mockTokenAmount); - const tx2 = await token.transfer(unassocUser.address, mockTokenAmount, {gasPrice, gasLimit}); - await tx2.wait(); + await estimateAndCall(token, "transfer", [unassocUser.address, mockTokenAmount]) + const managerConnected = manager.connect(unassocUser); const erc20TokenFactoryConnected = erc20TokenFactory.connect(unassocUser); const mockTokenConnected = token.connect(unassocUser); diff --git a/integration_test/dapp_tests/utils.js b/integration_test/dapp_tests/utils.js index 31a22a7f9..9c66a92a0 100644 --- a/integration_test/dapp_tests/utils.js +++ b/integration_test/dapp_tests/utils.js @@ -1,31 +1,15 @@ const {v4: uuidv4} = require("uuid"); const hre = require("hardhat"); -const { ABI, deployErc20PointerForCw20, getSeiAddress, deployWasm, execute, delay, isDocker } = require("../../contracts/test/lib.js"); +const { ABI, deployErc20PointerForCw20, deployErc721PointerForCw721, getSeiAddress, deployWasm, execute, delay, isDocker } = require("../../contracts/test/lib.js"); const path = require('path') async function deployTokenPool(managerContract, firstTokenAddr, secondTokenAddr, swapRatio=1, fee=3000) { const sqrtPriceX96 = BigInt(Math.sqrt(swapRatio) * (2 ** 96)); // Initial price (1:1) - const gasPrice = await hre.ethers.provider.getGasPrice(); const [token0, token1] = tokenOrder(firstTokenAddr, secondTokenAddr); - let gasLimit = await managerContract.estimateGas.createAndInitializePoolIfNecessary( - token0.address, - token1.address, - fee, - sqrtPriceX96, - ); - - gasLimit = gasLimit.mul(12).div(10) + await estimateAndCall(managerContract, "createAndInitializePoolIfNecessary", [token0.address, token1.address, fee, sqrtPriceX96]) // token0 addr must be < token1 addr - const poolTx = await managerContract.createAndInitializePoolIfNecessary( - token0.address, - token1.address, - fee, - sqrtPriceX96, - {gasLimit, gasPrice} - ); - await poolTx.wait(); console.log("Pool created and initialized"); } @@ -34,45 +18,18 @@ async function supplyLiquidity(managerContract, recipientAddr, firstTokenContrac // Define the amount of tokens to be approved and added as liquidity console.log("Supplying liquidity to pool") const [token0, token1] = tokenOrder(firstTokenContract.address, secondTokenContract.address, firstTokenAmt, secondTokenAmt); - const gasPrice = await hre.ethers.provider.getGasPrice(); - - let gasLimit = await firstTokenContract.estimateGas.approve(managerContract.address, firstTokenAmt); - gasLimit = gasLimit.mul(12).div(10) // Approve the NonfungiblePositionManager to spend the specified amount of firstToken - const approveFirstTokenTx = await firstTokenContract.approve(managerContract.address, firstTokenAmt, {gasLimit, gasPrice}); - await approveFirstTokenTx.wait(); + await estimateAndCall(firstTokenContract, "approve", [managerContract.address, firstTokenAmt]); let allowance = await firstTokenContract.allowance(recipientAddr, managerContract.address); let balance = await firstTokenContract.balanceOf(recipientAddr); - gasLimit = await secondTokenContract.estimateGas.approve(managerContract.address, secondTokenAmt); - gasLimit = gasLimit.mul(12).div(10) // Approve the NonfungiblePositionManager to spend the specified amount of secondToken - const approveSecondTokenTx = await secondTokenContract.approve(managerContract.address, secondTokenAmt, {gasLimit, gasPrice}); - await approveSecondTokenTx.wait(); - - allowance = await secondTokenContract.allowance(recipientAddr, managerContract.address); - balance = await secondTokenContract.balanceOf(recipientAddr); - - gasLimit = await managerContract.estimateGas.mint({ - token0: token0.address, - token1: token1.address, - fee: 3000, // Fee tier (0.3%) - tickLower: -887220, - tickUpper: 887220, - amount0Desired: token0.amount, - amount1Desired: token1.amount, - amount0Min: 0, - amount1Min: 0, - recipient: recipientAddr, - deadline: Math.floor(Date.now() / 1000) + 60 * 10, // 10 minutes from now - }) - - gasLimit = gasLimit.mul(12).div(10) + await estimateAndCall(secondTokenContract, "approve", [managerContract.address, secondTokenAmt]) // Add liquidity to the pool - const liquidityTx = await managerContract.mint({ + await estimateAndCall(managerContract, "mint", [{ token0: token0.address, token1: token1.address, fee: 3000, // Fee tier (0.3%) @@ -84,9 +41,8 @@ async function supplyLiquidity(managerContract, recipientAddr, firstTokenContrac amount1Min: 0, recipient: recipientAddr, deadline: Math.floor(Date.now() / 1000) + 60 * 10, // 10 minutes from now - }, {gasLimit, gasPrice}); + }]); - await liquidityTx.wait(); console.log("Liquidity added"); } @@ -122,6 +78,19 @@ async function deployCw20WithPointer(deployerSeiAddr, signer, time, evmRpc="") { return {"pointerContract": pointerContract, "cw20Address": cw20Address} } +async function deployCw721WithPointer(deployerSeiAddr, signer, time, evmRpc="") { + const CW721_BASE_PATH = (await isDocker()) ? '../integration_test/dapp_tests/nftMarketplace/cw721_base.wasm' : path.resolve(__dirname, '../dapp_tests/nftMarketplace/cw721_base.wasm') + const cw721Address = await deployWasm(CW721_BASE_PATH, deployerSeiAddr, "cw721", { + "name": `testCw721${time}`, + "symbol": "TESTNFT", + "minter": deployerSeiAddr, + "withdraw_address": deployerSeiAddr, + }, deployerSeiAddr); + const pointerAddr = await deployErc721PointerForCw721(hre.ethers.provider, cw721Address, deployerSeiAddr, evmRpc); + const pointerContract = new hre.ethers.Contract(pointerAddr, ABI.ERC721, signer); + return {"pointerContract": pointerContract, "cw721Address": cw721Address} +} + async function deployEthersContract(name, abi, bytecode, deployer, deployParams=[]) { const contract = new hre.ethers.ContractFactory(abi, bytecode, deployer); const deployTx = contract.getDeployTransaction(...deployParams); @@ -141,6 +110,12 @@ 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}`); + } + const gasLimit = await signer.estimateGas({ to: recipient, value: hre.ethers.utils.parseEther(amountSei) @@ -159,6 +134,50 @@ async function sendFunds(amountSei, recipient, signer) { await fundUser.wait(); } +async function estimateAndCall(contract, method, args=[], value=0) { + let gasLimit; + try { + if (value) { + gasLimit = await contract.estimateGas[method](...args, {value: value}); + } else { + gasLimit = await contract.estimateGas[method](...args); + } + } catch (error) { + if (error.data) { + console.error("Transaction revert reason:", hre.ethers.utils.toUtf8String(error.data)); + } else { + console.error("Error fulfilling order:", error); + } + } + const gasPrice = await contract.signer.getGasPrice(); + let output; + if (value) { + output = await contract[method](...args, {gasPrice, gasLimit, value}) + } else { + output = await contract[method](...args, {gasPrice, gasLimit}) + } + await output.wait(); + return output; +} + +const mintCw721 = async (contractAddress, address, id) => { + const msg = { + mint: { + token_id: `${id}`, + owner: `${address}`, + token_uri:"" + }, + }; + const jsonString = JSON.stringify(msg).replace(/"/g, '\\"'); + const command = `seid tx wasm execute ${contractAddress} "${jsonString}" --from=${address} --gas=500000 --gas-prices=0.1usei --broadcast-mode=block -y --output=json`; + const output = await execute(command); + const response = JSON.parse(output); + if (response.code !== 0) { + throw new Error(response.raw_log); + } + return response; +}; + async function pollBalance(erc20Contract, address, criteria, maxAttempts=3) { let bal = 0; let attempt = 1; @@ -355,14 +374,17 @@ module.exports = { harvest, queryTokenBalance, addAccount, + estimateAndCall, addDeployerAccount, setupAccountWithMnemonic, transferTokens, deployTokenPool, supplyLiquidity, deployCw20WithPointer, + deployCw721WithPointer, deployEthersContract, doesTokenFactoryDenomExist, pollBalance, - sendFunds + sendFunds, + mintCw721 }; \ No newline at end of file From d5f2a57e21b93c8ef2690003711802cd29e762d3 Mon Sep 17 00:00:00 2001 From: Uday Patil Date: Fri, 6 Sep 2024 08:50:42 -0500 Subject: [PATCH 38/38] Bump dependencies (#1839) --- app/app.go | 2 +- go.mod | 6 +++--- go.sum | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/app.go b/app/app.go index cd13480a2..c6881ae2c 100644 --- a/app/app.go +++ b/app/app.go @@ -1040,7 +1040,7 @@ func (app *App) SetStoreUpgradeHandlers() { // configure store loader that checks if version == upgradeHeight and applies store upgrades app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades)) } - // TODO: change this upgrade name if the planned upgrade version number ends up changing more + if (upgradeInfo.Name == "v5.8.0") && !app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) { dexStoreKeyName := "dex" storeUpgrades := storetypes.StoreUpgrades{ diff --git a/go.mod b/go.mod index edb3e5ae0..f8063c924 100644 --- a/go.mod +++ b/go.mod @@ -344,14 +344,14 @@ require ( ) replace ( - github.com/CosmWasm/wasmd => github.com/sei-protocol/sei-wasmd v0.2.4-0.20240816184629-eb6d20caf603 + github.com/CosmWasm/wasmd => github.com/sei-protocol/sei-wasmd v0.2.4 github.com/confio/ics23/go => github.com/cosmos/cosmos-sdk/ics23/go v0.8.0 - github.com/cosmos/cosmos-sdk => github.com/sei-protocol/sei-cosmos v0.3.34 + github.com/cosmos/cosmos-sdk => github.com/sei-protocol/sei-cosmos v0.3.35 github.com/cosmos/iavl => github.com/sei-protocol/sei-iavl v0.1.9 github.com/cosmos/ibc-go/v3 => github.com/sei-protocol/sei-ibc-go/v3 v3.3.2 github.com/ethereum/go-ethereum => github.com/sei-protocol/go-ethereum v1.13.5-sei-22 github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 - github.com/sei-protocol/sei-db => github.com/sei-protocol/sei-db v0.0.43 + github.com/sei-protocol/sei-db => github.com/sei-protocol/sei-db v0.0.44 // Latest goleveldb is broken, we have to stick to this version github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 github.com/tendermint/tendermint => github.com/sei-protocol/sei-tendermint v0.3.8 diff --git a/go.sum b/go.sum index bfd59e249..256d52167 100644 --- a/go.sum +++ b/go.sum @@ -1347,10 +1347,10 @@ github.com/sei-protocol/go-ethereum v1.13.5-sei-22 h1:t/m1qXER+DEMrcpqgoYmUxifkA github.com/sei-protocol/go-ethereum v1.13.5-sei-22/go.mod h1:kcRZmuzRn1lVejiFNTz4l4W7imnpq1bDAnuKS/RyhbQ= github.com/sei-protocol/goutils v0.0.2 h1:Bfa7Sv+4CVLNM20QcpvGb81B8C5HkQC/kW1CQpIbXDA= github.com/sei-protocol/goutils v0.0.2/go.mod h1:iYE2DuJfEnM+APPehr2gOUXfuLuPsVxorcDO+Tzq9q8= -github.com/sei-protocol/sei-cosmos v0.3.34 h1:U2TqBEMJC9ztDqSxi7ET+HEEx0CyyAs6D+Y5VOfYTAc= -github.com/sei-protocol/sei-cosmos v0.3.34/go.mod h1:og/KbejR/zSQ8otapODEDU9zYNhFSUDbq9+tgeYePyU= -github.com/sei-protocol/sei-db v0.0.43 h1:m9kIWqSBCvKRLPGbAttlqCytIlPxVZbKchAEbVKSHHk= -github.com/sei-protocol/sei-db v0.0.43/go.mod h1:F/ZKZA8HJPcUzSZPA8yt6pfwlGriJ4RDR4eHKSGLStI= +github.com/sei-protocol/sei-cosmos v0.3.35 h1:mPj5AE21DE5Zpe4UzMv2YwsaPm8mCFLbb0WQoDL4AnQ= +github.com/sei-protocol/sei-cosmos v0.3.35/go.mod h1:ZwWxF/69WlcLEn4BzVjPPToTFkE2sjPanU8PNNyKoOk= +github.com/sei-protocol/sei-db v0.0.44 h1:HMgcyDTQlmXdJysHJxmIo66EKeXn1CSQT9qXDnxjJgI= +github.com/sei-protocol/sei-db v0.0.44/go.mod h1:F/ZKZA8HJPcUzSZPA8yt6pfwlGriJ4RDR4eHKSGLStI= github.com/sei-protocol/sei-iavl v0.1.9 h1:y4mVYftxLNRs6533zl7N0/Ch+CzRQc04JDfHolIxgBE= github.com/sei-protocol/sei-iavl v0.1.9/go.mod h1:7PfkEVT5dcoQE+s/9KWdoXJ8VVVP1QpYYPLdxlkSXFk= github.com/sei-protocol/sei-ibc-go/v3 v3.3.2 h1:BaMZ6gjwqe3R/5dLmcJ1TkSZ3omcWy2TjaAZAeOJH44= @@ -1359,8 +1359,8 @@ github.com/sei-protocol/sei-tendermint v0.3.8 h1:9o+A3tL6q1ki++dLng/J8MHHiT6y3l7 github.com/sei-protocol/sei-tendermint v0.3.8/go.mod h1:4LSlJdhl3nf3OmohliwRNUFLOB1XWlrmSodrIP7fLh4= github.com/sei-protocol/sei-tm-db v0.0.5 h1:3WONKdSXEqdZZeLuWYfK5hP37TJpfaUa13vAyAlvaQY= github.com/sei-protocol/sei-tm-db v0.0.5/go.mod h1:Cpa6rGyczgthq7/0pI31jys2Fw0Nfrc+/jKdP1prVqY= -github.com/sei-protocol/sei-wasmd v0.2.4-0.20240816184629-eb6d20caf603 h1:aOUWB+ABNMdAjghn/PqCKDuz5WTwfoYfre5I/rtOnKo= -github.com/sei-protocol/sei-wasmd v0.2.4-0.20240816184629-eb6d20caf603/go.mod h1:fKHnK3Nms+BZeGvXeIC3SEzUDfkB7/tYOf95kVOhiO4= +github.com/sei-protocol/sei-wasmd v0.2.4 h1:W++xiJ1P57BhBW8TGk8vfPRJlWXr1vp2kQCvSc8Qpaw= +github.com/sei-protocol/sei-wasmd v0.2.4/go.mod h1:fKHnK3Nms+BZeGvXeIC3SEzUDfkB7/tYOf95kVOhiO4= github.com/sei-protocol/tm-db v0.0.4 h1:7Y4EU62Xzzg6wKAHEotm7SXQR0aPLcGhKHkh3qd0tnk= github.com/sei-protocol/tm-db v0.0.4/go.mod h1:PWsIWOTwdwC7Ow/GUvx8HgUJTO691pBuorIQD8JvwAs= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=

      +i64Y9Hhv? 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 U?G!|?&mIeS6MO!r0NBU=50r}adH?_b diff --git a/x/dex/testdata/mars.wasm b/x/dex/testdata/mars.wasm deleted file mode 100644 index 8addcee304dbfe95128720b948d636864291403a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 191011 zcmeFa542}jRp)vC{QkY)pZ9+CFZEuk67KIuN?%Ep7LHOy$kKPKsU(O>Ovlw}o0(Kd ziXpE;NGb)5JsGM3X^0RoD6K(J3r(8{gpM}dlh%w@FhI0v32PWTJ&m)03L3Q^9$DqLsoL8PcdUxlN|M9vaF-lzojCC}{J#yoBe)o63^yO3UY>kDlyZ-nMZ{tc9fT&G}Noch> z*G}7c+HN+}@CKE51*npCXgW=s&D(>;xbo4$Ip{}@_ELyaV* zayQ?!Sv|M1R%1)DHLZ_Ipad?f0hL)*Fw!@lD5mG)sCn-E#Z!>u))JlSt>=8n?gs#y2H5_KzL8 z?aenGJ97JVw;#DFd1L4Ln{R&84XW^=w0q-`>h9;#O;trG_t^Ev-*hZ_7D7@ z(|?-2GksTjclu-LyVLii_oVMl7jC%W244HM^uy`DO#j#0jvc>c;UB-{tq-UF%c=BN z(|^K~hiLZ1!d>b6(jQOnRe!&n{#^F9g*&+V&Yw=-ys-b{>Az6%!q2C_kbW+G{laI{ zf0r(N=Wl1P|9utz`*cB7o=X2O9{tDki#+I{eRPE(mzlC zYx-=u@RQk3Wbe=ZJpJ+P-s}U}1KESwsqA#N@Qc~+WFO6bHT$*fce8()eIol;*}u)Y zAAYd=$?QMpY2!q;6#o^;VwTJ{(ngjiy&@_5%iNE%#*!X1Mro0i^EZ#Oe5pvwhMw^x z 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