Format docs

This commit is contained in:
JohnGuilding
2023-02-01 17:17:26 +00:00
parent d01df873e6
commit 7640415ab6
7 changed files with 168 additions and 123 deletions

View File

@@ -20,30 +20,32 @@ import {
// AggregatorProxyCallback,
// ^ Alternatively, for manual control, import AggregatorProxyCallback to
// just generate the req,res callback for use with http.createServer
} from 'bls-wallet-aggregator-proxy';
} from "bls-wallet-aggregator-proxy";
runAggregatorProxy(
'https://arbitrum-goerli.blswallet.org',
async bundle => {
console.log('proxying bundle', JSON.stringify(bundle, null, 2));
"https://arbitrum-goerli.blswallet.org",
async (bundle) => {
console.log("proxying bundle", JSON.stringify(bundle, null, 2));
// Return a different/augmented bundle to send to the upstream aggregator
return bundle;
},
8080,
'0.0.0.0',
"0.0.0.0",
() => {
console.log('Proxying aggregator on port 8080');
},
console.log("Proxying aggregator on port 8080");
}
);
```
## Instant wallet example without dapp-sponsored transaction
![Instant wallet without dapp-sponsored transactions](./../docs/images/system-overview/instant-wallet-without-dapp-sponsored-txs.jpg)
## Instant wallet example with dapp-sponsored transaction
![Instant wallet with dapp-sponsored transaction](./../docs/images/system-overview/instant-wallet-with-dapp-sponsored-txs.jpg)
## Example dApp using a proxy aggregator
- https://github.com/JohnGuilding/single-pool-dex
- https://github.com/JohnGuilding/single-pool-dex

View File

@@ -1,9 +1,11 @@
# BLS Contract Wallet
Lower-cost layer 2 transactions via a smart contract wallet.
**Note:** _while these contracts have been formally audited, they are not deemed ready for production use._
## Background
Smart contract wallets give users additional safety mechanisms independent of any wallet UI they may use, but are expensive to deploy (and use on) on Ethereum's layer 1.
Layer 2 solutions like Optimism and Arbitrum greatly lower this cost-barrier, and allow more users to benefit from smart contract wallets. This is primarily due to these being general purpose computation solutions.
@@ -11,9 +13,11 @@ Layer 2 solutions like Optimism and Arbitrum greatly lower this cost-barrier, an
DApps bridged to layer 2 will be more usable than those only on layer 1 thanks to faster transactions at lower-cost, but there are further gas savings to be had by dapps and users.
## Savings
Parameters of external layer 2 transactions are stored on layer 1 when "co-ordinators" record state changes. Reducing the size/number of parameters sent to layer 2 calls greatly reduces the layer 1 cost co-ordinators would need to recoup from users.
So as well as the benefits of smart contract wallets and layer 2 usage, gas savings from reduced call data is achieved in 3 ways:
1. single aggregated signature (BLS)
2. de-duplicate of parameters across aggregated txs
3. compressed parameters
@@ -21,38 +25,50 @@ So as well as the benefits of smart contract wallets and layer 2 usage, gas savi
Note: each of these savings is proportional to the number of transactions submitted in a batch. So when using all three methods, additional savings are roughly O(3n).
# Usage
1. Create bls keypair from signer/wallet
2. Sign creation message and either: send it via an agreggator, or directly pass in a call to the Verification Gateway contract
- receive contract wallet address
- receive contract wallet address
3. Create contract wallet with existing ECDSA keypair
## See it in action
See `extension`
# Components
## Layer 2 contract: Verification Gateway
Creates contract wallets deterministically (create2) with the hash of respective bls public keys. It verifies a set of actions (`Operation`) that have been signed with a known bls keypair, then calls the corresponding wallet passing parameters for it to action. Generally this will be an aggregated signature for many different wallets' Operations (`Bundle`).
## Layer 2 contract: BLS Wallet
A smart contract wallet for users to interact with layer 2 dapps. Created via the aforementioned verification gateway.
Wallets use the proxy upgrade method, and can call upon their proxy admin to change their implementation. Wallets can also choose to set a different contract as their trusted verification gateway.
### Upgradability
The verification gateway (VG1) is the `owner` of a single proxy admin (PA1), and is responsible for all VG1 wallets. A wallet can call `walletAdminCall` on VG1 to then call `upgrade` to change it's implementation.
If in the future a new verification gateway is created (say VG2/PA2), a wallet can choose to set it's trusted gateway to this instead. That means VG1 will no longer be permitted to make arbitrary calls to the wallet, only VG2. Note: PA1 will remain as the proxy admin of the wallet. The wallet can change this to PA2 via an admin call on VG1 to `changeProxyAdmin`.
## Client tool: BLS Wallet/Signer
Wallets (eg Metamask, Argent, ...) to implement BLS keypair generation and signing.
## Relayer node: Aggregators
Network to take bls-signed messages, aggregate signatures, then action them via a call to the Verification Gateway.
## Layer 2 node: Coordinators
Network that takes layer 2 transactions and creates blocks. general purpose computation solutions (Optimism, Arbitrum, zkSync)
## Message format
For a smart contract wallet to perform an action, the signed message must contain:
- the hash of the bls public key that signed the message (the full public key is mapped in the Verification Gateway)
- nonce of the smart contract wallet
- address of the smart contract for the wallet to call
@@ -61,23 +77,26 @@ For a smart contract wallet to perform an action, the signed message must contai
- amount to transfer
## Layer 2 contract: Further optimisations
While the Verification Gateway requires only one aggregated signature (rather than each signature of a set of messages and data), the other optimisations can be gained incrementally via preceding smart contracts.
| Compressed data | No duplicates | Aggregated signature | Contract to call |
|----|----|----|----|
| ✓ | ✓ | ✓ | Decompressor |
| | ✓ | ✓ | Expander |
| | | ✓ | Verification Gateway |
| Compressed data | No duplicates | Aggregated signature | Contract to call |
| --------------- | ------------- | -------------------- | -------------------- |
| ✓ | ✓ | ✓ | Decompressor |
| | ✓ | ✓ | Expander |
| | | ✓ | Verification Gateway |
# Diagrams
## Optimistic Rollups
"Currently every tx on OR puts an ECDSA signature on chain." - BWH
Simplification of Optimism's L2 solution:
![Optimistic Rollups](images/optimisticRollups.svg)
## Transactions via BLS signature aggregator
"We want to replace this with a BLS signature." - BWH
Proposed solution to make use of [BLS](https://github.com/thehubbleproject/hubble-contracts/blob/master/contracts/libs/BLS.sol) lib:
@@ -96,20 +115,24 @@ For each network, the deployer contract can be deployed with the following scrip
## Integration tests
To run integration tests:
1. cd into `./contracts` and run `yarn start-hardhat`
2. run `docker-compose up -d postgres` from the root directory
3. cd into `./aggregator` and run `./programs/aggregator.ts`
4. from `./contracts`, run `yarn test-integration`.
## Optimism's L2 (paused)
- clone https://github.com/ethereum-optimism/optimism
- follow instructions (using latest version of docker)
- in `opt/`, run script - `docker-compose up`
- L1 - http://localhost:9545 (chainId 31337)
- L2 - http://localhost:8545 (chainId 420)
- L1 - http://localhost:9545 (chainId 31337)
- L2 - http://localhost:8545 (chainId 420)
## Deploy scripts
Specify network - `yarn hardhat run scripts/<#_script.ts> --network arbitrum-goerli`
# License
MIT

