diff --git a/crates/by-chain/icepick-cosmos/src/coin_denoms.rs b/crates/by-chain/icepick-cosmos/src/coin_denoms.rs index 505ac66..31a64dd 100644 --- a/crates/by-chain/icepick-cosmos/src/coin_denoms.rs +++ b/crates/by-chain/icepick-cosmos/src/coin_denoms.rs @@ -161,11 +161,10 @@ pub fn default_chains() -> Vec { .coin_decimals(6) .coin_gecko_id("unknown") .build(); - // NOTE: high is listed as 0.03 on devnet, but simulating tx actually cost 30915 tkyve. let tkyve_gas = GasPriceStep::builder() .low(0.01) - .average(0.05) - .high(0.1) + .average(0.025) + .high(0.03) .build(); chains.push( diff --git a/crates/by-chain/icepick-cosmos/src/lib.rs b/crates/by-chain/icepick-cosmos/src/lib.rs index d80d251..0556e98 100644 --- a/crates/by-chain/icepick-cosmos/src/lib.rs +++ b/crates/by-chain/icepick-cosmos/src/lib.rs @@ -32,7 +32,7 @@ pub struct GetWalletAddress { } #[derive(Serialize, Deserialize, Debug)] -pub struct GetAccountInfo { +pub struct GetAccountData { account_id: String, blockchain_config: coin_denoms::Blockchain, @@ -57,7 +57,7 @@ pub struct Transfer { // TODO: find a way to simulate transaction and calculate gas necessary // for now, 0.01KYVE seems to be a reasonable mainnet number? // for testing purposes, i'm gonna go much lower. 0.0001. - gas: Option, + gas_factor: Option, blockchain_config: coin_denoms::Blockchain, } @@ -66,8 +66,8 @@ pub struct Transfer { pub struct Sign { fee: remote_serde::Fee, tx_messages: Vec, - account_number: String, - sequence_number: String, + account_number: u64, + sequence_number: u64, blockchain_config: coin_denoms::Blockchain, } @@ -94,7 +94,7 @@ pub enum Operation { GetChainInfo(GetChainInfo), GenerateWallet(GenerateWallet), GetWalletAddress(GetWalletAddress), - GetAccountInfo(GetAccountInfo), + GetAccountData(GetAccountData), AwaitFunds(AwaitFunds), Transfer(Transfer), Sign(Sign), @@ -188,7 +188,7 @@ impl Module for Cosmos { .argument(&address_prefix); let get_account_info = Operation::builder() - .name("get-account-info") + .name("get-account-data") .description("Get the account number and sequence number for an account.") .build() .argument( @@ -255,8 +255,8 @@ impl Module for Cosmos { ) .argument( &Argument::builder() - .name("gas") - .description("The amount of gas to supply.") + .name("gas_factor") + .description("The factor to multiply the default gas amount by.") .r#type(ArgumentType::Optional) .build(), ); @@ -336,7 +336,7 @@ impl Module for Cosmos { } })) } - Operation::GetAccountInfo(GetAccountInfo { + Operation::GetAccountData(GetAccountData { account_id, blockchain_config, }) => { @@ -437,7 +437,7 @@ impl Module for Cosmos { to_address, from_account: _, from_address, - gas: _, + gas_factor, blockchain_config, }) => { // Check if given denom is min denom or normal and adjust accordingly @@ -449,6 +449,13 @@ impl Module for Cosmos { panic!("{denom} not in {blockchain_config:?}"); }; + let gas_factor = gas_factor + .as_deref() + .map(f64::from_str) + .transpose() + .unwrap() + .unwrap_or(1.0); + let amount = f64::from_str(&amount).unwrap(); let adjusted_amount = if relevant_denom.coin_denom == denom { amount * 10f64.powi(i32::from(relevant_denom.coin_decimals)) @@ -474,11 +481,23 @@ impl Module for Cosmos { .to_any() .unwrap(); + let expected_gas = 100_000u64; + // convert gas "price" to minimum denom, + // multiply by amount of gas required, + // multiply by gas factor if necessary. + let expected_fee = blockchain_config.gas_price_step.high + // * dbg!(10f64.powi(relevant_denom.coin_decimals as i32)) + * expected_gas as f64 + * gas_factor; + + let fee_coin = cosmrs::Coin { + denom: relevant_denom.coin_minimal_denom.parse().unwrap(), + amount: expected_fee as u128, + }; + let fee = Fee::from_amount_and_gas( - coin, - (blockchain_config.gas_price_step.high - * 10f64.powi(relevant_denom.coin_decimals as i32)) - as u64, + fee_coin, + expected_gas, ); #[allow(clippy::identity_op)] @@ -508,11 +527,6 @@ impl Module for Cosmos { let fee = cosmrs::tx::Fee::from(&fee); let tx_body = BodyBuilder::new().msgs(tx_messages).finish(); - // TODO: these should be gained by the `broadcast` workflow, similar to - // how nonce data is acquired in Solana - let account_number: u64 = account_number.parse().unwrap(); - let sequence_number: u64 = sequence_number.parse().unwrap(); - let auth_info = SignerInfo::single_direct(Some(privkey.public_key()), sequence_number) .auth_info(fee); diff --git a/icepick.toml b/icepick.toml index 22330b3..ab8649f 100644 --- a/icepick.toml +++ b/icepick.toml @@ -225,3 +225,83 @@ inputs = { transaction = "signed_transaction" } name = "cosmos" derivation_prefix = "m/44'/118'/0'" algorithm = "Secp256k1" + +[[module.workflow]] +name = "transfer" +inputs = ["from_address", "to_address", "asset_name", "chain_name", "asset_amount"] + +[[module.workflow.step]] +# NOTE: chain_name can't be discoverable by filtering from asset_name, since +# some asset devnets reuse the name. There's no difference between KYVE on Kyve +# or Korellia (devnet). +type = "cosmos-get-chain-info" +inputs = { chain_name = "chain_name" } +outputs = { blockchain_config = "blockchain_config" } + +[[module.workflow.step]] +type = "internal-load-file" +values = { filename = "account_info.json" } +outputs = { account_number = "account_number", sequence_number = "sequence_number" } + +[[module.workflow.step]] +type = "cosmos-transfer" + +[module.workflow.step.inputs] +from_address = "from_address" +to_address = "to_address" +amount = "asset_amount" +denom = "asset_name" +blockchain_config = "blockchain_config" + +[module.workflow.step.outputs] +fee = "fee" +tx_messages = "tx_messages" + +[[module.workflow.step]] +type = "cosmos-sign" + +[module.workflow.step.inputs] +fee = "fee" +tx_messages = "tx_messages" +account_number = "account_number" +sequence_number = "sequence_number" +blockchain_config = "blockchain_config" + +[module.workflow.step.outputs] +transaction = "signed_transaction" + +[[module.workflow.step]] +type = "internal-save-file" +values = { filename = "transaction.json" } +inputs = { transaction = "signed_transaction" } + +[[module.workflow]] +name = "broadcast" +# NOTE: For the purpose of Cosmos, the nonce is a direct part of the signer's +# account. +inputs = ["nonce_address", "chain_name"] + +[[module.workflow.step]] +type = "cosmos-get-chain-info" +inputs = { chain_name = "chain_name" } +outputs = { blockchain_config = "blockchain_config" } + +[[module.workflow.step]] +type = "cosmos-get-account-data" +inputs = { account_id = "nonce_address", blockchain_config = "blockchain_config" } +outputs = { account_number = "account_number", sequence_number = "sequence_number" } + +[[module.workflow.step]] +type = "internal-save-file" +values = { filename = "account_info.json" } +inputs = { account_number = "account_number", sequence_number = "sequence_number" } + +[[module.workflow.step]] +type = "internal-load-file" +values = { filename = "transaction.json" } +outputs = { transaction = "transaction" } + +[[module.workflow.step]] +type = "cosmos-broadcast" +inputs = { blockchain_config = "blockchain_config", transaction = "transaction" } +outputs = { status = "status", url = "url", error = "error", error_code = "error_code" }