Skip to content

Commit

Permalink
Contract refactoring, API, README, etc (#706)
Browse files Browse the repository at this point in the history
* fix contract tests, add attached and required to errors

* error and error messages naming

* return more specific errors in user facing functions

* fix error conversion issue

* separate user facing functions into one impl block

* move some of the contract structs to primitives

* API and envs README

* revert MpcError -> SignError

* fmt

* Update chain-signatures/contract/src/errors.rs

Co-authored-by: DavidM-D <[email protected]>

* Update chain-signatures/contract/src/errors.rs

Co-authored-by: DavidM-D <[email protected]>

* Update chain-signatures/contract/src/errors.rs

Co-authored-by: DavidM-D <[email protected]>

* Update chain-signatures/contract/src/errors.rs

Co-authored-by: DavidM-D <[email protected]>

* ignore RUSTSEC-2024-0357

* make sign_helper private

---------

Co-authored-by: DavidM-D <[email protected]>
  • Loading branch information
volovyks and DavidM-D authored Jul 22, 2024
1 parent 0afe3e1 commit 7c4ba38
Show file tree
Hide file tree
Showing 8 changed files with 273 additions and 207 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/unit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,10 @@ jobs:
- name: Run Audit (FastAuth)
working-directory: integration-tests/fastauth
run: |
cargo audit --ignore RUSTSEC-2020-0071 --ignore RUSTSEC-2023-0052 --ignore RUSTSEC-2022-0093 --ignore RUSTSEC-2023-0071 --ignore RUSTSEC-2024-0019 --ignore RUSTSEC-2024-0344
cargo audit --ignore RUSTSEC-2020-0071 --ignore RUSTSEC-2023-0052 --ignore RUSTSEC-2022-0093 --ignore RUSTSEC-2023-0071 --ignore RUSTSEC-2024-0019 --ignore RUSTSEC-2024-0344 --ignore RUSTSEC-2024-0357
- name: Run Audit (Chain Signatures)
# even if previous audit step fails, run this audit step to ensure all crates are audited
if: always()
working-directory: integration-tests/chain-signatures
run: |
cargo audit --ignore RUSTSEC-2020-0071 --ignore RUSTSEC-2023-0052 --ignore RUSTSEC-2022-0093 --ignore RUSTSEC-2023-0071 --ignore RUSTSEC-2024-0019 --ignore RUSTSEC-2024-0344 --ignore RUSTSEC-2022-0093 --ignore RUSTSEC-2024-0346 --ignore RUSTSEC-2024-0347
cargo audit --ignore RUSTSEC-2020-0071 --ignore RUSTSEC-2023-0052 --ignore RUSTSEC-2022-0093 --ignore RUSTSEC-2023-0071 --ignore RUSTSEC-2024-0019 --ignore RUSTSEC-2024-0344 --ignore RUSTSEC-2022-0093 --ignore RUSTSEC-2024-0346 --ignore RUSTSEC-2024-0347 --ignore RUSTSEC-2024-0357
55 changes: 55 additions & 0 deletions chain-signatures/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Chain Signatures API

## `sign()`
This is the main function of the contract API. It is used to sign a request with the MPC service.
```rust
pub fn sign(&mut self, request: SignRequest) -> Result<near_sdk::Promise, MpcContractError>
```
Arguments and return type:
```rust
pub struct SignRequest {
pub payload: [u8; 32],
pub path: String,
pub key_version: u32,
}

pub struct SignResult {
pub big_r: String,
pub s: String,
}
```
- `key_version` must be less than or equal to the value at `latest_key_version`.
- `path` is a derivation path for the key that will be used to sign the payload.
- To avoid overloading the network with too many requests, we ask for a small deposit for each signature request. The fee changes based on how busy the network is.

## `public_key()`
This is the root public key combined from all the public keys of the participants.
```rust
pub fn public_key(&self) -> Result<PublicKey, MpcContractError>
```

## `derived_public_key()`
This is the derived public key of the caller given path and predecessor. If the predecessor is not provided, it will be the caller of the contract.
```rust
pub fn derived_public_key(
&self,
path: String,
predecessor: Option<AccountId>,
) -> Result<PublicKey, MpcContractError>
```

## `latest_key_version()`
Key versions refer new versions of the root key that we may choose to generate on cohort changes. Older key versions will always work but newer key versions were never held by older signers. Newer key versions may also add new security features, like only existing within a secure enclave. Currently only 0 is a valid key version.
```rust
pub const fn latest_key_version(&self) -> u32
```

For more details check `User contract API` impl block in the [chain-signatures/contracts/src/lib.rs](./chain-signatures/contracts/src/lib.rs) file.

# Environments
Currently, we have 3 environments:
1. Mainnet: `v1.multichain-mpc.near` // TODO: set when available
2. Testnet: `v2.multichain-mpc.testnet`
3. Dev: `v5.multichain-mpc-dev.testnet`

Contracts can be changed from v1 to v2, etc. Older contracts should continue functioning.
54 changes: 29 additions & 25 deletions chain-signatures/contract/src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,36 +1,40 @@
use near_sdk::Gas;

#[derive(Debug, thiserror::Error)]
pub enum SignError {
#[error("Signature request has timed out.")]
Timeout,
#[error("Signature request has already been submitted. Please, try again later.")]
#[error("Signature request has already been submitted. Please try again later.")]
PayloadCollision,
#[error("Payload hash cannot be convereted to Scalar.")]
PayloadMalform,
#[error("Contract version is greater than allowed.")]
VersionTooHigh,
#[error("Attached deposit is lower than required: {0}.")]
DepositInsufficient(String),
#[error("Provided gas is lower than required: {0}.")]
GasInsufficient(String),
#[error("Too many pending requests. Please, try again later.")]
#[error("Malformed payload: {0}")]
MalformedPayload(String),
#[error(
"This key version is not supported. Call latest_key_version() to get the latest supported version."
)]
UnsupportedKeyVersion,
#[error("Attached deposit is lower than required. Attached: {0}, Required: {1}.")]
InsufficientDeposit(u128, u128),
#[error("Provided gas is lower than required. Provided: {0}, required {1}.")]
InsufficientGas(Gas, Gas),
#[error("Too many pending requests. Please try again later.")]
RequestLimitExceeded,
#[error("This sign request was removed from pending requests: timed out or completed.")]
RequestNotInPending,
#[error("This sign request has timed out, was completed, or never existed.")]
RequestNotFound,
}

