Skip to content
This repository has been archived by the owner on Nov 5, 2023. It is now read-only.

Commit

Permalink
Create BLSWallets with deterministic addresses. Closes #15
Browse files Browse the repository at this point in the history
  • Loading branch information
jzaki committed Nov 6, 2021
1 parent b7f42f4 commit 8d20a5a
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 19 deletions.
11 changes: 8 additions & 3 deletions contracts/contracts/BLSWallet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,23 @@ interface IVerificationGateway {
function walletCrossCheck(bytes32 publicKeyHash) external;
}

contract BLSWallet
contract BLSWallet is Initializable
{
address public gateway;
uint256[4] public publicKey;
uint256 public nonce;

constructor(uint256[4] memory blsKey) {
constructor() {
gateway = msg.sender;
publicKey = blsKey;
nonce = 0;
}

function initialize(
uint256[4] memory blsKey
) external initializer onlyGateway {
publicKey = blsKey;
}

receive() external payable {}
fallback() external payable {}

Expand Down
42 changes: 33 additions & 9 deletions contracts/contracts/VerificationGateway.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ contract VerificationGateway is Initializable
uint8 constant BLS_LEN = 4;
// uint256[BLS_LEN] ZERO_BLS_SIG = [uint256(0), uint256(0), uint256(0), uint256(0)];

mapping (bytes32 => BLSWallet) public walletFromHash;

IBLS public blsLib;

/**
Expand Down Expand Up @@ -74,11 +72,35 @@ contract VerificationGateway is Initializable
require(verified, "VerificationGateway: All sigs not verified");
}

function hasCode(address a) private view returns (bool) {
uint256 size;
// solhint-disable-next-line no-inline-assembly
assembly { size := extcodesize(a) }
return size > 0;
}

/**
@param hash BLS public key hash used as salt for create2
@return BLSWallet at calculated address (if code exists), otherwise zero address
*/
function walletFromHash(bytes32 hash) public view returns (BLSWallet) {
address walletAddress = address(uint160(uint(keccak256(abi.encodePacked(
bytes1(0xff),
address(this),
hash,
keccak256(type(BLSWallet).creationCode)
)))));
if (!hasCode(walletAddress)) {
walletAddress = address(0);
}
return BLSWallet(payable(walletAddress));
}

/**
Useful no-op function to call when calling a wallet for the first time.
*/
function walletCrossCheck(bytes32 hash) public payable {
require(msg.sender == address(walletFromHash[hash]));
require(msg.sender == address(walletFromHash(hash)));
}

/**
Expand Down Expand Up @@ -107,7 +129,7 @@ contract VerificationGateway is Initializable

// construct params for signature verification
publicKeyHash = keccak256(abi.encodePacked(publicKeys[i]));
wallet = walletFromHash[publicKeyHash];
wallet = walletFromHash(publicKeyHash);

if (txs[i].nonce == wallet.nonce()) {
// action transaction (increments nonce)
Expand All @@ -132,12 +154,14 @@ contract VerificationGateway is Initializable
private // consider making external and VG stateless
{
bytes32 publicKeyHash = keccak256(abi.encodePacked(publicKey));
// wallet at publicKeyHash doesn't exist
if (address(walletFromHash[publicKeyHash]) == address(0)) {
// blsKeysFromHash[publicKeyHash] = publicKey;
walletFromHash[publicKeyHash] = new BLSWallet(publicKey);
BLSWallet blsWallet = walletFromHash(publicKeyHash);

// wallet with publicKeyHash doesn't exist at expected create2 address
if (address(blsWallet) == address(0)) {
blsWallet = new BLSWallet{salt: publicKeyHash}();
blsWallet.initialize(publicKey);
emit WalletCreated(
address(walletFromHash[publicKeyHash]),
address(blsWallet),
publicKey
);
}
Expand Down
2 changes: 1 addition & 1 deletion contracts/shared/helpers/Fixture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import blsSignFunction from "./blsSignFunction";
import blsKeyHash from "./blsKeyHash";
import { exit, send } from "process";
import Create2Fixture from "./Create2Fixture";
import { BLSExpander, BLSWallet__factory, VerificationGateway } from "../../typechain";
import { BLSExpander, BLSWallet, BLSWallet__factory, VerificationGateway } from "../../typechain";

const DOMAIN_HEX = utils.keccak256("0xfeedbee5");
const DOMAIN = arrayify(DOMAIN_HEX);
Expand Down
21 changes: 15 additions & 6 deletions contracts/test/walletAction-test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { expect, assert } from "chai";
import { expect } from "chai";
import expectRevert from "../shared/helpers/expectRevert";

import { ethers, network } from "hardhat";
Expand All @@ -12,10 +12,10 @@ import { aggregate } from "../shared/lib/hubble-bls/src/signer";
import { BigNumber } from "ethers";
import blsKeyHash from "../shared/helpers/blsKeyHash";
import blsSignFunction from "../shared/helpers/blsSignFunction";
import { formatUnits, parseEther } from "@ethersproject/units";
import { parseEther } from "@ethersproject/units";
import deployAndRunPrecompileCostEstimator from "../shared/helpers/deployAndRunPrecompileCostEstimator";
import getDeployedAddresses from "../shared/helpers/getDeployedAddresses";
import deployerContract, { defaultDeployerAddress } from "../shared/helpers/deployDeployer";
import { defaultDeployerAddress } from "../shared/helpers/deployDeployer";


describe('WalletActions', async function () {
Expand Down Expand Up @@ -62,15 +62,24 @@ describe('WalletActions', async function () {
let blsSigner = fx.blsSigners[0];
let walletAddress = await fx.createBLSWallet(blsSigner);

const BLSWallet = await ethers.getContractFactory("BLSWallet");

let calculatedAddress = ethers.utils.getCreate2Address(
fx.verificationGateway.address,
blsKeyHash(blsSigner),
ethers.utils.solidityKeccak256(
["bytes"],
[BLSWallet.bytecode]
)
);
expect(calculatedAddress).to.equal(walletAddress);

let blsWallet = fx.BLSWallet.attach(walletAddress);

await Promise.all(blsSigner.pubkey.map(async (keyPart, i) =>
expect(await blsWallet.publicKey(i))
.to.equal(keyPart)));

// Check revert when adding same wallet twice
// await expectRevert(fx.createBLSWallet(blsSigner));

});

it('should receive ETH', async function() {
Expand Down

0 comments on commit 8d20a5a

Please sign in to comment.