diff --git a/yarn-project/end-to-end/src/e2e_2_rpc_servers.test.ts b/yarn-project/end-to-end/src/e2e_2_rpc_servers.test.ts index 554ad930ff69..07fe8f805f22 100644 --- a/yarn-project/end-to-end/src/e2e_2_rpc_servers.test.ts +++ b/yarn-project/end-to-end/src/e2e_2_rpc_servers.test.ts @@ -1,10 +1,10 @@ import { AztecNodeService } from '@aztec/aztec-node'; import { AztecRPCServer, EthAddress, Fr } from '@aztec/aztec-rpc'; -import { AztecAddress, Wallet } from '@aztec/aztec.js'; +import { AztecAddress, Wallet, computeMessageSecretHash } from '@aztec/aztec.js'; import { DebugLogger } from '@aztec/foundation/log'; import { retryUntil } from '@aztec/foundation/retry'; import { toBigInt } from '@aztec/foundation/serialize'; -import { ChildContract, PrivateTokenContract } from '@aztec/noir-contracts/types'; +import { ChildContract, TokenContract } from '@aztec/noir-contracts/types'; import { AztecRPC, CompleteAddress, TxStatus } from '@aztec/types'; import { expectsNumOfEncryptedLogsInTheLastBlockToBe, setup, setupAztecRPCServer } from './fixtures/utils.js'; @@ -71,15 +71,27 @@ describe('e2e_2_rpc_servers', () => { await awaitUserSynchronised(wallet, owner); // Then check the balance - const contractWithWallet = await PrivateTokenContract.at(tokenAddress, wallet); - const balance = await contractWithWallet.methods.getBalance(owner).view({ from: owner }); + const contractWithWallet = await TokenContract.at(tokenAddress, wallet); + const balance = await contractWithWallet.methods.balance_of_private({ address: owner }).view({ from: owner }); logger(`Account ${owner} balance: ${balance}`); expect(balance).toBe(expectedBalance); }; const deployPrivateTokenContract = async (initialBalance: bigint, owner: AztecAddress) => { logger(`Deploying PrivateToken contract...`); - const contract = await PrivateTokenContract.deploy(walletA, initialBalance, owner).send().deployed(); + const contract = await TokenContract.deploy(walletA).send().deployed(); + expect((await contract.methods._initialize({ address: owner }).send().wait()).status).toBe(TxStatus.MINED); + + const secret = Fr.random(); + const secretHash = await computeMessageSecretHash(secret); + + expect((await contract.methods.mint_private(initialBalance, secretHash).send().wait()).status).toEqual( + TxStatus.MINED, + ); + expect( + (await contract.methods.redeem_shield({ address: owner }, initialBalance, secret).send().wait()).status, + ).toEqual(TxStatus.MINED); + logger('L2 contract deployed'); return contract.completeAddress; @@ -101,7 +113,7 @@ describe('e2e_2_rpc_servers', () => { // Add privateToken to RPC server B await aztecRpcServerB.addContracts([ { - abi: PrivateTokenContract.abi, + abi: TokenContract.abi, completeAddress: completeTokenAddress, portalContract: EthAddress.ZERO, }, @@ -113,12 +125,11 @@ describe('e2e_2_rpc_servers', () => { await expectsNumOfEncryptedLogsInTheLastBlockToBe(aztecNode, 1); // Transfer funds from A to B via RPC server A - const contractWithWalletA = await PrivateTokenContract.at(tokenAddress, walletA); - const txAToB = contractWithWalletA.methods.transfer(transferAmount1, userB.address).send(); - - await txAToB.isMined({ interval: 0.1 }); - const receiptAToB = await txAToB.getReceipt(); - + const contractWithWalletA = await TokenContract.at(tokenAddress, walletA); + const receiptAToB = await contractWithWalletA.methods + .transfer({ address: userA.address }, { address: userB.address }, transferAmount1, 0) + .send() + .wait(); expect(receiptAToB.status).toBe(TxStatus.MINED); // Check balances and logs are as expected @@ -127,8 +138,11 @@ describe('e2e_2_rpc_servers', () => { await expectsNumOfEncryptedLogsInTheLastBlockToBe(aztecNode, 2); // Transfer funds from B to A via RPC server B - const contractWithWalletB = await PrivateTokenContract.at(tokenAddress, walletB); - await contractWithWalletB.methods.transfer(transferAmount2, userA.address).send().wait({ interval: 0.1 }); + const contractWithWalletB = await TokenContract.at(tokenAddress, walletB); + await contractWithWalletB.methods + .transfer({ address: userB.address }, { address: userA.address }, transferAmount2, 0) + .send() + .wait({ interval: 0.1 }); // Check balances and logs are as expected await expectTokenBalance(walletA, tokenAddress, userA.address, initialBalance - transferAmount1 + transferAmount2); diff --git a/yarn-project/end-to-end/src/e2e_escrow_contract.test.ts b/yarn-project/end-to-end/src/e2e_escrow_contract.test.ts index 5121aaafdc7f..94571b751e1f 100644 --- a/yarn-project/end-to-end/src/e2e_escrow_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_escrow_contract.test.ts @@ -1,11 +1,11 @@ import { AztecNodeService } from '@aztec/aztec-node'; import { AztecRPCServer } from '@aztec/aztec-rpc'; -import { AccountWallet, AztecAddress, BatchCall, generatePublicKey } from '@aztec/aztec.js'; +import { AccountWallet, AztecAddress, BatchCall, computeMessageSecretHash, generatePublicKey } from '@aztec/aztec.js'; import { CompleteAddress, Fr, GrumpkinPrivateKey, GrumpkinScalar, getContractDeploymentInfo } from '@aztec/circuits.js'; import { DebugLogger } from '@aztec/foundation/log'; import { EscrowContractAbi } from '@aztec/noir-contracts/artifacts'; -import { EscrowContract, PrivateTokenContract } from '@aztec/noir-contracts/types'; -import { AztecRPC, PublicKey } from '@aztec/types'; +import { EscrowContract, TokenContract } from '@aztec/noir-contracts/types'; +import { AztecRPC, PublicKey, TxStatus } from '@aztec/types'; import { setup } from './fixtures/utils.js'; @@ -17,7 +17,7 @@ describe('e2e_escrow_contract', () => { let accounts: CompleteAddress[]; let logger: DebugLogger; - let privateTokenContract: PrivateTokenContract; + let token: TokenContract; let escrowContract: EscrowContract; let owner: AztecAddress; let recipient: AztecAddress; @@ -51,8 +51,19 @@ describe('e2e_escrow_contract', () => { logger(`Escrow contract deployed at ${escrowContract.address}`); // Deploy Private Token contract and mint funds for the escrow contract - privateTokenContract = await PrivateTokenContract.deploy(wallet, 100n, escrowContract.address).send().deployed(); - logger(`Token contract deployed at ${privateTokenContract.address}`); + token = await TokenContract.deploy(wallet).send().deployed(); + + expect((await token.methods._initialize({ address: owner }).send().wait()).status).toBe(TxStatus.MINED); + + const secret = Fr.random(); + const secretHash = await computeMessageSecretHash(secret); + + expect((await token.methods.mint_private(100n, secretHash).send().wait()).status).toEqual(TxStatus.MINED); + expect( + (await token.methods.redeem_shield({ address: escrowContract.address }, 100n, secret).send().wait()).status, + ).toEqual(TxStatus.MINED); + + logger(`Token contract deployed at ${token.address}`); }, 100_000); afterEach(async () => { @@ -61,7 +72,7 @@ describe('e2e_escrow_contract', () => { }, 30_000); const expectBalance = async (who: AztecAddress, expectedBalance: bigint) => { - const balance = await privateTokenContract.methods.getBalance(who).view({ from: who }); + const balance = await token.methods.balance_of_private({ address: who }).view({ from: who }); logger(`Account ${who} balance: ${balance}`); expect(balance).toBe(expectedBalance); }; @@ -72,7 +83,7 @@ describe('e2e_escrow_contract', () => { await expectBalance(escrowContract.address, 100n); logger(`Withdrawing funds from token contract to ${recipient}`); - await escrowContract.methods.withdraw(privateTokenContract.address, 30, recipient).send().wait(); + await escrowContract.methods.withdraw(token.address, 30, recipient).send().wait(); await expectBalance(owner, 0n); await expectBalance(recipient, 30n); @@ -81,21 +92,25 @@ describe('e2e_escrow_contract', () => { it('refuses to withdraw funds as a non-owner', async () => { await expect( - escrowContract - .withWallet(recipientWallet) - .methods.withdraw(privateTokenContract.address, 30, recipient) - .simulate(), + escrowContract.withWallet(recipientWallet).methods.withdraw(token.address, 30, recipient).simulate(), ).rejects.toThrowError(); }, 60_000); it('moves funds using multiple keys on the same tx (#1010)', async () => { logger(`Minting funds in token contract to ${owner}`); - await privateTokenContract.methods.mint(50, owner).send().wait(); + const secret = Fr.random(); + const secretHash = await computeMessageSecretHash(secret); + + expect((await token.methods.mint_private(50n, secretHash).send().wait()).status).toEqual(TxStatus.MINED); + expect((await token.methods.redeem_shield({ address: owner }, 50n, secret).send().wait()).status).toEqual( + TxStatus.MINED, + ); + await expectBalance(owner, 50n); const actions = [ - privateTokenContract.methods.transfer(10, recipient).request(), - escrowContract.methods.withdraw(privateTokenContract.address, 20, recipient).request(), + token.methods.transfer({ address: owner }, { address: recipient }, 10, 0).request(), + escrowContract.methods.withdraw(token.address, 20, recipient).request(), ]; await new BatchCall(wallet, actions).send().wait(); diff --git a/yarn-project/end-to-end/src/e2e_multiple_accounts_1_enc_key.test.ts b/yarn-project/end-to-end/src/e2e_multiple_accounts_1_enc_key.test.ts index 2c86c7007dd5..806c48f41117 100644 --- a/yarn-project/end-to-end/src/e2e_multiple_accounts_1_enc_key.test.ts +++ b/yarn-project/end-to-end/src/e2e_multiple_accounts_1_enc_key.test.ts @@ -1,9 +1,9 @@ import { AztecNodeService } from '@aztec/aztec-node'; import { AztecRPCServer } from '@aztec/aztec-rpc'; -import { AztecAddress, Wallet, generatePublicKey, getSchnorrAccount } from '@aztec/aztec.js'; -import { GrumpkinScalar } from '@aztec/circuits.js'; +import { AztecAddress, Wallet, computeMessageSecretHash, generatePublicKey, getSchnorrAccount } from '@aztec/aztec.js'; +import { Fr, GrumpkinScalar } from '@aztec/circuits.js'; import { DebugLogger } from '@aztec/foundation/log'; -import { PrivateTokenContract } from '@aztec/noir-contracts/types'; +import { TokenContract } from '@aztec/noir-contracts/types'; import { AztecRPC, TxStatus } from '@aztec/types'; import { expectsNumOfEncryptedLogsInTheLastBlockToBe, setup } from './fixtures/utils.js'; @@ -15,7 +15,7 @@ describe('e2e_multiple_accounts_1_enc_key', () => { const accounts: AztecAddress[] = []; let logger: DebugLogger; - let privateTokenAddress: AztecAddress; + let tokenAddress: AztecAddress; const initialBalance = 987n; const numAccounts = 3; @@ -42,12 +42,20 @@ describe('e2e_multiple_accounts_1_enc_key', () => { expect(account.publicKey).toEqual(encryptionPublicKey); } - logger(`Deploying Private Token...`); - privateTokenAddress = await PrivateTokenContract.deploy(wallets[0], initialBalance, accounts[0]) - .send() - .deployed() - .then(c => c.address); - logger(`Private Token deployed at ${privateTokenAddress}`); + logger(`Deploying Token...`); + const token = await TokenContract.deploy(wallets[0]).send().deployed(); + tokenAddress = token.address; + logger(`Token deployed at ${tokenAddress}`); + + expect((await token.methods._initialize({ address: accounts[0] }).send().wait()).status).toBe(TxStatus.MINED); + + const secret = Fr.random(); + const secretHash = await computeMessageSecretHash(secret); + + expect((await token.methods.mint_private(initialBalance, secretHash).send().wait()).status).toEqual(TxStatus.MINED); + expect( + (await token.methods.redeem_shield({ address: accounts[0] }, initialBalance, secret).send().wait()).status, + ).toEqual(TxStatus.MINED); }, 100_000); afterEach(async () => { @@ -62,8 +70,8 @@ describe('e2e_multiple_accounts_1_enc_key', () => { const owner = accounts[userIndex]; // Then check the balance - const contractWithWallet = await PrivateTokenContract.at(privateTokenAddress, wallet); - const balance = await contractWithWallet.methods.getBalance(owner).view({ from: owner }); + const contractWithWallet = await TokenContract.at(tokenAddress, wallet); + const balance = await contractWithWallet.methods.balance_of_private({ address: owner }).view({ from: owner }); logger(`Account ${owner} balance: ${balance}`); expect(balance).toBe(expectedBalance); }; @@ -79,12 +87,12 @@ describe('e2e_multiple_accounts_1_enc_key', () => { const sender = accounts[senderIndex]; const receiver = accounts[receiverIndex]; - const contractWithWallet = await PrivateTokenContract.at(privateTokenAddress, wallets[senderIndex]); - - const tx = contractWithWallet.methods.transfer(transferAmount, receiver).send(); - await tx.isMined({ interval: 0.1 }); - const receipt = await tx.getReceipt(); + const contractWithWallet = await TokenContract.at(tokenAddress, wallets[senderIndex]); + const receipt = await contractWithWallet.methods + .transfer({ address: sender }, { address: receiver }, transferAmount, 0) + .send() + .wait(); expect(receipt.status).toBe(TxStatus.MINED); for (let i = 0; i < expectedBalances.length; i++) { diff --git a/yarn-project/end-to-end/src/e2e_sandbox_example.test.ts b/yarn-project/end-to-end/src/e2e_sandbox_example.test.ts index d71c366c869b..eda0691b38e7 100644 --- a/yarn-project/end-to-end/src/e2e_sandbox_example.test.ts +++ b/yarn-project/end-to-end/src/e2e_sandbox_example.test.ts @@ -4,6 +4,8 @@ // docs:start:imports import { AztecRPC, + TxStatus, + computeMessageSecretHash, createAztecRpcClient, createDebugLogger, getSchnorrAccount, @@ -15,9 +17,9 @@ import { /* eslint-enable @typescript-eslint/no-unused-vars */ // Note: this is a hack to make the docs use http://localhost:8080 and CI to use the SANDBOX_URL import { createAztecRpcClient as createAztecRpcClient2 } from '@aztec/aztec.js'; -import { GrumpkinScalar } from '@aztec/circuits.js'; +import { Fr, GrumpkinScalar } from '@aztec/circuits.js'; import { defaultFetch } from '@aztec/foundation/json-rpc/client'; -import { PrivateTokenContract } from '@aztec/noir-contracts/types'; +import { TokenContract } from '@aztec/noir-contracts/types'; const { SANDBOX_URL = 'http://localhost:8080' } = process.env; @@ -104,15 +106,29 @@ describe('e2e_sandbox_example', () => { const initialSupply = 1_000_000n; logger(`Deploying private token contract minting an initial ${initialSupply} tokens to Alice...`); - const contract = await PrivateTokenContract.deploy( - aztecRpc, - initialSupply, // the initial supply - alice, // the owner of the initial supply - ) - .send() - .deployed(); + const contract = await TokenContract.deploy(aztecRpc).send().deployed(); + + // Create the contract abstraction and link to Alice's wallet for future signing + const tokenContractAlice = await TokenContract.at(contract.address, await accounts[0].getWallet()); + + expect((await tokenContractAlice.methods._initialize({ address: alice }).send().wait()).status).toBe( + TxStatus.MINED, + ); + expect((await tokenContractAlice.methods.set_minter({ address: bob }, 1).send().wait()).status).toBe( + TxStatus.MINED, + ); logger(`Contract successfully deployed at address ${contract.address.toShortString()}`); + + const secret = Fr.random(); + const secretHash = await computeMessageSecretHash(secret); + + expect((await tokenContractAlice.methods.mint_private(initialSupply, secretHash).send().wait()).status).toEqual( + TxStatus.MINED, + ); + expect( + (await tokenContractAlice.methods.redeem_shield({ address: alice }, initialSupply, secret).send().wait()).status, + ).toEqual(TxStatus.MINED); // docs:end:Deployment // ensure that private token contract is registered in the rpc @@ -122,16 +138,13 @@ describe('e2e_sandbox_example', () => { ////////////// QUERYING THE TOKEN BALANCE FOR EACH ACCOUNT ////////////// - // Create the contract abstraction and link to Alice's wallet for future signing - const tokenContractAlice = await PrivateTokenContract.at(contract.address, await accounts[0].getWallet()); - // Bob wants to mint some funds, the contract is already deployed, create an abstraction and link it his wallet - const tokenContractBob = await PrivateTokenContract.at(contract.address, await accounts[1].getWallet()); + const tokenContractBob = await TokenContract.at(contract.address, await accounts[1].getWallet()); - let aliceBalance = await tokenContractAlice.methods.getBalance(alice).view(); + let aliceBalance = await tokenContractAlice.methods.balance_of_private({ address: alice }).view(); logger(`Alice's balance ${aliceBalance}`); - let bobBalance = await tokenContractBob.methods.getBalance(bob).view(); + let bobBalance = await tokenContractBob.methods.balance_of_private({ address: bob }).view(); logger(`Bob's balance ${bobBalance}`); // docs:end:Balance @@ -145,13 +158,13 @@ describe('e2e_sandbox_example', () => { // We will now transfer tokens from ALice to Bob const transferQuantity = 543n; logger(`Transferring ${transferQuantity} tokens from Alice to Bob...`); - await tokenContractAlice.methods.transfer(transferQuantity, bob).send().wait(); + await tokenContractAlice.methods.transfer({ address: alice }, { address: bob }, transferQuantity, 0).send().wait(); // Check the new balances - aliceBalance = await tokenContractAlice.methods.getBalance(alice).view(); + aliceBalance = await tokenContractAlice.methods.balance_of_private({ address: alice }).view(); logger(`Alice's balance ${aliceBalance}`); - bobBalance = await tokenContractBob.methods.getBalance(bob).view(); + bobBalance = await tokenContractBob.methods.balance_of_private({ address: bob }).view(); logger(`Bob's balance ${bobBalance}`); // docs:end:Transfer @@ -164,13 +177,18 @@ describe('e2e_sandbox_example', () => { // Now mint some further funds for Bob const mintQuantity = 10_000n; logger(`Minting ${mintQuantity} tokens to Bob...`); - await tokenContractBob.methods.mint(mintQuantity, bob).send().wait(); + expect((await tokenContractBob.methods.mint_private(mintQuantity, secretHash).send().wait()).status).toEqual( + TxStatus.MINED, + ); + expect( + (await tokenContractBob.methods.redeem_shield({ address: bob }, mintQuantity, secret).send().wait()).status, + ).toEqual(TxStatus.MINED); // Check the new balances - aliceBalance = await tokenContractAlice.methods.getBalance(alice).view(); + aliceBalance = await tokenContractAlice.methods.balance_of_private({ address: alice }).view(); logger(`Alice's balance ${aliceBalance}`); - bobBalance = await tokenContractBob.methods.getBalance(bob).view(); + bobBalance = await tokenContractBob.methods.balance_of_private({ address: bob }).view(); logger(`Bob's balance ${bobBalance}`); // docs:end:Mint diff --git a/yarn-project/end-to-end/src/guides/writing_an_account_contract.test.ts b/yarn-project/end-to-end/src/guides/writing_an_account_contract.test.ts index 68f762c7e700..6d5566e7142c 100644 --- a/yarn-project/end-to-end/src/guides/writing_an_account_contract.test.ts +++ b/yarn-project/end-to-end/src/guides/writing_an_account_contract.test.ts @@ -6,14 +6,16 @@ import { Entrypoint, FunctionCall, NodeInfo, + TxStatus, buildPayload, buildTxExecutionRequest, + computeMessageSecretHash, hashPayload, } from '@aztec/aztec.js'; -import { GrumpkinPrivateKey, GrumpkinScalar } from '@aztec/circuits.js'; +import { Fr, GrumpkinPrivateKey, GrumpkinScalar } from '@aztec/circuits.js'; import { Schnorr } from '@aztec/circuits.js/barretenberg'; import { ContractAbi } from '@aztec/foundation/abi'; -import { PrivateTokenContract, SchnorrHardcodedAccountContractAbi } from '@aztec/noir-contracts/types'; +import { SchnorrHardcodedAccountContractAbi, TokenContract } from '@aztec/noir-contracts/types'; import { setup } from '../fixtures/utils.js'; @@ -89,24 +91,30 @@ describe('guides/writing_an_account_contract', () => { logger(`Deployed account contract at ${address}`); // docs:start:account-contract-works - const token = await PrivateTokenContract.deploy(wallet, 100, address).send().deployed(); + const token = await TokenContract.deploy(wallet).send().deployed(); logger(`Deployed token contract at ${token.address}`); + expect((await token.methods._initialize({ address }).send().wait()).status).toBe(TxStatus.MINED); - await token.methods.mint(50, address).send().wait(); - const balance = await token.methods.getBalance(address).view(); + const secret = Fr.random(); + const secretHash = await computeMessageSecretHash(secret); + + expect((await token.methods.mint_private(50, secretHash).send().wait()).status).toBe(TxStatus.MINED); + expect((await token.methods.redeem_shield({ address }, 50, secret).send().wait()).status).toEqual(TxStatus.MINED); + + const balance = await token.methods.balance_of_private({ address }).view(); logger(`Balance of wallet is now ${balance}`); // docs:end:account-contract-works - expect(balance).toEqual(150n); + expect(balance).toEqual(50n); // docs:start:account-contract-fails const wrongKey = GrumpkinScalar.random(); const wrongAccountContract = new SchnorrHardcodedKeyAccountContract(wrongKey); const wrongAccount = new Account(rpc, encryptionPrivateKey, wrongAccountContract, wallet.getCompleteAddress()); const wrongWallet = await wrongAccount.getWallet(); - const tokenWithWrongWallet = await PrivateTokenContract.at(token.address, wrongWallet); + const tokenWithWrongWallet = await TokenContract.at(token.address, wrongWallet); try { - await tokenWithWrongWallet.methods.mint(200, address).simulate(); + await tokenWithWrongWallet.methods.mint_private(200, secretHash).simulate(); } catch (err) { logger(`Failed to send tx: ${err}`); } diff --git a/yarn-project/noir-contracts/src/contracts/escrow_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/escrow_contract/src/main.nr index 81131fae5e38..b287671792b7 100644 --- a/yarn-project/noir-contracts/src/contracts/escrow_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/escrow_contract/src/main.nr @@ -1,5 +1,4 @@ mod address_note; -mod private_token_contract_interface; // Sample escrow contract that stores a balance of a private token on behalf of an owner. contract Escrow { @@ -14,6 +13,7 @@ contract Escrow { utils as note_utils, }, oracle::get_public_key::get_public_key, + oracle::compute_selector::compute_selector, state_vars::set::Set, }; @@ -23,8 +23,6 @@ contract Escrow { ADDRESS_NOTE_LEN, }; - use crate::private_token_contract_interface::PrivateTokenPrivateContextInterface; - struct Storage { owners: Set, } @@ -59,9 +57,9 @@ contract Escrow { // Withdraws balance. Requires that msg.sender is registered as an owner. #[aztec(private)] fn withdraw( - token: pub Field, - amount: pub Field, - recipient: pub Field, + token: Field, + amount: Field, + recipient: Field, ) { let this = context.this_address(); let sender = context.msg_sender(); @@ -75,7 +73,12 @@ contract Escrow { assert(note.address == sender); assert(note.owner == this); - let _callStackItem = PrivateTokenPrivateContextInterface::at(token).transfer(&mut context, amount, recipient); + let selector = compute_selector("transfer((Field),(Field),Field,Field)"); + let _callStackItem = context.call_private_function( + token, + selector, + [this, recipient, amount, 0] + ); } unconstrained fn compute_note_hash_and_nullifier(contract_address: Field, nonce: Field, storage_slot: Field, preimage: [Field; ADDRESS_NOTE_LEN]) -> [Field; 4] { diff --git a/yarn-project/noir-contracts/src/contracts/escrow_contract/src/private_token_contract_interface.nr b/yarn-project/noir-contracts/src/contracts/escrow_contract/src/private_token_contract_interface.nr deleted file mode 120000 index 0f8207f8b98e..000000000000 --- a/yarn-project/noir-contracts/src/contracts/escrow_contract/src/private_token_contract_interface.nr +++ /dev/null @@ -1 +0,0 @@ -../../private_token_contract/src/interface.nr \ No newline at end of file