getwax / bls-wallet

Core components to use layer 2 smart contract wallets with the BLS signature scheme
MIT License
177 stars 46 forks source link

Use compression in aggregator #584

Closed voltrevo closed 1 year ago

voltrevo commented 1 year ago

Dependent PR

This PR depends on https://github.com/web3well/bls-wallet/pull/586.

After that's merged, toggle the target branch back and forth or push an empty commit to fix the diff. (Preview of this PR's changes.)

(If you want, you can also just review+merge this one directly. Github will automerge the previous PRs.)

What is this PR doing?

Uses compression in aggregator. Reduces the data field when sending a single ETH transfer from 836 bytes down to 164 bytes.

How can these changes be manually tested?

(Replicating this test isn't required.)

Use Quill to do an ETH transfer and verify the transaction data is about 324 bytes. Here's what I got on arbitrum goerli:

Screen Shot 2023-04-24 at 3 33 07 pm

Explorer link

To reduce this further, use ./manualTests/registerWallet.ts to register the source BLS key and address, as well as the destination address. Verify that reduces the transaction data down to about 164 bytes:

Screen Shot 2023-04-24 at 3 33 17 pm

Explorer link

For comparison I used version f8a8c490 (git checkout f8a8c490) (this is right before the contract-updates merge, which naturally changes the contracts so main currently doesn't work with the existing deployment). Here's the transaction data from that one:

Screen Shot 2023-04-24 at 3 55 20 pm

Explorer link

Wait, wait, still 164 bytes? 😰

Yeah. That's just the data field too. If you include the full transaction data (including the envelope with the aggregator's signature and gas settings etc), then there's another 115 bytes or so (total is about 279 bytes).

Anyway, 164 bytes in the data field is a lot more than we need, and it's because there's still some cleanup to do. Here's the breakdown of those bytes:

0x

3a276523
  - method id of run()

0000000000000000000000000000000000000000000000000000000000000020
  - location of byte array for `stream` calldata argument

0000000000000000000000000000000000000000000000000000000000000056
  - `stream` is 86 bytes long
    (==0x56 but solidity abi uses an entire uint256 word for this)

01
  - one operation

00
  - use expander id 0 (fallback expander)

07
  - 0x07 = 0b111 - bit stream:
    - 1: Use registry for sendWallet's public key
    - 1: Include a tx.origin payment
    - 1: Use registry for recvWallet's address

000000
  - id of sender's bls public key

01
  - nonce

0cb730
  - 56,708 gas

02
  - two actions (send ETH and pay tx.origin)

7900
  - 0.0001 ETH

000001
  - id recipient's address

00
  - zero bytes for encodedFunction

3092cbb31e
  - pay 0.0000311872752 ETH to tx.origin

0b018b1989c5c62d43b0a0427f04781f2a4e201ab2c938ad23aa2d0a6c0a284a
03f37bd9fbdac1b34f3046363244c0e47a2a73add7cdfac41c2f134285256dfc
  - BLS signature

00000000000000000000
  - padding bytes from the solidity abi to make a multiple of 32 bytes

In summary:

We should be able to remove the ABI overhead by introducing another contract whose whole purpose is to call the expander with its raw argument.

Focusing on the positive, very small encodings for the actual operations have been achieved, and this means that the marginal data cost of each operation is this low number (20 bytes or so). This means you could add 100 transactions for 2100 bytes, so the whole transaction would be 2100+279=2379 bytes, or about 24 bytes per transaction. Then the marginal cost becomes dominant, BUT you need to wait for 100 transactions before you can submit.

Related improvements to work on:

Does this PR resolve or contribute to any issues?

Resolves #406.

Checklist

Guidelines