12 Commits

Author SHA1 Message Date
Blake Duncan
cdecab26ee Reorder workflow steps 2023-03-29 14:12:22 +01:00
Blake Duncan
e2b6e4f1ee Debug session 2023-03-29 14:05:40 +01:00
Blake Duncan
7c2901f243 update test verification gateway address 2023-03-29 13:26:26 +01:00
Blake Duncan
4a7331c4a7 Publish experimental bls-wallet-clients 2023-03-28 15:32:06 +01:00
Blake Duncan
1fb4a557ab Update param naming 2023-03-28 15:24:22 +01:00
Blake Duncan
7862b5278a Merge branch 'main' into auditIssue7 2023-03-28 15:16:40 +01:00
Blake Duncan
e2ef1ed62e Fix TS issue in aggregator 2023-03-28 14:42:46 +01:00
Blake Duncan
2f9a3442f8 Fix linting issues 2023-03-28 14:27:40 +01:00
Blake Duncan
8833c5f0af Rename variables and code cleanup 2023-03-28 14:11:47 +01:00
Blake Duncan
9505ed425b Using seperate domains for proof of possession messages and for bundles 2023-03-28 13:11:08 +01:00
Blake Duncan
fedf05cc7e Fix test by signing message with correct verification gateway 2023-03-27 17:28:43 +01:00
Blake Duncan
7dc7bb4a5e use chainId and verification gateway in bls domain 2023-03-27 13:35:59 +01:00
20 changed files with 117 additions and 73 deletions

View File

@@ -76,3 +76,5 @@ jobs:
- run: cp .env.local.example .env
- run: deno test --allow-net --allow-env --allow-read
- uses: mxschmitt/action-tmate@v3
- run: sleep 3600

View File

@@ -21,7 +21,7 @@
"@types/koa__cors": "^3.3.0",
"@types/koa__router": "^8.0.11",
"@types/node-fetch": "^2.6.1",
"bls-wallet-clients": "0.8.2-1452ef5",
"bls-wallet-clients": "0.8.2-1fb4a55",
"fp-ts": "^2.12.1",
"io-ts": "^2.2.16",
"io-ts-reporters": "^2.0.1",

View File

@@ -887,10 +887,10 @@ bech32@1.1.4:
resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.4.tgz#e38c9f37bf179b8eb16ae3a772b40c356d4832e9"
integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==
bls-wallet-clients@0.8.2-1452ef5:
version "0.8.2-1452ef5"
resolved "https://registry.yarnpkg.com/bls-wallet-clients/-/bls-wallet-clients-0.8.2-1452ef5.tgz#d76e938ca45ec5da44c8e59699d1bd5f6c69dcd2"
integrity sha512-bg7WLr9NRbvDzj+zgkLNfaPzr1m0m13Cc8RJoZ2s6s+ic7WxSiwxTkZGc2SChFgmG8ZGi1O9DnR6//lrTsMVUA==
bls-wallet-clients@0.8.2-1fb4a55:
version "0.8.2-1fb4a55"
resolved "https://registry.yarnpkg.com/bls-wallet-clients/-/bls-wallet-clients-0.8.2-1fb4a55.tgz#bab40801ee1e60ffbc9c0bc924943c6f90605e7c"
integrity sha512-2tlwOSUGzsOiam0G7GBmsN3W5cHjUwTmHR/DvGRH584zLkCC/8TFdAn2/laSF2baTYvegtIHwQNl1zX5DWivEQ==
dependencies:
"@thehubbleproject/bls" "^0.5.1"
ethers "^5.7.2"

View File

@@ -53,7 +53,7 @@ export type {
PublicKey,
Signature,
VerificationGateway,
} from "https://esm.sh/bls-wallet-clients@0.8.2-1452ef5";
} from "https://esm.sh/bls-wallet-clients@0.8.2-1fb4a55";
export {
Aggregator as AggregatorClient,
@@ -64,10 +64,10 @@ export {
getConfig,
MockERC20__factory,
VerificationGateway__factory,
} from "https://esm.sh/bls-wallet-clients@0.8.2-1452ef5";
} from "https://esm.sh/bls-wallet-clients@0.8.2-1fb4a55";
// Workaround for esbuild's export-star bug
import blsWalletClients from "https://esm.sh/bls-wallet-clients@0.8.2-1452ef5";
import blsWalletClients from "https://esm.sh/bls-wallet-clients@0.8.2-1fb4a55";
const { bundleFromDto, bundleToDto, initBlsWalletSigner } = blsWalletClients;
export { bundleFromDto, bundleToDto, initBlsWalletSigner };

