diff --git a/package.json b/package.json index c92dafa5..6f42cae2 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,9 @@ "test:feemarket": "NO_WAIT_CHANNEL1=1 NO_WAIT_HTTP2=1 NO_WAIT_CHANNEL2=1 NO_WAIT_DELAY=1 vitest --run src/testcases/run_in_band/feemarket --bail 1", "lint": "eslint ./src", "fmt": "eslint ./src --fix", - "postinstall": "[ -d './node_modules/@neutron-org/neutronjsplus/dist' ] || tsc -p ./node_modules/@neutron-org/neutronjsplus/tsconfig.json" + "build:neutronjsplus": "[ -d './node_modules/@neutron-org/neutronjsplus/dist' ] || tsc -p ./node_modules/@neutron-org/neutronjsplus/tsconfig.json", + "build:neutronjs": "[ -d './node_modules/@neutron-org/neutronjs/dist' ] || { tsc -p ./node_modules/@neutron-org/neutronjs/tsconfig.json && cp -R ./node_modules/@neutron-org/neutronjs/build/* ./node_modules/@neutron-org/neutronjs/ ; }", + "postinstall": "yarn build:neutronjs && yarn build:neutronjsplus" }, "author": "Neutron", "license": "Apache-2.0", @@ -41,8 +43,8 @@ "@cosmjs/cosmwasm-stargate": "^0.32.4", "@cosmjs/stargate": "0.32.4", "@cosmjs/tendermint-rpc": "^0.32.4", - "@neutron-org/neutronjs": "4.2.0", - "@neutron-org/neutronjsplus": "https://github.com/neutron-org/neutronjsplus.git#88b4e5391a8b80c90a7c7e25b8f6948b7cdd2e7c", + "@neutron-org/neutronjs": "https://github.com/neutron-org/neutronjs.git#f5334307decfa549283d03e626cd45582667c13f", + "@neutron-org/neutronjsplus": "https://github.com/neutron-org/neutronjsplus.git#1e4527ef6971f4dc2c202cb3cc2a50b0a4491f54", "@types/lodash": "^4.14.182", "axios": "1.6.0", "commander": "^10.0.0", @@ -85,4 +87,4 @@ "engines": { "node": ">=20.0" } -} +} \ No newline at end of file diff --git a/setup/Makefile b/setup/Makefile index ff5cf1b9..5c36f342 100644 --- a/setup/Makefile +++ b/setup/Makefile @@ -1,5 +1,5 @@ APP_DIR ?= ../.. -COMPOSE ?= docker-compose +COMPOSE ?= docker compose build-gaia: @docker buildx build --load --build-context app=$(APP_DIR)/gaia --build-context setup=$(APP_DIR)/neutron/network -t gaia-node -f dockerbuilds/Dockerfile.gaia --build-arg BINARY=gaiad . diff --git a/src/helpers/interchainqueries.ts b/src/helpers/interchainqueries.ts index 2ec00ea0..1d0c5f2b 100644 --- a/src/helpers/interchainqueries.ts +++ b/src/helpers/interchainqueries.ts @@ -6,6 +6,7 @@ import { getNeutronDAOCore, } from '@neutron-org/neutronjsplus/dist/dao'; import { QueryClientImpl as AdminQueryClient } from '@neutron-org/neutronjs/cosmos/adminmodule/adminmodule/query.rpc.Query'; +import { QueryClientImpl as InterchainqQuerier } from '@neutron-org/neutronjs/neutron/interchainqueries/query.rpc.Query'; import { paramChangeProposal } from '@neutron-org/neutronjsplus/dist/proposal'; import { CosmWasmClient, @@ -21,6 +22,46 @@ import { Coin } from '@neutron-org/neutronjs/cosmos/base/v1beta1/coin'; import { QueryClientImpl as BankQuerier } from 'cosmjs-types/cosmos/bank/v1beta1/query'; import { MsgRemoveInterchainQueryRequest } from '@neutron-org/neutronjs/neutron/interchainqueries/tx'; +export const executeUpdateInterchainQueriesParams = async ( + chainManagerAddress: string, + interchainQueriesQuerier: InterchainqQuerier, + mainDao: Dao, + daoMember: DaoMember, + maxKvQueryKeysCount?: number, + maxTransactionsFilters?: number, +) => { + const params = (await interchainQueriesQuerier.params()).params; + if (maxKvQueryKeysCount != undefined) { + params.maxKvQueryKeysCount = BigInt(maxKvQueryKeysCount); + } + + if (maxTransactionsFilters != undefined) { + params.maxTransactionsFilters = BigInt(maxTransactionsFilters); + } + + const proposalId = + await daoMember.submitUpdateParamsInterchainqueriesProposal( + chainManagerAddress, + 'Change Proposal - InterchainQueriesParams', + 'Param change proposal. It will change enabled params of interchainquries module.', + { + query_submit_timeout: Number(params.querySubmitTimeout), + query_deposit: params.queryDeposit, + tx_query_removal_limit: Number(params.txQueryRemovalLimit), + max_kv_query_keys_count: Number(params.maxKvQueryKeysCount), + max_transactions_filters: Number(params.maxTransactionsFilters), + }, + '1000', + ); + + await daoMember.voteYes(proposalId, 'single', { + gas: '4000000', + amount: [{ denom: NEUTRON_DENOM, amount: '100000' }], + }); + await mainDao.checkPassedProposal(proposalId); + await daoMember.executeProposalWithAttempts(proposalId); +}; + export const getKvCallbackStatus = async ( client: SigningNeutronClient, contractAddress: string, @@ -594,13 +635,13 @@ export const registerTransfersQuery = async ( contractAddress: string, connectionId: string, updatePeriod: number, - recipient: string, + recipients: string[], ) => { const res = await client.execute(contractAddress, { register_transfers_query: { connection_id: connectionId, update_period: updatePeriod, - recipient: recipient, + recipients: recipients, }, }); diff --git a/src/testcases/parallel/interchain_tx_query_resubmit.test.ts b/src/testcases/parallel/interchain_tx_query_resubmit.test.ts index 581cee75..08eb4e15 100644 --- a/src/testcases/parallel/interchain_tx_query_resubmit.test.ts +++ b/src/testcases/parallel/interchain_tx_query_resubmit.test.ts @@ -87,7 +87,7 @@ describe('Neutron / Interchain TX Query Resubmit', () => { contractAddress, connectionId, query1UpdatePeriod, - watchedAddr1, + [watchedAddr1], ); }); diff --git a/src/testcases/run_in_band/interchain_kv_query.test.ts b/src/testcases/run_in_band/interchain_kv_query.test.ts index 5a3bffca..b4ff53a8 100644 --- a/src/testcases/run_in_band/interchain_kv_query.test.ts +++ b/src/testcases/run_in_band/interchain_kv_query.test.ts @@ -1,8 +1,10 @@ import { acceptInterchainqueriesParamsChangeProposal, + executeUpdateInterchainQueriesParams, filterIBCDenoms, } from '../../helpers/interchainqueries'; import '@neutron-org/neutronjsplus'; +import { QueryClientImpl as AdminQueryClient } from '@neutron-org/neutronjs/cosmos/adminmodule/adminmodule/query.rpc.Query'; import { getEventAttribute } from '@neutron-org/neutronjsplus/dist/cosmos'; import { inject } from 'vitest'; import { @@ -66,6 +68,7 @@ describe('Neutron / Interchain KV Query', () => { 3: 4, 4: 3, 5: 4, + 6: 11, }; let testState: LocalState; let neutronClient: SigningNeutronClient; @@ -80,6 +83,9 @@ describe('Neutron / Interchain KV Query', () => { let bankQuerierGaia: BankQuerier; let slashingQuerier: SlashingQuerier; let contractAddress: string; + let daoMember: DaoMember; + let mainDao: Dao; + let chainManagerAddress: string; beforeAll(async () => { testState = await LocalState.create(config, inject('mnemonics')); @@ -114,9 +120,9 @@ describe('Neutron / Interchain KV Query', () => { neutronRpcClient, ); const daoContracts = await getDaoContracts(neutronClient, daoCoreAddress); - const dao = new Dao(neutronClient, daoContracts); - const daoMember = new DaoMember( - dao, + mainDao = new Dao(neutronClient, daoContracts); + daoMember = new DaoMember( + mainDao, neutronClient.client, neutronWallet.address, NEUTRON_DENOM, @@ -126,6 +132,10 @@ describe('Neutron / Interchain KV Query', () => { bankQuerier = new BankQuerier(neutronRpcClient); bankQuerierGaia = new BankQuerier(await testState.gaiaRpcClient()); slashingQuerier = new SlashingQuerier(await testState.gaiaRpcClient()); + + const adminQuery = new AdminQueryClient(neutronRpcClient); + const admins = await adminQuery.admins(); + chainManagerAddress = admins.admins[0]; }); describe('Instantiate interchain queries contract', () => { @@ -223,6 +233,45 @@ describe('Neutron / Interchain KV Query', () => { expect(balances.balances.length).toEqual(0); }); + + test('should throw exception because of too many keys', async () => { + await neutronClient.sendTokens( + contractAddress, + [{ denom: NEUTRON_DENOM, amount: '1000000' }], + { + gas: '200000', + amount: [{ denom: NEUTRON_DENOM, amount: '1000' }], + }, + ); + await expect( + neutronClient.execute(contractAddress, { + register_balances_query: { + connection_id: connectionId, + denoms: Array.from(Array(33).keys()).map((v) => 'denom' + v), + addr: gaiaWallet.address, + update_period: 10, + }, + }), + ).rejects.toThrowError(/keys count cannot be more than 32/); + await executeUpdateInterchainQueriesParams( + chainManagerAddress, + interchainqQuerier, + mainDao, + daoMember, + 10, + undefined, + ); + await expect( + neutronClient.execute(contractAddress, { + register_balances_query: { + connection_id: connectionId, + denoms: Array.from(Array(11).keys()).map((v) => 'denom' + v), + addr: gaiaWallet.address, + update_period: 10, + }, + }), + ).rejects.toThrowError(/keys count cannot be more than 10/); + }); }); describe('Successfully', () => { @@ -281,6 +330,25 @@ describe('Neutron / Interchain KV Query', () => { testState.wallets.cosmos.val1.address, ); }); + + test('register icq #6: 100 keys', async () => { + await executeUpdateInterchainQueriesParams( + chainManagerAddress, + interchainqQuerier, + mainDao, + daoMember, + 100, + undefined, + ); + await registerBalancesQuery( + neutronClient, + contractAddress, + connectionId, + updatePeriods[6], + Array.from(Array(100).keys()).map((v) => 'denom' + v), + testState.wallets.cosmos.val1.address, + ); + }); }); }); @@ -367,8 +435,33 @@ describe('Neutron / Interchain KV Query', () => { ); }); - test("registered icq #6 doesn't exist", async () => { + test('get registered icq #6: 100 keys', async () => { const queryId = 6; + const queryResult = await getRegisteredQuery( + neutronClient, + contractAddress, + queryId, + ); + expect(queryResult.registered_query.id).toEqual(queryId); + expect(queryResult.registered_query.owner).toEqual(contractAddress); + expect(queryResult.registered_query.keys.length).toEqual(100); + for (let i = 0; i < queryResult.registered_query.keys.length; i++) { + expect(queryResult.registered_query.keys[i].path).toEqual('bank'); + expect(queryResult.registered_query.keys[i].key.length).toBeGreaterThan( + 0, + ); + } + + expect(queryResult.registered_query.query_type).toEqual('kv'); + expect(queryResult.registered_query.transactions_filter).toEqual(''); + expect(queryResult.registered_query.connection_id).toEqual(connectionId); + expect(queryResult.registered_query.update_period).toEqual( + updatePeriods[queryId], + ); + }); + + test("registered icq #7 doesn't exist", async () => { + const queryId = 7; await expect( getRegisteredQuery(neutronClient, contractAddress, queryId), ).rejects.toThrow(); @@ -575,7 +668,7 @@ describe('Neutron / Interchain KV Query', () => { address: contractAddress, }); - expect(balances.balances[0].amount).toEqual('1000000'); + expect(balances.balances[0].amount).toEqual('2000000'); }); test('should fail to remove icq #2 from non owner address before timeout expiration', async () => { diff --git a/src/testcases/run_in_band/interchain_tx_query_plain.test.ts b/src/testcases/run_in_band/interchain_tx_query_plain.test.ts index ede4657a..a4e85928 100644 --- a/src/testcases/run_in_band/interchain_tx_query_plain.test.ts +++ b/src/testcases/run_in_band/interchain_tx_query_plain.test.ts @@ -3,11 +3,15 @@ import { LocalState } from '../../helpers/local_state'; import { defaultRegistryTypes, MsgSendEncodeObject, + ProtobufRpcClient, SigningStargateClient, } from '@cosmjs/stargate'; import { SigningNeutronClient } from '../../helpers/signing_neutron_client'; import { Registry } from '@cosmjs/proto-signing'; +import { QueryClientImpl as AdminQueryClient } from '@neutron-org/neutronjs/cosmos/adminmodule/adminmodule/query.rpc.Query'; +import { QueryClientImpl as InterchainqQuerier } from '@neutron-org/neutronjs/neutron/interchainqueries/query.rpc.Query'; import { + executeUpdateInterchainQueriesParams, getRegisteredQuery, queryRecipientTxs, queryTransfersNumber, @@ -23,15 +27,26 @@ import { QueryClientImpl as BankQuerier } from 'cosmjs-types/cosmos/bank/v1beta1 import config from '../../config.json'; import { Wallet } from '../../helpers/wallet'; +import { + Dao, + DaoMember, + getDaoContracts, + getNeutronDAOCore, +} from '@neutron-org/neutronjsplus/dist/dao'; describe('Neutron / Interchain TX Query', () => { let testState: LocalState; let neutronClient: SigningNeutronClient; + let neutronRpcClient: ProtobufRpcClient; let gaiaClient: SigningStargateClient; let neutronWallet: Wallet; let gaiaWallet: Wallet; let contractAddress: string; let bankQuerierGaia: BankQuerier; + let interchainqQuerier: InterchainqQuerier; + let daoMember: DaoMember; + let mainDao: Dao; + let chainManagerAddress: string; const connectionId = 'connection-0'; beforeAll(async (suite: Suite) => { @@ -51,6 +66,26 @@ describe('Neutron / Interchain TX Query', () => { { registry: new Registry(defaultRegistryTypes) }, ); bankQuerierGaia = new BankQuerier(await testState.gaiaRpcClient()); + + neutronRpcClient = await testState.neutronRpcClient(); + const daoCoreAddress = await getNeutronDAOCore( + neutronClient, + neutronRpcClient, + ); + const daoContracts = await getDaoContracts(neutronClient, daoCoreAddress); + mainDao = new Dao(neutronClient, daoContracts); + daoMember = new DaoMember( + mainDao, + neutronClient.client, + neutronWallet.address, + NEUTRON_DENOM, + ); + await daoMember.bondFunds('1000000000'); + interchainqQuerier = new InterchainqQuerier(neutronRpcClient); + + const adminQuery = new AdminQueryClient(neutronRpcClient); + const admins = await adminQuery.admins(); + chainManagerAddress = admins.admins[0]; }); describe('deploy contract', () => { @@ -95,7 +130,7 @@ describe('Neutron / Interchain TX Query', () => { contractAddress, connectionId, query1UpdatePeriod, - watchedAddr1, + [watchedAddr1], ); }); @@ -258,7 +293,7 @@ describe('Neutron / Interchain TX Query', () => { contractAddress, connectionId, query2UpdatePeriod, - watchedAddr2, + [watchedAddr2], ); }); @@ -327,7 +362,7 @@ describe('Neutron / Interchain TX Query', () => { contractAddress, connectionId, query3UpdatePeriod, - watchedAddr3, + [watchedAddr3], ); }); @@ -626,14 +661,14 @@ describe('Neutron / Interchain TX Query', () => { contractAddress, connectionId, query4UpdatePeriod, - watchedAddr4, + [watchedAddr4], ); await registerTransfersQuery( neutronClient, contractAddress, connectionId, query5UpdatePeriod, - watchedAddr5, + [watchedAddr5], ); await neutronClient.waitBlocks(2); // wait for queries handling on init }); @@ -768,6 +803,65 @@ describe('Neutron / Interchain TX Query', () => { }); }); + describe('Multiple keys', () => { + test('Should fail. register filter with 50 keys', async () => { + // Top up contract address before running query + await neutronClient.sendTokens( + contractAddress, + [{ denom: NEUTRON_DENOM, amount: '1000000' }], + { + gas: '200000', + amount: [{ denom: NEUTRON_DENOM, amount: '1000' }], + }, + ); + await expect( + registerTransfersQuery( + neutronClient, + contractAddress, + connectionId, + query2UpdatePeriod, + Array(50).fill(watchedAddr2), + ), + ).rejects.toThrowError( + /failed to validate MsgRegisterInterchainQuery: too many transactions filters, provided=50, max=32/, + ); + }); + + test('Should pass. register filter with 50 keys after a proposal', async () => { + await executeUpdateInterchainQueriesParams( + chainManagerAddress, + interchainqQuerier, + mainDao, + daoMember, + undefined, + 50, + ); + + await registerTransfersQuery( + neutronClient, + contractAddress, + connectionId, + query2UpdatePeriod, + Array(50).fill(watchedAddr2), + ); + }); + + test('check registered transfers query', async () => { + const query = await getRegisteredQuery(neutronClient, contractAddress, 6); + expect(query.registered_query.id).toEqual(6); + expect(query.registered_query.owner).toEqual(contractAddress); + expect(query.registered_query.keys.length).toEqual(0); + expect(query.registered_query.query_type).toEqual('tx'); + expect(JSON.parse(query.registered_query.transactions_filter)).toEqual( + Array(50) + .fill(watchedAddr2) + .map((v) => ({ field: 'transfer.recipient', op: 'Eq', value: v })), + ); + expect(query.registered_query.connection_id).toEqual(connectionId); + expect(query.registered_query.update_period).toEqual(query2UpdatePeriod); + }); + }); + describe('check contract state is reverted on failed sudo', () => { // contract handles only transfers <= 20000, otherwise it ends callback with an error. const amountToAddrForth2 = 21000; diff --git a/src/testcases/run_in_band/parameters.test.ts b/src/testcases/run_in_band/parameters.test.ts index 9d48481f..a1ccc65b 100644 --- a/src/testcases/run_in_band/parameters.test.ts +++ b/src/testcases/run_in_band/parameters.test.ts @@ -12,7 +12,6 @@ import { updateCronParamsProposal, updateFeeburnerParamsProposal, updateFeerefunderParamsProposal, - updateInterchainqueriesParamsProposal, updateInterchaintxsParamsProposal, updateTokenfactoryParamsProposal, updateTransferParamsProposal, @@ -112,11 +111,13 @@ describe('Neutron / Parameters', () => { chainManagerAddress, 'Proposal #1', 'Param change proposal. This one will pass', - updateInterchainqueriesParamsProposal({ + { query_submit_timeout: 30, query_deposit: null, tx_query_removal_limit: 20, - }), + max_kv_query_keys_count: 10, + max_transactions_filters: 10, + }, '1000', ); }); @@ -153,6 +154,8 @@ describe('Neutron / Parameters', () => { ); expect(paramsAfter.params.querySubmitTimeout).toEqual(30n); expect(paramsAfter.params.txQueryRemovalLimit).toEqual(20n); + expect(paramsAfter.params.maxKvQueryKeysCount).toEqual(10n); + expect(paramsAfter.params.maxTransactionsFilters).toEqual(10n); }); }); }); diff --git a/yarn.lock b/yarn.lock index d2bbd6d3..41a27c33 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1307,14 +1307,13 @@ resolved "https://registry.yarnpkg.com/@neutron-org/cosmjs-types/-/cosmjs-types-0.9.2-rc1.tgz#ca1fc1dc9566858dbd765e8f82c8a70097bcc84b" integrity sha512-ju2AqJ14yO4+JF8RwY4ZVy7f2HVjhdf66SfhS6y4ucBZm997/E/yYVMnpWmUncVg8ARooISOKaOYNagqz0am6Q== -"@neutron-org/neutronjs@4.2.0": - version "4.2.0" - resolved "https://registry.yarnpkg.com/@neutron-org/neutronjs/-/neutronjs-4.2.0.tgz#7d98d4bc1568f22c015736d6fbe768ddfba14798" - integrity sha512-l3ILkT8H6bO522RoNb37NMQkqlp8qvKNm7v6QlzORtClqbM7VbRv2/INgy8wn8USV5AmcnCdl9M4KfvvGw5k9w== +"@neutron-org/neutronjs@https://github.com/neutron-org/neutronjs.git#f5334307decfa549283d03e626cd45582667c13f": + version "0.1.0-rc5" + resolved "https://github.com/neutron-org/neutronjs.git#f5334307decfa549283d03e626cd45582667c13f" -"@neutron-org/neutronjsplus@https://github.com/neutron-org/neutronjsplus.git#88b4e5391a8b80c90a7c7e25b8f6948b7cdd2e7c": +"@neutron-org/neutronjsplus@https://github.com/neutron-org/neutronjsplus.git#1e4527ef6971f4dc2c202cb3cc2a50b0a4491f54": version "0.5.0" - resolved "https://github.com/neutron-org/neutronjsplus.git#88b4e5391a8b80c90a7c7e25b8f6948b7cdd2e7c" + resolved "https://github.com/neutron-org/neutronjsplus.git#1e4527ef6971f4dc2c202cb3cc2a50b0a4491f54" dependencies: "@cosmjs/cosmwasm-stargate" "^0.32.4" "@cosmjs/proto-signing" "^0.32.4"