feat: add client method to sign a transaction#113
Conversation
| /// # Ok(()) | ||
| /// # } | ||
| /// ``` | ||
| pub async fn get_pubkey<R: Runtime>( |
There was a problem hiding this comment.
This method is not really necessary, but I thought that it's nice to provide some utility functions to make things as easy as possible for end users. As a bonus we can re-use this method in:
- the docs for
sign_transactionabove basic_solana(and use the chain code to derive child keys locally -- we could potentially even add an example in the doc here on how to derive child keys locally)- the end-to-end tests (in an upcoming PR where the end-to-end tests will use threshold signing)
Another candidate here would be a helper function to derive child public keys, but this seems like stretching it a bit imo.
WDYT?
| /// # Ok(()) | ||
| /// # } | ||
| /// ``` | ||
| pub async fn sign_transaction<R: Runtime>( |
There was a problem hiding this comment.
This method is a building block for the build_transaction method which will come in an upcoming PR. For both transactions using a recent blockhash and those using a durable nonce, it is necessary to sign the transaction (using threshold signing) if we want to have a single method call, which I find would make the most sense. The alternative would be to build an unsigned transaction, and then ask the end-users to sign the transaction themselves, but I think it's nice to make it as easy as possible for them here. Especially since we anyways need this code for end-to-end tests and basic_solana.
| transaction: &solana_transaction::Transaction, | ||
| key_id: Ed25519KeyId, | ||
| derivation_path: Option<&DerivationPath>, | ||
| ) -> RpcResult<solana_signature::Signature> { |
There was a problem hiding this comment.
The reason I don't return the signed transaction here, is that this might need to be called multiple times for transactions that have multiple signatures. AFAIK we cannot currently batch threshold signature calls, so latency might be a problem here if a transaction has many signers.
gregorydemay
left a comment
There was a problem hiding this comment.
Thanks @lpahlavi for this PR! some first high level comments
libs/client/src/threshold_sig.rs
Outdated
| use sol_rpc_types::{DerivationPath, Ed25519KeyId, RpcError, RpcResult}; | ||
|
|
||
| // Source: https://internetcomputer.org/docs/current/references/t-sigs-how-it-works/#fees-for-the-t-schnorr-production-key | ||
| const SIGN_WITH_SCHNORR_FEE: u128 = 26_153_846_153; |
There was a problem hiding this comment.
There was a problem hiding this comment.
Interesting! I initially had a look at the ic-cdk code and it seems they don't make that distinction there... I pinged the crypto channel to check which way is correct and they said it's just a simplification in the ic-cdk code and the extra cycles just get returned. Nevertheless, easy enough for us to make the distinction here. Done.
Just one follow-up question: what about the local development key? Do you know how cycles management works with local dfx deployment? Should the fee be 0 there?
There was a problem hiding this comment.
Thanks for checking with crypto!
Just one follow-up question: what about the local development key? Do you know how cycles management works with local dfx deployment? Should the fee be 0 there?
I would also expect 0.
lpahlavi
left a comment
There was a problem hiding this comment.
Thanks a lot for the initial review @gregorydemay! I've incorporated all of your feedback PTAL and let me know what you think.
libs/client/src/threshold_sig.rs
Outdated
| use sol_rpc_types::{DerivationPath, Ed25519KeyId, RpcError, RpcResult}; | ||
|
|
||
| // Source: https://internetcomputer.org/docs/current/references/t-sigs-how-it-works/#fees-for-the-t-schnorr-production-key | ||
| const SIGN_WITH_SCHNORR_FEE: u128 = 26_153_846_153; |
There was a problem hiding this comment.
Interesting! I initially had a look at the ic-cdk code and it seems they don't make that distinction there... I pinged the crypto channel to check which way is correct and they said it's just a simplification in the ic-cdk code and the extra cycles just get returned. Nevertheless, easy enough for us to make the distinction here. Done.
Just one follow-up question: what about the local development key? Do you know how cycles management works with local dfx deployment? Should the fee be 0 there?
gregorydemay
left a comment
There was a problem hiding this comment.
Thanks @lpahlavi for the changes! Some minor comments but otherwise LGTM!
| sol_rpc_int_tests = { path = "../integration_tests" } | ||
| solana-commitment-config = { workspace = true } | ||
| solana-hash = { workspace = true } | ||
| solana-message = { workspace = true } |
There was a problem hiding this comment.
why is this change needed?
|
@gregorydemay I realized actually that the two new methods return an |
@lpahlavi : yes I also think using |
## 🤖 New release * `sol_rpc_canister`: 0.2.0 <details><summary><i><b>Changelog</b></i></summary><p> <blockquote> ## [0.2.0] - 2025-05-27 ### Added - Add client method to sign a transaction ([#113](#113)) - Add Chainstack RPC provider ([#118](#118)) - Add support for `getSignaturesForAddress` ([#106](#106)) - Add support for `getSignatureStatuses` RPC method ([#96](#96)) - Add support for `getTokenAccountBalance` RPC method ([#90](#90)) - Add support for `getTransaction` RPC method ([#68](#68)) - Add `getBlock` RPC method ([#53](#53)) - Add `sendTransaction` RPC method ([#59](#59)) - Add NOTICE to Apache license ([#60](#60)) - Add `getAccountInfo` RPC method ([#49](#49)) - Add metrics ([#41](#41)) - Add logging crate ([#13](#13)) - Add support for override providers ([#12](#12)) ### Changed - Bump version to 0.2 - Candid NonZeroU8 ([#108](#108)) - Add `RoundingError` to `sol_rpc_types` ([#105](#105)) - Use secure primitive types for `Pubkey`, `Signature` and `Hash` ([#98](#98)) - Add support for `getRecentPrioritizationFees` ([#92](#92)) - Simplify API keys provisioning script ([#89](#89)) - Release v0.1.0 ([#88](#88)) - Use `canlog_derive` and `canlog` from crates.io ([#84](#84)) - Release pipeline ([#4](#4)) - Clean-up TODOs ([#81](#81)) - Support method `getBalance` ([#74](#74)) - Remove http_types module and use external ic-http-types crate ([#73](#73)) - Rename some enum variants to camel case when serializing ([#72](#72)) - Use constant size JSON-RPC request ID ([#62](#62)) - Use method from JSON-RPC request for metric ([#61](#61)) - Cycles cost ([#52](#52)) - Client builder ([#54](#54)) - Round result from `getSlot` RPC method ([#48](#48)) - Use `canhttp` `multi` feature ([#46](#46)) - Implement a method for making generic RPC request ([#39](#39)) - Implement getSlot RPC method ([#33](#33)) - Add some tested RPC providers for Solana Mainnet and Devnet ([#15](#15)) - Streamline providers ([#32](#32)) - Update rust toolchain to 1.85 ([#21](#21)) - Remove unnecessary Storable implementations ([#14](#14)) - Add support for API keys ([#10](#10)) - Hard-code SOL RPC providers ([#9](#9)) - Reproducible build ([#3](#3)) - Initial cargo workspace and build pipeline ([#2](#2)) ### Fixed - Missing `TraceHttp` logs ([#129](#129)) - End-to-end tests for `sendTransaction` ([#104](#104)) - Unit test for `getRecentPrioritizationFees` parameters serialization ([#107](#107)) - Integration test for `verifyApiKey` ([#82](#82)) - Set `maxSupportedTransactionVersion` to zero for end-to-end tests ([#85](#85)) - API keys ([#58](#58)) - End-to-end tests ([#45](#45)) - Correct Solana cluster for dRPC and Helius providers ([#47](#47)) - E2e test with Solana test validator ([#20](#20)) - Create test canister on ICP mainnet ([#8](#8)) ### Removed - Remove default/non-default providers ([#122](#122)) </blockquote> </p></details> --- This PR was generated with [release-plz](https://github.com/release-plz/release-plz/). --------- Co-authored-by: gregorydemay <gregory.demay@dfinity.org> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
## 🤖 New release * `sol_rpc_canister`: 1.0.0 <details><summary><i><b>Changelog</b></i></summary><p> <blockquote> ## [1.0.0] - 2025-06-12 ### Added - Add support for `transactionDetails=accounts` ([#139](#139)) - Add support for `rewards` parameter for `getBlock` ([#135](#135)) - Add helper methods for request builders ([#136](#136)) - Add client method to sign a transaction ([#113](#113)) - Add Chainstack RPC provider ([#118](#118)) - Add support for `getSignaturesForAddress` ([#106](#106)) - Add support for `getSignatureStatuses` RPC method ([#96](#96)) - Add support for `getTokenAccountBalance` RPC method ([#90](#90)) - Add support for `getTransaction` RPC method ([#68](#68)) - Add `getBlock` RPC method ([#53](#53)) - Add `sendTransaction` RPC method ([#59](#59)) - Add NOTICE to Apache license ([#60](#60)) - Add `getAccountInfo` RPC method ([#49](#49)) - Add metrics ([#41](#41)) - Add logging crate ([#13](#13)) - Add support for override providers ([#12](#12)) ### Changed - Bump to 1.0.0 - Inline request parameters `is_default_config` methods ([#138](#138)) - Release v0.2.0 ([#131](#131)) - Bump version and use a release notes template ([#130](#130)) - Candid NonZeroU8 ([#108](#108)) - Add `RoundingError` to `sol_rpc_types` ([#105](#105)) - Use secure primitive types for `Pubkey`, `Signature` and `Hash` ([#98](#98)) - Add support for `getRecentPrioritizationFees` ([#92](#92)) - Simplify API keys provisioning script ([#89](#89)) - Release v0.1.0 ([#88](#88)) - Use `canlog_derive` and `canlog` from crates.io ([#84](#84)) - Release pipeline ([#4](#4)) - Clean-up TODOs ([#81](#81)) - Support method `getBalance` ([#74](#74)) - Remove http_types module and use external ic-http-types crate ([#73](#73)) - Rename some enum variants to camel case when serializing ([#72](#72)) - Use constant size JSON-RPC request ID ([#62](#62)) - Use method from JSON-RPC request for metric ([#61](#61)) - Cycles cost ([#52](#52)) - Client builder ([#54](#54)) - Round result from `getSlot` RPC method ([#48](#48)) - Use `canhttp` `multi` feature ([#46](#46)) - Implement a method for making generic RPC request ([#39](#39)) - Implement getSlot RPC method ([#33](#33)) - Add some tested RPC providers for Solana Mainnet and Devnet ([#15](#15)) - Streamline providers ([#32](#32)) - Update rust toolchain to 1.85 ([#21](#21)) - Remove unnecessary Storable implementations ([#14](#14)) - Add support for API keys ([#10](#10)) - Hard-code SOL RPC providers ([#9](#9)) - Reproducible build ([#3](#3)) - Initial cargo workspace and build pipeline ([#2](#2)) ### Fixed - Missing `TraceHttp` logs ([#129](#129)) - End-to-end tests for `sendTransaction` ([#104](#104)) - Unit test for `getRecentPrioritizationFees` parameters serialization ([#107](#107)) - Integration test for `verifyApiKey` ([#82](#82)) - Set `maxSupportedTransactionVersion` to zero for end-to-end tests ([#85](#85)) - API keys ([#58](#58)) - End-to-end tests ([#45](#45)) - Correct Solana cluster for dRPC and Helius providers ([#47](#47)) - E2e test with Solana test validator ([#20](#20)) - Create test canister on ICP mainnet ([#8](#8)) ### Removed - Remove default/non-default providers ([#122](#122)) </blockquote> </p></details> --- This PR was generated with [release-plz](https://github.com/release-plz/release-plz/). --------- Co-authored-by: gregorydemay <gregory.demay@dfinity.org> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: gregorydemay <112856886+gregorydemay@users.noreply.github.com>
(XC-317) Add a helper method in the
sol_rpc_clientmodule to signa a Solana transaction using threshold EdDSA. This method is not part of the clientstructas it does not interact with the SOL RPC canister, but instead with the management canister. However, it takes a runtime argument to be re-usable in tests and prod code.