View File

@@ -136,6 +136,7 @@ export default class EthereumService {
const blsWalletSigner = await initBlsWalletSigner({
chainId,
privateKey: aggPrivateKey,
verificationGatewayAddress,
});
return new EthereumService(

View File

@@ -332,8 +332,13 @@ import { initBlsWalletSigner } from "bls-wallet-clients";
(async () => {
const privateKey = "0x...256 bits of private hex data here";
const verificationGatewayAddress = "0x123...456";
const signer = await initBlsWalletSigner({ chainId: 10, privateKey });
const signer = await initBlsWalletSigner({
chainId: 10,
privateKey,
verificationGatewayAddress
});
const someToken = new ethers.Contract(
...

View File

@@ -74,6 +74,7 @@ export default class BlsWalletWrapper {
const blsWalletSigner = await this.#BlsWalletSigner(
signerOrProvider,
privateKey,
verificationGatewayAddress,
);
const verificationGateway = VerificationGateway__factory.connect(
@@ -147,6 +148,7 @@ export default class BlsWalletWrapper {
const blsWalletSigner = await initBlsWalletSigner({
chainId: (await verificationGateway.provider.getNetwork()).chainId,
privateKey,
verificationGatewayAddress,
});
const blsWalletWrapper = new BlsWalletWrapper(
@@ -321,13 +323,18 @@ export default class BlsWalletWrapper {
static async #BlsWalletSigner(
signerOrProvider: SignerOrProvider,
privateKey: string,
verificationGatewayAddress: string,
): Promise<BlsWalletSigner> {
const chainId =
"getChainId" in signerOrProvider
? await signerOrProvider.getChainId()
: (await signerOrProvider.getNetwork()).chainId;
return await initBlsWalletSigner({ chainId, privateKey });
return await initBlsWalletSigner({
chainId,
privateKey,
verificationGatewayAddress,
});
}
/**
@@ -347,6 +354,7 @@ export default class BlsWalletWrapper {
const newBlsWalletSigner = await initBlsWalletSigner({
chainId,
privateKey,
verificationGatewayAddress: this.walletContract.address,
});
this.blsWalletSigner = newBlsWalletSigner;

View File

@@ -1,3 +0,0 @@
import { arrayify, keccak256 } from "ethers/lib/utils";
export default arrayify(keccak256("0xfeedbee5"));

View File

@@ -1,7 +1,7 @@
import { keccak256, solidityPack } from "ethers/lib/utils";
import { Operation } from "./types";
export default (chainId: number) =>
export default () =>
(operation: Operation, walletAddress: string): string => {
let encodedActionData = "0x";
@@ -18,7 +18,7 @@ export default (chainId: number) =>
}
return solidityPack(
["uint256", "address", "uint256", "bytes32"],
[chainId, walletAddress, operation.nonce, keccak256(encodedActionData)],
["address", "uint256", "bytes32"],
[walletAddress, operation.nonce, keccak256(encodedActionData)],
);
};

View File

@@ -0,0 +1,15 @@
import { arrayify, solidityPack } from "ethers/lib/utils";
import { utils } from "ethers";
export default (
chainId: number,
verificationGatewayAddress: string,
type: string,
): Uint8Array => {
const encoded = solidityPack(
["uint256", "address", "string"],
[chainId, verificationGatewayAddress, type],
);
return arrayify(utils.keccak256(encoded));
};

View File

@@ -1,7 +1,7 @@
import { signer } from "@thehubbleproject/bls";
import aggregate from "./aggregate";
import defaultDomain from "./defaultDomain";
import getDomain from "./getDomain";
import getPublicKey from "./getPublicKey";
import getPublicKeyHash from "./getPublicKeyHash";
import getPublicKeyStr from "./getPublicKeyStr";
@@ -16,11 +16,11 @@ export * from "./conversions";
export type BlsWalletSigner = AsyncReturnType<typeof initBlsWalletSigner>;
export async function initBlsWalletSigner({
domain = defaultDomain,
chainId,
privateKey,
verificationGatewayAddress,
}: {
domain?: Uint8Array;
verificationGatewayAddress: string;
chainId: number;
privateKey: string;
}) {
@@ -32,14 +32,17 @@ export async function initBlsWalletSigner({
// properly initialized for all use cases, not just signing.
const signerFactory = await signer.BlsSignerFactory.new();
const bundleDomain = getDomain(chainId, verificationGatewayAddress, "Bundle");
const walletDomain = getDomain(chainId, verificationGatewayAddress, "Wallet");
return {
aggregate,
getPublicKey: getPublicKey(signerFactory, domain, privateKey),
getPublicKeyHash: getPublicKeyHash(signerFactory, domain, privateKey),
getPublicKeyStr: getPublicKeyStr(signerFactory, domain, privateKey),
sign: sign(signerFactory, domain, chainId, privateKey),
signMessage: signMessage(signerFactory, domain, privateKey),
verify: verify(domain, chainId),
getPublicKey: getPublicKey(signerFactory, bundleDomain, privateKey),
getPublicKeyHash: getPublicKeyHash(signerFactory, bundleDomain, privateKey),
getPublicKeyStr: getPublicKeyStr(signerFactory, bundleDomain, privateKey),
sign: sign(signerFactory, bundleDomain, chainId, privateKey),
signMessage: signMessage(signerFactory, walletDomain, privateKey),
verify: verify(bundleDomain, chainId),
privateKey,
};
}

View File

@@ -11,7 +11,7 @@ export default (
) =>
(operation: Operation, walletAddress: string): Bundle => {
const signer = signerFactory.getSigner(domain, privateKey);
const message = encodeMessageForSigning(chainId)(operation, walletAddress);
const message = encodeMessageForSigning()(operation, walletAddress);
const signature = signer.sign(message);
return {

View File

@@ -26,7 +26,7 @@ export default (domain: Uint8Array, chainId: number) =>
BigNumber.from(n3).toHexString(),
]),
bundle.operations.map((op) =>
encodeMessageForSigning(chainId)(op, walletAddress),
encodeMessageForSigning()(op, walletAddress),
),
);
};

View File

@@ -1,12 +1,10 @@
import { BigNumber } from "ethers";
import { keccak256, arrayify } from "ethers/lib/utils";
import { expect } from "chai";
import { initBlsWalletSigner, Bundle, Operation } from "../src/signer";
import Range from "./helpers/Range";
const domain = arrayify(keccak256("0xfeedbee5"));
const weiPerToken = BigNumber.from(10).pow(18);
const samples = (() => {
@@ -52,22 +50,22 @@ describe("index", () => {
const { sign, verify } = await initBlsWalletSigner({
chainId: 123,
domain,
verificationGatewayAddress: "0xC8CD2BE653759aed7B0996315821AAe71e1FEAdF",
privateKey,
});
const bundle = sign(bundleTemplate, walletAddress);
expect(bundle.signature).to.deep.equal([
"0x2c1b0dc6643375e05a6f2ba3d23b1ce941253010b13a127e22f5db647dc37952",
"0x0338f96fc67ce194a74a459791865ac2eb304fc214fd0962775078d12aea5b7e",
"0x21135f40b38f55236ceb637ad8f2d6d4e8081bc1c37ea08273838f839008b9cd",
"0x16515fb0821c039e127dd8e4a70c7004aec1baf698802fc16e7cf8d2ae0bb14a",
]);
expect(verify(bundle, walletAddress)).to.equal(true);
const { sign: signWithOtherPrivateKey } = await initBlsWalletSigner({
chainId: 123,
domain,
verificationGatewayAddress: "0xC8CD2BE653759aed7B0996315821AAe71e1FEAdF",
privateKey: otherPrivateKey,
});
@@ -111,12 +109,12 @@ describe("index", () => {
const { sign, aggregate, verify } = await initBlsWalletSigner({
chainId: 123,
domain,
verificationGatewayAddress: "0xC8CD2BE653759aed7B0996315821AAe71e1FEAdF",
privateKey,
});
const { sign: signWithOtherPrivateKey } = await initBlsWalletSigner({
chainId: 123,
domain,
verificationGatewayAddress: "0xC8CD2BE653759aed7B0996315821AAe71e1FEAdF",
privateKey: otherPrivateKey,
});
@@ -125,8 +123,8 @@ describe("index", () => {
const aggBundle = aggregate([bundle1, bundle2]);
expect(aggBundle.signature).to.deep.equal([
"0x2319fc81d339dce4678c73429dfd2f11766742ed1e41df5a2ba2bf4863d877b5",
"0x1bb25c15ad1f2f967a80a7a65c7593fcd66b59bf092669707baf2db726e8e714",
"0x20c3afd45d2c7cd72003752377cf6853569bccd23abf962967a9245091b69c3b",
"0x1ff4a18f1e920206f849e50df41e7bab6377d3908a8198d9c9268ca01ae70552",
]);
expect(verify(bundle1, walletAddress)).to.equal(true);
@@ -163,7 +161,7 @@ describe("index", () => {
const { sign, aggregate, verify } = await initBlsWalletSigner({
chainId: 123,
domain,
verificationGatewayAddress: "0xC8CD2BE653759aed7B0996315821AAe71e1FEAdF",
privateKey,
});
@@ -195,7 +193,7 @@ describe("index", () => {
const { getPublicKeyStr } = await initBlsWalletSigner({
chainId: 123,
domain,
verificationGatewayAddress: "0xC8CD2BE653759aed7B0996315821AAe71e1FEAdF",
privateKey,
});
@@ -215,7 +213,7 @@ describe("index", () => {
const { aggregate } = await initBlsWalletSigner({
chainId: 123,
domain,
verificationGatewayAddress: "0xC8CD2BE653759aed7B0996315821AAe71e1FEAdF",
privateKey,
});
@@ -230,7 +228,7 @@ describe("index", () => {
const { aggregate, verify } = await initBlsWalletSigner({
chainId: 123,
domain,
verificationGatewayAddress: "0xC8CD2BE653759aed7B0996315821AAe71e1FEAdF",
privateKey,
});

View File

@@ -9,6 +9,8 @@ import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.so
import "./interfaces/IWallet.sol";
import "hardhat/console.sol";
/**
A non-upgradable gateway used to create BLSWallets and call them with
verified Operations that have been respectively signed.
@@ -18,8 +20,8 @@ is the calling wallet's address.
*/
contract VerificationGateway
{
/** Domain chosen arbitrarily */
bytes32 BLS_DOMAIN = keccak256(abi.encodePacked(uint32(0xfeedbee5)));
bytes32 WALLET_DOMAIN;
bytes32 BUNDLE_DOMAIN;
uint8 constant BLS_KEY_LEN = 4;
IBLS public immutable blsLib;
@@ -73,6 +75,16 @@ contract VerificationGateway
blsLib = bls;
blsWalletLogic = blsWalletImpl;
walletProxyAdmin = ProxyAdmin(proxyAdmin);
WALLET_DOMAIN = keccak256(abi.encodePacked(
block.chainid,
address(this),
"Wallet"
));
BUNDLE_DOMAIN = keccak256(abi.encodePacked(
block.chainid,
address(this),
"Bundle"
));
}
/** Throw if bundle not valid or signature verification fails */
@@ -353,7 +365,7 @@ contract VerificationGateway
) private {
// verify the given wallet was signed for by the bls key
uint256[2] memory addressMsg = blsLib.hashToPoint(
BLS_DOMAIN,
WALLET_DOMAIN,
abi.encodePacked(wallet)
);
require(
@@ -411,9 +423,8 @@ contract VerificationGateway
);
}
return blsLib.hashToPoint(
BLS_DOMAIN,
BUNDLE_DOMAIN,
abi.encodePacked(
block.chainid,
walletAddress,
op.nonce,
keccak256(encodedActionData)

View File

@@ -146,7 +146,11 @@ export default class Fixture {
blsExpander,
utilities,
BLSWallet,
await initBlsWalletSigner({ chainId, privateKey }),
await initBlsWalletSigner({
chainId,
privateKey,
verificationGatewayAddress: verificationGateway.address,
}),
);
}

View File

@@ -441,7 +441,7 @@ describe("BlsProvider", () => {
value: parseEther("1"),
});
const expectedToAddress = "0x689A095B4507Bfa302eef8551F90fB322B3451c6"; // Verification Gateway address
const expectedToAddress = "0x14EE47429DEf3462142AE5f8d1E263E0B137bA63"; // Verification Gateway address
const expectedFromAddress = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"; // Aggregator address (Hardhat account 0)
// Act
@@ -502,7 +502,7 @@ describe("BlsProvider", () => {
value: parseEther("1"),
});
const expectedToAddress = "0x689A095B4507Bfa302eef8551F90fB322B3451c6"; // Verification Gateway address
const expectedToAddress = "0x14EE47429DEf3462142AE5f8d1E263E0B137bA63"; // Verification Gateway address
const expectedFromAddress = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"; // Aggregator address (Hardhat account 0)
// Act

View File

@@ -121,14 +121,14 @@ describe("Upgrade", async function () {
const walletAddress = walletOldVg.address;
const blsSecret = walletOldVg.blsWalletSigner.privateKey;
const wallet = await BlsWalletWrapper.connect(
blsSecret,
fx.verificationGateway.address,
fx.verificationGateway.provider,
);
// Sign simple address message
const addressMessage = solidityPack(["address"], [walletAddress]);
const addressSignature = wallet.signMessage(addressMessage);
const walletNewVg = await BlsWalletWrapper.connect(
blsSecret,
vg2.address,
vg2.provider,
);
const addressSignature = walletNewVg.signMessage(addressMessage);
const proxyAdmin2Address = await vg2.walletProxyAdmin();
// Get admin action to change proxy
@@ -181,19 +181,18 @@ describe("Upgrade", async function () {
{
// Fail if setExternalWalletAction is skipped
const { successes } =
await fx.verificationGateway.callStatic.processBundle(
walletOldVg.sign({
nonce: BigNumber.from(2),
actions: [
// skip: setExternalWalletAction,
changeProxyAction,
setTrustedBLSGatewayAction,
],
}),
);
const result = await fx.verificationGateway.callStatic.processBundle(
walletOldVg.sign({
nonce: BigNumber.from(2),
actions: [
// skip: setExternalWalletAction,
changeProxyAction,
setTrustedBLSGatewayAction,
],
}),
);
expect(successes).to.deep.equal([false]);
expect(result.successes).to.deep.equal([false]);
}
{
@@ -276,10 +275,11 @@ describe("Upgrade", async function () {
// Check new verification gateway was set
expect(await blsWallet.trustedBLSGateway()).to.equal(vg2.address);
await walletNewVg.syncWallet(vg2);
// Check new gateway has wallet via static call through new gateway
const bundleResult = await vg2.callStatic.processBundle(
fx.blsWalletSigner.aggregate([
walletOldVg.sign({
walletNewVg.sign({
nonce: BigNumber.from(3),
actions: [
{

View File

@@ -36,7 +36,7 @@
"advanced-css-reset": "^1.2.2",
"async-mutex": "^0.3.2",
"axios": "^0.27.2",
"bls-wallet-clients": "0.8.2-1452ef5",
"bls-wallet-clients": "0.8.2-1fb4a55",
"browser-passworder": "^2.0.3",
"bs58check": "^2.1.2",
"crypto-browserify": "^3.12.0",

View File

@@ -2907,10 +2907,10 @@ blakejs@^1.1.0:
resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.2.1.tgz#5057e4206eadb4a97f7c0b6e197a505042fc3814"
integrity sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==
bls-wallet-clients@0.8.2-1452ef5:
version "0.8.2-1452ef5"
resolved "https://registry.yarnpkg.com/bls-wallet-clients/-/bls-wallet-clients-0.8.2-1452ef5.tgz#d76e938ca45ec5da44c8e59699d1bd5f6c69dcd2"
integrity sha512-bg7WLr9NRbvDzj+zgkLNfaPzr1m0m13Cc8RJoZ2s6s+ic7WxSiwxTkZGc2SChFgmG8ZGi1O9DnR6//lrTsMVUA==
bls-wallet-clients@0.8.2-1fb4a55:
version "0.8.2-1fb4a55"
resolved "https://registry.yarnpkg.com/bls-wallet-clients/-/bls-wallet-clients-0.8.2-1fb4a55.tgz#bab40801ee1e60ffbc9c0bc924943c6f90605e7c"
integrity sha512-2tlwOSUGzsOiam0G7GBmsN3W5cHjUwTmHR/DvGRH584zLkCC/8TFdAn2/laSF2baTYvegtIHwQNl1zX5DWivEQ==
dependencies:
"@thehubbleproject/bls" "^0.5.1"
ethers "^5.7.2"