Get started
Variance is an Account Abstraction Developer toolkit that is designed to simplify the development of Ethereum smart accounts and Entrypoint interactions. It relies on the Web3dart library.
Installation
To use the Variance SDK in your Flutter project, open your terminal and run the following command:
flutter pub add variance_dart
flutter pub add web3_signers
flutter pub add web3dart
Chain Configuration
First, import the necessary classes and configure the EVM network you want to work with:
import 'package:web3_signers/web3_signers.dart';
import 'package:variance_dart/variance_dart.dart';
import 'package:web3dart/web3dart.dart';
// Configure the chain
static const rpc = "https://api.pimlico.io/v2/84532/rpc?apikey=API_KEY";
final Uint256 salt = Uint256.zero;
final Chain chain = Chains.getChain(Network.baseTestnet)
// For Safe Accounts, use `Constants.safeProxyFactoryAddress` as the account factory.
..accountFactory = Constants.lightAccountFactoryAddressv07
..bundlerUrl = rpc
..paymasterUrl = rpc;
The Chains
class provides a list of available networks, including ethereum
, polygon
, optimism
, base
, arbitrum
, linea
, fuse
, scroll
, and testnets like sepolia
and baseTestnet
.
Signer Setup
The Variance SDK supports various types of signers, which are responsible for signing UserOperation hashes to be verified on-chain. The signers are managed in a separate package called web3signers, which provides the following functionalities:
PrivateKey Signer
The PrivateKeySigner
is the most basic signer and conforms to the multi-signer interface. You can create a random private key or load it from an encrypted backup:
// Create a random private key
final PrivateKeySigner signer = PrivateKeySigner.createRandom("password");
// Load from an encrypted backup
final PrivateKeySigner signer = PrivateKeySigner.fromJson("source", "password");
Passkey Signer
The PassKeySigner
conforms to the multi-signer interface and allows you to sign payloads using your device's passkeys. It falls under the secp256r1
category and can be verified on-chain using a P256 Verifier
on-chain:
final options = PassKeysOptions(
name: "variance", // Replace with your relying party name
namespace: "variance.space", // Replace with your relying party ID (domain name)
origin: "https://variance.space", // Replace with your relying party origin
userVerification: "required",
requireResidentKey: true,
sharedWebauthnSigner: EthereumAddress.fromHex("0xfD90FAd33ee8b58f32c00aceEad1358e4AFC23f9"));
final PassKeySigner signer = PassKeySigner(options);
// Register a new passkey
PassKeyPair pkp = await pkpSigner.register("user@variance.space", "test user");
The PassKeySigner supports various signing methods, including personalSign
, signToEc
, and signToPasskeySignature
.
EOA Wallet (Seed Phrases)
The EOAWallet
signer allows you to sign transactions using seed phrases (also known as mnemonics). It conforms to the multi-signer interface and can be used with simple smart accounts and safe accounts.
Once you have set up the appropriate signer, you can create a SmartWalletFactory
instance and proceed with creating and interacting with smart wallets.
final signer = EOAWallet.createWallet();
A note on prefix:
SignatureOptions
is used to specify a prefix for the specific signer. This is required for alchemy light accounts. It is not required for safe smart accounts.
Smart Wallet Factory
With the chain configuration and signer set up, you can create a SmartWalletFactory
instance:
final SmartWalletFactory smartWalletFactory = SmartWalletFactory(chain, signer);
Creating a Smart Wallet
The SmartWalletFactory
class provides methods to create different types of smart wallets, such as AlchemyLightAccount
, SafeAccountWithPasskey
, and SafeAccount
. Here's an example of creating a simple smart account:
final salt = Uint256.zero;
final SmartWallet wallet = await smartWalletFactory.createSafeAccount(salt);
print("Simple wallet address: ${wallet.address.hex}");
Interacting with the Smart Wallet
Once you have a SmartWallet
instance, you can interact with it using various methods:
Retrieve the balance
final EtherAmount balance = await wallet.balance;
print("Account balance: ${balance.getInWei}");
Retrieve the account nonce
final Uint256 nonce = await wallet.nonce;
print("Account nonce: ${nonce.toInt()}");
Check if the wallet is deployed
final bool deployed = await wallet.deployed;
print("Account deployed: $deployed");
Get the init code
final String initCode = wallet.initCode;
print("Account init code: $initCode");
Send ether to another account
await wallet.send(
EthereumAddress.fromHex("0x5bb137D4b0FDCD49DcA30c7CF57E578a026d2789"), // Recipient address
EtherAmount.fromInt(EtherUnit.ether, 0.7142), // Amount in ether
);