View File

@@ -2,7 +2,7 @@
[![npm version](https://img.shields.io/npm/v/bls-wallet-clients)](https://www.npmjs.com/package/bls-wallet-clients)
*Client libraries for interacting with BLS Wallet components*
_Client libraries for interacting with BLS Wallet components_
## Network Config
@@ -25,9 +25,9 @@ Exposes typed functions for interacting with the Aggregator's HTTP API.
### Add a bundle to an aggregator
```ts
import { Aggregator } from 'bls-wallet-clients';
import { Aggregator } from "bls-wallet-clients";
const aggregator = new Aggregator('https://arbitrum-goerli.blswallet.org');
const aggregator = new Aggregator("https://arbitrum-goerli.blswallet.org");
const resp = await aggregator.add(bundle); // See BlsWalletWrapper section below
// Aggregator did not accept bundle
if ("failures" in resp) {
@@ -42,9 +42,9 @@ You will have to poll for the bundle receipt once you have added a bundle to an
Note this transaction will include all operations included in the bundle, and does not represent individual operations. To retrieve information about individual operations, use the get `getOperationResults` helper method which is explained under the [VerificationGateway](#verificationgateway) section below.
```ts
import { Aggregator } from 'bls-wallet-clients';
import { Aggregator } from "bls-wallet-clients";
const aggregator = new Aggregator('https://arbitrum-goerli.blswallet.org');
const aggregator = new Aggregator("https://arbitrum-goerli.blswallet.org");
const resp = await aggregator.add(bundle); // See BlsWalletWrapper section below
// Aggregator did not accept bundle
if ("failures" in resp) {
@@ -69,7 +69,7 @@ Wraps a BLS wallet, storing the private key and providing `.sign(...)` to
produce a `Bundle`, that can be used with `aggregator.add(...)`. Make sure the bls wallet you're trying to use has enough ETH to send transactions. You can either fund a wallet before it's created, or after the wallet is lazily created from its first transaction (bundle).
```ts
import { BlsWalletWrapper } from 'bls-wallet-clients';
import { BlsWalletWrapper } from "bls-wallet-clients";
const wallet = await BlsWalletWrapper.connect(
privateKey,
@@ -83,10 +83,10 @@ const bundle = wallet.sign({
{
ethValue: 0,
contractAddress: someToken.address, // An ethers.Contract
encodedFunction: someToken.interface.encodeFunctionData(
"transfer",
["0x...some address...", ethers.BigNumber.from(1).pow(18)],
),
encodedFunction: someToken.interface.encodeFunctionData("transfer", [
"0x...some address...",
ethers.BigNumber.from(1).pow(18),
]),
},
// Additional actions can go here. When using multiple actions, they'll
// either all succeed or all fail.
@@ -100,8 +100,8 @@ await aggregator.add(bundle);
```ts
// Follow the same steps as the first BlsWalletWrapper example, but construct the bundle actions like so:
const amountToTransfer = ethers.utils.parseUnits('1');
const reciever = "0x1234..."
const amountToTransfer = ethers.utils.parseUnits("1");
const reciever = "0x1234...";
const bundle = wallet.sign({
nonce,
@@ -121,16 +121,16 @@ const bundle = wallet.sign({
// Follow the same steps as the first BlsWalletWrapper example, but construct the bundle actions like so:
const tranactions = [
{
value: ethers.utils.parseUnits('1'), // amount of ETH you want to transfer
value: ethers.utils.parseUnits("1"), // amount of ETH you want to transfer
to: "0x1234...", // to address. Can be a contract address or an EOA
}
},
];
const actions: ActionData[] = tranactions.map((tx) => ({
ethValue: tx.value ?? '0',
contractAddress: tx.to,
encodedFunction: tx.data ?? '0x',
}));
ethValue: tx.value ?? "0",
contractAddress: tx.to,
encodedFunction: tx.data ?? "0x",
}));
const bundle = wallet.sign({
nonce,
@@ -248,7 +248,7 @@ Exposes `VerificationGateway` and `VerificationGateway__factory` generated by
interactions with the `VerificationGateway`.
```ts
import { VerificationGateway__factory } from 'bls-wallet-clients';
import { VerificationGateway__factory } from "bls-wallet-clients";
const verificationGateway = VerificationGateway__factory.connect(
verificationGatewayAddress,
@@ -303,9 +303,8 @@ import { initBlsWalletSigner } from "bls-wallet-clients";
const privateKey = "0x...256 bits of private hex data here";
const someToken = new ethers.Contract(
// See https://docs.ethers.io/v5/getting-started/
);
const someToken = new ethers.Contract();
// See https://docs.ethers.io/v5/getting-started/
const bundle = signer.sign(
{
@@ -315,10 +314,10 @@ import { initBlsWalletSigner } from "bls-wallet-clients";
// If you don't want to call a function and just send `ethValue` above,
// use '0x' to signify an empty byte array here
encodedFunction: someToken.interface.encodeFunctionData(
"transfer",
["0x...some address...", ethers.BigNumber.from(10).pow(18)],
),
encodedFunction: someToken.interface.encodeFunctionData("transfer", [
"0x...some address...",
ethers.BigNumber.from(10).pow(18),
]),
},
privateKey,
);
@@ -359,4 +358,4 @@ yarn "link bls-wallet-clients"
## Troubleshooting tips
- Make sure your bls-wallet-clients package is up-to-date and check out our [releases page](https://github.com/web3well/bls-wallet/releases) for info on breaking changes.
- Check network values such as the verification gateway address or the aggregator url are up-to-date. The most up-to-date values are located in the relevant [network config](./../contracts/networks) file. If you're deploying to a custom network, you'll have to check these against your own records as these won't be in the network directory.
- Check network values such as the verification gateway address or the aggregator url are up-to-date. The most up-to-date values are located in the relevant [network config](./../contracts/networks) file. If you're deploying to a custom network, you'll have to check these against your own records as these won't be in the network directory.

View File

@@ -6,4 +6,3 @@
- Setup the BLS Wallet components for:
- [Local develeopment](./local_development.md)
- [Remote development](./remote_development.md)

View File

@@ -25,7 +25,11 @@ You can use [esm.sh](https://esm.sh/) or a similar service to get Deno compatibl
```typescript
import { providers } from "https://esm.sh/ethers@latest";
import { Aggregator, BlsWalletWrapper, getConfig } from "https://esm.sh/bls-wallet-clients@latest";
import {
Aggregator,
BlsWalletWrapper,
getConfig,
} from "https://esm.sh/bls-wallet-clients@latest";
```
## Get Deployed Contract Addresses
@@ -37,18 +41,20 @@ If you would like to deploy to a remote network, see [Remote development](./remo
## Send a transaction
```typescript
import { readFile } from 'fs/promises';
import { readFile } from "fs/promises";
// import fetch from 'node-fetch'; // Add this if using nodejs<18
import { ethers, providers } from 'ethers';
import { Aggregator, BlsWalletWrapper, getConfig } from 'bls-wallet-clients';
import { ethers, providers } from "ethers";
import { Aggregator, BlsWalletWrapper, getConfig } from "bls-wallet-clients";
// globalThis.fetch = fetch; // Add this if using nodejs<18
// Instantiate a provider via browser extension, such as Metamask
// Instantiate a provider via browser extension, such as Metamask
// const provider = new providers.Web3Provider(window.ethereum);
// Or via RPC
const provider = new providers.JsonRpcProvider('https://goerli-rollup.arbitrum.io/rpc');
const provider = new providers.JsonRpcProvider(
"https://goerli-rollup.arbitrum.io/rpc"
);
// See https://docs.ethers.io/v5/getting-started/ for more options
// Get the deployed contract addresses for the network.
@@ -56,12 +62,13 @@ const provider = new providers.JsonRpcProvider('https://goerli-rollup.arbitrum.i
// See local_development.md for deploying locally and
// remote_development.md for deploying to a remote network.
const netCfg = await getConfig(
'../contracts/networks/arbitrum-goerli.json',
async (path) => readFile(path),
"../contracts/networks/arbitrum-goerli.json",
async (path) => readFile(path)
);
// 32 random bytes
const privateKey = '0x0001020304050607080910111213141516171819202122232425262728293031';
const privateKey =
"0x0001020304050607080910111213141516171819202122232425262728293031";
// Note that if a wallet doesn't yet exist, it will be
// lazily created on the first transaction.
@@ -72,13 +79,11 @@ const wallet = await BlsWalletWrapper.connect(
);
const erc20Address = netCfg.addresses.testToken; // Or some other ERC20 token
const erc20Abi = [
'function mint(address to, uint amount) returns (bool)',
];
const erc20Abi = ["function mint(address to, uint amount) returns (bool)"];
const erc20 = new ethers.Contract(erc20Address, erc20Abi, provider);
console.log('Contract wallet:', wallet.address);
console.log('Test token:', erc20.address);
console.log("Contract wallet:", wallet.address);
console.log("Test token:", erc20.address);
const nonce = await wallet.Nonce();
// All of the actions in a bundle are atomic, if one
@@ -90,38 +95,38 @@ const bundle = wallet.sign({
// Mint ourselves one test token
ethValue: 0,
contractAddress: erc20.address,
encodedFunction: erc20.interface.encodeFunctionData(
'mint',
[wallet.address, ethers.utils.parseUnits('1', 18)],
),
encodedFunction: erc20.interface.encodeFunctionData("mint", [
wallet.address,
ethers.utils.parseUnits("1", 18),
]),
},
],
});
const aggregator = new Aggregator('https://arbitrum-goerli.blswallet.org');
const aggregator = new Aggregator("https://arbitrum-goerli.blswallet.org");
console.log('Sending bundle to the aggregator');
console.log("Sending bundle to the aggregator");
const addResult = await aggregator.add(bundle);
if ('failures' in addResult) {
throw new Error(addResult.failures.join('\n'));
if ("failures" in addResult) {
throw new Error(addResult.failures.join("\n"));
}
console.log('Bundle hash:', addResult.hash);
console.log("Bundle hash:", addResult.hash);
const checkConfirmation = async () => {
console.log('Checking for confirmation')
console.log("Checking for confirmation");
const maybeReceipt = await aggregator.lookupReceipt(addResult.hash);
if (maybeReceipt === undefined) {
return;
}
console.log('Confirmed in block', maybeReceipt.blockNumber);
provider.off('block', checkConfirmation);
console.log("Confirmed in block", maybeReceipt.blockNumber);
provider.off("block", checkConfirmation);
};
provider.on('block', checkConfirmation);
provider.on("block", checkConfirmation);
```
## More

View File

@@ -27,8 +27,9 @@ After installing the extension, Quill will auto-open and guide you through the s
Next, connect your dApp to Quill just like you would any other extension wallet.
`ethers.js`
```typescript
import { providers } from 'ethers';
import { providers } from "ethers";
const provider = new providers.Web3Provider(window.ethereum);
@@ -91,7 +92,9 @@ const transactionHash = await window.ethereum.request({
params: [approveTransaction, swapTransaction],
});
const transactionReceipt = await provider.getTransactionReceipt(transactionHash);
const transactionReceipt = await provider.getTransactionReceipt(
transactionHash
);
// Do anything else you need to with the transaction receipt.
```
@@ -111,7 +114,7 @@ See the [System Overview](./system_overview.md) for more details on what's happe
## Example dApps Which Use BLS Wallet
- https://github.com/kautukkundan/BLSWallet-ERC20-demo
- https://github.com/kautukkundan/BLSWallet-ERC20-demo
- https://github.com/voltrevo/bls-wallet-billboard
- https://github.com/JohnGuilding/single-pool-dex

View File

@@ -1,79 +1,93 @@
# Quill - easy, fast, and low-cost Ethereum transactions
## Overview
Interaction with web3 applications can be slow, costly, and risky.
**Quill** leverages BLS signature aggregation on Ethereum layer 2 solutions, easily bringing fast and low-cost Ethereum transactions to your browser.
### Additional Benefits
* send multiple txs as one to ensure atomic execution
* pay even less gas by reducing on chain footprint of signatures
- send multiple txs as one to ensure atomic execution
- pay even less gas by reducing on chain footprint of signatures
### How to use it
1. install the plugin
2. create a contract wallet (uses bls keys)
3. transfer L2 erc20 tokens
4. use contract wallet with L2 dapps (coming soon)
## Feature Summary
### MVP (uses Optimism)
* Chrome/Brave plugin
* Secure storage of BLS private-keys
* Sign tx data:
* wallet creation
* erc20 transfers
* Submit txs to hosted [aggregator](https://github.com/jzaki/bls-wallet-aggregator)
* Basic feedback from aggregator for UI updates (tx received, tx mined. tx dropped?)
- Chrome/Brave plugin
- Secure storage of BLS private-keys
- Sign tx data:
- wallet creation
- erc20 transfers
- Submit txs to hosted [aggregator](https://github.com/jzaki/bls-wallet-aggregator)
- Basic feedback from aggregator for UI updates (tx received, tx mined. tx dropped?)
### Upcoming
* Secure storage of EDDSA and ECDSA keys
* Social recovery
* nominate guardians
* recover contract wallet
* Receive tx data from existing L2 dapps on networks:
* Optimism
* Arbitrum (coming soon)
* ...
* Receive and review multiple txs from dapps
* sign all and submit to aggregator
* Wallet feedback (from L2 sequencer)
* listening to wallet events
* wallet tx history
- Secure storage of EDDSA and ECDSA keys
- Social recovery
- nominate guardians
- recover contract wallet
- Receive tx data from existing L2 dapps on networks:
- Optimism
- Arbitrum (coming soon)
- ...
- Receive and review multiple txs from dapps
- sign all and submit to aggregator
- Wallet feedback (from L2 sequencer)
- listening to wallet events
- wallet tx history
### Future
* Sign and submit multiple transactions as one (to L2 sequencer)
* local signature aggregation
* Review and sign typed data (712)
- Sign and submit multiple transactions as one (to L2 sequencer)
- local signature aggregation
- Review and sign typed data (712)
## Requirements
### Secure storage
* Safe storage options for extension
- Safe storage options for extension
### BLS components
* signing transactions
* signature verification
* signature aggregation
- signing transactions
- signature verification
- signature aggregation
### Servers
* Aggregator
* Future: L2 Sequencer
- Aggregator
- Future: L2 Sequencer
### User Interface Base
* Extension for Chrome/Brave and Firefox
* Web Extensions? combined extensions standard
* [storyboard](https://drive.protonmail.com/urls/J7EECNCGS0#2xqYOqlIzeaB)
* Common:
* Network name (hover chainId)
* Current BLS Key (option to create)
* Associated contract wallet address if any (option to create)
* contract wallet balance (L2 ETH token)
* Action to Transfer (starts tx data)
* tx edit section:
* Method name "transfer" (show methodId)
* Params as text fields
* address with checks (length, checksum)
* balance as decimal (*10^18)
* signed tx section:
* signed txs per row
* method name - nonce - (send)
* (aggregate) - (send all)
- Extension for Chrome/Brave and Firefox
- Web Extensions? combined extensions standard
- [storyboard](https://drive.protonmail.com/urls/J7EECNCGS0#2xqYOqlIzeaB)
- Common:
- Network name (hover chainId)
- Current BLS Key (option to create)
- Associated contract wallet address if any (option to create)
- contract wallet balance (L2 ETH token)
- Action to Transfer (starts tx data)
- tx edit section:
- Method name "transfer" (show methodId)
- Params as text fields
- address with checks (length, checksum)
- balance as decimal (\*10^18)
- signed tx section:
- signed txs per row
- method name - nonce - (send)
- (aggregate) - (send all)
## Development