diff --git a/.github/workflows/cache.yml b/.github/workflows/cache.yml index d8079104..bc690cc9 100644 --- a/.github/workflows/cache.yml +++ b/.github/workflows/cache.yml @@ -17,7 +17,7 @@ jobs: runner_label: ${{ fromJSON('["lionco-runner-1", "lionco-runner-2", "lionco-runner-3", "lionco-runner-4", "lionco-runner-5", "lionco-runner-6"]') }} steps: - name: Stop old containers - run: docker ps -q | grep -q . && docker stop $(docker ps -q) || echo "No containers to stop" + run: docker ps -q | grep -q . && docker stop $(docker ps -q) -t0 || echo "No containers to stop" - name: Remove old containers run: docker ps -a -q | grep -q . && docker rm $(docker ps -a -q) || echo "No containers to remove" - name: Delete old images diff --git a/contracts/factory/src/contract.rs b/contracts/factory/src/contract.rs index a68e52af..757c2e9e 100644 --- a/contracts/factory/src/contract.rs +++ b/contracts/factory/src/contract.rs @@ -90,9 +90,27 @@ pub fn execute( }, ExecuteMsg::UpdateConfig(msg) => execute_update_config(deps, env, info, *msg), ExecuteMsg::Proxy(msg) => execute_proxy_msg(deps, env, info, msg), + ExecuteMsg::AdminExecute { addr, msg } => execute_admin_execute(deps, env, info, addr, msg), } } +fn execute_admin_execute( + deps: DepsMut, + _env: Env, + info: MessageInfo, + addr: String, + msg: Binary, +) -> ContractResult> { + let attrs = vec![attr("action", "admin-execute")]; + cw_ownable::assert_owner(deps.storage, &info.sender)?; + let msg = CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: addr, + msg, + funds: vec![], + }); + Ok(response("execute-admin", CONTRACT_NAME, attrs).add_message(msg)) +} + fn execute_update_config( deps: DepsMut, _env: Env, diff --git a/contracts/factory/src/msg.rs b/contracts/factory/src/msg.rs index 1399f6f8..5d07dcf8 100644 --- a/contracts/factory/src/msg.rs +++ b/contracts/factory/src/msg.rs @@ -1,6 +1,6 @@ use crate::state::{CodeIds, RemoteOpts}; use cosmwasm_schema::{cw_serde, QueryResponses}; -use cosmwasm_std::Uint128; +use cosmwasm_std::{Binary, Uint128}; use lido_staking_base::msg::token::DenomMetadata; #[cw_serde] @@ -65,6 +65,10 @@ pub enum ExecuteMsg { Callback(CallbackMsg), UpdateConfig(Box), Proxy(ProxyMsg), + AdminExecute { + addr: String, + msg: Binary, + }, } #[cw_serde] pub enum MigrateMsg {} diff --git a/contracts/puppeteer/src/contract.rs b/contracts/puppeteer/src/contract.rs index 28d7777a..70caeda4 100644 --- a/contracts/puppeteer/src/contract.rs +++ b/contracts/puppeteer/src/contract.rs @@ -36,7 +36,7 @@ use lido_puppeteer_base::{ }, }; use lido_staking_base::{ - msg::puppeteer::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryExtMsg}, + msg::puppeteer::{ExecuteMsg, FeesResponse, InstantiateMsg, MigrateMsg, QueryExtMsg}, state::puppeteer::{Config, KVQueryType, DELEGATIONS_AND_BALANCE}, }; use neutron_sdk::interchain_queries::v045::new_register_delegator_unbonding_delegations_query_msg; @@ -115,11 +115,23 @@ pub fn query( .collect::>>()?, ) .map_err(ContractError::Std), + QueryExtMsg::Fees {} => query_fees(deps), }, _ => Puppeteer::default().query(deps, env, msg), } } +fn query_fees(deps: Deps) -> ContractResult { + let fees = Puppeteer::default().ibc_fee.load(deps.storage)?; + let register_fee = Puppeteer::default().register_fee.load(deps.storage)?; + Ok(to_json_binary(&FeesResponse { + recv_fee: fees.recv_fee, + ack_fee: fees.ack_fee, + timeout_fee: fees.timeout_fee, + register_fee, + })?) +} + fn query_delegations(deps: Deps) -> ContractResult { let data = DELEGATIONS_AND_BALANCE.load(deps.storage)?; to_json_binary(&(data.0, data.2)).map_err(ContractError::Std) diff --git a/integration_tests/src/generated/contractLib/lidoFactory.ts b/integration_tests/src/generated/contractLib/lidoFactory.ts index 3cf65f99..bd71d220 100644 --- a/integration_tests/src/generated/contractLib/lidoFactory.ts +++ b/integration_tests/src/generated/contractLib/lidoFactory.ts @@ -107,10 +107,16 @@ export type ValidatorSetMsg = validator: ValidatorData; }; }; +/** + * Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline. + * + * This is only needed as serde-json-{core,wasm} has a horrible encoding for Vec. See also . + */ +export type Binary = string; export interface LidoFactorySchema { responses: State; - execute: InitArgs | CallbackArgs | UpdateConfigArgs | ProxyArgs; + execute: InitArgs | CallbackArgs | UpdateConfigArgs | ProxyArgs | AdminExecuteArgs; [k: string]: unknown; } export interface State { @@ -168,6 +174,10 @@ export interface ValidatorData { valoper_address: string; weight: number; } +export interface AdminExecuteArgs { + addr: string; + msg: Binary; +} function isSigningCosmWasmClient( @@ -219,4 +229,8 @@ export class Client { if (!isSigningCosmWasmClient(this.client)) { throw this.mustBeSigningClient(); } return this.client.execute(sender, this.contractAddress, { proxy: args }, fee || "auto", memo, funds); } + adminExecute = async(sender:string, args: AdminExecuteArgs, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]): Promise => { + if (!isSigningCosmWasmClient(this.client)) { throw this.mustBeSigningClient(); } + return this.client.execute(sender, this.contractAddress, { admin_execute: args }, fee || "auto", memo, funds); + } } diff --git a/integration_tests/src/generated/contractLib/lidoPuppeteer.ts b/integration_tests/src/generated/contractLib/lidoPuppeteer.ts index 12d0febd..e18518cb 100644 --- a/integration_tests/src/generated/contractLib/lidoPuppeteer.ts +++ b/integration_tests/src/generated/contractLib/lidoPuppeteer.ts @@ -107,6 +107,9 @@ export type QueryExtMsg = | { balances: {}; } + | { + fees: {}; + } | { unbonding_delegations: {}; }; diff --git a/integration_tests/src/testcases/core.test.ts b/integration_tests/src/testcases/core.test.ts index cc96aef6..672849c3 100644 --- a/integration_tests/src/testcases/core.test.ts +++ b/integration_tests/src/testcases/core.test.ts @@ -435,11 +435,10 @@ describe('Core', () => { ); }); it('set fees for puppeteer', async () => { - const { neutronUserAddress, factoryContractClient: contractClient } = - context; - const res = await contractClient.updateConfig(neutronUserAddress, { + const { neutronUserAddress, factoryContractClient } = context; + const res = await factoryContractClient.updateConfig(neutronUserAddress, { puppeteer_fees: { - timeout_fee: '10000', + timeout_fee: '20000', ack_fee: '10000', recv_fee: '0', register_fee: '1000000', @@ -447,6 +446,38 @@ describe('Core', () => { }); expect(res.transactionHash).toHaveLength(64); }); + it('update by factory admin execute', async () => { + const { neutronUserAddress, factoryContractClient: contractClient } = + context; + const res = await contractClient.adminExecute( + neutronUserAddress, + { + addr: context.puppeteerContractClient.contractAddress, + msg: Buffer.from( + JSON.stringify({ + set_fees: { + timeout_fee: '10000', + ack_fee: '10000', + recv_fee: '0', + register_fee: '1000000', + }, + }), + ).toString('base64'), + }, + 1.5, + ); + expect(res.transactionHash).toHaveLength(64); + const fees: any = await context.puppeteerContractClient.queryExtention({ + msg: { fees: {} }, + }); + expect(fees).toEqual({ + recv_fee: [{ denom: 'untrn', amount: '0' }], + ack_fee: [{ denom: 'untrn', amount: '10000' }], + timeout_fee: [{ denom: 'untrn', amount: '10000' }], + register_fee: { denom: 'untrn', amount: '1000000' }, + }); + }); + it('register ICA', async () => { const { puppeteerContractClient, neutronUserAddress } = context; const res = await puppeteerContractClient.registerICA( @@ -632,7 +663,6 @@ describe('Core', () => { owner: context.neutronUserAddress, }); expect(vouchers.tokens.length).toBe(2); - expect(vouchers.tokens[0]).toBe(`0_${neutronUserAddress}_1`); let tokenId = vouchers.tokens[0]; let voucher = await withdrawalVoucherContractClient.queryNftInfo({ @@ -671,7 +701,6 @@ describe('Core', () => { }, token_uri: null, }); - expect(vouchers.tokens[1]).toBe(`0_${neutronUserAddress}_2`); tokenId = vouchers.tokens[1]; voucher = await withdrawalVoucherContractClient.queryNftInfo({ diff --git a/packages/base/src/msg/puppeteer.rs b/packages/base/src/msg/puppeteer.rs index f1c1a78a..b6dc9e8d 100644 --- a/packages/base/src/msg/puppeteer.rs +++ b/packages/base/src/msg/puppeteer.rs @@ -102,6 +102,14 @@ pub type DelegationsResponse = (Delegations, u64); pub type BalancesResponse = (Balances, u64); +#[cw_serde] +pub struct FeesResponse { + pub recv_fee: Vec, + pub ack_fee: Vec, + pub timeout_fee: Vec, + pub register_fee: cosmwasm_std::Coin, +} + #[cw_serde] #[derive(QueryResponses)] pub enum QueryExtMsg { @@ -109,6 +117,8 @@ pub enum QueryExtMsg { Delegations {}, #[returns(BalancesResponse)] Balances {}, + #[returns(FeesResponse)] + Fees {}, #[returns(Vec)] UnbondingDelegations {}, }