mirror of
https://github.com/getwax/bls-wallet.git
synced 2026-01-09 15:48:11 -05:00
Merge pull request #600 from web3well/392-blsWalletSigner-verify-cannot-verify-bundles-with-multiple-addresses
Add ability to blsWalletSigner to verify multiple addresses
This commit is contained in:
@@ -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.9.0",
|
||||
"bls-wallet-clients": "0.9.0-1620721",
|
||||
"fp-ts": "^2.12.1",
|
||||
"io-ts": "^2.2.16",
|
||||
"io-ts-reporters": "^2.0.1",
|
||||
|
||||
@@ -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.9.0:
|
||||
version "0.9.0"
|
||||
resolved "https://registry.yarnpkg.com/bls-wallet-clients/-/bls-wallet-clients-0.9.0.tgz#edfbdb24011856b52d9b438af174b6acbeda27ec"
|
||||
integrity sha512-ebEifAPkGfTft6xdVVgQfC6HEXzgw+wX2d76w2K1OUsB4FeKiAYRLMXtnKtl7tdQoMknHElD6xrLChKaCACYLQ==
|
||||
bls-wallet-clients@0.9.0-1620721:
|
||||
version "0.9.0-1620721"
|
||||
resolved "https://registry.yarnpkg.com/bls-wallet-clients/-/bls-wallet-clients-0.9.0-1620721.tgz#572798d10fa6246ab44bbd0e11b97df11abd6d15"
|
||||
integrity sha512-ekSrK2bCiWoTuhnqdKTp0kXDuIUmE3lc9pqtonOAZC/6ReU2cVbW+F6U1/echtagdWL6GBArJgB2JnVQVznRpg==
|
||||
dependencies:
|
||||
"@thehubbleproject/bls" "^0.5.1"
|
||||
ethers "^5.7.2"
|
||||
|
||||
@@ -54,7 +54,7 @@ export type {
|
||||
PublicKey,
|
||||
Signature,
|
||||
VerificationGateway,
|
||||
} from "https://esm.sh/bls-wallet-clients@0.9.0";
|
||||
} from "https://esm.sh/bls-wallet-clients@0.9.0-1620721";
|
||||
|
||||
export {
|
||||
Aggregator as AggregatorClient,
|
||||
@@ -70,10 +70,10 @@ export {
|
||||
getConfig,
|
||||
MockERC20Factory,
|
||||
VerificationGatewayFactory,
|
||||
} from "https://esm.sh/bls-wallet-clients@0.9.0";
|
||||
} from "https://esm.sh/bls-wallet-clients@0.9.0-1620721";
|
||||
|
||||
// Workaround for esbuild's export-star bug
|
||||
import blsWalletClients from "https://esm.sh/bls-wallet-clients@0.9.0";
|
||||
import blsWalletClients from "https://esm.sh/bls-wallet-clients@0.9.0-1620721";
|
||||
const { bundleFromDto, bundleToDto, initBlsWalletSigner } = blsWalletClients;
|
||||
export { bundleFromDto, bundleToDto, initBlsWalletSigner };
|
||||
|
||||
|
||||
@@ -156,14 +156,15 @@ export default class BundleService {
|
||||
|
||||
const failures: TransactionFailure[] = [];
|
||||
|
||||
for (const walletAddr of walletAddresses) {
|
||||
const signedCorrectly = this.blsWalletSigner.verify(bundle, walletAddr);
|
||||
if (!signedCorrectly) {
|
||||
failures.push({
|
||||
type: "invalid-signature",
|
||||
description: `invalid signature for wallet address ${walletAddr}`,
|
||||
});
|
||||
}
|
||||
const signedCorrectly = this.blsWalletSigner.verify(
|
||||
bundle,
|
||||
walletAddresses,
|
||||
);
|
||||
if (!signedCorrectly) {
|
||||
failures.push({
|
||||
type: "invalid-signature",
|
||||
description: `invalid bundle signature for signature ${bundle.signature}`,
|
||||
});
|
||||
}
|
||||
|
||||
failures.push(...await this.ethereumService.checkNonces(bundle));
|
||||
|
||||
@@ -54,7 +54,7 @@ Fixture.test("rejects bundle with invalid signature", async (fx) => {
|
||||
// sig test)
|
||||
tx.signature = otherTx.signature;
|
||||
|
||||
assertEquals(await bundleService.bundleTable.count(), 0);
|
||||
assertEquals(bundleService.bundleTable.count(), 0);
|
||||
|
||||
const res = await bundleService.add(tx);
|
||||
if ("hash" in res) {
|
||||
@@ -63,7 +63,47 @@ Fixture.test("rejects bundle with invalid signature", async (fx) => {
|
||||
assertEquals(res.failures.map((f) => f.type), ["invalid-signature"]);
|
||||
|
||||
// Bundle table remains empty
|
||||
assertEquals(await bundleService.bundleTable.count(), 0);
|
||||
assertEquals(bundleService.bundleTable.count(), 0);
|
||||
});
|
||||
|
||||
Fixture.test("rejects bundle with valid signature but invalid public key", async (fx) => {
|
||||
const bundleService = fx.createBundleService();
|
||||
const [wallet, otherWallet] = await fx.setupWallets(2);
|
||||
|
||||
const operation: Operation = {
|
||||
nonce: await wallet.Nonce(),
|
||||
gas: 0,
|
||||
actions: [
|
||||
{
|
||||
ethValue: 0,
|
||||
contractAddress: fx.testErc20.address,
|
||||
encodedFunction: fx.testErc20.interface.encodeFunctionData(
|
||||
"mint",
|
||||
[wallet.address, "3"],
|
||||
),
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const tx = wallet.sign(operation);
|
||||
const otherTx = otherWallet.sign(operation);
|
||||
|
||||
// Make the signature invalid
|
||||
// Note: Bug in bls prevents just corrupting the signature (see other invalid
|
||||
// sig test)
|
||||
tx.senderPublicKeys[0] = otherTx.senderPublicKeys[0];
|
||||
|
||||
assertEquals(bundleService.bundleTable.count(), 0);
|
||||
|
||||
const res = await bundleService.add(tx);
|
||||
if ("hash" in res) {
|
||||
throw new Error("expected bundle to fail");
|
||||
}
|
||||
assertEquals(res.failures.map((f) => f.type), ["invalid-signature"]);
|
||||
assertEquals(res.failures.map((f) => f.description), [`invalid bundle signature for signature ${tx.signature}`]);
|
||||
|
||||
// Bundle table remains empty
|
||||
assertEquals(bundleService.bundleTable.count(), 0);
|
||||
});
|
||||
|
||||
Fixture.test("rejects bundle with nonce from the past", async (fx) => {
|
||||
@@ -85,7 +125,7 @@ Fixture.test("rejects bundle with nonce from the past", async (fx) => {
|
||||
],
|
||||
});
|
||||
|
||||
assertEquals(await bundleService.bundleTable.count(), 0);
|
||||
assertEquals(bundleService.bundleTable.count(), 0);
|
||||
|
||||
const res = await bundleService.add(tx);
|
||||
if ("hash" in res) {
|
||||
@@ -94,7 +134,7 @@ Fixture.test("rejects bundle with nonce from the past", async (fx) => {
|
||||
assertEquals(res.failures.map((f) => f.type), ["duplicate-nonce"]);
|
||||
|
||||
// Bundle table remains empty
|
||||
assertEquals(await bundleService.bundleTable.count(), 0);
|
||||
assertEquals(bundleService.bundleTable.count(), 0);
|
||||
});
|
||||
|
||||
Fixture.test(
|
||||
@@ -128,7 +168,7 @@ Fixture.test(
|
||||
// https://github.com/thehubbleproject/hubble-bls/pull/20
|
||||
tx.signature = otherTx.signature;
|
||||
|
||||
assertEquals(await bundleService.bundleTable.count(), 0);
|
||||
assertEquals(bundleService.bundleTable.count(), 0);
|
||||
|
||||
const res = await bundleService.add(tx);
|
||||
if ("hash" in res) {
|
||||
@@ -141,7 +181,7 @@ Fixture.test(
|
||||
);
|
||||
|
||||
// Bundle table remains empty
|
||||
assertEquals(await bundleService.bundleTable.count(), 0);
|
||||
assertEquals(bundleService.bundleTable.count(), 0);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -164,11 +204,11 @@ Fixture.test("adds bundle with future nonce", async (fx) => {
|
||||
],
|
||||
});
|
||||
|
||||
assertEquals(await bundleService.bundleTable.count(), 0);
|
||||
assertEquals(bundleService.bundleTable.count(), 0);
|
||||
|
||||
assertBundleSucceeds(await bundleService.add(tx));
|
||||
|
||||
assertEquals(await bundleService.bundleTable.count(), 1);
|
||||
assertEquals(bundleService.bundleTable.count(), 1);
|
||||
});
|
||||
|
||||
// TODO (merge-ok): Add a mechanism for limiting the number of stored
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "bls-wallet-clients",
|
||||
"version": "0.9.0",
|
||||
"version": "0.9.0-1620721",
|
||||
"description": "Client libraries for interacting with BLS Wallet components",
|
||||
"main": "dist/src/index.js",
|
||||
"types": "dist/src/index.d.ts",
|
||||
|
||||
@@ -6,7 +6,7 @@ import type { Bundle } from "./types";
|
||||
import isValidEmptyBundle from "./isValidEmptyBundle";
|
||||
|
||||
export default (domain: Uint8Array) =>
|
||||
(bundle: Bundle, walletAddress: string): boolean => {
|
||||
(bundle: Bundle, walletAddresses: Array<string>): boolean => {
|
||||
// hubbleBls verifier incorrectly rejects empty bundles
|
||||
if (isValidEmptyBundle(bundle)) {
|
||||
return true;
|
||||
@@ -25,8 +25,8 @@ export default (domain: Uint8Array) =>
|
||||
BigNumber.from(n2).toHexString(),
|
||||
BigNumber.from(n3).toHexString(),
|
||||
]),
|
||||
bundle.operations.map((op) =>
|
||||
encodeMessageForSigning()(op, walletAddress),
|
||||
bundle.operations.map((op, i) =>
|
||||
encodeMessageForSigning()(op, walletAddresses[i]),
|
||||
),
|
||||
);
|
||||
};
|
||||
|
||||
@@ -65,7 +65,7 @@ describe("index", () => {
|
||||
"0x2f90b24bbc03de665816b3a632e0c7b5fb837c87541d9337480671613cf1359c",
|
||||
]);
|
||||
|
||||
expect(verify(bundle, walletAddress)).to.equal(true);
|
||||
expect(verify(bundle, [walletAddress])).to.equal(true);
|
||||
|
||||
const { sign: signWithOtherPrivateKey } = await initBlsWalletSigner({
|
||||
chainId: 123,
|
||||
@@ -79,7 +79,7 @@ describe("index", () => {
|
||||
.signature,
|
||||
};
|
||||
|
||||
expect(verify(bundleBadSig, walletAddress)).to.equal(false);
|
||||
expect(verify(bundleBadSig, [walletAddress])).to.equal(false);
|
||||
|
||||
const bundleBadMessage: Bundle = {
|
||||
senderPublicKeys: bundle.senderPublicKeys,
|
||||
@@ -99,7 +99,7 @@ describe("index", () => {
|
||||
signature: bundle.signature,
|
||||
};
|
||||
|
||||
expect(verify(bundleBadMessage, walletAddress)).to.equal(false);
|
||||
expect(verify(bundleBadMessage, [walletAddress])).to.equal(false);
|
||||
});
|
||||
|
||||
it("aggregates transactions", async () => {
|
||||
@@ -131,11 +131,15 @@ describe("index", () => {
|
||||
"0x0235a99bcd1f0793efb7f3307cd349f211a433f60cfab795f5f976298f17a768",
|
||||
]);
|
||||
|
||||
expect(verify(bundle1, walletAddress)).to.equal(true);
|
||||
expect(verify(bundle2, otherWalletAddress)).to.equal(true);
|
||||
expect(verify(bundle1, [walletAddress])).to.equal(true);
|
||||
expect(verify(bundle2, [otherWalletAddress])).to.equal(true);
|
||||
|
||||
expect(verify(bundle1, otherWalletAddress)).to.equal(false);
|
||||
expect(verify(bundle2, walletAddress)).to.equal(false);
|
||||
expect(verify(bundle1, [otherWalletAddress])).to.equal(false);
|
||||
expect(verify(bundle2, [walletAddress])).to.equal(false);
|
||||
|
||||
expect(verify(aggBundle, [walletAddress, otherWalletAddress])).to.equal(
|
||||
true,
|
||||
);
|
||||
|
||||
const aggBundleBadMessage: Bundle = {
|
||||
...aggBundle,
|
||||
@@ -156,8 +160,12 @@ describe("index", () => {
|
||||
],
|
||||
};
|
||||
|
||||
expect(verify(aggBundleBadMessage, walletAddress)).to.equal(false);
|
||||
expect(verify(aggBundleBadMessage, otherWalletAddress)).to.equal(false);
|
||||
expect(
|
||||
verify(aggBundleBadMessage, [walletAddress, otherWalletAddress]),
|
||||
).to.equal(false);
|
||||
expect(
|
||||
verify(aggBundleBadMessage, [otherWalletAddress, walletAddress]),
|
||||
).to.equal(false);
|
||||
});
|
||||
|
||||
it("can aggregate transactions which already have multiple subTransactions", async () => {
|
||||
@@ -188,8 +196,39 @@ describe("index", () => {
|
||||
const aggBundle2 = aggregate(bundles.slice(2, 4));
|
||||
|
||||
const aggAggBundle = aggregate([aggBundle1, aggBundle2]);
|
||||
const walletAddresses = new Array(4).fill(walletAddress);
|
||||
|
||||
expect(verify(aggAggBundle, walletAddress)).to.equal(true);
|
||||
expect(verify(aggAggBundle, walletAddresses)).to.equal(true);
|
||||
});
|
||||
|
||||
it("should fail to verify bundle with wallet address mismatches", async () => {
|
||||
const {
|
||||
bundleTemplate,
|
||||
privateKey,
|
||||
otherPrivateKey,
|
||||
walletAddress,
|
||||
otherWalletAddress,
|
||||
verificationGatewayAddress,
|
||||
} = samples;
|
||||
|
||||
const { sign, aggregate, verify } = await initBlsWalletSigner({
|
||||
chainId: 123,
|
||||
verificationGatewayAddress,
|
||||
privateKey,
|
||||
});
|
||||
const { sign: signWithOtherPrivateKey } = await initBlsWalletSigner({
|
||||
chainId: 123,
|
||||
verificationGatewayAddress,
|
||||
privateKey: otherPrivateKey,
|
||||
});
|
||||
|
||||
const bundle1 = sign(bundleTemplate, walletAddress);
|
||||
const bundle2 = signWithOtherPrivateKey(bundleTemplate, otherWalletAddress);
|
||||
const aggBundle = aggregate([bundle1, bundle2]);
|
||||
|
||||
expect(verify(aggBundle, [otherWalletAddress, walletAddress])).to.equal(
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
it("generates expected publicKeyStr", async () => {
|
||||
@@ -238,6 +277,6 @@ describe("index", () => {
|
||||
|
||||
const emptyBundle = aggregate([]);
|
||||
|
||||
expect(verify(emptyBundle, samples.walletAddress)).to.equal(true);
|
||||
expect(verify(emptyBundle, [samples.walletAddress])).to.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -116,8 +116,6 @@ describe("BlsProvider", () => {
|
||||
|
||||
it("should throw an error when sending a modified signed transaction", async () => {
|
||||
// Arrange
|
||||
const address = await blsSigner.getAddress();
|
||||
|
||||
const signedTransaction = await blsSigner.signTransaction({
|
||||
value: parseEther("1"),
|
||||
to: ethers.Wallet.createRandom().address,
|
||||
@@ -134,7 +132,7 @@ describe("BlsProvider", () => {
|
||||
// Assert
|
||||
await expect(result()).to.be.rejectedWith(
|
||||
Error,
|
||||
`[{"type":"invalid-signature","description":"invalid signature for wallet address ${address}"}]`,
|
||||
`[{"type":"invalid-signature","description":"invalid bundle signature for signature ${userBundle.signature}"}]`,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -286,8 +284,6 @@ describe("BlsProvider", () => {
|
||||
|
||||
it("should throw an error when sending a modified signed transaction", async () => {
|
||||
// Arrange
|
||||
const address = await blsSigner.getAddress();
|
||||
|
||||
const signedTransaction = await blsSigner.signTransactionBatch({
|
||||
transactions: [
|
||||
{
|
||||
@@ -309,7 +305,7 @@ describe("BlsProvider", () => {
|
||||
// Assert
|
||||
await expect(result()).to.be.rejectedWith(
|
||||
Error,
|
||||
`[{"type":"invalid-signature","description":"invalid signature for wallet address ${address}"}]`,
|
||||
`[{"type":"invalid-signature","description":"invalid bundle signature for signature ${userBundle.signature}"}]`,
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
"assert-browserify": "^2.0.0",
|
||||
"async-mutex": "^0.3.2",
|
||||
"axios": "^0.27.2",
|
||||
"bls-wallet-clients": "0.9.0",
|
||||
"bls-wallet-clients": "0.9.0-1620721",
|
||||
"browser-passworder": "^2.0.3",
|
||||
"bs58check": "^2.1.2",
|
||||
"crypto-browserify": "^3.12.0",
|
||||
|
||||
@@ -2898,10 +2898,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.9.0:
|
||||
version "0.9.0"
|
||||
resolved "https://registry.yarnpkg.com/bls-wallet-clients/-/bls-wallet-clients-0.9.0.tgz#edfbdb24011856b52d9b438af174b6acbeda27ec"
|
||||
integrity sha512-ebEifAPkGfTft6xdVVgQfC6HEXzgw+wX2d76w2K1OUsB4FeKiAYRLMXtnKtl7tdQoMknHElD6xrLChKaCACYLQ==
|
||||
bls-wallet-clients@0.9.0-1620721:
|
||||
version "0.9.0-1620721"
|
||||
resolved "https://registry.yarnpkg.com/bls-wallet-clients/-/bls-wallet-clients-0.9.0-1620721.tgz#572798d10fa6246ab44bbd0e11b97df11abd6d15"
|
||||
integrity sha512-ekSrK2bCiWoTuhnqdKTp0kXDuIUmE3lc9pqtonOAZC/6ReU2cVbW+F6U1/echtagdWL6GBArJgB2JnVQVznRpg==
|
||||
dependencies:
|
||||
"@thehubbleproject/bls" "^0.5.1"
|
||||
ethers "^5.7.2"
|
||||
|
||||
Reference in New Issue
Block a user