diff --git a/Cargo.toml b/Cargo.toml index 27ce7fde4..6663546fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ version = "1.2.0" authors = [ "Gabe R. ", "Larry Engineer ", - "Piotr Babel ", + "Piotr B. ", "Spike Spiegel ", "Brianna M. ", "Ahmad Kaouk", diff --git a/scripts/deploy/addresses/neutron-1.json b/scripts/deploy/addresses/neutron-1.json new file mode 100644 index 000000000..99cd60db9 --- /dev/null +++ b/scripts/deploy/addresses/neutron-1.json @@ -0,0 +1,8 @@ +{ + "address-provider": "neutron17yehp4x7n79zq9dlw4g7xmnrvwdjjj2yecq26844sg8yu74knlxqfx5vqv", + "red-bank": "neutron1n97wnm7q6d2hrcna3rqlnyqw2we6k0l8uqvmyqq6gsml92epdu7quugyph", + "incentives": "neutron1aszpdh35zsaz0yj80mz7f5dtl9zq5jfl8hgm094y0j0vsychfekqxhzd39", + "oracle": "neutron1dwp6m7pdrz6rnhdyrx5ha0acsduydqcpzkylvfgspsz60pj2agxqaqrr7g", + "rewards-collector": "neutron1h4l6rvylzcuxwdw3gzkkdzfjdxf4mv2ypfdgvnvag0dtz6x07gps6fl2vm", + "swapper": "neutron1udr9fc3kd743dezrj38v2ac74pxxr6qsx4xt4nfpcfczgw52rvyqyjp5au" +} diff --git a/scripts/deploy/addresses/pion-1.json b/scripts/deploy/addresses/pion-1.json index dc69275dd..aa66c6ee7 100644 --- a/scripts/deploy/addresses/pion-1.json +++ b/scripts/deploy/addresses/pion-1.json @@ -1,8 +1,8 @@ { - "address-provider": "neutron15y9umftrhft509l2lkegqseafddrhvvfze3u5zghtf2l6zgc0dwsxqc89e", - "red-bank": "neutron15yd62stm3y3rrea6tw8xj3232navey8ugzyr29e8jc0wzgkuu2mqlnhfkt", - "incentives": "neutron1dj6jfctqmtzu3497yp2s0px5ucaakere8mahwgleqftgmkn6eers2rtdyp", - "oracle": "neutron13nyf8s03z30ha4ry9utv7y0pnwr3txnvdan6m0p5t549skzqwmxqx9h0xa", - "rewards-collector": "neutron16uvtpuh7qrqeg05kv8sgsjew3xg44sfj77yvse24l35nlu3gqswq303m40", - "swapper": "neutron1dax7tl6ydtpa2gym6xyaqdlrvqkkwh96q8e557fd03n945c0ux8q5k3r4j" + "address-provider": "neutron187fjlesys2c0z7xzhu43we4rx7tc4twnr5m6r2u7u5hpm03wvjqs0gk2lp", + "red-bank": "neutron15dn9w9vcdkpp2kfjuz4suqh2w8ajyqsgujlykm9x58hsjss5ff7qpmhlln", + "incentives": "neutron187hw8pqfhmxt4tk9star7tkjhu438k566jtgjskz4889pndp2vysh73ezh", + "oracle": "neutron1g4samkydfdyjec424ccucvjcuuls0ql8mfp2glf739mg0uqr74yqhdx9kn", + "rewards-collector": "neutron1re4v85k6kr8r7f3j4s4vrk3dvlyefc3xeg7jetv2jlpskahs5xrs8d6vw5", + "swapper": "neutron16xdh5w4dynfjrvnfuhv9h2znks94fyt4gp448jhtmjs3xd6smjvqumh9x2" } diff --git a/scripts/deploy/base/deployer.ts b/scripts/deploy/base/deployer.ts index f37772595..6ee676aae 100644 --- a/scripts/deploy/base/deployer.ts +++ b/scripts/deploy/base/deployer.ts @@ -137,7 +137,7 @@ export class Deployer { async instantiateOracle(init_params?: WasmOracleCustomInitParams) { const msg: OracleInstantiateMsg = { owner: this.deployerAddress, - base_denom: this.config.baseAssetDenom, + base_denom: this.config.oracleBaseDenom, custom_init: init_params, } await this.instantiate('oracle', this.storage.codeIds.oracle!, msg) @@ -151,15 +151,16 @@ export class Deployer { safety_fund_denom: this.config.safetyFundDenom, fee_collector_denom: this.config.feeCollectorDenom, channel_id: this.config.channelId, - timeout_seconds: this.config.rewardCollectorTimeoutSeconds, + timeout_seconds: this.config.rewardsCollectorTimeoutSeconds, slippage_tolerance: this.config.slippage_tolerance, + neutron_ibc_config: this.config.rewardsCollectorNeutronIbcConfig, } await this.instantiate('rewards-collector', this.storage.codeIds['rewards-collector']!, msg) } async instantiateSwapper() { const msg: SwapperInstantiateMsg = { - owner: this.storage.owner!, + owner: this.deployerAddress, } await this.instantiate('swapper', this.storage.codeIds.swapper!, msg) @@ -302,6 +303,8 @@ export class Deployer { printYellow(`Twap snapshots recorded for denoms: ${denoms.join(',')}.`) } async setOracle(oracleConfig: OracleConfig) { + printBlue(`Setting oracle price source: ${JSON.stringify(oracleConfig)}`) + const msg = { set_price_source: oracleConfig, } @@ -317,7 +320,7 @@ export class Deployer { })) as { price: number; denom: string } printGreen( - `${this.config.chainId} :: ${oracleConfig.denom} oracle price : ${JSON.stringify( + `${this.config.chainId} :: ${oracleConfig.denom} oracle price: ${JSON.stringify( oracleResult, )}`, ) @@ -421,62 +424,74 @@ export class Deployer { const coins = [ { denom: this.config.atomDenom, - amount: '2000000', + amount: '20000', }, ] - await this.client.sendTokens( - this.deployerAddress, - this.storage.addresses['rewards-collector']!, - coins, - 'auto', - ) - - // Check contract balance before swap - const atomBalanceBefore = await this.client.getBalance( - this.storage.addresses['rewards-collector']!, - this.config.atomDenom, - ) - const baseAssetBalanceBefore = await this.client.getBalance( - this.storage.addresses['rewards-collector']!, - this.config.baseAssetDenom, - ) - printYellow( - `Rewards Collector balance: - ${atomBalanceBefore.amount} ${atomBalanceBefore.denom} - ${baseAssetBalanceBefore.amount} ${baseAssetBalanceBefore.denom}`, - ) - // Execute swap - const msg = { - swap_asset: { - denom: this.config.atomDenom, - }, - } - await this.client.execute( + const deployerAtomBalance = await this.client.getBalance( this.deployerAddress, - this.storage.addresses['rewards-collector']!, - msg, - 'auto', - ) - // Check contract balance after swap - const atomBalanceAfter = await this.client.getBalance( - this.storage.addresses['rewards-collector']!, this.config.atomDenom, ) - const baseAssetBalanceAfter = await this.client.getBalance( - this.storage.addresses['rewards-collector']!, - this.config.baseAssetDenom, - ) - printYellow( - `Swap executed. Rewards Collector balance: - ${atomBalanceAfter.amount} ${atomBalanceAfter.denom}, - ${baseAssetBalanceAfter.amount} ${baseAssetBalanceAfter.denom}`, - ) - // swapped all atom balance - assert.equal(Number(atomBalanceAfter.amount), 0) - // base asset balance should be greater after swap - assert(Number(baseAssetBalanceAfter.amount) > Number(baseAssetBalanceBefore.amount)) + if (Number(deployerAtomBalance.amount) < Number(coins[0].amount)) { + printRed( + `not enough ATOM tokens to complete rewards-collector swap action, ${this.deployerAddress} has ${deployerAtomBalance.amount} ATOM but needs ${coins[0].amount}.`, + ) + } else { + await this.client.sendTokens( + this.deployerAddress, + this.storage.addresses['rewards-collector']!, + coins, + 'auto', + ) + + // Check contract balance before swap + const atomBalanceBefore = await this.client.getBalance( + this.storage.addresses['rewards-collector']!, + this.config.atomDenom, + ) + const baseAssetBalanceBefore = await this.client.getBalance( + this.storage.addresses['rewards-collector']!, + this.config.baseAssetDenom, + ) + printYellow( + `Rewards Collector balance: + ${atomBalanceBefore.amount} ${atomBalanceBefore.denom} + ${baseAssetBalanceBefore.amount} ${baseAssetBalanceBefore.denom}`, + ) + + // Execute swap + const msg = { + swap_asset: { + denom: this.config.atomDenom, + }, + } + await this.client.execute( + this.deployerAddress, + this.storage.addresses['rewards-collector']!, + msg, + 'auto', + ) + // Check contract balance after swap + const atomBalanceAfter = await this.client.getBalance( + this.storage.addresses['rewards-collector']!, + this.config.atomDenom, + ) + const baseAssetBalanceAfter = await this.client.getBalance( + this.storage.addresses['rewards-collector']!, + this.config.baseAssetDenom, + ) + printYellow( + `Swap executed. Rewards Collector balance: + ${atomBalanceAfter.amount} ${atomBalanceAfter.denom}, + ${baseAssetBalanceAfter.amount} ${baseAssetBalanceAfter.denom}`, + ) + + // swapped all atom balance + assert.equal(Number(atomBalanceAfter.amount), 0) + // base asset balance should be greater after swap + assert(Number(baseAssetBalanceAfter.amount) > Number(baseAssetBalanceBefore.amount)) + } } async updateIncentivesContractOwner() { @@ -494,7 +509,7 @@ export class Deployer { { config: {}, }, - )) as { proposed_new_owner: string; prefix: string } + )) as { proposed_new_owner: string } printRed(`${incentivesConfig.proposed_new_owner}`) assert.equal(incentivesConfig.proposed_new_owner, this.config.multisigAddr) @@ -520,7 +535,7 @@ export class Deployer { { config: {}, }, - )) as { proposed_new_owner: string; prefix: string } + )) as { proposed_new_owner: string } assert.equal(redbankConfig.proposed_new_owner, this.config.multisigAddr) } @@ -537,7 +552,7 @@ export class Deployer { printYellow('Owner updated to Mutlisig for Oracle') const oracleConfig = (await this.client.queryContractSmart(this.storage.addresses.oracle!, { config: {}, - })) as { proposed_new_owner: string; prefix: string } + })) as { proposed_new_owner: string } assert.equal(oracleConfig.proposed_new_owner, this.config.multisigAddr) } @@ -562,11 +577,28 @@ export class Deployer { { config: {}, }, - )) as { proposed_new_owner: string; prefix: string } + )) as { proposed_new_owner: string } assert.equal(rewardsConfig.proposed_new_owner, this.config.multisigAddr) } + async updateSwapperContractOwner() { + const msg = { + update_owner: { + propose_new_owner: { + proposed: this.storage.owner, + }, + }, + } + await this.client.execute(this.deployerAddress, this.storage.addresses.swapper!, msg, 'auto') + printYellow('Owner updated to Mutlisig for Swapper') + const swapperConfig = (await this.client.queryContractSmart(this.storage.addresses.swapper!, { + owner: {}, + })) as { proposed: string } + + assert.equal(swapperConfig.proposed, this.config.multisigAddr) + } + async updateAddressProviderContractOwner() { const msg = { update_owner: { @@ -587,7 +619,7 @@ export class Deployer { { config: {}, }, - )) as { proposed_new_owner: string; prefix: string } + )) as { proposed_new_owner: string } assert.equal(addressProviderConfig.proposed_new_owner, this.config.multisigAddr) } diff --git a/scripts/deploy/base/index.ts b/scripts/deploy/base/index.ts index 38eb9c0b6..86c48bc53 100644 --- a/scripts/deploy/base/index.ts +++ b/scripts/deploy/base/index.ts @@ -14,7 +14,10 @@ export const taskRunner = async (config: DeploymentConfig) => { await deployer.upload('address-provider', 'mars_address_provider.wasm') await deployer.upload('incentives', 'mars_incentives.wasm') await deployer.upload('oracle', `mars_oracle_${config.oracleName}.wasm`) - await deployer.upload('rewards-collector', `mars_rewards_collector.wasm`) + await deployer.upload( + 'rewards-collector', + `mars_rewards_collector_${config.rewardsCollectorName}.wasm`, + ) await deployer.upload('swapper', `mars_swapper_${config.swapperDexName}.wasm`) // Instantiate contracts @@ -37,7 +40,7 @@ export const taskRunner = async (config: DeploymentConfig) => { await deployer.setOracle(oracleConfig) } - //run tests + // run tests if (config.runTests) { await deployer.executeDeposit() await deployer.executeBorrow() @@ -51,6 +54,7 @@ export const taskRunner = async (config: DeploymentConfig) => { await deployer.updateRedBankContractOwner() await deployer.updateOracleContractOwner() await deployer.updateRewardsContractOwner() + await deployer.updateSwapperContractOwner() await deployer.updateAddressProviderContractOwner() printGreen('It is confirmed that all contracts have transferred ownership to the Multisig') } else { diff --git a/scripts/deploy/neutron/config.ts b/scripts/deploy/neutron/config.ts deleted file mode 100644 index 4928c0bcc..000000000 --- a/scripts/deploy/neutron/config.ts +++ /dev/null @@ -1,212 +0,0 @@ -import { DeploymentConfig, AssetConfig, OracleConfig } from '../../types/config' - -const axlUSDCTestnet = 'ibc/EFB00E728F98F0C4BBE8CA362123ACAB466EDA2826DC6837E49F4C1902F21BBA' // TODO: This is actually ASTRO since there is no pool for axlUSDC on testnet -const atomTestnet = 'ibc/C4CFF46FD6DE35CA4CF4CE031E643C8FDC9BA4B99AE598E9B0ED98FE3A2319F9' -const marsTestnet = 'ibc/584A4A23736884E0C198FD1EE932455A9357A492A7B94324E4A02B5628687831' -const protocolAdminAddrTestnet = 'neutron1ke0vqqzyymlp5esr8gjwuzh94ysnpvj8er5hm7' -const astroportFactoryTestnet = 'neutron1jj0scx400pswhpjes589aujlqagxgcztw04srynmhf0f6zplzn2qqmhwj7' -const astroportRouterTestnet = 'neutron12jm24l9lr9cupufqjuxpdjnnweana4h66tsx5cl800mke26td26sq7m05p' - -// note the following three addresses are all 'mars' bech32 prefix -const safetyFundAddr = 'mars1s4hgh56can3e33e0zqpnjxh0t5wdf7u3pze575' -const feeCollectorAddr = 'mars17xpfvakm2amg962yls6f84z3kell8c5ldy6e7x' - -export const ntrnAsset: AssetConfig = { - denom: 'untrn', - max_loan_to_value: '0.59', - reserve_factor: '0.2', - liquidation_threshold: '0.61', - liquidation_bonus: '0.15', - interest_rate_model: { - optimal_utilization_rate: '0.6', - base: '0', - slope_1: '0.15', - slope_2: '3', - }, - deposit_cap: '2500000000000', - deposit_enabled: true, - borrow_enabled: true, - symbol: 'NTRN', -} - -export const atomAsset: AssetConfig = { - denom: atomTestnet, - max_loan_to_value: '0.68', - reserve_factor: '0.2', - liquidation_threshold: '0.7', - liquidation_bonus: '0.15', - interest_rate_model: { - optimal_utilization_rate: '0.6', - base: '0', - slope_1: '0.15', - slope_2: '3', - }, - deposit_cap: '100000000000', - deposit_enabled: true, - borrow_enabled: true, - symbol: 'ATOM', -} - -export const axlUSDCAsset: AssetConfig = { - denom: axlUSDCTestnet, - max_loan_to_value: '0.74', - reserve_factor: '0.2', - liquidation_threshold: '0.75', - liquidation_bonus: '0.1', - interest_rate_model: { - optimal_utilization_rate: '0.8', - base: '0', - slope_1: '0.2', - slope_2: '2', - }, - deposit_cap: '500000000000', - deposit_enabled: true, - borrow_enabled: true, - symbol: 'axlUSDC', -} - -export const ntrnOracleTestnet: OracleConfig = { - denom: 'untrn', - price_source: { - astroport_twap: { - window_size: 1800, // 30 minutes - tolerance: 120, // 2 minutes - pair_address: 'neutron1vwrktvvxnevy7s5t7v44z72pdxncnq9gdsjwq9607cdd6vl2lfcs33fpah', - }, - }, -} - -export const atomOracleTestnet: OracleConfig = { - denom: atomTestnet, - price_source: { - astroport_twap: { - window_size: 1800, // 30 minutes - tolerance: 120, // 2 minutes - pair_address: 'neutron1sm23jnz4lqd88etklvwlm66a0x6mhflaqlv65wwr7nwwxa6258ks6nshpq', - }, - }, -} - -export const axlUSDCOracleTestnet: OracleConfig = { - denom: axlUSDCTestnet, - price_source: { - fixed: { - price: '1.0', - }, - }, -} - -export const neutronTestnetConfig: DeploymentConfig = { - oracleName: 'wasm', - atomDenom: atomTestnet, - baseAssetDenom: 'untrn', - gasPrice: '0untrn', - // gasPrice: '1untrn', // when using polkachu we cannot have 0 gas price - chainId: 'pion-1', - chainPrefix: 'neutron', - channelId: 'channel-97', - marsDenom: marsTestnet, - rewardCollectorTimeoutSeconds: 600, - rpcEndpoint: 'https://rpc-palvus.pion-1.ntrn.tech:443', - // rpcEndpoint: 'https://neutron-testnet-rpc.polkachu.com:443', - safetyFundFeeShare: '0.5', - deployerMnemonic: - 'bundle bundle orchard jeans office umbrella bird around taxi arrive infant discover elder they joy misery photo crunch gift fancy pledge attend adult eight', // TODO: Set mnemonic before deploying - slippage_tolerance: '0.01', - base_asset_symbol: 'NTRN', - second_asset_symbol: 'ATOM', - runTests: true, - mainnet: false, - feeCollectorDenom: marsTestnet, - safetyFundDenom: axlUSDCTestnet, - swapRoutes: [ - { - denom_in: atomTestnet, - denom_out: 'untrn', - route: { - factory: astroportFactoryTestnet, - operations: [ - { - astro_swap: { - ask_asset_info: { - native_token: { - denom: 'untrn', - }, - }, - offer_asset_info: { - native_token: { - denom: atomTestnet, - }, - }, - }, - }, - ], - oracle: '', // Will be filled in by deploy script - router: astroportRouterTestnet, - }, - }, - { - denom_in: atomTestnet, - denom_out: axlUSDCTestnet, - route: { - factory: astroportFactoryTestnet, - operations: [ - { - astro_swap: { - ask_asset_info: { - native_token: { - denom: axlUSDCTestnet, - }, - }, - offer_asset_info: { - native_token: { - denom: atomTestnet, - }, - }, - }, - }, - ], - oracle: '', // Will be filled in by deploy script - router: astroportRouterTestnet, - }, - }, - { - denom_in: 'untrn', - denom_out: axlUSDCTestnet, - route: { - factory: astroportFactoryTestnet, - operations: [ - { - astro_swap: { - ask_asset_info: { - native_token: { - denom: axlUSDCTestnet, - }, - }, - offer_asset_info: { - native_token: { - denom: 'untrn', - }, - }, - }, - }, - ], - oracle: '', // Will be filled in by deploy script - router: astroportRouterTestnet, - }, - }, - ], - safetyFundAddr: safetyFundAddr, - protocolAdminAddr: protocolAdminAddrTestnet, - feeCollectorAddr: feeCollectorAddr, - swapperDexName: 'astroport', - assets: [ntrnAsset, atomAsset], - oracleConfigs: [axlUSDCOracleTestnet, ntrnOracleTestnet, atomOracleTestnet], - maxCloseFactor: '0.5', - oracleCustomInitParams: { - astroport_factory: 'neutron1jj0scx400pswhpjes589aujlqagxgcztw04srynmhf0f6zplzn2qqmhwj7', - }, - incentiveEpochDuration: 604800, // 1 week - maxWhitelistedIncentiveDenoms: 10, - targetHealthFactor: '1.2', -} diff --git a/scripts/deploy/neutron/config_mainnet.ts b/scripts/deploy/neutron/config_mainnet.ts new file mode 100644 index 000000000..96b360b40 --- /dev/null +++ b/scripts/deploy/neutron/config_mainnet.ts @@ -0,0 +1,356 @@ +import { DeploymentConfig, AssetConfig, OracleConfig } from '../../types/config' +import { NeutronIbcConfig } from '../../types/generated/mars-rewards-collector-base/MarsRewardsCollectorBase.types' + +const axlUsdcDenom = 'ibc/F082B65C88E4B6D5EF1DB243CDA1D331D002759E938A0F5CD3FFDC5D53B3E349' +const atomDenom = 'ibc/C4CFF46FD6DE35CA4CF4CE031E643C8FDC9BA4B99AE598E9B0ED98FE3A2319F9' +const marsDenom = 'ibc/9598CDEB7C6DB7FC21E746C8E0250B30CD5154F39CA111A9D4948A4362F638BD' + +const protocolAdminAddr = 'neutron1ltzuv25ltw9mkwuvvmt7e54a6ene283hfj7l0c' + +const marsNeutronChannelId = 'channel-16' +const gasPrice = '0.01untrn' +const chainId = 'neutron-1' +const rpcEndpoint = + 'https://neutron.rpc.p2p.world:443/qgrnU6PsQZA8F9S5Fb8Fn3tV3kXmMBl2M9bcc9jWLjQy8p' + +// Astroport configuration +const astroportFactory = 'neutron1hptk0k5kng7hjy35vmh009qd5m6l33609nypgf2yc6nqnewduqasxplt4e' +const astroportRouter = 'neutron1eeyntmsq448c68ez06jsy6h2mtjke5tpuplnwtjfwcdznqmw72kswnlmm0' +const astroportNtrnAtomPair = 'neutron1e22zh5p8meddxjclevuhjmfj69jxfsa8uu3jvht72rv9d8lkhves6t8veq' +const astroportMarsUsdcPair = 'neutron165m0r6rkhqxs30wch00t7mkykxxvgve9yyu254wknwhhjn34rmqsh6vfcj' + +// note the following three addresses are all 'mars' bech32 prefix +const safetyFundAddr = 'mars1s4hgh56can3e33e0zqpnjxh0t5wdf7u3pze575' +const feeCollectorAddr = 'mars17xpfvakm2amg962yls6f84z3kell8c5ldy6e7x' + +// Pyth configuration +const pythAddr = 'neutron1m2emc93m9gpwgsrsf2vylv9xvgqh654630v7dfrhrkmr5slly53spg85wv' +const pythAtomID = 'b00b60f88b03a6a625a8d1c048c3f66653edf217439983d037e7222c4e612819' +const pythUsdcID = 'eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a' + +// IBC config for rewards-collector. See https://neutron.rpc.p2p.world/qgrnU6PsQZA8F9S5Fb8Fn3tV3kXmMBl2M9bcc9jWLjQy8p/lcd/neutron-org/neutron/feerefunder/params +export const neutronIbcConfig: NeutronIbcConfig = { + source_port: 'transfer', + acc_fee: [ + { + denom: 'untrn', + amount: '100000', + }, + ], + timeout_fee: [ + { + denom: 'untrn', + amount: '100000', + }, + ], +} + +// Oracle configurations +export const marsOracle: OracleConfig = { + denom: marsDenom, + price_source: { + astroport_twap: { + window_size: 1800, // 30 minutes + tolerance: 120, // 2 minutes + pair_address: astroportMarsUsdcPair, + }, + }, +} + +export const ntrnOracle: OracleConfig = { + denom: 'untrn', + price_source: { + astroport_twap: { + window_size: 1800, // 30 minutes + tolerance: 120, // 2 minutes + pair_address: astroportNtrnAtomPair, + }, + }, +} + +export const atomOracle: OracleConfig = { + denom: atomDenom, + price_source: { + pyth: { + contract_addr: pythAddr, + price_feed_id: pythAtomID, + denom_decimals: 6, + max_staleness: 60, + }, + }, +} + +export const axlUSDCOracle: OracleConfig = { + denom: axlUsdcDenom, + price_source: { + pyth: { + contract_addr: pythAddr, + price_feed_id: pythUsdcID, + denom_decimals: 6, + max_staleness: 60, + }, + }, +} + +export const usdOracle: OracleConfig = { + denom: 'usd', + price_source: { + fixed: { + price: '1000000', + }, + }, +} + +// Router configurations +export const atomUsdcRoute = { + denom_in: atomDenom, + denom_out: axlUsdcDenom, + route: { + factory: astroportFactory, + operations: [ + { + astro_swap: { + ask_asset_info: { + native_token: { + denom: axlUsdcDenom, + }, + }, + offer_asset_info: { + native_token: { + denom: atomDenom, + }, + }, + }, + }, + ], + oracle: '', // Will be filled in by deploy script + router: astroportRouter, + }, +} + +export const ntrnUsdcRoute = { + denom_in: 'untrn', + denom_out: axlUsdcDenom, + route: { + factory: astroportFactory, + operations: [ + { + astro_swap: { + ask_asset_info: { + native_token: { + denom: axlUsdcDenom, + }, + }, + offer_asset_info: { + native_token: { + denom: 'untrn', + }, + }, + }, + }, + ], + oracle: '', // Will be filled in by deploy script + router: astroportRouter, + }, +} + +export const atomMarsRoute = { + denom_in: atomDenom, + denom_out: marsDenom, + route: { + factory: astroportFactory, + operations: [ + { + astro_swap: { + ask_asset_info: { + native_token: { + denom: axlUsdcDenom, + }, + }, + offer_asset_info: { + native_token: { + denom: atomDenom, + }, + }, + }, + }, + { + astro_swap: { + ask_asset_info: { + native_token: { + denom: marsDenom, + }, + }, + offer_asset_info: { + native_token: { + denom: axlUsdcDenom, + }, + }, + }, + }, + ], + oracle: '', // Will be filled in by deploy script + router: astroportRouter, + }, +} + +export const ntrnMarsRoute = { + denom_in: 'untrn', + denom_out: marsDenom, + route: { + factory: astroportFactory, + operations: [ + { + astro_swap: { + ask_asset_info: { + native_token: { + denom: axlUsdcDenom, + }, + }, + offer_asset_info: { + native_token: { + denom: 'untrn', + }, + }, + }, + }, + { + astro_swap: { + ask_asset_info: { + native_token: { + denom: marsDenom, + }, + }, + offer_asset_info: { + native_token: { + denom: axlUsdcDenom, + }, + }, + }, + }, + ], + oracle: '', // Will be filled in by deploy script + router: astroportRouter, + }, +} + +export const usdcMarsRoute = { + denom_in: axlUsdcDenom, + denom_out: marsDenom, + route: { + factory: astroportFactory, + operations: [ + { + astro_swap: { + ask_asset_info: { + native_token: { + denom: marsDenom, + }, + }, + offer_asset_info: { + native_token: { + denom: axlUsdcDenom, + }, + }, + }, + }, + ], + oracle: '', // Will be filled in by deploy script + router: astroportRouter, + }, +} + +// Asset configurations +export const ntrnAsset: AssetConfig = { + denom: 'untrn', + max_loan_to_value: '0.35', + reserve_factor: '0.1', + liquidation_threshold: '0.40', + liquidation_bonus: '0.15', + interest_rate_model: { + optimal_utilization_rate: '0.6', + base: '0', + slope_1: '0.15', + slope_2: '3', + }, + deposit_cap: '5000000000000', + deposit_enabled: true, + borrow_enabled: true, + symbol: 'NTRN', +} + +export const atomAsset: AssetConfig = { + denom: atomDenom, + max_loan_to_value: '0.68', + reserve_factor: '0.1', + liquidation_threshold: '0.7', + liquidation_bonus: '0.1', + interest_rate_model: { + optimal_utilization_rate: '0.7', + base: '0', + slope_1: '0.2', + slope_2: '3', + }, + deposit_cap: '150000000000', + deposit_enabled: true, + borrow_enabled: true, + symbol: 'ATOM', +} + +export const axlUSDCAsset: AssetConfig = { + denom: axlUsdcDenom, + max_loan_to_value: '0.74', + reserve_factor: '0.1', + liquidation_threshold: '0.75', + liquidation_bonus: '0.1', + interest_rate_model: { + optimal_utilization_rate: '0.8', + base: '0', + slope_1: '0.125', + slope_2: '2', + }, + deposit_cap: '500000000000', + deposit_enabled: true, + borrow_enabled: true, + symbol: 'axlUSDC', +} + +export const neutronMainnetConfig: DeploymentConfig = { + oracleName: 'wasm', + oracleBaseDenom: 'uusd', + rewardsCollectorName: 'neutron', + rewardsCollectorNeutronIbcConfig: neutronIbcConfig, + atomDenom: atomDenom, + baseAssetDenom: 'untrn', + gasPrice: gasPrice, + chainId: chainId, + chainPrefix: 'neutron', + channelId: marsNeutronChannelId, + marsDenom: marsDenom, + rewardsCollectorTimeoutSeconds: 600, + rpcEndpoint: rpcEndpoint, + safetyFundFeeShare: '0.5', + deployerMnemonic: '', // TODO: Set mnemonic before deploying + multisigAddr: protocolAdminAddr, + slippage_tolerance: '0.01', + base_asset_symbol: 'NTRN', + second_asset_symbol: 'ATOM', + runTests: false, + mainnet: true, + feeCollectorDenom: marsDenom, + safetyFundDenom: axlUsdcDenom, + swapRoutes: [atomUsdcRoute, atomMarsRoute, ntrnUsdcRoute, ntrnMarsRoute, usdcMarsRoute], + safetyFundAddr: safetyFundAddr, + protocolAdminAddr: protocolAdminAddr, + feeCollectorAddr: feeCollectorAddr, + swapperDexName: 'astroport', + assets: [ntrnAsset, atomAsset, axlUSDCAsset], + oracleConfigs: [usdOracle, axlUSDCOracle, marsOracle, atomOracle, ntrnOracle], + maxCloseFactor: '0.5', + oracleCustomInitParams: { + astroport_factory: astroportFactory, + }, + incentiveEpochDuration: 604800, // 1 week + maxWhitelistedIncentiveDenoms: 10, + targetHealthFactor: '1.2', +} diff --git a/scripts/deploy/neutron/config_testnet.ts b/scripts/deploy/neutron/config_testnet.ts new file mode 100644 index 000000000..24bc0db21 --- /dev/null +++ b/scripts/deploy/neutron/config_testnet.ts @@ -0,0 +1,315 @@ +import { DeploymentConfig, AssetConfig, OracleConfig } from '../../types/config' +import { NeutronIbcConfig } from '../../types/generated/mars-rewards-collector-base/MarsRewardsCollectorBase.types' + +const axlUsdcDenom = 'ibc/F91EA2C0A23697A1048E08C2F787E3A58AC6F706A1CD2257A504925158CFC0F3' +const atomDenom = 'ibc/C4CFF46FD6DE35CA4CF4CE031E643C8FDC9BA4B99AE598E9B0ED98FE3A2319F9' +const marsDenom = 'ibc/584A4A23736884E0C198FD1EE932455A9357A492A7B94324E4A02B5628687831' + +const protocolAdminAddr = 'neutron1ke0vqqzyymlp5esr8gjwuzh94ysnpvj8er5hm7' + +const marsNeutronChannelId = 'channel-97' +const gasPrice = '0.01untrn' +const chainId = 'pion-1' +const rpcEndpoint = 'https://testnet-neutron-rpc.marsprotocol.io:443' + +// Astroport configuration +const astroportFactory = 'neutron1jj0scx400pswhpjes589aujlqagxgcztw04srynmhf0f6zplzn2qqmhwj7' +const astroportRouter = 'neutron12jm24l9lr9cupufqjuxpdjnnweana4h66tsx5cl800mke26td26sq7m05p' +const astroportNtrnAtomPair = 'neutron1sm23jnz4lqd88etklvwlm66a0x6mhflaqlv65wwr7nwwxa6258ks6nshpq' + +// note the following three addresses are all 'mars' bech32 prefix +const safetyFundAddr = 'mars1s4hgh56can3e33e0zqpnjxh0t5wdf7u3pze575' +const feeCollectorAddr = 'mars17xpfvakm2amg962yls6f84z3kell8c5ldy6e7x' + +// Pyth configuration +const pythAddr = 'neutron1f86ct5az9qpz2hqfd5uxru02px2a3tz5zkw7hugd7acqq496dcms22ehpy' +const pythAtomID = 'b00b60f88b03a6a625a8d1c048c3f66653edf217439983d037e7222c4e612819' +const pythUsdcID = 'eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a' + +// IBC config for rewards-collector. See https://rest-palvus.pion-1.ntrn.tech/neutron-org/neutron/feerefunder/params +export const neutronIbcConfig: NeutronIbcConfig = { + source_port: 'transfer', + acc_fee: [ + { + denom: 'untrn', + amount: '1000', + }, + ], + timeout_fee: [ + { + denom: 'untrn', + amount: '1000', + }, + ], +} + +// Oracle configurations +export const ntrnOracle: OracleConfig = { + denom: 'untrn', + price_source: { + astroport_twap: { + window_size: 1800, // 30 minutes + tolerance: 120, // 2 minutes + pair_address: astroportNtrnAtomPair, + }, + }, +} + +export const atomOracle: OracleConfig = { + denom: atomDenom, + price_source: { + pyth: { + contract_addr: pythAddr, + price_feed_id: pythAtomID, + denom_decimals: 6, + max_staleness: 300, // 5 minutes + }, + }, +} + +export const axlUSDCOracle: OracleConfig = { + denom: axlUsdcDenom, + price_source: { + pyth: { + contract_addr: pythAddr, + price_feed_id: pythUsdcID, + denom_decimals: 6, + max_staleness: 300, // 5 minutes + }, + }, +} + +export const usdOracle: OracleConfig = { + denom: 'usd', + price_source: { + fixed: { + price: '1000000', + }, + }, +} + +// Router configurations +export const atomUsdcRoute = { + denom_in: atomDenom, + denom_out: axlUsdcDenom, + route: { + factory: astroportFactory, + operations: [ + { + astro_swap: { + ask_asset_info: { + native_token: { + denom: axlUsdcDenom, + }, + }, + offer_asset_info: { + native_token: { + denom: atomDenom, + }, + }, + }, + }, + ], + oracle: '', // Will be filled in by deploy script + router: astroportRouter, + }, +} + +export const ntrnUsdcRoute = { + denom_in: 'untrn', + denom_out: axlUsdcDenom, + route: { + factory: astroportFactory, + operations: [ + { + astro_swap: { + ask_asset_info: { + native_token: { + denom: axlUsdcDenom, + }, + }, + offer_asset_info: { + native_token: { + denom: 'untrn', + }, + }, + }, + }, + ], + oracle: '', // Will be filled in by deploy script + router: astroportRouter, + }, +} + +export const atomMarsRoute = { + denom_in: atomDenom, + denom_out: marsDenom, + route: { + factory: astroportFactory, + operations: [ + { + astro_swap: { + ask_asset_info: { + native_token: { + denom: marsDenom, + }, + }, + offer_asset_info: { + native_token: { + denom: atomDenom, + }, + }, + }, + }, + ], + oracle: '', // Will be filled in by deploy script + router: astroportRouter, + }, +} + +export const ntrnMarsRoute = { + denom_in: 'untrn', + denom_out: marsDenom, + route: { + factory: astroportFactory, + operations: [ + { + astro_swap: { + ask_asset_info: { + native_token: { + denom: marsDenom, + }, + }, + offer_asset_info: { + native_token: { + denom: 'untrn', + }, + }, + }, + }, + ], + oracle: '', // Will be filled in by deploy script + router: astroportRouter, + }, +} + +export const usdcMarsRoute = { + denom_in: axlUsdcDenom, + denom_out: marsDenom, + route: { + factory: astroportFactory, + operations: [ + { + astro_swap: { + ask_asset_info: { + native_token: { + denom: marsDenom, + }, + }, + offer_asset_info: { + native_token: { + denom: axlUsdcDenom, + }, + }, + }, + }, + ], + oracle: '', // Will be filled in by deploy script + router: astroportRouter, + }, +} + +// Asset configurations +export const ntrnAsset: AssetConfig = { + denom: 'untrn', + max_loan_to_value: '0.35', + reserve_factor: '0.1', + liquidation_threshold: '0.40', + liquidation_bonus: '0.15', + interest_rate_model: { + optimal_utilization_rate: '0.6', + base: '0', + slope_1: '0.15', + slope_2: '3', + }, + deposit_cap: '5000000000000', + deposit_enabled: true, + borrow_enabled: true, + symbol: 'NTRN', +} + +export const atomAsset: AssetConfig = { + denom: atomDenom, + max_loan_to_value: '0.68', + reserve_factor: '0.1', + liquidation_threshold: '0.7', + liquidation_bonus: '0.1', + interest_rate_model: { + optimal_utilization_rate: '0.7', + base: '0', + slope_1: '0.2', + slope_2: '3', + }, + deposit_cap: '150000000000', + deposit_enabled: true, + borrow_enabled: true, + symbol: 'ATOM', +} + +export const axlUSDCAsset: AssetConfig = { + denom: axlUsdcDenom, + max_loan_to_value: '0.74', + reserve_factor: '0.1', + liquidation_threshold: '0.75', + liquidation_bonus: '0.1', + interest_rate_model: { + optimal_utilization_rate: '0.8', + base: '0', + slope_1: '0.125', + slope_2: '2', + }, + deposit_cap: '500000000000', + deposit_enabled: true, + borrow_enabled: true, + symbol: 'axlUSDC', +} + +export const neutronTestnetConfig: DeploymentConfig = { + oracleName: 'wasm', + oracleBaseDenom: 'uusd', + rewardsCollectorName: 'neutron', + rewardsCollectorNeutronIbcConfig: neutronIbcConfig, + atomDenom: atomDenom, + baseAssetDenom: 'untrn', + gasPrice: gasPrice, + chainId: chainId, + chainPrefix: 'neutron', + channelId: marsNeutronChannelId, + marsDenom: marsDenom, + rewardsCollectorTimeoutSeconds: 600, + rpcEndpoint: rpcEndpoint, + safetyFundFeeShare: '0.5', + deployerMnemonic: + 'bundle bundle orchard jeans office umbrella bird around taxi arrive infant discover elder they joy misery photo crunch gift fancy pledge attend adult eight', + slippage_tolerance: '0.01', + base_asset_symbol: 'NTRN', + second_asset_symbol: 'ATOM', + runTests: true, + mainnet: false, + feeCollectorDenom: marsDenom, + safetyFundDenom: axlUsdcDenom, + swapRoutes: [atomUsdcRoute, atomMarsRoute, ntrnUsdcRoute, ntrnMarsRoute, usdcMarsRoute], + safetyFundAddr: safetyFundAddr, + protocolAdminAddr: protocolAdminAddr, + feeCollectorAddr: feeCollectorAddr, + swapperDexName: 'astroport', + assets: [ntrnAsset, atomAsset, axlUSDCAsset], + oracleConfigs: [usdOracle, axlUSDCOracle, atomOracle, ntrnOracle], + maxCloseFactor: '0.5', + oracleCustomInitParams: { + astroport_factory: astroportFactory, + }, + incentiveEpochDuration: 604800, // 1 week + maxWhitelistedIncentiveDenoms: 10, + targetHealthFactor: '1.2', +} diff --git a/scripts/deploy/neutron/config_testnet_multisig.ts b/scripts/deploy/neutron/config_testnet_multisig.ts new file mode 100644 index 000000000..00e5f9878 --- /dev/null +++ b/scripts/deploy/neutron/config_testnet_multisig.ts @@ -0,0 +1,355 @@ +import { DeploymentConfig, AssetConfig, OracleConfig } from '../../types/config' +import { NeutronIbcConfig } from '../../types/generated/mars-rewards-collector-base/MarsRewardsCollectorBase.types' + +const axlUsdcDenom = 'ibc/F91EA2C0A23697A1048E08C2F787E3A58AC6F706A1CD2257A504925158CFC0F3' +const atomDenom = 'ibc/C4CFF46FD6DE35CA4CF4CE031E643C8FDC9BA4B99AE598E9B0ED98FE3A2319F9' +const marsDenom = 'ibc/584A4A23736884E0C198FD1EE932455A9357A492A7B94324E4A02B5628687831' + +const protocolAdminAddr = 'neutron1ltzuv25ltw9mkwuvvmt7e54a6ene283hfj7l0c' + +const marsNeutronChannelId = 'channel-97' +const gasPrice = '0.01untrn' +const chainId = 'pion-1' +const rpcEndpoint = 'https://testnet-neutron-rpc.marsprotocol.io:443' + +// Astroport configuration +const astroportFactory = 'neutron1jj0scx400pswhpjes589aujlqagxgcztw04srynmhf0f6zplzn2qqmhwj7' +const astroportRouter = 'neutron12jm24l9lr9cupufqjuxpdjnnweana4h66tsx5cl800mke26td26sq7m05p' +const astroportNtrnAtomPair = 'neutron1sm23jnz4lqd88etklvwlm66a0x6mhflaqlv65wwr7nwwxa6258ks6nshpq' +const astroportMarsUsdcPair = 'neutron1xf0awuvhkrq553p543narplfp5x7ltjwwys6dyzfnmvs75v3yfqsw65lyp' +const astroportAtomUsdcPair = 'neutron18j9jfw9dlw3ep8fkyfftpag70656cv7q60plluaf9tjwyn9wx0pq9t9wtu' + +// note the following three addresses are all 'mars' bech32 prefix +const safetyFundAddr = 'mars1s4hgh56can3e33e0zqpnjxh0t5wdf7u3pze575' +const feeCollectorAddr = 'mars17xpfvakm2amg962yls6f84z3kell8c5ldy6e7x' + +// Pyth configuration +const pythAddr = 'neutron1f86ct5az9qpz2hqfd5uxru02px2a3tz5zkw7hugd7acqq496dcms22ehpy' +const pythUsdcID = 'eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a' + +// IBC config for rewards-collector. See https://rest-palvus.pion-1.ntrn.tech/neutron-org/neutron/feerefunder/params +export const neutronIbcConfig: NeutronIbcConfig = { + source_port: 'transfer', + acc_fee: [ + { + denom: 'untrn', + amount: '1000', + }, + ], + timeout_fee: [ + { + denom: 'untrn', + amount: '1000', + }, + ], +} + +// Oracle configurations +export const marsOracle: OracleConfig = { + denom: marsDenom, + price_source: { + astroport_twap: { + window_size: 300, // 5 minutes + tolerance: 120, // 2 minutes + pair_address: astroportMarsUsdcPair, + }, + }, +} + +export const ntrnOracle: OracleConfig = { + denom: 'untrn', + price_source: { + astroport_twap: { + window_size: 300, // 5 minutes + tolerance: 120, // 2 minutes + pair_address: astroportNtrnAtomPair, + }, + }, +} + +export const atomOracle: OracleConfig = { + denom: atomDenom, + price_source: { + astroport_twap: { + window_size: 300, // 5 minutes + tolerance: 120, // 2 minutes + pair_address: astroportAtomUsdcPair, + }, + }, +} + +export const axlUSDCOracle: OracleConfig = { + denom: axlUsdcDenom, + price_source: { + pyth: { + contract_addr: pythAddr, + price_feed_id: pythUsdcID, + denom_decimals: 6, + max_staleness: 300, // 5 minutes + }, + }, +} + +export const usdOracle: OracleConfig = { + denom: 'usd', + price_source: { + fixed: { + price: '1000000', + }, + }, +} + +// Router configurations +export const atomUsdcRoute = { + denom_in: atomDenom, + denom_out: axlUsdcDenom, + route: { + factory: astroportFactory, + operations: [ + { + astro_swap: { + ask_asset_info: { + native_token: { + denom: axlUsdcDenom, + }, + }, + offer_asset_info: { + native_token: { + denom: atomDenom, + }, + }, + }, + }, + ], + oracle: '', // Will be filled in by deploy script + router: astroportRouter, + }, +} + +export const ntrnUsdcRoute = { + denom_in: 'untrn', + denom_out: axlUsdcDenom, + route: { + factory: astroportFactory, + operations: [ + { + astro_swap: { + ask_asset_info: { + native_token: { + denom: axlUsdcDenom, + }, + }, + offer_asset_info: { + native_token: { + denom: 'untrn', + }, + }, + }, + }, + ], + oracle: '', // Will be filled in by deploy script + router: astroportRouter, + }, +} + +export const atomMarsRoute = { + denom_in: atomDenom, + denom_out: marsDenom, + route: { + factory: astroportFactory, + operations: [ + { + astro_swap: { + ask_asset_info: { + native_token: { + denom: axlUsdcDenom, + }, + }, + offer_asset_info: { + native_token: { + denom: atomDenom, + }, + }, + }, + }, + { + astro_swap: { + ask_asset_info: { + native_token: { + denom: marsDenom, + }, + }, + offer_asset_info: { + native_token: { + denom: axlUsdcDenom, + }, + }, + }, + }, + ], + oracle: '', // Will be filled in by deploy script + router: astroportRouter, + }, +} + +export const ntrnMarsRoute = { + denom_in: 'untrn', + denom_out: marsDenom, + route: { + factory: astroportFactory, + operations: [ + { + astro_swap: { + ask_asset_info: { + native_token: { + denom: axlUsdcDenom, + }, + }, + offer_asset_info: { + native_token: { + denom: 'untrn', + }, + }, + }, + }, + { + astro_swap: { + ask_asset_info: { + native_token: { + denom: marsDenom, + }, + }, + offer_asset_info: { + native_token: { + denom: axlUsdcDenom, + }, + }, + }, + }, + ], + oracle: '', // Will be filled in by deploy script + router: astroportRouter, + }, +} + +export const usdcMarsRoute = { + denom_in: axlUsdcDenom, + denom_out: marsDenom, + route: { + factory: astroportFactory, + operations: [ + { + astro_swap: { + ask_asset_info: { + native_token: { + denom: marsDenom, + }, + }, + offer_asset_info: { + native_token: { + denom: axlUsdcDenom, + }, + }, + }, + }, + ], + oracle: '', // Will be filled in by deploy script + router: astroportRouter, + }, +} + +// Asset configurations +export const ntrnAsset: AssetConfig = { + denom: 'untrn', + max_loan_to_value: '0.35', + reserve_factor: '0.1', + liquidation_threshold: '0.40', + liquidation_bonus: '0.15', + interest_rate_model: { + optimal_utilization_rate: '0.6', + base: '0', + slope_1: '0.15', + slope_2: '3', + }, + deposit_cap: '5000000000000', + deposit_enabled: true, + borrow_enabled: true, + symbol: 'NTRN', +} + +export const atomAsset: AssetConfig = { + denom: atomDenom, + max_loan_to_value: '0.68', + reserve_factor: '0.1', + liquidation_threshold: '0.7', + liquidation_bonus: '0.1', + interest_rate_model: { + optimal_utilization_rate: '0.7', + base: '0', + slope_1: '0.2', + slope_2: '3', + }, + deposit_cap: '150000000000', + deposit_enabled: true, + borrow_enabled: true, + symbol: 'ATOM', +} + +export const axlUSDCAsset: AssetConfig = { + denom: axlUsdcDenom, + max_loan_to_value: '0.74', + reserve_factor: '0.1', + liquidation_threshold: '0.75', + liquidation_bonus: '0.1', + interest_rate_model: { + optimal_utilization_rate: '0.8', + base: '0', + slope_1: '0.125', + slope_2: '2', + }, + deposit_cap: '500000000000', + deposit_enabled: true, + borrow_enabled: true, + symbol: 'axlUSDC', +} + +export const neutronTetstnetMultisigConfig: DeploymentConfig = { + oracleName: 'wasm', + oracleBaseDenom: 'uusd', + rewardsCollectorName: 'neutron', + rewardsCollectorNeutronIbcConfig: neutronIbcConfig, + atomDenom: atomDenom, + baseAssetDenom: 'untrn', + gasPrice: gasPrice, + chainId: chainId, + chainPrefix: 'neutron', + channelId: marsNeutronChannelId, + marsDenom: marsDenom, + rewardsCollectorTimeoutSeconds: 600, + rpcEndpoint: rpcEndpoint, + safetyFundFeeShare: '0.5', + deployerMnemonic: + 'bundle bundle orchard jeans office umbrella bird around taxi arrive infant discover elder they joy misery photo crunch gift fancy pledge attend adult eight', + multisigAddr: protocolAdminAddr, + slippage_tolerance: '0.01', + base_asset_symbol: 'NTRN', + second_asset_symbol: 'ATOM', + runTests: false, + mainnet: false, + feeCollectorDenom: marsDenom, + safetyFundDenom: axlUsdcDenom, + swapRoutes: [atomUsdcRoute, atomMarsRoute, ntrnUsdcRoute, ntrnMarsRoute, usdcMarsRoute], + safetyFundAddr: safetyFundAddr, + protocolAdminAddr: protocolAdminAddr, + feeCollectorAddr: feeCollectorAddr, + swapperDexName: 'astroport', + assets: [ntrnAsset, atomAsset, axlUSDCAsset], + oracleConfigs: [usdOracle, axlUSDCOracle, marsOracle, atomOracle, ntrnOracle], + maxCloseFactor: '0.5', + oracleCustomInitParams: { + astroport_factory: astroportFactory, + }, + incentiveEpochDuration: 604800, // 1 week + maxWhitelistedIncentiveDenoms: 10, + targetHealthFactor: '1.2', +} diff --git a/scripts/deploy/neutron/mainIndex.ts b/scripts/deploy/neutron/mainIndex.ts new file mode 100644 index 000000000..b53b1288b --- /dev/null +++ b/scripts/deploy/neutron/mainIndex.ts @@ -0,0 +1,6 @@ +import { taskRunner } from '../base' +import { neutronMainnetConfig } from './config_mainnet.js' + +void (async function () { + await taskRunner(neutronMainnetConfig) +})() diff --git a/scripts/deploy/neutron/multisigIndex.ts b/scripts/deploy/neutron/multisigIndex.ts new file mode 100644 index 000000000..bdb9f9240 --- /dev/null +++ b/scripts/deploy/neutron/multisigIndex.ts @@ -0,0 +1,6 @@ +import { taskRunner } from '../base' +import { neutronTetstnetMultisigConfig } from './config_testnet_multisig' + +void (async function () { + await taskRunner(neutronTetstnetMultisigConfig) +})() diff --git a/scripts/deploy/neutron/recordTwapSnapshots.ts b/scripts/deploy/neutron/recordTwapSnapshots.ts index 5cdbe4491..b58d77ddd 100644 --- a/scripts/deploy/neutron/recordTwapSnapshots.ts +++ b/scripts/deploy/neutron/recordTwapSnapshots.ts @@ -1,5 +1,5 @@ import { setupDeployer } from '../base/setupDeployer' -import { neutronTestnetConfig } from './config' +import { neutronTestnetConfig } from './config_testnet' async function main() { const deployer = await setupDeployer(neutronTestnetConfig) diff --git a/scripts/deploy/neutron/setPrice.ts b/scripts/deploy/neutron/setPrice.ts index 52cdbf184..feff2e336 100644 --- a/scripts/deploy/neutron/setPrice.ts +++ b/scripts/deploy/neutron/setPrice.ts @@ -1,10 +1,10 @@ import { setupDeployer } from '../base/setupDeployer' -import { neutronTestnetConfig, atomOracleTestnet } from './config' +import { neutronTestnetConfig, atomOracle } from './config_testnet' async function main() { const deployer = await setupDeployer(neutronTestnetConfig) - await deployer.setOracle(atomOracleTestnet) + await deployer.setOracle(atomOracle) } main() diff --git a/scripts/deploy/neutron/testIndex.ts b/scripts/deploy/neutron/testIndex.ts index d6d2efc60..a3a3edac6 100644 --- a/scripts/deploy/neutron/testIndex.ts +++ b/scripts/deploy/neutron/testIndex.ts @@ -1,5 +1,5 @@ import { taskRunner } from '../base' -import { neutronTestnetConfig } from './config.js' +import { neutronTestnetConfig } from './config_testnet.js' void (async function () { await taskRunner(neutronTestnetConfig) diff --git a/scripts/deploy/osmosis/config.ts b/scripts/deploy/osmosis/config.ts index 176a950bf..0031c49bd 100644 --- a/scripts/deploy/osmosis/config.ts +++ b/scripts/deploy/osmosis/config.ts @@ -190,6 +190,8 @@ export const marsOracleTest: OracleConfig = { // axlUSDC does not have a pool on testnet so config can't have swapRoutes configured correctly export const osmosisTestnetConfig: DeploymentConfig = { oracleName: 'osmosis', + oracleBaseDenom: 'uusd', + rewardsCollectorName: 'osmosis', atomDenom: atom, baseAssetDenom: 'uosmo', gasPrice: '0.1uosmo', @@ -197,7 +199,7 @@ export const osmosisTestnetConfig: DeploymentConfig = { chainPrefix: 'osmo', channelId: 'channel-2083', marsDenom: marsTest, - rewardCollectorTimeoutSeconds: 600, + rewardsCollectorTimeoutSeconds: 600, rpcEndpoint: 'https://rpc-test.osmosis.zone', safetyFundFeeShare: '0.5', deployerMnemonic: @@ -227,6 +229,8 @@ export const osmosisTestnetConfig: DeploymentConfig = { // axlUSDC does not have a pool on testnet so config can't have swapRoutes configured correctly export const osmosisTestMultisig: DeploymentConfig = { oracleName: 'osmosis', + oracleBaseDenom: 'uusd', + rewardsCollectorName: 'osmosis', atomDenom: atom, baseAssetDenom: 'uosmo', gasPrice: '0.1uosmo', @@ -234,7 +238,7 @@ export const osmosisTestMultisig: DeploymentConfig = { chainPrefix: 'osmo', channelId: 'channel-2083', marsDenom: marsTest, - rewardCollectorTimeoutSeconds: 600, + rewardsCollectorTimeoutSeconds: 600, rpcEndpoint: 'https://rpc-test.osmosis.zone', safetyFundFeeShare: '0.5', deployerMnemonic: @@ -264,6 +268,8 @@ export const osmosisTestMultisig: DeploymentConfig = { export const osmosisMainnet: DeploymentConfig = { oracleName: 'osmosis', + oracleBaseDenom: 'uusd', + rewardsCollectorName: 'osmosis', atomDenom: atom, baseAssetDenom: 'uosmo', gasPrice: '0.1uosmo', @@ -271,7 +277,7 @@ export const osmosisMainnet: DeploymentConfig = { chainPrefix: 'osmo', channelId: 'channel-557', marsDenom: mars, - rewardCollectorTimeoutSeconds: 600, + rewardsCollectorTimeoutSeconds: 600, rpcEndpoint: 'https://rpc.osmosis.zone', safetyFundFeeShare: '0.5', deployerMnemonic: 'TO BE INSERTED AT TIME OF DEPLOYMENT', @@ -329,6 +335,8 @@ export const osmosisMainnet: DeploymentConfig = { export const osmosisLocalConfig: DeploymentConfig = { oracleName: 'osmosis', + oracleBaseDenom: 'uosmo', + rewardsCollectorName: 'osmosis', atomDenom: atom, baseAssetDenom: 'uosmo', gasPrice: '0.1uosmo', @@ -336,7 +344,7 @@ export const osmosisLocalConfig: DeploymentConfig = { chainPrefix: 'osmo', channelId: 'channel-1', marsDenom: 'umars', - rewardCollectorTimeoutSeconds: 600, + rewardsCollectorTimeoutSeconds: 600, rpcEndpoint: 'http://localhost:26657', safetyFundFeeShare: '0.2', deployerMnemonic: diff --git a/scripts/multisig/neutron/README.md b/scripts/multisig/neutron/README.md index baa04d376..f6212b456 100644 --- a/scripts/multisig/neutron/README.md +++ b/scripts/multisig/neutron/README.md @@ -16,7 +16,7 @@ a. Some Ledgers are not able to sign large messages such as contract uploads b. If you are travelling a lot it's best to leave your hardware wallet at home in a secure place, and so if this is the case it might actually be more secure to have a hot wallet as hardware wallets are easily recognisable in airport security etc. ```bash -neutrond keys add [name] +neutrond keys add [name]_ntrn ``` 2. Note down the mnemonic - it is important that you are able to recover this account as a multisig signer. @@ -46,7 +46,7 @@ neutrond query account [address] --node=[node_URL] 2. Add each public key to the keys list in your local network. ```bash - neutrond keys add [name] --pubkey=[pubkey] + neutrond keys add [name]_ntrn --pubkey=[pubkey] ``` Note: The pubkey must be entered with the same syntax as shown in Step 1. @@ -67,6 +67,175 @@ neutrond query account [address] --node=[node_URL] 5. Update the config with the new mutlisig address in `red-bank/scripts/deploy/neutron/config`, which will set the owner and admin of the smart contracts to the multisig upon deployment. +## Set up environment variables + +These variables change based on the network, transaction, time, and user. Therefore, they should be provided to the multisig holders before each transaction and updated as needed on your machine. + +For `# bash`: + +```bash +# Neutron Mainnet variables +export NEUTRON_MULTI="neutron1ltzuv25ltw9mkwuvvmt7e54a6ene283hfj7l0c" +export NEUTRON_CHAINID="neutron-1" +export NEUTRON_NODE="https://neutron.rpc.p2p.world:443/qgrnU6PsQZA8F9S5Fb8Fn3tV3kXmMBl2M9bcc9jWLjQy8p" +export NEUTRON_ACCOUNT="51587" +export NEUTRON_ADDR_PROVIDER="contract_address_here_once_deployed" +export NEUTRON_REDBANK="contract_address_here_once_deployed" +export NEUTRON_INCENTIVES="contract_address_here_once_deployed" +export NEUTRON_ORACLE="contract_address_here_once_deployed" +export NEUTRON_REWARDS_COLLECTOR="contract_address_here_once_deployed" +export NEUTRON_SWAPPER="contract_address_here_once_deployed" +export NEUTRON_LIQUIDATION_FILTERER="contract_address_here_once_deployed" + +# Transaction specific variables (must be created at time of transaction) +export CODEID="new_code_ID_to_migrate_to" +export SEQUENCE="current_account_sequence" +export UNSIGNED="unsignedTX_filename.JSON" +export SIGNEDTX="signedTX_filenme.JSON" +export EXECUTE="msg_to_execute" + +# User specific variables +export SINGLE_SIGN="your_name.JSON" +export NEUTRON_ADDR="your_wallet_address" +``` + +**Note:** + +`NEUTRON_ACCOUNT` and `SEQUENCE` can be found by running: + +```bash +neutrond query account \ +--node=$NEUTRON_NODE \ +--chain-id=$NEUTRON_CHAINID \ +$NEUTRON_MULTI +``` + +## Verifying Contracts + +1. Get the wasm binary executable on your local machine. + + For address-provider, incentives, oracle, red-bank, rewards-collector, swapper contracts: + + ```bash + git clone https://github.com/mars-protocol/red-bank.git + git checkout + cargo make rust-optimizer + ``` + + For liquidation-filterer contract + + ```bash + git clone https://github.com/mars-protocol/liquidation-helpers + git checkout + cargo make rust-optimizer + ``` + + Note: Intel/AMD 64-bit processor is required. While there is experimental ARM support for CosmWasm/rust-optimizer, it's discouraged to use in production and the wasm bytecode will not match up to an Intel compiled wasm file. + +2. Download the wasm from the chain. + + ```bash + neutrond query wasm code $CODEID -- $NODE download.wasm + ``` + +3. Verify that the diff is empty between them. If any value is returned, then the wasm files differ. + + ```bash + diff artifacts/$CONTRACTNAME.wasm download.wasm + ``` + +## Query contract configs + +- Red Bank Contract Config: + + ```bash + QUERY='{"config": {}}' + neutrond query wasm contract-state smart $NEUTRON_REDBANK "$QUERY" --output json --node=$NEUTRON_NODE + ``` + +- Oracle Config: + + ```bash + QUERY='{"config": {}}' + neutrond query wasm contract-state smart $NEUTRON_ORACLE "$QUERY" --output json --node=$NEUTRON_NODE + ``` + +- Incentives Config: + + ```bash + QUERY='{"config": {}}' + neutrond query wasm contract-state smart $NEUTRON_INCENTIVES "$QUERY" --output json --node=$NEUTRON_NODE + ``` + +- Address Provider Config: + + ```bash + QUERY='{"config": {}}' + neutrond query wasm contract-state smart $NEUTRON_ADDR_PROVIDER "$QUERY" --output json --node=$NEUTRON_NODE + ``` + +- Rewards Collector Config: + + ```bash + QUERY='{"config": {}}' + neutrond query wasm contract-state smart $NEUTRON_REWARDS_COLLECTOR "$QUERY" --output json --node=$NEUTRON_NODE + ``` + +- Swapper Config: + + ```bash + QUERY='{"owner": {}}' + neutrond query wasm contract-state smart $NEUTRON_SWAPPER "$QUERY" --output json --node=$NEUTRON_NODE + ``` + +- Liquidation Filterer Config: + + ```bash + QUERY='{"config": {}}' + neutrond query wasm contract-state smart $NEUTRON_LIQUIDATION_FILTERER "$QUERY" --output json --node=$NEUTRON_NODE + ``` + +- Verify NTRN, ATOM, and axlUSDC are initialized in the red bank market and have the correct params: + + ```bash + QUERY='{"market":{"denom":"utrn"}}' + neutrond query wasm contract-state smart $NEUTRON_REDBANK "$QUERY" --output json --node=$NEUTRON_NODE + + QUERY='{"market":{"denom":"ibc/C4CFF46FD6DE35CA4CF4CE031E643C8FDC9BA4B99AE598E9B0ED98FE3A2319F9"}}' + neutrond query wasm contract-state smart $NEUTRON_REDBANK "$QUERY" --output json --node=$NEUTRON_NODE + + QUERY='{"market":{"denom":"ibc/F082B65C88E4B6D5EF1DB243CDA1D331D002759E938A0F5CD3FFDC5D53B3E349"}}' + neutrond query wasm contract-state smart $NEUTRON_REDBANK "$QUERY" --output json --node=$NEUTRON_NODE + ``` + +- Verify Oracle Price Source is set correctly: + + ```bash + QUERY='{"price_sources":{}}' + neutrond query wasm contract-state smart $NEUTRON_ORACLE "$QUERY" --output json --node=$NEUTRON_NODE + ``` + +- Verify Swaper Routes are set correctly: + + ```bash + QUERY='{"routes":{}}' + neutrond query wasm contract-state smart $NEUTRON_SWAPPER "$QUERY" --output json --node=$NEUTRON_NODE + ``` + +- Verify Admin is set correctly: + + _Note: If admin is not set, contracts are immutable_ + + ```bash + neutrond query wasm contract $NEUTRON_REWARDS_COLLECTOR --node=$NEUTRON_NODE + neutrond query wasm contract $NEUTRON_RED_BANK --node=$NEUTRON_NODE + neutrond query wasm contract $NEUTRON_ADDR_PROVIDER --node=$NEUTRON_NODE + neutrond query wasm contract $NEUTRON_ORACLE --node=$NEUTRON_NODE + neutrond query wasm contract $NEUTRON_INCENTIVES --node=$NEUTRON_NODE + neutrond query wasm contract $NEUTRON_SWAPPER --node=$NEUTRON_NODE + neutrond query wasm contract $NEUTRON_LIQUIDATION_FILTERER --node=$NEUTRON_NODE + ``` + ## Signing a TX with the multisig - Testnet Migrate Msg Example **Every multisig holder is responsible for verifying the contract's newly uploaded code for every migrate msg.** diff --git a/scripts/package.json b/scripts/package.json index 12f8eab99..81867c6ce 100644 --- a/scripts/package.json +++ b/scripts/package.json @@ -7,6 +7,8 @@ "deploy:osmosis-mainnet": "yarn build && node build/deploy/osmosis/mainIndex.js", "deploy:osmosis-testnet-multisig": "yarn build && node build/deploy/osmosis/multisig.js", "deploy:neutron-testnet": "yarn build && node build/deploy/neutron/testIndex.js", + "deploy:neutron-testnet-multisig": "yarn build && node build/deploy/neutron/multisigIndex.js", + "deploy:neutron-mainnet": "yarn build && node build/deploy/neutron/mainIndex.js", "generate-types": "yarn rust-schema && tsc --project codegen-tsconfig.json && rm -rf types/generated && node build/codegen && node build/codegen/insertIgnores.js && yarn format", "rust-schema": "cd ../ && cargo make generate-all-schemas && cd scripts", "compile-wasm": "cd ../ && cargo make rust-optimizer && cd scripts", diff --git a/scripts/types/config.ts b/scripts/types/config.ts index bf7733f58..225793b39 100644 --- a/scripts/types/config.ts +++ b/scripts/types/config.ts @@ -5,6 +5,7 @@ import { WasmOracleCustomInitParams, WasmPriceSourceForString, } from './generated/mars-oracle-wasm/MarsOracleWasm.types' +import { NeutronIbcConfig } from './generated/mars-rewards-collector-base/MarsRewardsCollectorBase.types' type SwapRoute = { denom_in: string @@ -26,7 +27,10 @@ export function isAstroportRoute(route: OsmosisRoute | AstroportRoute): route is export interface DeploymentConfig { oracleName: string - rewardCollectorTimeoutSeconds: number + oracleBaseDenom: string + rewardsCollectorName: string + rewardsCollectorTimeoutSeconds: number + rewardsCollectorNeutronIbcConfig?: NeutronIbcConfig | null marsDenom: string baseAssetDenom: string gasPrice: string