diff --git a/package.json b/package.json index cfcd20fa..ad5f4f44 100644 --- a/package.json +++ b/package.json @@ -45,8 +45,8 @@ "@cosmjs/cosmwasm-stargate": "^0.32.4", "@cosmjs/stargate": "0.32.4", "@cosmjs/tendermint-rpc": "^0.32.4", - "@neutron-org/neutronjs": "https://github.com/neutron-org/neutronjs.git#7f45328320b53b4fa2b572bc25bb96bf80260181", - "@neutron-org/neutronjsplus": "https://github.com/neutron-org/neutronjsplus.git#39dd19b17165ef206b40018ff437054210c2bdbc", + "@neutron-org/neutronjs": "https://github.com/neutron-org/neutronjs.git#8ca4875e81fc7cdfffab513bb410ca7cff09db78", + "@neutron-org/neutronjsplus": "https://github.com/neutron-org/neutronjsplus.git#14dc348bea4955821565ae030bbce81b0557717f", "@types/lodash": "^4.14.182", "axios": "1.6.0", "commander": "^10.0.0", @@ -90,4 +90,4 @@ "engines": { "node": ">=20.0" } -} +} \ No newline at end of file diff --git a/setup/Makefile b/setup/Makefile index 5c36f342..d8476750 100644 --- a/setup/Makefile +++ b/setup/Makefile @@ -8,7 +8,7 @@ build-neutron: cd $(APP_DIR)/neutron && $(MAKE) build-docker-image build-hermes: - @docker build -f dockerbuilds/Dockerfile.hermes -t hermes:1.10.1 . + @docker build -f dockerbuilds/Dockerfile.hermes -t hermes:1.10.4 . build-relayer: cd $(APP_DIR)/neutron-query-relayer/ && make build-docker diff --git a/setup/docker-compose.yml b/setup/docker-compose.yml index 5e68d789..426682ad 100644 --- a/setup/docker-compose.yml +++ b/setup/docker-compose.yml @@ -36,7 +36,7 @@ services: - neutron-testing hermes: - image: hermes:1.10.1 + image: hermes:1.10.4 depends_on: - "neutron-node" - "gaia-node" diff --git a/setup/dockerbuilds/Dockerfile.hermes b/setup/dockerbuilds/Dockerfile.hermes index a6b313a5..23ff045f 100644 --- a/setup/dockerbuilds/Dockerfile.hermes +++ b/setup/dockerbuilds/Dockerfile.hermes @@ -1,9 +1,9 @@ -FROM ubuntu:23.04 +FROM ubuntu:24.04 COPY ./hermes/ /app/network/hermes/ WORKDIR /app RUN apt-get update && apt-get install -y wget && \ PLATFORM=`uname -a | awk '{print $(NF-1)}'` && \ - VERSION=v1.10.1 && \ + VERSION=v1.10.4 && \ TARNAME="hermes-${VERSION}-${PLATFORM}-unknown-linux-gnu.tar.gz" && \ wget "https://github.com/informalsystems/hermes/releases/download/${VERSION}/${TARNAME}" && \ tar -xf "$TARNAME" && \ diff --git a/src/testcases/run_in_band/chain_manager.test.ts b/src/testcases/run_in_band/chain_manager.test.ts index afc70de1..0e78e7f7 100644 --- a/src/testcases/run_in_band/chain_manager.test.ts +++ b/src/testcases/run_in_band/chain_manager.test.ts @@ -13,6 +13,8 @@ import { updateTokenfactoryParamsProposal, AddSchedule, RemoveSchedule, + updateGlobalFeeParamsProposal, + updateConsumerParamsProposal, } from '@neutron-org/neutronjsplus/dist/proposal'; import { LocalState } from '../../helpers/local_state'; import { RunnerTestSuite, inject } from 'vitest'; @@ -23,10 +25,14 @@ import { QueryClientImpl as AdminQueryClient } from '@neutron-org/neutronjs/cosm import { QueryClientImpl as TokenfactoryQueryClient } from '@neutron-org/neutronjs/osmosis/tokenfactory/v1beta1/query.rpc.Query'; import { QueryClientImpl as UpgradeQueryClient } from '@neutron-org/neutronjs/cosmos/upgrade/v1beta1/query.rpc.Query'; import { QueryClientImpl as DexQueryClient } from '@neutron-org/neutronjs/neutron/dex/query.rpc.Query'; +import { QueryClientImpl as DynamicfeesQueryClient } from '@neutron-org/neutronjs/neutron/dynamicfees/v1/query.rpc.Query'; +import { QueryClientImpl as GlobalfeeQueryClient } from '@neutron-org/neutronjs/gaia/globalfee/v1beta1/query.rpc.Query'; +import { QueryClientImpl as CCVQueryClient } from '@neutron-org/neutronjs/interchain_security/ccv/consumer/v1/query.rpc.Query'; import { SigningNeutronClient } from '../../helpers/signing_neutron_client'; import config from '../../config.json'; import { Wallet } from '../../helpers/wallet'; import { ADMIN_MODULE_ADDRESS } from '@neutron-org/neutronjsplus/dist/constants'; +import { Duration } from '@neutron-org/neutronjs/google/protobuf/duration'; describe('Neutron / Chain Manager', () => { let testState: LocalState; @@ -39,6 +45,9 @@ describe('Neutron / Chain Manager', () => { let cronQuerier: CronQueryClient; let tokenfactoryQuerier: TokenfactoryQueryClient; let dexQuerier: DexQueryClient; + let dynamicfeesQuerier: DynamicfeesQueryClient; + let globalfeeQuerier: GlobalfeeQueryClient; + let ccvQuerier: CCVQueryClient; let upgradeQuerier: UpgradeQueryClient; let chainManagerAddress: string; @@ -97,6 +106,9 @@ describe('Neutron / Chain Manager', () => { cronQuerier = new CronQueryClient(neutronRpcClient); dexQuerier = new DexQueryClient(neutronRpcClient); upgradeQuerier = new UpgradeQueryClient(neutronRpcClient); + dynamicfeesQuerier = new DynamicfeesQueryClient(neutronRpcClient); + globalfeeQuerier = new GlobalfeeQueryClient(neutronRpcClient); + ccvQuerier = new CCVQueryClient(neutronRpcClient); }); // We need to do this because the real main dao has a super long voting period. @@ -205,6 +217,34 @@ describe('Neutron / Chain Manager', () => { good_til_purge_allowance: true, }, }, + { + update_ccv_params_permission: { + blocks_per_distribution_transmission: true, + distribution_transmission_channel: true, + provider_fee_pool_addr_str: true, + ccv_timeout_period: true, + transfer_timeout_period: true, + consumer_redistribution_fraction: true, + historical_entries: true, + unbonding_period: true, + soft_opt_out_threshold: true, + reward_denoms: true, + provider_reward_denoms: true, + retry_delay_period: true, + }, + }, + { + update_globalfee_params_permission: { + minimum_gas_prices: true, + bypass_min_fee_msg_types: true, + max_total_bypass_min_fee_msg_gas_usage: true, + }, + }, + { + update_dynamicfees_params_permission: { + ntrn_prices: true, + }, + }, ], }, }, @@ -252,6 +292,7 @@ describe('Neutron / Chain Manager', () => { }); test('execute timelocked: success', async () => { + const cronParamsBefore = await cronQuerier.params(); await waitSeconds(10); await subdaoMember1.executeTimelockedProposal(proposalId); @@ -262,6 +303,12 @@ describe('Neutron / Chain Manager', () => { const cronParams = await cronQuerier.params(); expect(cronParams.params.limit).toEqual(42n); + // check that every params field before proposal execution differs from the field after proposal execution + expect( + Object.keys(cronParamsBefore).every( + (key) => cronParamsBefore[key] !== cronParams[key], + ), + ).toBeTrue(); }); }); @@ -290,13 +337,13 @@ describe('Neutron / Chain Manager', () => { const timelockedProp = await subdaoMember1.supportAndExecuteProposal( proposalId, ); - expect(timelockedProp.id).toEqual(proposalId); expect(timelockedProp.status).toEqual('timelocked'); expect(timelockedProp.msgs).toHaveLength(1); }); test('execute timelocked: success', async () => { + const tokenfactoryParamsBefore = await tokenfactoryQuerier.params(); await waitSeconds(10); await subdaoMember1.executeTimelockedProposal(proposalId); @@ -319,13 +366,21 @@ describe('Neutron / Chain Manager', () => { denomCreator: 'neutron1m9l358xunhhwds0568za49mzhvuxx9ux8xafx2', }, ]); + // check that every params field before proposal execution differs from the field after proposal execution + expect( + Object.keys(tokenfactoryParamsBefore).every( + (key) => tokenfactoryParamsBefore[key] !== tokenfactoryParams[key], + ), + ).toBeTrue(); }); }); describe('ALLOW_ONLY: change DEX parameters', () => { let proposalId: number; const newParams = { - fee_tiers: [1, 2, 99], + // types mixed on purpose, to check contract parser. + // Numeric types in neutron-std can be deserialized from both number and string + fee_tiers: ['1', '2', 99], paused: true, max_jits_per_block: 11, good_til_purge_allowance: 50000, @@ -349,6 +404,7 @@ describe('Neutron / Chain Manager', () => { }); test('execute timelocked: success', async () => { + const dexParamsBefore = await dexQuerier.params(); await waitSeconds(10); await subdaoMember1.executeTimelockedProposal(proposalId); @@ -362,6 +418,200 @@ describe('Neutron / Chain Manager', () => { expect(dexParams.params.paused).toEqual(true); expect(dexParams.params.maxJitsPerBlock).toEqual(11n); expect(dexParams.params.goodTilPurgeAllowance).toEqual(50000n); + // check that every params field before proposal execution differs from the field after proposal execution + expect( + Object.keys(dexParamsBefore).every( + (key) => dexParamsBefore[key] !== dexParams[key], + ), + ).toBeTrue(); + }); + }); + + describe('ALLOW_ONLY: change Dynamicfees parameters', () => { + let proposalId: number; + beforeAll(async () => { + proposalId = await subdaoMember1.submitDynamicfeesChangeParamsProposal( + chainManagerAddress, + 'Proposal #2', + 'Dynamicfees update params proposal. Will pass', + '1000', + { + ntrn_prices: [{ denom: 'newdenom', amount: '0.5' }], + }, + ); + + const timelockedProp = await subdaoMember1.supportAndExecuteProposal( + proposalId, + ); + + expect(timelockedProp.id).toEqual(proposalId); + expect(timelockedProp.status).toEqual('timelocked'); + expect(timelockedProp.msgs).toHaveLength(1); + }); + + test('execute timelocked: success', async () => { + const dynamicfeesParamsBefore = await dynamicfeesQuerier.params(); + await waitSeconds(10); + + await subdaoMember1.executeTimelockedProposal(proposalId); + const timelockedProp = await subDao.getTimelockedProposal(proposalId); + expect(timelockedProp.id).toEqual(proposalId); + expect(timelockedProp.status).toEqual('executed'); + expect(timelockedProp.msgs).toHaveLength(1); + + const dynamicfeesParams = await dynamicfeesQuerier.params(); + expect(dynamicfeesParams.params.ntrnPrices).toEqual([ + { denom: 'newdenom', amount: '0.5' }, + ]); + // check that every params field before proposal execution differs from the field after proposal execution + expect( + Object.keys(dynamicfeesParamsBefore).every( + (key) => dynamicfeesParamsBefore[key] !== dynamicfeesParams[key], + ), + ).toBeTrue(); + }); + }); + + describe('ALLOW_ONLY: change Globalfee parameters', () => { + let proposalId: number; + beforeAll(async () => { + proposalId = await subdaoMember1.submitUpdateParamsGlobalfeeProposal( + chainManagerAddress, + 'Proposal #3', + 'Globalfee update params proposal. Will pass', + updateGlobalFeeParamsProposal({ + minimum_gas_prices: [{ denom: 'untrn', amount: '0.00111' }], + bypass_min_fee_msg_types: ['/gaia.globalfee.v1beta1.MsgUpdateParams'], + max_total_bypass_min_fee_msg_gas_usage: '12345', + }), + '1000', + ); + + const timelockedProp = await subdaoMember1.supportAndExecuteProposal( + proposalId, + ); + + expect(timelockedProp.id).toEqual(proposalId); + expect(timelockedProp.status).toEqual('timelocked'); + expect(timelockedProp.msgs).toHaveLength(1); + }); + + test('execute timelocked: success', async () => { + const globalfeeParamsBefore = await globalfeeQuerier.params(); + await waitSeconds(10); + + await subdaoMember1.executeTimelockedProposal(proposalId); + const timelockedProp = await subDao.getTimelockedProposal(proposalId); + expect(timelockedProp.id).toEqual(proposalId); + expect(timelockedProp.status).toEqual('executed'); + expect(timelockedProp.msgs).toHaveLength(1); + + const globalfeeParams = await globalfeeQuerier.params(); + expect(globalfeeParams.params.minimumGasPrices).toEqual([ + { denom: 'untrn', amount: '0.00111' }, + ]); + expect(globalfeeParams.params.bypassMinFeeMsgTypes).toEqual([ + '/gaia.globalfee.v1beta1.MsgUpdateParams', + ]); + expect(globalfeeParams.params.maxTotalBypassMinFeeMsgGasUsage).toEqual( + 12345n, + ); + // check that every params field before proposal execution differs from the field after proposal execution + expect( + Object.keys(globalfeeParamsBefore).every( + (key) => globalfeeParamsBefore[key] !== globalfeeParams[key], + ), + ).toBeTrue(); + }); + }); + + describe('ALLOW_ONLY: change ccv consumer parameters', () => { + let proposalId: number; + beforeAll(async () => { + proposalId = await subdaoMember1.submitUpdateParamsConsumerProposal( + chainManagerAddress, + 'Proposal #4', + 'Consumer update params proposal. Will pass', + updateConsumerParamsProposal({ + enabled: true, + blocksPerDistributionTransmission: 321n, + distributionTransmissionChannel: 'channel-23', + providerFeePoolAddrStr: chainManagerAddress, + ccvTimeoutPeriod: Duration.fromPartial({ seconds: 32n }), + transferTimeoutPeriod: Duration.fromPartial({ seconds: 23n }), + consumerRedistributionFraction: '0.33', + historicalEntries: 123n, + unbondingPeriod: Duration.fromPartial({ seconds: 43n }), + softOptOutThreshold: '0.55', + rewardDenoms: ['tia'], + providerRewardDenoms: ['tia'], + retryDelayPeriod: Duration.fromPartial({ seconds: 43n }), + }), + '1000', + ); + + const timelockedProp = await subdaoMember1.supportAndExecuteProposal( + proposalId, + ); + + expect(timelockedProp.id).toEqual(proposalId); + expect(timelockedProp.status).toEqual('timelocked'); + expect(timelockedProp.msgs).toHaveLength(1); + }); + + test('execute timelocked: success', async () => { + const ccvParamsBefore = await ccvQuerier.queryParams(); + await waitSeconds(10); + + await subdaoMember1.executeTimelockedProposal(proposalId); + console.log( + 'subdao', + subdaoMember1.dao.contracts.proposals['single'].pre_propose.timelock + .address, + ); + const timelockedProp = await subDao.getTimelockedProposal(proposalId); + expect(timelockedProp.id).toEqual(proposalId); + expect(timelockedProp.status).toEqual('executed'); + expect(timelockedProp.msgs).toHaveLength(1); + + const ccvParams = await ccvQuerier.queryParams(); + expect(ccvParams.params.enabled).toEqual(true); + expect(ccvParams.params.blocksPerDistributionTransmission).toEqual(321n); + expect(ccvParams.params.distributionTransmissionChannel).toEqual( + 'channel-23', + ); + expect(ccvParams.params.providerFeePoolAddrStr).toEqual( + chainManagerAddress, + ); + expect(ccvParams.params.ccvTimeoutPeriod).toEqual({ + nanos: 0, + seconds: 32n, + }); + expect(ccvParams.params.transferTimeoutPeriod).toEqual({ + nanos: 0, + seconds: 23n, + }); + expect(ccvParams.params.consumerRedistributionFraction).toEqual('0.33'); + expect(ccvParams.params.historicalEntries).toEqual(123n); + expect(ccvParams.params.unbondingPeriod).toEqual({ + nanos: 0, + seconds: 43n, + }); + expect(ccvParams.params.softOptOutThreshold).toEqual('0.55'); + expect(ccvParams.params.rewardDenoms).toEqual(['tia']); + expect(ccvParams.params.providerRewardDenoms).toEqual(['tia']); + expect(ccvParams.params.retryDelayPeriod).toEqual({ + nanos: 0, + seconds: 43n, + }); + // field 'enabled' is readonly, and should not be changed, always equals true + delete ccvParamsBefore['enabled']; + // check that every params field before proposal execution differs from the field after proposal execution + expect( + Object.keys(ccvParamsBefore).every( + (key) => ccvParamsBefore[key] !== ccvParams[key], + ), + ).toBeTrue(); }); }); diff --git a/yarn.lock b/yarn.lock index 0c07889a..1299bd8b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1341,18 +1341,22 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" -"@neutron-org/neutronjs@https://github.com/neutron-org/neutronjs.git#7f45328320b53b4fa2b572bc25bb96bf80260181": +"@neutron-org/neutronjs@https://github.com/neutron-org/neutronjs.git#8ca4875e81fc7cdfffab513bb410ca7cff09db78": version "4.2.0" - resolved "https://github.com/neutron-org/neutronjs.git#7f45328320b53b4fa2b572bc25bb96bf80260181" + resolved "https://github.com/neutron-org/neutronjs.git#8ca4875e81fc7cdfffab513bb410ca7cff09db78" -"@neutron-org/neutronjsplus@https://github.com/neutron-org/neutronjsplus.git#39dd19b17165ef206b40018ff437054210c2bdbc": +"@neutron-org/neutronjs@https://github.com/neutron-org/neutronjs.git#95a719604fecba39de5540b6ac99ded3e7aacfaa": + version "4.2.0" + resolved "https://github.com/neutron-org/neutronjs.git#95a719604fecba39de5540b6ac99ded3e7aacfaa" + +"@neutron-org/neutronjsplus@https://github.com/neutron-org/neutronjsplus.git#14dc348bea4955821565ae030bbce81b0557717f": version "0.5.0" - resolved "https://github.com/neutron-org/neutronjsplus.git#39dd19b17165ef206b40018ff437054210c2bdbc" + resolved "https://github.com/neutron-org/neutronjsplus.git#14dc348bea4955821565ae030bbce81b0557717f" dependencies: "@cosmjs/cosmwasm-stargate" "^0.32.4" "@cosmjs/proto-signing" "^0.32.4" "@cosmjs/stargate" "0.32.4" - "@neutron-org/neutronjs" "https://github.com/neutron-org/neutronjs.git#7f45328320b53b4fa2b572bc25bb96bf80260181" + "@neutron-org/neutronjs" "https://github.com/neutron-org/neutronjs.git#95a719604fecba39de5540b6ac99ded3e7aacfaa" axios "1.6.0" bip39 "^3.1.0" long "^5.2.1"