Skip to content
Merged
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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ clap = { version = "4.5.4", features = ["derive", "env", "string"] }
derive_more = { version = "=1.0.0-beta.6", features = ["display", "from", "deref", "constructor"]}
dotenv = "0.15.0"
futures = "0.3.30"
hex = "0.4.3"
homedir = "0.2.1"
humantime = "2.1.0"
prometheus-client = "0.22.2"
Expand Down
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ The application can be configured using environment variables:

You can run different transaction types at different intervals using the `INTERVAL_OVERWRITE` environment variable. This is useful when you want to run certain transactions more frequently than others.

Example: Run MpcSign every 5 minutes and Swap every 10 minutes, while keeping other transactions at the default 15-minute interval:
Example: Run MpcSignEcdsa every 5 minutes and Swap every 10 minutes, while keeping other transactions at the default 15-minute interval:

```bash
export INTERVAL_OVERWRITE='{"MpcSign": "5m", "Swap": "10m"}'
export INTERVAL_OVERWRITE='{"MpcSignEcdsa": "5m", "Swap": "10m"}'
```

The JSON format supports all transaction types:
Expand All @@ -44,7 +44,9 @@ The JSON format supports all transaction types:
- `TokenTransferFinal`
- `FungibleTokenTransfer`
- `Swap`
- `MpcSign`
- `MpcSignEcdsa`
- `MpcSignEddsa`
- `MpcCkd`

