Smart Wallets

2 minute read Published: 2022-06-20

Smart Wallets

When working with Smart Wallets - question on how to verify their signatures may arise. This blog post will give you a basic understanding of theory and practice regarding this question.

TL;DR

Smart Wallets' Contracts have no key-pair to sign and verify messages. Instead Wallet's Contract will implement EIP-1271 and provide isValidSignature method to call it on.

Theory

Before I faced an issue to deal with Smart Wallets I had understanding of crypto wallet as ordinary Externally Owned Accounts with key-pair: private key used to sing messages and public keys used to verify messages' signatures.

It turns out that Smart Wallets lack this feature - they are contracts deployed to a blockchain network and can confirm their signature using EIP-1271. They use a state and isValidSignature method to provide an ability to verify their signatures.

Pracice

If you are interested in writing some code and spending some ethereum - welcome to our next section. Here we will create an Ambire Wallet, sign some message, transform Ethereum ABI to Rust API and verify the signature in the end.

Wallet Creation and Activation

Message Sign

API Generation


[package]
name = "swsv"
version = "0.1.0"
edition = "2021"
[dependencies]
ethers = "0.6.2"
hex = "^0.4.3"
serde_json = "^1.0.64"
tokio = { version = "^1.5", features = ["full"] }
use ethers::prelude::*;

fn main() {
    Abigen::new(
        "AmbireSmartWallet",
        "https://etherscan.io/address/YOUR_WALLET_ADDRESS",
    )
    .unwrap()
    .generate()
    .unwrap()
    .write_to_file("src/ambire.rs")
    .unwrap();
}
use ethers::prelude::*;

mod ambire;

fn main() {}

Call Execution

use std::sync::Arc;

use ethers::prelude::*;

mod ambire;

use ambire::AmbireSmartWallet;

#[tokio::main]
async fn main() {
    //TODO: Get your token from https://docs.infura.io/infura/getting-started and put in URL below
    let provider =
        Provider::<Http>::try_from("https://mainnet.infura.io/v3/YOUR_INFURA_TOKEN")
            .expect("could not instantiate HTTP Provider");
    //TODO: Put yours wallet's address here
    let address = "YOUR_WALLET_ADDRESS"
        .parse::<Address>()
        .unwrap();
    //TODO: Put yours message here
    let hash =
        hash_message("YOUR_MESSAGE").to_fixed_bytes();
    let contract = AmbireSmartWallet::new(address, Arc::new(provider));
    //TODO: Put yours signature here without prefix `0x`
    let sig = Bytes::from(hex::decode("SIGNATURE").unwrap());
    let result = contract.is_valid_signature(hash, sig).call().await.unwrap();
    assert_eq!("1626ba7e", hex::encode(result));
}