From 71c9e854bf12d3d759a188d0bb6744904382c486 Mon Sep 17 00:00:00 2001 From: LHerskind Date: Mon, 11 Sep 2023 15:17:18 +0000 Subject: [PATCH] feat: Include contract address in message hash --- .../end-to-end/src/e2e_token_contract.test.ts | 20 ++++++++++++------- .../src/contracts/token_contract/src/main.nr | 16 +++++++-------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/yarn-project/end-to-end/src/e2e_token_contract.test.ts b/yarn-project/end-to-end/src/e2e_token_contract.test.ts index 76a4adcf1db5..db2cbdc6088e 100644 --- a/yarn-project/end-to-end/src/e2e_token_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_token_contract.test.ts @@ -187,7 +187,7 @@ describe('e2e_token_contract', () => { afterEach(async () => { await tokenSim.check(); - }); + }, 30_000); describe('Access controlled functions', () => { it('Set admin', async () => { @@ -351,6 +351,7 @@ describe('e2e_token_contract', () => { ) => { return await hashPayload([ caller.address.toField(), + asset.address.toField(), FunctionSelector.fromSignature('transfer_public((Field),(Field),Field,Field)').toField(), from.address.toField(), to.address.toField(), @@ -416,7 +417,7 @@ describe('e2e_token_contract', () => { await txReplay.isMined(); const receiptReplay = await txReplay.getReceipt(); expect(receiptReplay.status).toBe(TxStatus.DROPPED); - }, 30_000); + }, 45_000); describe('failure cases', () => { it('transfer more than balance', async () => { @@ -477,7 +478,7 @@ describe('e2e_token_contract', () => { expect(await asset.methods.balance_of_public({ address: accounts[0].address }).view()).toEqual(balance0); expect(await asset.methods.balance_of_public({ address: accounts[1].address }).view()).toEqual(balance1); - }); + }, 30_000); it('transfer on behalf of other, wrong designated caller', async () => { const balance0 = await asset.methods.balance_of_public({ address: accounts[0].address }).view(); @@ -523,6 +524,7 @@ describe('e2e_token_contract', () => { ) => { return await hashPayload([ caller.address.toField(), + asset.address.toField(), FunctionSelector.fromSignature('transfer((Field),(Field),Field,Field)').toField(), from.address.toField(), to.address.toField(), @@ -541,7 +543,7 @@ describe('e2e_token_contract', () => { const receipt = await tx.wait(); expect(receipt.status).toBe(TxStatus.MINED); tokenSim.transferPrivate(accounts[0].address, accounts[1].address, amount); - }); + }, 30_000); it('transfer to self', async () => { const balance0 = await asset.methods.balance_of_private({ address: accounts[0].address }).view(); @@ -553,7 +555,7 @@ describe('e2e_token_contract', () => { const receipt = await tx.wait(); expect(receipt.status).toBe(TxStatus.MINED); tokenSim.transferPrivate(accounts[0].address, accounts[0].address, amount); - }); + }, 30_000); it('transfer on behalf of other', async () => { const balance0 = await asset.methods.balance_of_private({ address: accounts[0].address }).view(); @@ -695,6 +697,7 @@ describe('e2e_token_contract', () => { ) => { return await hashPayload([ caller.address.toField(), + asset.address.toField(), FunctionSelector.fromSignature('shield((Field),Field,Field,Field)').toField(), from.address.toField(), new Fr(amount), @@ -733,7 +736,7 @@ describe('e2e_token_contract', () => { await txClaimDoubleSpend.isMined(); const receiptDoubleSpend = await txClaimDoubleSpend.getReceipt(); expect(receiptDoubleSpend.status).toBe(TxStatus.DROPPED); - }); + }, 30_000); it('on behalf of other', async () => { const balancePub = await asset.methods.balance_of_public({ address: accounts[0].address }).view(); @@ -783,7 +786,7 @@ describe('e2e_token_contract', () => { await txClaimDoubleSpend.isMined(); const receiptDoubleSpend = await txClaimDoubleSpend.getReceipt(); expect(receiptDoubleSpend.status).toBe(TxStatus.DROPPED); - }, 30_000); + }, 60_000); describe('failure cases', () => { it('on behalf of self (more than balance)', async () => { @@ -887,6 +890,7 @@ describe('e2e_token_contract', () => { ) => { return await hashPayload([ caller.address.toField(), + asset.address.toField(), FunctionSelector.fromSignature('unshield((Field),(Field),Field,Field)').toField(), accounts[0].address.toField(), accounts[1].address.toField(), @@ -1017,6 +1021,7 @@ describe('e2e_token_contract', () => { const burnMessageHash = async (caller: CompleteAddress, from: CompleteAddress, amount: bigint, nonce: Fr) => { return await hashPayload([ caller.address.toField(), + asset.address.toField(), FunctionSelector.fromSignature('burn_public((Field),Field,Field)').toField(), from.address.toField(), new Fr(amount), @@ -1153,6 +1158,7 @@ describe('e2e_token_contract', () => { const burnMessageHash = async (caller: CompleteAddress, from: CompleteAddress, amount: bigint, nonce: Fr) => { return await hashPayload([ caller.address.toField(), + asset.address.toField(), FunctionSelector.fromSignature('burn((Field),Field,Field)').toField(), from.address.toField(), new Fr(amount), diff --git a/yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr index 1daf8a9c74e1..7c1a0891b812 100644 --- a/yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr @@ -5,8 +5,8 @@ mod util; // Minimal token implementation that supports `AuthWit` accounts. // The auth message follows a similar pattern to the cross-chain message and includes a designated caller. // The designated caller is ALWAYS used here, and not based on a flag as cross-chain. -// message hash = H([caller, selector, , ...args]) -// To be read as `caller` calls function defined by `selector` with `args` +// message hash = H([caller, contract, selector, ...args]) +// To be read as `caller` calls function at `contract` defined by `selector` with `args` // Including a nonce in the message hash ensures that the message can only be used once. contract Token { @@ -165,7 +165,7 @@ contract Token { if (from.address != context.msg_sender()) { // The redeem is only spendable once, so we need to ensure that you cannot insert multiple shields from the same message. let selector = compute_selector("shield((Field),Field,Field,Field)"); - let message_field = compute_message_hash([context.msg_sender(), selector, from.address, amount, secret_hash, nonce]); + let message_field = compute_message_hash([context.msg_sender(), context.this_address(), selector, from.address, amount, secret_hash, nonce]); AccountContract::at(from.address).is_valid(Context::public(&mut context), message_field); } else { assert(nonce == 0, "invalid nonce"); @@ -193,7 +193,7 @@ contract Token { if (from.address != context.msg_sender()) { let selector = compute_selector("transfer_public((Field),(Field),Field,Field)"); - let message_field = compute_message_hash([context.msg_sender(), selector, from.address, to.address, amount, nonce]); + let message_field = compute_message_hash([context.msg_sender(), context.this_address(), selector, from.address, to.address, amount, nonce]); AccountContract::at(from.address).is_valid(Context::public(&mut context), message_field); } else { assert(nonce == 0, "invalid nonce"); @@ -217,7 +217,7 @@ contract Token { if (from.address != context.msg_sender()) { let selector = compute_selector("burn_public((Field),Field,Field)"); - let message_field = compute_message_hash([context.msg_sender(), selector, from.address, amount, nonce]); + let message_field = compute_message_hash([context.msg_sender(), context.this_address(), selector, from.address, amount, nonce]); AccountContract::at(from.address).is_valid(Context::public(&mut context), message_field); } else { assert(nonce == 0, "invalid nonce"); @@ -257,7 +257,7 @@ contract Token { if (from.address != context.msg_sender()) { let selector = compute_selector("unshield((Field),(Field),Field,Field)"); - let message_field = compute_message_hash([context.msg_sender(), selector, from.address, to.address, amount, nonce]); + let message_field = compute_message_hash([context.msg_sender(), context.this_address(), selector, from.address, to.address, amount, nonce]); AccountContract::at(from.address).is_valid(Context::private(&mut context), message_field); } else { assert(nonce == 0, "invalid nonce"); @@ -281,7 +281,7 @@ contract Token { if (from.address != context.msg_sender()) { let selector = compute_selector("transfer((Field),(Field),Field,Field)"); - let message_field = compute_message_hash([context.msg_sender(), selector, from.address, to.address, amount, nonce]); + let message_field = compute_message_hash([context.msg_sender(), context.this_address(), selector, from.address, to.address, amount, nonce]); AccountContract::at(from.address).is_valid(Context::private(&mut context), message_field); } else { assert(nonce == 0, "invalid nonce"); @@ -304,7 +304,7 @@ contract Token { if (from.address != context.msg_sender()) { let selector = compute_selector("burn((Field),Field,Field)"); - let message_field = compute_message_hash([context.msg_sender(), selector, from.address, amount, nonce]); + let message_field = compute_message_hash([context.msg_sender(), context.this_address(), selector, from.address, amount, nonce]); AccountContract::at(from.address).is_valid(Context::private(&mut context), message_field); } else { assert(nonce == 0, "invalid nonce");