Duration formats supported:
- `5m` (5 minutes)
Expand Down
10 changes: 5 additions & 5 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ pub struct Opts {
/// Time delay between each intervalgroup of transactions
#[clap(env, short, long, value_parser = humantime::parse_duration, default_value = "5s")]
pub group_delay: std::time::Duration,
/// Override intervals for specific transaction types (JSON format: {"MpcSign": "5m", "Swap": "10m"})
/// Override intervals for specific transaction types (JSON format: {"MpcSignEcdsa": "5m", "Swap": "10m"})
#[clap(env, long, value_parser = parse_interval_overwrite)]
pub interval_overwrite: Option<HashMap<TransactionKind, std::time::Duration>>,
/// Metric server address.
Expand Down Expand Up @@ -114,12 +114,12 @@ mod tests {

#[test]
fn test_parse_interval_overwrite() {
let json = r#"{"mpc-sign": "5m", "swap": "10m"}"#;
let json = r#"{"mpc-sign-ecdsa": "5m", "swap": "10m"}"#;
let result = parse_interval_overwrite(json).unwrap();

assert_eq!(result.len(), 2);
assert_eq!(
result.get(&TransactionKind::MpcSign).unwrap(),
result.get(&TransactionKind::MpcSignEcdsa).unwrap(),
&std::time::Duration::from_secs(300)
); // 5 minutes
assert_eq!(
Expand All @@ -130,7 +130,7 @@ mod tests {

#[test]
fn test_parse_interval_overwrite_invalid_json() {
let json = r#"{"MpcSign": "5m", "Swap":}"#;
let json = r#"{"mpc-sign-ecdsa": "5m", "Swap":}"#;
let result = parse_interval_overwrite(json);
assert!(result.is_err());
}
Expand All @@ -144,7 +144,7 @@ mod tests {

#[test]
fn test_parse_interval_overwrite_invalid_duration() {
let json = r#"{"MpcSign": "invalid"}"#;
let json = r#"{"mpc-sign-ecdsa": "invalid"}"#;
let result = parse_interval_overwrite(json);
assert!(result.is_err());
}
Expand Down
12 changes: 9 additions & 3 deletions src/transaction/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ use tracing::{error, info, warn};
use crate::{
metrics::{Labels, Metrics},
transaction::{
fungible_token_transfer::FungibleTokenTransfer, mpc_sign::MpcSign, swap::Swap,
token_transfer_default::TokenTransferDefault, token_transfer_final::TokenTransferFinal,
fungible_token_transfer::FungibleTokenTransfer,
mpc::{MpcSignEcdsa, MpcSignEddsa},
swap::Swap,
token_transfer_default::TokenTransferDefault,
token_transfer_final::TokenTransferFinal,
token_transfer_included_final::TokenTransferIncludedFinal,
},
TransactionSample,
Expand Down Expand Up @@ -45,7 +48,10 @@ impl Engine {
add_transaction!(TokenTransferIncludedFinal);
add_transaction!(FungibleTokenTransfer);
add_transaction!(Swap);
add_transaction!(MpcSign);
add_transaction!(MpcSignEcdsa);
add_transaction!(MpcSignEddsa);
// This is not yet functional, so failures are expected for these transactions
// add_transaction!(MpcCkd);

Engine { transactions }
}
Expand Down
6 changes: 4 additions & 2 deletions src/transaction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use near_primitives::views::{ExecutionStatusView, FinalExecutionStatus};
pub mod engine;

mod fungible_token_transfer;
mod mpc_sign;
mod mpc;
mod swap;
mod token_transfer_default;
mod token_transfer_final;
Expand All @@ -34,7 +34,9 @@ pub enum TransactionKind {
TokenTransferFinal,
FungibleTokenTransfer,
Swap,
MpcSign,
MpcSignEcdsa,
MpcSignEddsa,
MpcCkd,
}

#[async_trait]
Expand Down
152 changes: 152 additions & 0 deletions src/transaction/mpc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
use super::TransactionKind;
use crate::config::Opts;
use crate::TransactionSample;
use async_trait::async_trait;
use near_crypto::InMemorySigner;
use near_jsonrpc_primitives::types::transactions::RpcSendTransactionRequest;
use near_primitives::action::FunctionCallAction;
use near_primitives::hash::CryptoHash;
use near_primitives::transaction::{Action, Transaction, TransactionV0};
use near_primitives::types::Nonce;
use near_primitives::views::TxExecutionStatus;
use rand::Rng;

pub struct MpcSignEcdsa {}
pub struct MpcSignEddsa {}
#[allow(unused)]
pub struct MpcCkd {}

#[async_trait]
impl TransactionSample for MpcSignEcdsa {
fn kind(&self) -> TransactionKind {
TransactionKind::MpcSignEcdsa
}

fn get_name(&self) -> &str {
"Call MPC ecdsa sign function"
}

fn get_transaction_request(
&self,
signer: InMemorySigner,
opts: Opts,
nonce: Nonce,
block_hash: CryptoHash,
) -> RpcSendTransactionRequest {
let domain_id = 0;
let mut rng = rand::thread_rng();
let mut random_bytes = [0u8; 32];
rng.fill(&mut random_bytes);
let payload = hex::encode(random_bytes);
let transaction = Transaction::V0(TransactionV0 {
signer_id: signer.account_id.clone(),
public_key: signer.public_key.clone(),
nonce: nonce + 1,
receiver_id: opts.mpc_contract_id,
block_hash,
actions: vec![Action::FunctionCall(Box::new(FunctionCallAction {
method_name: "sign".to_string(),
args: serde_json::json!({"request": {"domain_id": domain_id,"path": "","payload_v2": {"Ecdsa": payload}}})
.to_string()
.into_bytes(),
gas: 15_000_000_000_000, // 15 TeraGas
deposit: 1,
}))],
});
RpcSendTransactionRequest {
signed_transaction: transaction.sign(&signer.into()),
wait_until: TxExecutionStatus::Final,
}
}
}

#[async_trait]
impl TransactionSample for MpcSignEddsa {
fn kind(&self) -> TransactionKind {
TransactionKind::MpcSignEddsa
}

fn get_name(&self) -> &str {
"Call MPC eddsa sign function"
}

fn get_transaction_request(
&self,
signer: InMemorySigner,
opts: Opts,
nonce: Nonce,
block_hash: CryptoHash,
) -> RpcSendTransactionRequest {
let domain_id = 1;
let mut rng = rand::thread_rng();
let mut random_bytes = [0u8; 32];
rng.fill(&mut random_bytes);
let payload = hex::encode(random_bytes);
let transaction = Transaction::V0(TransactionV0 {
signer_id: signer.account_id.clone(),
public_key: signer.public_key.clone(),
nonce: nonce + 1,
receiver_id: opts.mpc_contract_id,
block_hash,
actions: vec![Action::FunctionCall(Box::new(FunctionCallAction {
method_name: "sign".to_string(),
args: serde_json::json!({"request": {"domain_id": domain_id,"path": "","payload_v2": {"Eddsa": payload}}})
.to_string()
.into_bytes(),
gas: 15_000_000_000_000, // 15 TeraGas
deposit: 1,
}))],
});
RpcSendTransactionRequest {
signed_transaction: transaction.sign(&signer.into()),
wait_until: TxExecutionStatus::Final,
}
}
}

#[async_trait]
impl TransactionSample for MpcCkd {
fn kind(&self) -> TransactionKind {
TransactionKind::MpcCkd
}

fn get_name(&self) -> &str {
"Call MPC ckd function"
}

fn get_transaction_request(
&self,
signer: InMemorySigner,
opts: Opts,
nonce: Nonce,
block_hash: CryptoHash,
) -> RpcSendTransactionRequest {
let domain_id = 2;
// To generate this value randomly we need to add a few dependencies
// This means that if a request is sent before the previous
// one is replied, it might fail as the nodes optimize repeated requests.
// This should not be a problem here, as we should only submit one ckd request
// every 5 minutes, and we expect them to be replied in less than a minute.
let app_public_key =
"bls12381g1:6KtVVcAAGacrjNGePN8bp3KV6fYGrw1rFsyc7cVJCqR16Zc2ZFg3HX3hSZxSfv1oH6";
let transaction = Transaction::V0(TransactionV0 {
signer_id: signer.account_id.clone(),
public_key: signer.public_key.clone(),
nonce: nonce + 1,
receiver_id: opts.mpc_contract_id,
block_hash,
actions: vec![Action::FunctionCall(Box::new(FunctionCallAction {
method_name: "request_app_private_key".to_string(),
args: serde_json::json!({"request": {"domain_id": domain_id,"app_public_key": app_public_key}})
.to_string()
.into_bytes(),
gas: 15_000_000_000_000, // 15 TeraGas
deposit: 1,
}))],
});
RpcSendTransactionRequest {
signed_transaction: transaction.sign(&signer.into()),
wait_until: TxExecutionStatus::Final,
}
}
}
58 changes: 0 additions & 58 deletions src/transaction/mpc_sign.rs

This file was deleted.