Skip to content

Commit

Permalink
feat: Cairo 2 support
Browse files Browse the repository at this point in the history
BREAKING CHANGE: Optimize signers model for storage and extend account initializer

- Bump version to v001.000.000
- Initializer: Support initializing advanced signer types, multisig, and daily withdrawal limit on account deployment
- Initializer: Support deployment from deploy syscall (external deployer, not via DEPLOY_ACCOUNT)
- Signers: Save Poseidon(pub key) instead of flattened pub key to optimize storage (i.e., every signer is represented as 1 felt)
  - Changes signature structure for advanced signer types since public key is not directly stored
- Signers: Add optimized WebAuthn support (currently uses Cairo 0 SHA256 lib until an optimized Cairo version is available)
- Multisig: Generalize support to more than 2 signers (i.e., allow multiple hardware signers in the same account)
- Daily withdrawal limit: A new optional feature that allows relaxation of signing security requirements for low-value transactions (uses mySwap CL TWAP for asset prices)
- Outside execution: SNIP-9 version 2 support
  • Loading branch information
yoga-braavos committed Feb 6, 2024
1 parent a781740 commit e8753ad
Show file tree
Hide file tree
Showing 83 changed files with 60,674 additions and 437,495 deletions.
26 changes: 0 additions & 26 deletions .github/workflows/pr-contracts.yml

This file was deleted.

3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,6 @@ dmypy.json
# nile
artifacts/
node.json

*.DS_Store
*.swp
4 changes: 0 additions & 4 deletions .gitmodules

This file was deleted.

27 changes: 0 additions & 27 deletions CHANGELOG.md

This file was deleted.

4 changes: 2 additions & 2 deletions LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -631,8 +631,8 @@ to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

Braavos Account Contract for Starknet
Copyright (C) 2023 FREEBRAAVOS ltd.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
Expand Down
136 changes: 100 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,56 +1,120 @@
# Braavos Account Contract
# Braavos Account Contract v1.0.0

## MAINNET ALPHA DISCLAIMER
#### Class Hashes
*Braavos Account* - `0x00816dd0297efc55dc1e7559020a3a825e81ef734b558f03c83325d4da7e6253`

The Braavos Account is in alpha stage, as well as the StarkNet network itself.
*Braavos Base Account* - `0x013bfe114fb1cf405bfc3a7f8dbe2d91db146c17521d40dcf57e16d6b59fa8e6`

Things can break and in extreme cases can lead to loss of funds. The contract code have
not yet been audited, the wallet code as well as the contracts themselves can be upgraded
without a timelock.
## Architecture

## Design
### Deployment

The Braavos account contract is comprised of 3 main modules:
Braavos account deployment enables account addresses to be dependent only on the Stark public key while still supporting additional initialization parameters and using the most up-to-date
account implementation class hash. This is achieved by:

1. Basic account functionality - validation and execution of Multicall based on
OpenZeppelin's implementation. Can be found under `src/account`.
2. Signer management - adding / removing of additional signers, namely the secp256r1-based
Hardware Signer. Can be found under `src/signers`
3. Multisig - implementation of M of N signers for transaction execution. Currently
supports 2 of 2. Can be found under `src/multisig`
1. Having a base implementation class hash that rarely changes (`src/presets/braavos_base_account.cairo`). Account deployments should always use this class hash.
2. Send additional initialization parameters via the deployment signature instead of constructor params.
3. Additional initialization parameters are signed and verified in the base implementation (see `assert_valid_deploy_base`).
4. After validation, the base implementation replaces the underlying implementation to the latest one via a `replace_class_syscall` (`src/presets/braavos_account.cairo`) and the actual implementation initializer is called.

This account contract is intended to be used as an implementation of a Proxy contract.
We've used OpenZeppelin's Proxy implementation for this purpose.
NOTE: The actual account implementation is not expected to be directly deployed and therefore its constructor panics.

### Signer Management
### Signers (`src/signers/`)

When adding an additional signer, a _Hardware Signer_ or _Protected Signer_, the basic
seed-based signer cannot sign transactions anymore besides a request to remove the
additional signer and revert back to seed-based signer. The request is time-delayed
(currently for 4 days).
The Braavos account supports 3 different types of signers:

