Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A doc with examples of commands #913

Merged
merged 15 commits into from
Nov 8, 2024
Merged
Changes from 9 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
8 changes: 7 additions & 1 deletion API.md
Original file line number Diff line number Diff line change
@@ -55,4 +55,10 @@ For more details check `User contract API` impl block in the [chain-signatures/c

# Environments
1. Mainnet: `v1.signer`
2. Testnet: `v1.sigenr-prod.testnet`
2. Testnet: `v1.signer-dev.testnet`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no mistake, it should be v1.sigenr-prod.testnet.


# Interact using NEAR CLI

There is an `Example Commands` in the [chain-signatures/contract/example.md](./chain-signature/contract/EXAMPLE.md) file.

These commands work for the latest versions of `Near-cli`(4.0.0+). For installing near-cli [[click here]](https://github.com/near/near-cli/tree/v4.0.13?tab=readme-ov-file#setup)
49 changes: 49 additions & 0 deletions chain-signatures/contract/EXAMPLE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Iteracting with contract using NEAR CLI
All data is fake and used for example purposes
It's necessary to update script after contract API changes
## User contract API

near call v1.signer-dev.testnet sign '{"request":{"key_version":0,"path":"test","payload":[12,1,2,0,4,5,6,8,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,44]}}' --accountId alexkushnir.testnet --gas 300000000000000 --deposit 1

near view v1.signer-dev.testnet public_key

near view v1.signer-dev.testnet derived_public_key {"path":"test","predecessor":"alexkushnir.testnet"}

near view v1.signer-dev.testnet latest_key_version

near view v1.signer-dev.testnet experimental_signature_deposit


## Node API

near call v1.signer-dev.testnet respond '{"request":{"epsilon":{"scalar":"72DB59A313FA266B1C3B40F20325C9023DDC564E7790363BCC2AE76580339648"},"payload_hash":{"scalar":"05FCB4470106774DCC5A3C7689FD2917C15AB81B6FA44960843E6389780A5364"}},"response":{"big_r":{"affine_point":"02EC7FA686BB430A4B700BDA07F2E07D6333D9E33AEEF270334EB2D00D0A6FEC6C"},"recovery_id":0,"s":{"scalar":"20F90C540EE00133C911EA2A9ADE2ABBCC7AD820687F75E011DFEEC94DB10CD6"}}}' --accountId alexkushnir.testnet --gas 300000000000000

near call v1.signer-dev.testnet join '{"cipher_pk":[59,105,187,93,147,173,85,119,242,237,171,117,87,221,135,181,28,120,239,58,50,198,137,77,219,16,151,195,93,140,92,88],"sign_pk":"ed25519:J75xXmF7WUPS3xCm3hy2tgwLCKdYM1iJd4BWF8sWVnae","url":"http://localhost:3030"}' --accountId alexkushnir.testnet --gas 300000000000000

near call v1.signer-dev.testnet vote_join '{"candidate":"alexkushnir.testnet"}' --accountId alexkushnir.testnet --gas 300000000000000

near call v1.signer-dev.testnet vote_leave '{"kick":"alexkushnir.testnet"}' --accountId alexkushnir.testnet --gas 300000000000000

near call v1.signer-dev.testnet vote_pk '{"public_key": ed25519:J75xXmF7WUPS3xCm3hy2tgwLCKdYM1iJd4BWF8sWVnae}' --accountId alexkushnir.testnet --gas 300000000000000

near call v1.signer-dev.testnet vote_reshared '{"epoch": 1}' --accountId alexkushnir.testnet --gas 300000000000000

near call v1.signer-dev.testnet propose_update --base64 "AAHgkwQAAAAAAADdbQAAAAAAAgAAAEAAAAAABAAAAABAAMAnCQAAAAAAAAAAAAACAAAAACAAyK8AAAAAAAAAAAAAyK8AAAAAAABADQMAAAAAAABcJgUAAAAAAAAAAAAAAAAAAAAA" --accountId alexkushnir.testnet --gas 300000000000000

near call v1.signer-dev.testnet vote_update '{"id": 0}' --accountId alexkushnir.testnet --gas 300000000000000


## Contract developer helper API

near call v1.signer-dev.testnet init '{"candidates":{"candidates":{"alice.near":{"account_id":"alice.near","cipher_pk":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"sign_pk":"ed25519:J75xXmF7WUPS3xCm3hy2tgwLCKdYM1iJd4BWF8sWVnae","url":"127.0.0.1"},"bob.near":{"account_id":"bob.near","cipher_pk":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"sign_pk":"ed25519:J75xXmF7WUPS3xCm3hy2tgwLCKdYM1iJd4BWF8sWVnae","url":"127.0.0.1"},"caesar.near":{"account_id":"caesar.near","cipher_pk":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"sign_pk":"ed25519:J75xXmF7WUPS3xCm3hy2tgwLCKdYM1iJd4BWF8sWVnae","url":"127.0.0.1"}}},"threshold":1}' --accountId alexkushnir.testnet --gas 300000000000000

near call v1.signer-dev.testnet init_running '{"epoch":0,"participants":{"account_to_participant_id":{"alice.near":0,"bob.near":1,"caesar.near":2},"next_id":3,"participants":{"alice.near":{"account_id":"alice.near","cipher_pk":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"sign_pk":"ed25519:J75xXmF7WUPS3xCm3hy2tgwLCKdYM1iJd4BWF8sWVnae","url":"127.0.0.1"},"bob.near":{"account_id":"bob.near","cipher_pk":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"sign_pk":"ed25519:J75xXmF7WUPS3xCm3hy2tgwLCKdYM1iJd4BWF8sWVnae","url":"127.0.0.1"},"caesar.near":{"account_id":"caesar.near","cipher_pk":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"sign_pk":"ed25519:J75xXmF7WUPS3xCm3hy2tgwLCKdYM1iJd4BWF8sWVnae","url":"127.0.0.1"}}},"public_key":"ed25519:J75xXmF7WUPS3xCm3hy2tgwLCKdYM1iJd4BWF8sWVnae","threshold":2}' --accountId alexkushnir.testnet --gas 300000000000000

near view v1.signer-dev.testnet migrate

near view v1.signer-dev.testnet state

near view v1.signer-dev.testnet config

near view v1.signer-dev.testnet version

1 change: 1 addition & 0 deletions integration-tests/chain-signatures/Cargo.lock

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

3 changes: 2 additions & 1 deletion integration-tests/chain-signatures/Cargo.toml
Original file line number Diff line number Diff line change
@@ -28,6 +28,7 @@ tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
thiserror = "1"
url = { version = "2.4.0", features = ["serde"] }
web3 = "0.19.0"
deadpool-redis = "0.18.0"

# crypto dependencies
@@ -41,6 +42,7 @@ k256 = { version = "0.13.1", features = ["sha256", "ecdsa", "serde"] }
near-account-id = "1"
near-crypto = "0.26.0"
near-fetch = "0.6.0"
near-sdk = "5.2.1"
near-jsonrpc-client = "0.13.0"
near-primitives = "0.26.0"
near-lake-framework = { git = "https://github.com/near/near-lake-framework-rs", branch = "node/2.3.0" }
@@ -60,7 +62,6 @@ test-log = { version = "0.2.12", features = ["log", "trace"] }
# crypto dependencies
ecdsa = "0.16.9"
ethers-core = "2.0.13"
web3 = "0.19.0"
secp256k1 = "0.28.2"

[build-dependencies]
164 changes: 164 additions & 0 deletions integration-tests/chain-signatures/src/commands.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
use std::str::FromStr;

use crypto_shared::{ScalarExt, SerializableAffinePoint, SerializableScalar, SignatureResponse};
use k256::Scalar;
use mpc_contract::{
config::Config,
primitives::{CandidateInfo, Candidates, Participants, SignRequest, SignatureRequest},
update::ProposeUpdateArgs,
};
use mpc_keys::hpke;
use near_account_id::AccountId;
use near_primitives::borsh;
use near_sdk::PublicKey;
use serde_json::json;

const PAYLOAD: [u8; 32] = [
12, 1, 2, 0, 4, 5, 6, 8, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
26, 27, 28, 29, 30, 44,
];

const SIGN_PK: &str = "ed25519:J75xXmF7WUPS3xCm3hy2tgwLCKdYM1iJd4BWF8sWVnae";

pub fn sing_command(contract_id: &AccountId, caller_id: &AccountId) -> anyhow::Result<String> {
let sign_request = SignRequest {
payload: PAYLOAD,
path: "test".into(),
key_version: 0,
};

let request_json = format!(
"'{}'",
serde_json::to_string(&json!({"request": sign_request}))?
);

Ok(format!(
"near call {} sign {} --accountId {} --gas 300000000000000 --deposit 1",
contract_id, request_json, caller_id
))
}

pub fn respond_command(contract_id: &AccountId, caller_id: &AccountId) -> anyhow::Result<String> {
let payload_hashed = web3::signing::keccak256(&PAYLOAD);

let request = SignatureRequest::new(
Scalar::from_bytes(payload_hashed)
.ok_or_else(|| anyhow::anyhow!("Failed to convert bytes to Scalar"))?,
caller_id,
"test",
);

let big_r = serde_json::from_value(
"02EC7FA686BB430A4B700BDA07F2E07D6333D9E33AEEF270334EB2D00D0A6FEC6C".into(),
)?; // Fake BigR
let s = serde_json::from_value(
"20F90C540EE00133C911EA2A9ADE2ABBCC7AD820687F75E011DFEEC94DB10CD6".into(),
)?; // Fake S

let response = SignatureResponse {
big_r: SerializableAffinePoint {
affine_point: big_r,
},
s: SerializableScalar { scalar: s },
recovery_id: 0,
};

let request_json = format!(
"'{}'",
serde_json::to_string(&json!({"request": request, "response": response})).unwrap()
);

Ok(format!(
"near call {} respond {} --accountId {} --gas 300000000000000",
contract_id, request_json, caller_id
))
}

pub fn join_command(contract_id: &AccountId, caller_id: &AccountId) -> anyhow::Result<String> {
let url = "http://localhost:3030";
let (_, cipher_pk) = hpke::generate();
let sign_pk = PublicKey::from_str(SIGN_PK)?;

let join_json = format!(
"'{}'",
serde_json::to_string(&json!({"url": url, "cipher_pk": cipher_pk, "sign_pk": sign_pk}))?
);

Ok(format!(
"near call {} join {} --accountId {} --gas 300000000000000",
contract_id, join_json, caller_id
))
}

pub fn proposed_updates_command(
contract_id: &AccountId,
caller_id: &AccountId,
) -> anyhow::Result<String> {
let args = ProposeUpdateArgs {
code: None,
config: Some(Config::default()),
};

let borsh_args = borsh::to_vec(&args)?;

let base64_encoded = near_primitives::serialize::to_base64(borsh_args.as_slice());

Ok(format!(
"near call {} propose_update --base64 {:?} --accountId {} --gas 300000000000000",
contract_id, base64_encoded, caller_id
))
}

pub fn init_command(contract_id: &AccountId, caller_id: &AccountId) -> anyhow::Result<String> {
let threshold: usize = 1;
let candidates: Candidates = dummy_candidates();

let init_json = format!(
"'{}'",
serde_json::to_string(&json!({"threshold": threshold, "candidates": candidates}))?
);

Ok(format!(
"near call {} init {} --accountId {} --gas 300000000000000",
contract_id, init_json, caller_id
))
}

pub fn init_running_command(
contract_id: &AccountId,
caller_id: &AccountId,
) -> anyhow::Result<String> {
let init_running_json = format!(
"'{}'",
serde_json::to_string(
&json!({"epoch": 0, "participants": Participants::from(dummy_candidates()), "threshold": 2,"public_key": PublicKey::from_str(SIGN_PK)? })
)?
);

Ok(format!(
"near call {} init_running {} --accountId {} --gas 300000000000000",
contract_id, init_running_json, caller_id
))
}

pub fn dummy_candidates() -> Candidates {
let mut candidates = Candidates::new();
let names: Vec<AccountId> = vec![
"alice.near".parse().unwrap(),
"bob.near".parse().unwrap(),
"caesar.near".parse().unwrap(),
];

for account_id in names {
candidates.insert(
account_id.clone(),
CandidateInfo {
account_id,
url: "127.0.0.1".into(),
cipher_pk: [0; 32],
sign_pk: PublicKey::from_str(SIGN_PK).unwrap(),
},
);
}
candidates
}
104 changes: 104 additions & 0 deletions integration-tests/chain-signatures/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
use std::fs::File;
use std::io::Write;
use std::str::FromStr;
use std::vec;

use clap::Parser;
use integration_tests_chain_signatures::containers::DockerClient;
use integration_tests_chain_signatures::{dry_run, run, utils, MultichainConfig};
use near_account_id::AccountId;
use near_crypto::PublicKey;
use serde_json::json;
use tokio::signal;
use tracing_subscriber::EnvFilter;

mod commands;

#[derive(Parser, Debug)]
enum Cli {
/// Spin up dependent services and mpc nodes
@@ -15,6 +25,8 @@ enum Cli {
},
/// Spin up dependent services but not mpc nodes
DepServices,
/// Example of commands to interact with the contract
ContractCommands,
}

#[tokio::main]
@@ -79,6 +91,98 @@ async fn main() -> anyhow::Result<()> {
println!("Received Ctrl-C");
println!("Stopped dependency services");
}
Cli::ContractCommands => {
println!("Building a doc with example commands");
let path = "../../chain-signatures/contract/EXAMPLE.md";
let mut file = File::create(path)?;
let mut doc: Vec<String> = vec![];
let contract_account_id = AccountId::from_str("v1.signer-dev.testnet")?;
let caller_account_id = AccountId::from_str("v1.signer-dev.testnet")?;
let public_key: PublicKey =
"ed25519:J75xXmF7WUPS3xCm3hy2tgwLCKdYM1iJd4BWF8sWVnae".parse()?;

doc.push(
"# Iteracting with contract using NEAR CLI\nAll data is fake and used for example purposes\nIt's necessary to update script after contract API changes\n## User contract API"
.to_string()
);

doc.push(commands::sing_command(
&contract_account_id,
&caller_account_id,
)?);
doc.push(format!("near view {} public_key", contract_account_id));

doc.push(format!(
"near view {} derived_public_key {}",
contract_account_id,
serde_json::to_string(&json!({"path": "test","predecessor": caller_account_id}))?
));

doc.push(format!(
"near view {} latest_key_version",
contract_account_id
));

doc.push(format!(
"near view {} experimental_signature_deposit",
contract_account_id
));

doc.push(format!(
"\n## Node API\n\n{}\n\n{}",
commands::respond_command(&contract_account_id, &caller_account_id,)?,
commands::join_command(&contract_account_id, &caller_account_id,)?
));

doc.push(format!(
"near call {} vote_join '{{\"candidate\":\"{}\"}}' --accountId {} --gas 300000000000000",
contract_account_id, caller_account_id, caller_account_id
));

doc.push(format!(
"near call {} vote_leave '{{\"kick\":\"{}\"}}' --accountId {} --gas 300000000000000",
contract_account_id, caller_account_id, caller_account_id
));

doc.push(format!(
"near call {} vote_pk '{{\"public_key\": {}}}' --accountId {} --gas 300000000000000",
contract_account_id, public_key, caller_account_id
));

doc.push(format!(
"near call {} vote_reshared '{{\"epoch\": 1}}' --accountId {} --gas 300000000000000",
contract_account_id, caller_account_id
));

doc.push(commands::proposed_updates_command(
&contract_account_id,
&caller_account_id,
)?);

doc.push(format!(
"near call {} vote_update '{{\"id\": 0}}' --accountId {} --gas 300000000000000",
contract_account_id, caller_account_id
));

doc.push(format!(
"\n## Contract developer helper API\n\n{}\n\n{}",
commands::init_command(&contract_account_id, &caller_account_id,)?,
commands::init_running_command(&contract_account_id, &caller_account_id,)?
));

doc.push(format!("near view {} migrate", contract_account_id));

doc.push(format!("near view {} state", contract_account_id));

doc.push(format!("near view {} config", contract_account_id));

doc.push(format!("near view {} version", contract_account_id));

for arg in doc {
file.write_all(arg.as_bytes())?;
file.write_all("\n\n".as_bytes())?;
}
}
}

Ok(())