Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: chainmanager globalfee dynamicfee ccv params #NTRN-408 #368

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -90,4 +90,4 @@
"engines": {
"node": ">=20.0"
}
}
}
2 changes: 1 addition & 1 deletion setup/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion setup/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ services:
- neutron-testing

hermes:
image: hermes:1.10.1
image: hermes:1.10.4
depends_on:
- "neutron-node"
- "gaia-node"
Expand Down
4 changes: 2 additions & 2 deletions setup/dockerbuilds/Dockerfile.hermes
Original file line number Diff line number Diff line change
@@ -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" && \
Expand Down
254 changes: 252 additions & 2 deletions src/testcases/run_in_band/chain_manager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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,
},
},
],
},
},
Expand Down Expand Up @@ -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);
Expand All @@ -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();
});
});

Expand Down Expand Up @@ -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);
Expand All @@ -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,
Expand All @@ -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);
Expand All @@ -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' },
]);
sotnikov-s marked this conversation as resolved.
Show resolved Hide resolved
// 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();
});
});

Expand Down
Loading