#[derive(Debug, thiserror::Error)]
pub enum RespondError {
#[error("This sign request was removed from pending requests: timed out or completed.")]
RequestNotInPending,
#[error("Signature could not be verified.")]
SignatureNotVerified,
#[error("Protocol state is not running.")]
ProtocolStateNotRunning,
#[error("This sign request has timed out, was completed, or never existed.")]
RequestNotFound,
#[error("The provided signature is invalid.")]
InvalidSignature,
#[error("The protocol is not Running.")]
ProtocolNotInRunningState,
}

#[derive(Debug, thiserror::Error)]
pub enum JoinError {
#[error("Protocol state is not running")]
#[error("The protocol is not Running.")]
ProtocolStateNotRunning,
}

Expand All @@ -50,20 +54,20 @@ pub enum InitError {

#[derive(Debug, thiserror::Error)]
pub enum VoteError {
#[error("Voting account is not not in the participant set.")]
#[error("Voting account is not in the participant set.")]
VoterNotParticipant,
#[error("Account to be kicked is not not in the participant set.")]
#[error("Account to be kicked is not in the participant set.")]
KickNotParticipant,
#[error("Account to join is not not in the candidates set.")]
#[error("Account to join is not in the candidate set.")]
JoinNotCandidate,
#[error("Account to join is already in the participant set.")]
JoinAlreadyParticipant,
#[error("Mismatched epoch.")]
MismatchedEpoch,
EpochMismatch,
#[error("Number of participants cannot go below threshold.")]
ParticipantsBelowThreshold,
#[error("Protocol state is not the expected: {0}")]
ProtocolStateNotExpected(String),
#[error("Unexpected protocol state: {0}")]
UnexpectedProtocolState(String),
}

#[derive(Debug, thiserror::Error)]
Expand Down
Loading

0 comments on commit 7c4ba38

Please sign in to comment.