Skip to content

v0.13.0

Latest

Choose a tag to compare

@github-actions github-actions released this 17 Oct 17:52
· 100 commits to master since this release
v0.13.0
c02d03a

Smaller installs

The library and the CLI are still two crates, and each one now compiles only what it uses:

cargo install safe-rs-cli --locked                       # the `safe` CLI, with Ledger support
cargo install safe-rs-cli --locked --no-default-features # without Ledger (no libusb)
[dependencies]
safe-rs = "0.13"                                             # with fork simulation
safe-rs = { version = "0.13", default-features = false }      # without revm
safe-rs = { version = "0.13", features = ["hd-wallet"] }      # + keystores and RotatingSafe
Feature Default Adds
simulation yes Fork simulation with revm: simulate() on the builders, ForkSession, simulate_exec*
hd-wallet no Encrypted mnemonic keystores, HD keys and RotatingSafe (implies simulation)
ledger no Owner keys on a Ledger (implies hd-wallet)

Neither crate enables alloy's full or tokio's full any more, which dropped the WebSocket and IPC transports, pubsub and the anvil/txpool/debug provider APIs. A library build without default features compiles 242 crates instead of 331, without revm, c-kzg, blst or secp256k1-sys. Without simulation, the builders still execute(), with gas from eth_estimateGas, so a reverting call still fails before anything is broadcast.

Multi-owner Safes

  • SignedSafeTx holds several owners' signatures, sorted. New functions pack, unpack and recover them, and build approveHash calldata.
  • safe send, safe send --rotate and safe rotate read the Safe's owners, threshold and on-chain approvedHashes. They then pick one of:
    • collecting signatures offchain in a bundle file (--bundle, --sign-only, --merge-bundle)
    • approving the hash on chain (--approve-hash)
    • executing
  • New library functions: read_approved_owners, simulate_exec_with_threshold, simulate_approve_hash and OuterTxParams::approve_hash.

One-time owner keys

Every transaction can swap the Safe's owner for a fresh key, so the key that signed is no longer an owner once its signature is public.

  • CLI:
    • safe send --rotate --hd-wallet <name> appends the swap and then moves the old key's ETH to the new one.
    • safe rotate does the swap on its own, finds the Safe when you don't name one, and moves an existing Safe onto the wallet.
    • safe create --hd-wallet deploys from a funding key, so the owner key has never signed anything.
    • safe wallet new|import|list|address|status|sync|sweep manage the encrypted phrase and the record of used keys.
  • Library: the hd-wallet feature adds RotatingSafe, HdWallet, encrypted keystores, and rebuilding the rotation state from on-chain owner events.

Ledger

  • CLI: --ledger takes the owner keys from a Ledger, wherever --hd-wallet is accepted. It uses the same derivation path, so a Ledger seeded with a phrase shares that phrase's state. It's a default feature of the CLI.
  • Library: the ledger feature adds LedgerKeys. Safe transactions are now signed as EIP-712 typed data, which the device can display. For a local key the signatures are unchanged.

Safe v1.5.0

  • safe create deploys v1.5.0 Safes by default. Pass --safe-version 1.4.1 for the old version.
  • Owner rotation works on v1.5.0.
  • Batches go through the MultiSend contracts of the Safe's own version (ChainAddresses::for_version, detect_addresses).

Breaking changes

  • safe-rs no longer turns on alloy's full feature. If your code relied on it for WebSocket, IPC or the extra provider APIs, enable those on your own alloy dependency.
  • CallBuilder::simulate, simulation_result and simulation_success exist only with the simulation feature, which is on by default.
  • safe info takes the Safe address as a positional argument, defaults to the signer's own Safe, and no longer reads SAFE_ADDRESS.
  • SignedSafeTx holds a map of signatures instead of a single signature.

Fixes

  • execute() estimates gas itself, so a send that fails estimation no longer leaves the provider a nonce ahead with the next transaction stuck.
  • A batch whose MultiSend target has no code is refused before signing. That applies to SafeBuilder and to RotatingSafe. Before, it looked successful while none of the calls ran.
  • The fork backend runs on the caller's runtime, so simulate() followed by another call on the same provider can no longer hang.
  • WalletBuilder::connect_with_config keeps the configured contract addresses.
  • Every sweep still owed from an earlier key stays on record across later rotations.
  • Deployment checks no longer fail on a stale read from another RPC node.

Full changelog: v0.12.0...v0.13.0