diff --git a/packages/shared/src/types.ts b/packages/shared/src/types.ts index 8d4b96cdb..8d5ea9f0c 100644 --- a/packages/shared/src/types.ts +++ b/packages/shared/src/types.ts @@ -30,10 +30,11 @@ export type PackedUserOperationToSign = { nonce: bigint | number; initCode: `0x${string}` | Uint8Array; callData: `0x${string}` | Uint8Array; - accountGasLimit: `0x${string}` | Uint8Array; + accountGasLimits: `0x${string}` | Uint8Array; preVerificationGas: bigint | number; gasFees: `0x${string}` | Uint8Array; paymasterAndData: `0x${string}` | Uint8Array; + signature?: `0x${string}` | Uint8Array | undefined; }; function getBigIntValue(value: bigint | number): bigint { @@ -101,7 +102,7 @@ export function toCorePackedUserOperation( getBigIntValue(packedUserOperation.nonce), getUint8ArrayValue(packedUserOperation.initCode), getUint8ArrayValue(packedUserOperation.callData), - getUint8ArrayValue(packedUserOperation.accountGasLimit), + getUint8ArrayValue(packedUserOperation.accountGasLimits), getBigIntValue(packedUserOperation.preVerificationGas), getUint8ArrayValue(packedUserOperation.gasFees), getUint8ArrayValue(packedUserOperation.paymasterAndData), diff --git a/packages/shared/test/porter.test.ts b/packages/shared/test/porter.test.ts index ae057ba54..046894664 100644 --- a/packages/shared/test/porter.test.ts +++ b/packages/shared/test/porter.test.ts @@ -289,7 +289,7 @@ describe('PorterClient Signing', () => { BigInt(123), // nonce fromHexString('0xabc'), // initCode fromHexString('0xdef'), // callData - fromHexString('0x01020304'), // accountGasLimit + fromHexString('0x01020304'), // accountGasLimits BigInt(101112), // preVerificationGas fromHexString('0x05060708'), // gasFees fromHexString('0x090a0b0c'), // paymasterAndData diff --git a/packages/taco/src/index.ts b/packages/taco/src/index.ts index 34e6bdf0f..866ce1c24 100644 --- a/packages/taco/src/index.ts +++ b/packages/taco/src/index.ts @@ -1,6 +1,8 @@ export { DkgPublicKey, ThresholdMessageKit } from '@nucypher/nucypher-core'; export { Domain, + PackedUserOperationToSign, + UserOperationToSign, domains, fromBytes, getPorterUris, diff --git a/packages/taco/src/sign.ts b/packages/taco/src/sign.ts index ef2df329b..31b5c62bf 100644 --- a/packages/taco/src/sign.ts +++ b/packages/taco/src/sign.ts @@ -51,20 +51,30 @@ export type SignResult = { }; function aggregateSignatures( - signaturesByAddress: { - [checksumAddress: string]: TacoSignature; - }, + signatures: TacoSignature[], threshold: number, ): string { - // Aggregate hex signatures by concatenating them; being careful to remove the '0x' prefix from each signature except the first one. - const signatures = Object.values(signaturesByAddress) - .map((sig) => sig.signature) - .slice(0, threshold); - if (signatures.length === 1) { - return signatures[0]; + // Aggregate hex signatures by concatenating them; being careful to sort + // and remove the '0x' prefix from each signature except the first one. + + // sort by signer address + const sortedSignatures = [...signatures] + .sort((a, b) => + a.signerAddress + .toLowerCase() + .localeCompare(b.signerAddress.toLowerCase()), + ) + .map((sig) => sig.signature); + + const thresholdSignatures = sortedSignatures.slice(0, threshold); + if (thresholdSignatures.length === 1) { + return thresholdSignatures[0]; } + // Concatenate signatures - const allBytes = signatures.flatMap((hex) => Array.from(fromHexString(hex))); + const allBytes = thresholdSignatures.flatMap((sig) => + Array.from(fromHexString(sig)), + ); return `0x${toHexString(new Uint8Array(allBytes))}`; } @@ -197,7 +207,7 @@ export async function signUserOp( ); const aggregatedSignature = aggregateSignatures( - signaturesToAggregate, + Object.values(signaturesToAggregate), threshold, ); @@ -300,7 +310,7 @@ function collectSignatures( // Insufficient signatures for a message hash to meet the threshold if (!signaturesToAggregate) { - //we have multiple hashes, which means we have mismatched hashes from different nodes + // we have multiple hashes, which means we have mismatched hashes from different nodes // we don't really expect this to happen (other than some malicious nodes) console.error( 'Porter returned mismatched message hashes:', diff --git a/packages/taco/test/taco-sign.test.ts b/packages/taco/test/taco-sign.test.ts index ed73e3c03..fcce85295 100644 --- a/packages/taco/test/taco-sign.test.ts +++ b/packages/taco/test/taco-sign.test.ts @@ -53,11 +53,11 @@ function checkPackedUserOpEquality( : fromHexString(op1.callData); expect(callData).toEqual(op2.callData); - const accountGasLimit = - op1.accountGasLimit instanceof Uint8Array - ? op1.accountGasLimit - : fromHexString(op1.accountGasLimit); - expect(accountGasLimit).toEqual(op2.accountGasLimits); + const accountGasLimits = + op1.accountGasLimits instanceof Uint8Array + ? op1.accountGasLimits + : fromHexString(op1.accountGasLimits); + expect(accountGasLimits).toEqual(op2.accountGasLimits); expect(toBigInt(op1.preVerificationGas)).toEqual(op2.preVerificationGas); @@ -290,7 +290,7 @@ describe('TACo Signing', () => { nonce: BigInt(123), initCode: fromHexString('0xabc'), callData: fromHexString('0xdef'), - accountGasLimit: fromHexString('0x01020304'), + accountGasLimits: fromHexString('0x01020304'), preVerificationGas: BigInt(101112), gasFees: fromHexString('0x05060708'), paymasterAndData: fromHexString('0x090a0b0c'), @@ -307,7 +307,7 @@ describe('TACo Signing', () => { nonce: 1, initCode: '0xabc', callData: '0xdef', - accountGasLimit: '0x01020304', + accountGasLimits: '0x01020304', preVerificationGas: 4096, gasFees: '0x05060708', paymasterAndData: '0x090a0b0c', @@ -333,7 +333,7 @@ describe('TACo Signing', () => { nonce: BigInt(1), initCode: fromHexString('0xabc'), callData: fromHexString('0xdef'), - accountGasLimit: fromHexString('0x01020304'), + accountGasLimits: fromHexString('0x01020304'), preVerificationGas: BigInt(101112), gasFees: fromHexString('0x05060708'), paymasterAndData: fromHexString('0x090a0b0c'), @@ -357,24 +357,25 @@ describe('TACo Signing', () => { userOp: UserOperationToSign | PackedUserOperationToSign, ) => { const encryptedResponses = { - '0xnode1': new SignatureResponse( - signersInfo['0xnode1'].signerAddress, + // return out of order to ensure sorting works correctly + '0xnode2': new SignatureResponse( + signersInfo['0xnode2'].signerAddress, fromHexString('0xa1'), - fromHexString('0xdead'), + fromHexString('0xbeef'), 0, ).encrypt( requesterSk.deriveSharedSecret( - signersInfo['0xnode1'].signingRequestStaticKey, + signersInfo['0xnode2'].signingRequestStaticKey, ), ), - '0xnode2': new SignatureResponse( - signersInfo['0xnode2'].signerAddress, + '0xnode1': new SignatureResponse( + signersInfo['0xnode1'].signerAddress, fromHexString('0xa1'), - fromHexString('0xbeef'), + fromHexString('0xdead'), 0, ).encrypt( requesterSk.deriveSharedSecret( - signersInfo['0xnode2'].signingRequestStaticKey, + signersInfo['0xnode1'].signingRequestStaticKey, ), ), };