### Multisig
1. _Stark Signer_ - the native signer based on the Stark friendly curve.
2. _Hardware Signer_ - Uses the physical device secure enclave to sign - based on the secp256r1 curve.
3. _Webauthn Signer_ - Uses the physical device [Webauthn protocol](https://w3.org/TR/webauthn/) (aka Passkeys) implementation to sign - also based on the secp256r1 curve with a webauthn compatible signature format.

The account can be moved into Multisig mode (currently supports 2 of 2) and it will not
execute any transaction before the 2 signers defined in the account sign the transaction.
The seed can request to disable multisig with a time-delay (currently 4 days).
The native Stark signer is added by default on account deployment and is usually derived from the seed phrase.

## Building
The _Hardware Signer_ and _Webauthn Signer_ are considered to be _Strong Signers_ as they facilitate 2FA.
When a _Strong Signer_ is added to the account the default _Stark Signer_ is disabled and not allowed to issue transactions. Only a _Strong Signer_ can.

### Account Contract
Note that an account can have both _Hardware Signer_ and _Webauthn Signer_ defined, in which case, any of them can sign as a 'Strong Signer' in the account.

> nile compile --directory src/account
#### Multisig

### Proxy Contract
In addition, a multisig threshold can be enabled and support _m-of-n_ signer threshold in order to execute a transaction.
When an account have both _Hardware signer_ and _Webauthn signer_ defined, then both of them MUST be present in the multisig.

> nile compile --directory lib/openzeppelin/upgrades/
#### Deferred Removal of _Strong Signers_ and _Multisig_

## Testing
When there is a _Strong Signer_ defined in the account, the _Stark Signer_ role is reduced to removing all _Strong Signers_ and _Multisig_ with a time lock.
The purpose of this mechanism is to allow the user to recover access to his account even if he lost access to the device containing his _Strong Signer_.
The time-lock guarantees that the user have ample time to respond in case his seed phrase was stolen and an attacker tries to remove _Strong Signer_ protection
and take over the account.

### Running End-to-End tests
The default time lock is defined to be 4 days.

> pytest -n auto tests/
#### Signature Format

The signature format is as follows:
```[ signer #1 sig #1, signer #2 sig, signer #3 sig, ... ]```

Where each instance of a _signer sig_ is:
```[ signer type, signer pub key, ...actual signature fields]```

Some important details to note here:

1. We send the `signer pub key` since each signer is saved in the account as a single `felt252` - _guid_. When verifying a signature, the _guid_ is
calculated from the public key and we verify that it matches one of the guids that are saved in the account.
For the _Hardware Signer_ and _Webauthn Signer_ the guid is `poseidon(secp256r1 pub key)`
2. `Signer type` indicates in which signer list we should look for the computed _guid_. The applicable types are:
_Stark Signer_: *1*, _Hardware Signer_: *2*, _Webauthn Signer_: *5*

3. Since currently only the default _Stark Signer_ is supported, when sending a Stark signature there is no need to send the `pub key` together with the signature. In this scenario there are 2 possible formats:
- The native `(r, s)` format for compatibility with tooling and SDKs
- ```[ signer type (==1), r, s]```

4. More than one signer can be sent in the signature array to allow for `m-of-n` signers in _Multisig_ mode.

### Daily Withdrawal Limit (`src/dwl/`)

The Daily Withdrawal Limit is a feature that allows relaxtion of _Strong Signer_ and _Multisig_ requirements
for certain types of transactions. All applicable transactions are analyzed for their value (actual token value + gas) and are accumulated per calendar day. While the
accumulated amount is under a certain threshold, a weaker signer can be used to validate enabling lower fees and simpler User Experience for lower value transactions.

The Withdrawal Limit thresholds are set in USDC. For example, to set a low withdrawal limit of 100$, withdrawal limit should be set to `100 * 10**6`. We use
MySwap-CL's TWAP pricing to determine the value of an applicable transaction in USDC terms.

Applicable transactions are either `transfer` or `approve` transactions on the most commonly used tokens (ETH, USDC, USDT, DAI, WBTC) or a whitelisted set of protocol entrypoints.
This whitelist for both tokens and contract entrypoints can be configured manually using the `update_rate_config` entrypoint

Two thresholds can be set as part of the daily withdrawal limit:

1. Low Limit - controls under which accumulated daily transaction value the _Stark Signer_ can sign even if there are _Strong Signers_ or _Multisig_ defined in the account.
2. High Limit - Defines under which accumulated daily transaction value a _Strong Signer_ can be used even if _Multisig_ is defined

When a transaction is validated without utilizing the Daily Withdrawal Limit's use of a weaker signer,
i.e. using _Strong Signer_ even though Daily Withdrawal Limit allows usage of _Stark Signer_ for that transaction
then the transaction value is not accumulated towards the Withdraw Limit.

### Outside Execution (`src/outside_execution/`)
This feature is intended to allow different protocols to submit transactions on behalf of the user, given the user had signed the appropriate transactions beforhand. This contract implements [SNIP-9 version 2](https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-9.md).

## Building and Testing

### Build

This repo is built using [Scarb v2.5.1](https://docs.swmansion.com/scarb/). After installation, run:
> scarb build
### Tests

Prerequisites:
1. Install Python requirements
> pip install -r requirements.txt
2. Setup [starknet-devnet-rs](https://github.com/0xSpaceShard/starknet-devnet-rs)
3. Define `STARKNET_DEVNET` env variable to point to `starknet-devnet-rs` executable

To run tests:
>
> pytest
## Acknowledgements
- This project utilzes 2 separate implementations of SHA256 for pre/post regenesis support:
- Cairo 0 implementation (as a library call) by the Cartridge team: [cairo-sha256](https://github.com/cartridge-gg/cairo-sha256)
- Cairo implementation from the [Alexandria](https://github.com/keep-starknet-strange/alexandria) project

## Credits
1. Thanks to the OpenZeppelin team for providing reference implementations for both the basic account functionality and the Proxy pattern at https://github.com/OpenZeppelin/cairo-contracts
2. Thanks to EulerSmile for providing the reference `secp256k1` implementation - https://github.com/EulerSmile/common-ec-cairo
6 changes: 6 additions & 0 deletions Scarb.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Code generated by scarb DO NOT EDIT.
version = 1

[[package]]
name = "braavos_account"
version = "1.0.0"
12 changes: 12 additions & 0 deletions Scarb.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "braavos_account"
version = "1.0.0"

[dependencies]
starknet = ">=2.3.1"

[[target.starknet-contract]]
allowed-libfuncs-list.name = "all"
casm-add-pythonic-hints = true
casm = true

Loading

0 comments on commit e8753ad

Please sign in to comment.