From a0e408020fe93bfd3d95e36cf032c6a794234f4e Mon Sep 17 00:00:00 2001 From: Westlad Date: Mon, 27 Mar 2023 13:48:13 +0100 Subject: [PATCH 01/11] refactor: move offchain code --- cli/lib/nf3.mjs | 104 +++++++++++------- nightfall-client/src/services/burn.mjs | 5 +- .../src/services/commitment-storage.mjs | 20 ++++ nightfall-client/src/services/deposit.mjs | 5 +- nightfall-client/src/services/tokenise.mjs | 5 +- nightfall-client/src/services/transfer.mjs | 5 +- nightfall-client/src/services/transform.mjs | 5 +- nightfall-client/src/services/withdraw.mjs | 5 +- .../src/utils/submitTransaction.mjs | 65 ----------- 9 files changed, 95 insertions(+), 124 deletions(-) delete mode 100644 nightfall-client/src/utils/submitTransaction.mjs diff --git a/cli/lib/nf3.mjs b/cli/lib/nf3.mjs index a7debd70b..818113407 100644 --- a/cli/lib/nf3.mjs +++ b/cli/lib/nf3.mjs @@ -108,6 +108,8 @@ class Nf3 { clientAuthenticationKey; + NEXT_N_PROPOSERS = 3; + // min fee or reward one should hold for withdaw // in State contract. minL1Balance = DEFAULT_MIN_L1_WITHDRAW; @@ -534,7 +536,7 @@ class Nf3 { if (res.data.error) { throw new Error(res.data.error); } - return res.status; + return this.sendOffchainTransaction(res.data.transaction); } /** @@ -568,7 +570,7 @@ class Nf3 { if (res.data.error) { throw new Error(res.data.error); } - return res.status; + return this.sendOffchainTransaction(res.data.transaction); } /** @@ -604,7 +606,7 @@ class Nf3 { if (res.data.error && res.data.error === 'No suitable commitments') { throw new Error('No suitable commitments'); } - return res.status; + return this.sendOffchainTransaction(res.data.transaction); } /** @@ -731,23 +733,21 @@ class Nf3 { if (res.data.error) { throw new Error(res.data.error); } - if (!offchain) { - return new Promise((resolve, reject) => { - userQueue.push(async () => { - try { - const receipt = await this.submitTransaction( - res.data.txDataToSign, - this.shieldContractAddress, - 0, - ); - resolve(receipt); - } catch (err) { - reject(err); - } - }); + if (offchain) return this.sendOffchainTransaction(res.data.transaction); + return new Promise((resolve, reject) => { + userQueue.push(async () => { + try { + const receipt = await this.submitTransaction( + res.data.txDataToSign, + this.shieldContractAddress, + 0, + ); + resolve(receipt); + } catch (err) { + reject(err); + } }); - } - return res.status; + }); } /** @@ -797,23 +797,21 @@ class Nf3 { throw new Error(res.data.error); } this.latestWithdrawHash = res.data.transaction.transactionHash; - if (!offchain) { - return new Promise((resolve, reject) => { - userQueue.push(async () => { - try { - const receipt = await this.submitTransaction( - res.data.txDataToSign, - this.shieldContractAddress, - 0, - ); - resolve(receipt); - } catch (err) { - reject(err); - } - }); + if (offchain) return this.sendOffchainTransaction(res.data.transaction); + return new Promise((resolve, reject) => { + userQueue.push(async () => { + try { + const receipt = await this.submitTransaction( + res.data.txDataToSign, + this.shieldContractAddress, + 0, + ); + resolve(receipt); + } catch (err) { + reject(err); + } }); - } - return res.status; + }); } /** @@ -1308,19 +1306,43 @@ class Nf3 { } /** - Send offchain transaction to Optimist + Send offchain transaction to all Optimists that the chain knows about @method @async @param {string} transaction @returns {array} A promise that resolves to the API call status */ async sendOffchainTransaction(transaction) { - const res = axios.post( - `${this.optimistBaseUrl}/proposer/offchain-transaction`, - { transaction }, - { timeout: 3600000 }, + // dig up connection peers + const currentProposer = await this.stateContract.methods.currentProposer().call(); + const peerList = { [currentProposer.thisAddress]: currentProposer.url }; + let nextProposer = await this.stateContract.methods + .proposers(currentProposer.nextAddress) + .call(); + let proposerIdx = 0; + while ( + currentProposer.thisAddress !== nextProposer.thisAddress && + proposerIdx <= this.NEXT_N_PROPOSERS + ) { + peerList[nextProposer.thisAddress] = nextProposer.url; + // eslint-disable-next-line no-await-in-loop + nextProposer = await this.stateContract.methods.proposers(nextProposer.nextAddress).call(); + proposerIdx += 1; + } + + logger.debug({ msg: 'Peer List', peerList }); + await Promise.any( + Object.keys(peerList).map(async address => { + logger.debug( + `offchain transaction - calling ${peerList[address]}/proposer/offchain-transaction`, + ); + return axios.post( + `${peerList[address]}/proposer/offchain-transaction`, + { transaction }, + { timeout: 3600000 }, + ); + }), ); - return res.status; } /** diff --git a/nightfall-client/src/services/burn.mjs b/nightfall-client/src/services/burn.mjs index 466073b1e..9a256bd47 100644 --- a/nightfall-client/src/services/burn.mjs +++ b/nightfall-client/src/services/burn.mjs @@ -9,10 +9,9 @@ import { import gen from 'general-number'; import Transaction from '@polygon-nightfall/common-files/classes/transaction.mjs'; import { compressProof } from '@polygon-nightfall/common-files/utils/curve-maths/curves.mjs'; -import { clearPending } from './commitment-storage.mjs'; +import { clearPending, saveExtendedTransaction } from './commitment-storage.mjs'; import { getCommitmentInfo } from '../utils/getCommitmentInfo.mjs'; import { computeCircuitInputs } from '../utils/computeCircuitInputs.mjs'; -import { submitTransaction } from '../utils/submitTransaction.mjs'; import { ZkpKeys } from './keys.mjs'; const { VK_IDS } = config; @@ -124,7 +123,7 @@ async function burn(burnParams) { const rawTransaction = await shieldContractInstance.methods .submitTransaction(Transaction.buildSolidityStruct(transaction)) .encodeABI(); - await submitTransaction( + await saveExtendedTransaction( transaction, commitmentsInfo, compressedZkpPublicKey, diff --git a/nightfall-client/src/services/commitment-storage.mjs b/nightfall-client/src/services/commitment-storage.mjs index e6a2c991b..30aff74a8 100644 --- a/nightfall-client/src/services/commitment-storage.mjs +++ b/nightfall-client/src/services/commitment-storage.mjs @@ -1072,3 +1072,23 @@ export async function getCommitmentsDepositedRollbacked(compressedZkpPublicKey) return db.collection(COMMITMENTS_COLLECTION).find(query).toArray(); } + +// saves a transaction with extended information about nullifiers and commitments +export const saveExtendedTransaction = async ( + transaction, + commitmentsInfo, + compressedZkpPublicKey, + nullifierKey, +) => { + // Store new commitments that are ours. + logger.debug({ msg: 'storing commitments', commitments: commitmentsInfo.newCommitments }); + const storeNewCommitments = commitmentsInfo.newCommitments + .filter(c => c.compressedZkpPublicKey.hex(32) === compressedZkpPublicKey.hex(32)) + .map(c => storeCommitment(c, nullifierKey)); + + logger.debug({ msg: 'nullifying commitments', commitments: commitmentsInfo.oldCommitments }); + const nullifyOldCommitments = commitmentsInfo.oldCommitments.map(c => + markNullified(c, transaction), + ); + await Promise.all([...storeNewCommitments, ...nullifyOldCommitments]); +}; diff --git a/nightfall-client/src/services/deposit.mjs b/nightfall-client/src/services/deposit.mjs index 5ab46c8bc..30e1fb9ed 100644 --- a/nightfall-client/src/services/deposit.mjs +++ b/nightfall-client/src/services/deposit.mjs @@ -21,8 +21,7 @@ import { Commitment, Transaction } from '../classes/index.mjs'; import { ZkpKeys } from './keys.mjs'; import { computeCircuitInputs } from '../utils/computeCircuitInputs.mjs'; import { getCommitmentInfo } from '../utils/getCommitmentInfo.mjs'; -import { submitTransaction } from '../utils/submitTransaction.mjs'; -import { getCommitmentByHash } from './commitment-storage.mjs'; +import { getCommitmentByHash, saveExtendedTransaction } from './commitment-storage.mjs'; const { VK_IDS } = config; const { SHIELD_CONTRACT_NAME, BN128_GROUP_ORDER, DEPOSIT, DEPOSIT_FEE } = constants; @@ -186,7 +185,7 @@ async function deposit(depositParams) { const rawTransaction = await shieldContractInstance.methods .submitTransaction(Transaction.buildSolidityStruct(transaction)) .encodeABI(); - await submitTransaction( + await saveExtendedTransaction( transaction, commitmentsInfo, compressedZkpPublicKey, diff --git a/nightfall-client/src/services/tokenise.mjs b/nightfall-client/src/services/tokenise.mjs index 41347b2a8..ca679c09d 100644 --- a/nightfall-client/src/services/tokenise.mjs +++ b/nightfall-client/src/services/tokenise.mjs @@ -12,9 +12,8 @@ import gen from 'general-number'; import { ZkpKeys } from './keys.mjs'; import { Commitment, Transaction } from '../classes/index.mjs'; import { computeCircuitInputs } from '../utils/computeCircuitInputs.mjs'; -import { clearPending } from './commitment-storage.mjs'; +import { clearPending, saveExtendedTransaction } from './commitment-storage.mjs'; import { getCommitmentInfo } from '../utils/getCommitmentInfo.mjs'; -import { submitTransaction } from '../utils/submitTransaction.mjs'; const { VK_IDS } = config; const { SHIELD_CONTRACT_NAME, BN128_GROUP_ORDER, TOKENISE } = constants; @@ -129,7 +128,7 @@ async function tokenise(items) { const rawTransaction = await shieldContractInstance.methods .submitTransaction(Transaction.buildSolidityStruct(transaction)) .encodeABI(); - await submitTransaction( + await saveExtendedTransaction( transaction, commitmentsInfo, compressedZkpPublicKey, diff --git a/nightfall-client/src/services/transfer.mjs b/nightfall-client/src/services/transfer.mjs index 811ff258a..b50f17ac9 100644 --- a/nightfall-client/src/services/transfer.mjs +++ b/nightfall-client/src/services/transfer.mjs @@ -22,9 +22,8 @@ import { Transaction } from '../classes/index.mjs'; import { ZkpKeys } from './keys.mjs'; import { computeCircuitInputs } from '../utils/computeCircuitInputs.mjs'; import { encrypt, genEphemeralKeys, packSecrets } from './kem-dem.mjs'; -import { clearPending } from './commitment-storage.mjs'; +import { clearPending, saveExtendedTransaction } from './commitment-storage.mjs'; import { getCommitmentInfo } from '../utils/getCommitmentInfo.mjs'; -import { submitTransaction } from '../utils/submitTransaction.mjs'; const { VK_IDS } = config; const { SHIELD_CONTRACT_NAME, TRANSFER } = constants; @@ -161,7 +160,7 @@ async function transfer(transferParams) { const rawTransaction = await shieldContractInstance.methods .submitTransaction(Transaction.buildSolidityStruct(transaction)) .encodeABI(); - await submitTransaction( + await saveExtendedTransaction( transaction, commitmentsInfo, compressedZkpPublicKey, diff --git a/nightfall-client/src/services/transform.mjs b/nightfall-client/src/services/transform.mjs index 7961f2a84..bc75c4bde 100644 --- a/nightfall-client/src/services/transform.mjs +++ b/nightfall-client/src/services/transform.mjs @@ -12,10 +12,9 @@ import { import { compressProof } from '@polygon-nightfall/common-files/utils/curve-maths/curves.mjs'; import gen from 'general-number'; import { Commitment, Transaction } from '../classes/index.mjs'; -import { clearPending } from './commitment-storage.mjs'; +import { clearPending, saveExtendedTransaction } from './commitment-storage.mjs'; import { getCommitmentInfo } from '../utils/getCommitmentInfo.mjs'; import { computeCircuitInputs } from '../utils/computeCircuitInputs.mjs'; -import { submitTransaction } from '../utils/submitTransaction.mjs'; import { ZkpKeys } from './keys.mjs'; const { VK_IDS } = config; @@ -176,7 +175,7 @@ async function transform(transformParams) { .submitTransaction(Transaction.buildSolidityStruct(transaction)) .encodeABI(); - await submitTransaction( + await saveExtendedTransaction( transaction, commitmentInfo, compressedZkpPublicKey, diff --git a/nightfall-client/src/services/withdraw.mjs b/nightfall-client/src/services/withdraw.mjs index fa60090ad..ddfc68133 100644 --- a/nightfall-client/src/services/withdraw.mjs +++ b/nightfall-client/src/services/withdraw.mjs @@ -17,9 +17,8 @@ import { } from '@polygon-nightfall/common-files/utils/worker-calls.mjs'; import { Transaction } from '../classes/index.mjs'; import { computeCircuitInputs } from '../utils/computeCircuitInputs.mjs'; -import { clearPending } from './commitment-storage.mjs'; +import { clearPending, saveExtendedTransaction } from './commitment-storage.mjs'; import { getCommitmentInfo } from '../utils/getCommitmentInfo.mjs'; -import { submitTransaction } from '../utils/submitTransaction.mjs'; import { ZkpKeys } from './keys.mjs'; const { VK_IDS } = config; @@ -137,7 +136,7 @@ async function withdraw(withdrawParams) { const rawTransaction = await shieldContractInstance.methods .submitTransaction(Transaction.buildSolidityStruct(transaction)) .encodeABI(); - await submitTransaction( + await saveExtendedTransaction( transaction, commitmentsInfo, compressedZkpPublicKey, diff --git a/nightfall-client/src/utils/submitTransaction.mjs b/nightfall-client/src/utils/submitTransaction.mjs deleted file mode 100644 index a472a66e4..000000000 --- a/nightfall-client/src/utils/submitTransaction.mjs +++ /dev/null @@ -1,65 +0,0 @@ -import axios from 'axios'; -import logger from '@polygon-nightfall/common-files/utils/logger.mjs'; -import constants from '@polygon-nightfall/common-files/constants/index.mjs'; -import { getContractInstance } from '@polygon-nightfall/common-files/utils/contract.mjs'; -import { markNullified, storeCommitment } from '../services/commitment-storage.mjs'; - -const { STATE_CONTRACT_NAME } = constants; - -const NEXT_N_PROPOSERS = 3; - -// eslint-disable-next-line import/prefer-default-export -export const submitTransaction = async ( - transaction, - commitmentsInfo, - compressedZkpPublicKey, - nullifierKey, - offchain, -) => { - // Store new commitments that are ours. - logger.debug({ msg: 'storing commitments', commitments: commitmentsInfo.newCommitments }); - const storeNewCommitments = commitmentsInfo.newCommitments - .filter(c => c.compressedZkpPublicKey.hex(32) === compressedZkpPublicKey.hex(32)) - .map(c => storeCommitment(c, nullifierKey)); - - logger.debug({ msg: 'nullifying commitments', commitments: commitmentsInfo.oldCommitments }); - const nullifyOldCommitments = commitmentsInfo.oldCommitments.map(c => - markNullified(c, transaction), - ); - - await Promise.all([...storeNewCommitments, ...nullifyOldCommitments]); - - if (offchain) { - // dig up connection peers - const stateContractInstance = await getContractInstance(STATE_CONTRACT_NAME); - const currentProposer = await stateContractInstance.methods.currentProposer().call(); - const peerList = { [currentProposer.thisAddress]: currentProposer.url }; - let nextProposer = await stateContractInstance.methods - .proposers(currentProposer.nextAddress) - .call(); - let proposerIdx = 0; - while ( - currentProposer.thisAddress !== nextProposer.thisAddress && - proposerIdx <= NEXT_N_PROPOSERS - ) { - peerList[nextProposer.thisAddress] = nextProposer.url; - // eslint-disable-next-line no-await-in-loop - nextProposer = await stateContractInstance.methods.proposers(nextProposer.nextAddress).call(); - proposerIdx += 1; - } - - logger.debug({ msg: 'Peer List', peerList }); - await Promise.any( - Object.keys(peerList).map(async address => { - logger.debug( - `offchain transaction - calling ${peerList[address]}/proposer/offchain-transaction`, - ); - return axios.post( - `${peerList[address]}/proposer/offchain-transaction`, - { transaction }, - { timeout: 3600000 }, - ); - }), - ); - } -}; From 3f3c7176c084f9501a13e82c600e7810ac6cd12e Mon Sep 17 00:00:00 2001 From: Westlad Date: Mon, 27 Mar 2023 13:51:01 +0100 Subject: [PATCH 02/11] refactor: remove extraneous export --- nightfall-client/src/services/commitment-storage.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nightfall-client/src/services/commitment-storage.mjs b/nightfall-client/src/services/commitment-storage.mjs index 30aff74a8..99ecab352 100644 --- a/nightfall-client/src/services/commitment-storage.mjs +++ b/nightfall-client/src/services/commitment-storage.mjs @@ -129,7 +129,7 @@ export async function markPending(commitment) { } // function to mark a commitment as nullified for a mongo db -export async function markNullified(commitment, transaction) { +async function markNullified(commitment, transaction) { const connection = await mongo.connection(MONGO_URL); const query = { _id: commitment.hash.hex(32) }; const update = { From 28c1e8cf55389337fbab9b7ac5eead1fce1fb94b Mon Sep 17 00:00:00 2001 From: Westlad Date: Tue, 28 Mar 2023 11:23:58 +0100 Subject: [PATCH 03/11] fix: repoint tests to local optimist port, there being no proposers to proxy the requests --- test/adversary.test.mjs | 2 +- test/circuits.test.mjs | 5 ++++- test/e2e/tokens/erc1155.test.mjs | 5 ++++- test/e2e/tokens/erc20.test.mjs | 5 ++++- test/e2e/tokens/erc721.test.mjs | 5 ++++- test/e2e/tokens/l2tokenisation.test.mjs | 5 ++++- test/fee-and-reward-periodic-payment.test.mjs | 5 ++++- test/gas.test.mjs | 5 ++++- test/multisig/administrator.test.mjs | 6 +++--- test/optimist-resync.test.mjs | 8 ++++---- test/utils.mjs | 2 +- test/x509.test.mjs | 5 ++++- 12 files changed, 41 insertions(+), 17 deletions(-) diff --git a/test/adversary.test.mjs b/test/adversary.test.mjs index 737489c60..642de93e5 100644 --- a/test/adversary.test.mjs +++ b/test/adversary.test.mjs @@ -156,7 +156,7 @@ describe('Testing with an adversary', () => { // Proposer registration await nf3AdversarialProposer.registerProposer( - 'http://optimist', + 'http://localhost:8081', await nf3AdversarialProposer.getMinimumStake(), ); diff --git a/test/circuits.test.mjs b/test/circuits.test.mjs index b6c0d2a43..60d780e87 100644 --- a/test/circuits.test.mjs +++ b/test/circuits.test.mjs @@ -39,7 +39,10 @@ describe('General Circuit Test', () => { before(async () => { await nf3Proposer.init(mnemonics.proposer); // we must set the URL from the point of view of the client container - await nf3Proposer.registerProposer('http://optimist', await nf3Proposer.getMinimumStake()); + await nf3Proposer.registerProposer( + 'http://localhost:8081', + await nf3Proposer.getMinimumStake(), + ); await nf3Proposer.startProposer(); diff --git a/test/e2e/tokens/erc1155.test.mjs b/test/e2e/tokens/erc1155.test.mjs index 7824d15fd..16660014f 100644 --- a/test/e2e/tokens/erc1155.test.mjs +++ b/test/e2e/tokens/erc1155.test.mjs @@ -67,7 +67,10 @@ describe('ERC1155 tests', () => { await nf3User2.init(mnemonics.user2); await nf3Proposer.init(mnemonics.proposer); - await nf3Proposer.registerProposer('http://optimist', await nf3Proposer.getMinimumStake()); + await nf3Proposer.registerProposer( + 'http://localhost:8081', + await nf3Proposer.getMinimumStake(), + ); // Proposer listening for incoming events const newGasBlockEmitter = await nf3Proposer.startProposer(); diff --git a/test/e2e/tokens/erc20.test.mjs b/test/e2e/tokens/erc20.test.mjs index 71b29f270..43f31ecbf 100644 --- a/test/e2e/tokens/erc20.test.mjs +++ b/test/e2e/tokens/erc20.test.mjs @@ -75,7 +75,10 @@ describe('ERC20 tests', () => { if (DEPLOY_MOCKED_SANCTIONS_CONTRACT) await nf3UserSanctioned.init(mnemonics.sanctionedUser); await nf3Proposer.init(mnemonics.proposer); - await nf3Proposer.registerProposer('http://optimist', await nf3Proposer.getMinimumStake()); + await nf3Proposer.registerProposer( + 'http://localhost:8081', + await nf3Proposer.getMinimumStake(), + ); // Proposer listening for incoming events const newGasBlockEmitter = await nf3Proposer.startProposer(); newGasBlockEmitter.on('rollback', () => { diff --git a/test/e2e/tokens/erc721.test.mjs b/test/e2e/tokens/erc721.test.mjs index 6b909b136..cfc9fe5f8 100644 --- a/test/e2e/tokens/erc721.test.mjs +++ b/test/e2e/tokens/erc721.test.mjs @@ -59,7 +59,10 @@ describe('ERC721 tests', () => { await nf3User2.init(mnemonics.user2); await nf3Proposer.init(mnemonics.proposer); - await nf3Proposer.registerProposer('http://optimist', await nf3Proposer.getMinimumStake()); + await nf3Proposer.registerProposer( + 'http://localhost:8081', + await nf3Proposer.getMinimumStake(), + ); // Proposer listening for incoming events const newGasBlockEmitter = await nf3Proposer.startProposer(); diff --git a/test/e2e/tokens/l2tokenisation.test.mjs b/test/e2e/tokens/l2tokenisation.test.mjs index cefd4fb52..756eb0f93 100644 --- a/test/e2e/tokens/l2tokenisation.test.mjs +++ b/test/e2e/tokens/l2tokenisation.test.mjs @@ -53,7 +53,10 @@ let rollbackCount = 0; describe('L2 Tokenisation tests', () => { before(async () => { await nf3Proposer1.init(mnemonics.proposer); - await nf3Proposer1.registerProposer('http://optimist', await nf3Proposer1.getMinimumStake()); + await nf3Proposer1.registerProposer( + 'http://localhost:8081', + await nf3Proposer1.getMinimumStake(), + ); // Proposer listening for incoming events const newGasBlockEmitter = await nf3Proposer1.startProposer(); diff --git a/test/fee-and-reward-periodic-payment.test.mjs b/test/fee-and-reward-periodic-payment.test.mjs index ff56be709..d29e425ab 100644 --- a/test/fee-and-reward-periodic-payment.test.mjs +++ b/test/fee-and-reward-periodic-payment.test.mjs @@ -58,7 +58,10 @@ describe('Periodic Payment', () => { `-- proposer account balance before registration --- ${await web3.eth.getBalance(nf3Proposer.ethereumAddress)}`, ); - await nf3Proposer.registerProposer('http://optimist', await nf3Proposer.getMinimumStake()); + await nf3Proposer.registerProposer( + 'http://http://localhost:8081', + await nf3Proposer.getMinimumStake(), + ); await nf3Proposer.startProposer(); erc20Address = await nf3User.getContractAddress('ERC20Mock'); diff --git a/test/gas.test.mjs b/test/gas.test.mjs index 57bab4b73..d65465c67 100644 --- a/test/gas.test.mjs +++ b/test/gas.test.mjs @@ -48,7 +48,10 @@ describe('Gas test', () => { let txPerBlock; before(async () => { await nf3Proposer.init(mnemonics.proposer); - await nf3Proposer.registerProposer('http://optimist', await nf3Proposer.getMinimumStake()); + await nf3Proposer.registerProposer( + 'http://localhost:8081optimist', + await nf3Proposer.getMinimumStake(), + ); // Proposer listening for incoming events const newGasBlockEmitter = await nf3Proposer.startProposer(); diff --git a/test/multisig/administrator.test.mjs b/test/multisig/administrator.test.mjs index 2126626ca..d3e71c194 100644 --- a/test/multisig/administrator.test.mjs +++ b/test/multisig/administrator.test.mjs @@ -218,7 +218,7 @@ describe(`Testing Administrator`, () => { it('Allowing register first proposer', async () => { if (config.ENVIRONMENT !== 'aws') { - const res = await proposers[0].registerProposer('http://optimist', minimumStakeDef); + const res = await proposers[0].registerProposer('http://localhost:8081', minimumStakeDef); expectTransaction(res); } }); @@ -226,7 +226,7 @@ describe(`Testing Administrator`, () => { it('Not allowing register second proposer', async () => { let error = null; try { - const res = await proposers[1].registerProposer('http://optimist', minimumStakeDef); + const res = await proposers[1].registerProposer('http://localhost:8081', minimumStakeDef); expectTransaction(res); } catch (err) { error = err; @@ -258,7 +258,7 @@ describe(`Testing Administrator`, () => { }); it('Allowing register second proposer', async () => { - const res = await proposers[1].registerProposer('http://optimist', minimumStakeDef); + const res = await proposers[1].registerProposer('http://localhost:8081', minimumStakeDef); expectTransaction(res); }); diff --git a/test/optimist-resync.test.mjs b/test/optimist-resync.test.mjs index 9ede9a179..e3be29db1 100644 --- a/test/optimist-resync.test.mjs +++ b/test/optimist-resync.test.mjs @@ -54,7 +54,7 @@ describe('Optimist synchronisation tests', () => { await nf3Challenger.init(mnemonics.challenger); minimumStake = await nf3Proposer1.getMinimumStake(); // we must set the URL from the point of view of the client container - await nf3Proposer1.registerProposer('http://optimist', minimumStake); + await nf3Proposer1.registerProposer('http://localhost:8081', minimumStake); // Proposer listening for incoming events blockProposeEmitter = await nf3Proposer1.startProposer(); @@ -107,7 +107,7 @@ describe('Optimist synchronisation tests', () => { await restartOptimist(nf3Proposer1, false); // we need to remind optimist which proposer it's connected to - await nf3Proposer1.registerProposer('http://optimist', minimumStake); + await nf3Proposer1.registerProposer('http://localhost:8081', minimumStake); await waitForTimeout(5000); // TODO - get optimist to do this automatically. // Now we'll add another block and check that it's blocknumber is correct, indicating @@ -183,7 +183,7 @@ describe('Optimist synchronisation tests', () => { await restartOptimist(nf3Proposer1, true); // we need to remind optimist which proposer it's connected to - await nf3Proposer1.registerProposer('http://optimist', minimumStake); + await nf3Proposer1.registerProposer('http://localhost:8081', minimumStake); // TODO - get optimist to do this automatically. // Now we'll add another block and check that it's blocknumber is correct, indicating // that a resync correctly occured @@ -255,7 +255,7 @@ describe('Optimist synchronisation tests', () => { logger.debug('rollback complete event received'); // the rollback will have removed us as proposer. We need to re-register because we // were the only proposer in town! - await nf3Proposer1.registerProposer('http://optimist', minimumStake); + await nf3Proposer1.registerProposer('http://localhost:8081', minimumStake); // Now we'll add another block and check that it's blocknumber is correct, indicating // that a rollback correctly occured logger.debug(` Sending a deposit...`); diff --git a/test/utils.mjs b/test/utils.mjs index 62b6156d6..d602209b5 100644 --- a/test/utils.mjs +++ b/test/utils.mjs @@ -453,7 +453,7 @@ export const retrieveL2Balance = async (client, ercAddress) => { */ export const registerProposerOnNoProposer = async proposer => { if ((await proposer.getCurrentProposer()) === '0x0000000000000000000000000000000000000000') { - await proposer.registerProposer('http://optimist', await proposer.getMinimumStake()); + await proposer.registerProposer('http://localhost:8081', await proposer.getMinimumStake()); } }; diff --git a/test/x509.test.mjs b/test/x509.test.mjs index 70d8c95fb..751abafcc 100644 --- a/test/x509.test.mjs +++ b/test/x509.test.mjs @@ -59,7 +59,10 @@ describe('x509 tests', () => { nf3Proposer.ethereumAddress, ); // we must set the URL from the point of view of the client container - await nf3Proposer.registerProposer('http://optimist', await nf3Proposer.getMinimumStake()); + await nf3Proposer.registerProposer( + 'http://localhost:8081', + await nf3Proposer.getMinimumStake(), + ); await nf3Proposer.startProposer(); await nf3Users[0].init(mnemonics.user1); erc20Address = From 2b040076c39b9c96230969acc129e2566f93a041 Mon Sep 17 00:00:00 2001 From: Westlad Date: Wed, 29 Mar 2023 15:59:48 +0100 Subject: [PATCH 04/11] fix: forward through proposer --- apps/proposer/src/proposer.mjs | 4 ++- apps/proposer/src/routes/proposer.mjs | 5 ++-- cli/lib/nf3.mjs | 27 +++++++++++++++++--- docker/docker-compose.multiproposer-test.yml | 10 ++++++-- 4 files changed, 37 insertions(+), 9 deletions(-) diff --git a/apps/proposer/src/proposer.mjs b/apps/proposer/src/proposer.mjs index a9666c44e..3c76118be 100644 --- a/apps/proposer/src/proposer.mjs +++ b/apps/proposer/src/proposer.mjs @@ -76,7 +76,9 @@ async function checkAndRegisterProposer(nf3, proposerBaseUrl) { try { await nf3.registerProposer(proposerBaseUrl, minimumStake); } catch (err) { - logger.info(err); + logger.info( + `Error registering proposer ${proposerBaseUrl} with error message ${err.message}`, + ); } } diff --git a/apps/proposer/src/routes/proposer.mjs b/apps/proposer/src/routes/proposer.mjs index e2e5a0bfa..37ea7f585 100644 --- a/apps/proposer/src/routes/proposer.mjs +++ b/apps/proposer/src/routes/proposer.mjs @@ -15,7 +15,6 @@ const router = express.Router(); router.post('/offchain-transaction', async (req, res, next) => { const nf3 = req.app.get('nf3'); const { transaction } = req.body; - if (!transaction) { res.sendStatus(404); return; @@ -35,8 +34,8 @@ router.post('/offchain-transaction', async (req, res, next) => { } try { - await nf3.sendOffchainTransaction(transaction); - res.sendStatus(200); + const res2 = await nf3.forwardOffchainTransaction(transaction); + res.sendStatus(res2.status); } catch (error) { next(error); } diff --git a/cli/lib/nf3.mjs b/cli/lib/nf3.mjs index 818113407..0dca98f07 100644 --- a/cli/lib/nf3.mjs +++ b/cli/lib/nf3.mjs @@ -1306,11 +1306,32 @@ class Nf3 { } /** - Send offchain transaction to all Optimists that the chain knows about + Intended to be called by a Proposer acting as a Proxy for offchain transactions. This + function allows the Proposer to forward offchain transactions to its Optimist instance. @method @async - @param {string} transaction - @returns {array} A promise that resolves to the API call status + @param {object} transaction + @returns {object} A promise that resolves to the API call status + */ + async forwardOffchainTransaction(transaction) { + const res = await axios.post( + `${this.optimistBaseUrl}/proposer/offchain-transaction`, + { transaction }, + { timeout: 3600000 }, + ); + console.log(`FORWARDING TO ${this.optimistBaseUrl}/proposer/offchain-transaction`); + return res.status; + } + + /** + Send offchain transaction to all Proposers that the chain knows about + This is mainly intended to be called by a User to send the transaction to a Proposer + who will act as a proxy and forward the transaction to an Optimist (this allows an + Optimist to be firewalled off and only the Proposer exposed to Users). + @method + @async + @param {object} transaction + @returns {object} A promise that resolves to the API call status */ async sendOffchainTransaction(transaction) { // dig up connection peers diff --git a/docker/docker-compose.multiproposer-test.yml b/docker/docker-compose.multiproposer-test.yml index f42e3d133..5df14ffa4 100644 --- a/docker/docker-compose.multiproposer-test.yml +++ b/docker/docker-compose.multiproposer-test.yml @@ -308,7 +308,7 @@ services: OPTIMIST_HOST: proposer_optimist_1 OPTIMIST_PORT: 80 OPTIMIST_WS_PORT: 8080 - PROPOSER_HOST: proposer_1 + PROPOSER_HOST: localhost PROPOSER_PORT: 8093 PROPOSER_KEY: ${PROPOSER_KEY:-0xcbbf1d0686738a444cf9f66fdc96289035c384c4e8d26768f94fa81f3ab6596a} DEPLOYER_HOST: ${DEPLOYER_HOST:-deployer} @@ -319,6 +319,9 @@ services: - type: bind source: ../apps/proposer/src target: /app/src + - type: bind + source: ../cli + target: /app/cli proposer_2: build: @@ -337,7 +340,7 @@ services: OPTIMIST_HOST: proposer_optimist_2 OPTIMIST_PORT: 80 OPTIMIST_WS_PORT: 8080 - PROPOSER_HOST: proposer_2 + PROPOSER_HOST: localhost PROPOSER_PORT: 8094 PROPOSER_KEY: ${PROPOSER2_KEY:-0xabf4ed9f30bd1e4a290310d726c7bbdf39cd75a25eebd9a3a4874e10b4a0c4ce} DEPLOYER_HOST: ${DEPLOYER_HOST:-deployer} @@ -348,6 +351,9 @@ services: - type: bind source: ../apps/proposer/src target: /app/src + - type: bind + source: ../cli + target: /app/cli challenger_1: build: From 242eb15934751536ad6b4213017aa6aa960caebc Mon Sep 17 00:00:00 2001 From: Westlad Date: Thu, 30 Mar 2023 15:24:49 +0100 Subject: [PATCH 05/11] fix: ping-pong test --- cli/lib/nf3.mjs | 7 ++++--- docker/proposer.Dockerfile | 2 +- test/ping-pong/index.mjs | 9 ++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/cli/lib/nf3.mjs b/cli/lib/nf3.mjs index 0dca98f07..e995e649e 100644 --- a/cli/lib/nf3.mjs +++ b/cli/lib/nf3.mjs @@ -1320,12 +1320,12 @@ class Nf3 { { timeout: 3600000 }, ); console.log(`FORWARDING TO ${this.optimistBaseUrl}/proposer/offchain-transaction`); - return res.status; + return res; } /** Send offchain transaction to all Proposers that the chain knows about - This is mainly intended to be called by a User to send the transaction to a Proposer + This is intended to be called by a User to send the transaction to a Proposer who will act as a proxy and forward the transaction to an Optimist (this allows an Optimist to be firewalled off and only the Proposer exposed to Users). @method @@ -1334,6 +1334,7 @@ class Nf3 { @returns {object} A promise that resolves to the API call status */ async sendOffchainTransaction(transaction) { + // we're proxying offchain transactions through the proposers. We send the transaction to every proposer // dig up connection peers const currentProposer = await this.stateContract.methods.currentProposer().call(); const peerList = { [currentProposer.thisAddress]: currentProposer.url }; @@ -1352,7 +1353,7 @@ class Nf3 { } logger.debug({ msg: 'Peer List', peerList }); - await Promise.any( + return Promise.any( Object.keys(peerList).map(async address => { logger.debug( `offchain transaction - calling ${peerList[address]}/proposer/offchain-transaction`, diff --git a/docker/proposer.Dockerfile b/docker/proposer.Dockerfile index 5d6bc2b62..1637cdef8 100644 --- a/docker/proposer.Dockerfile +++ b/docker/proposer.Dockerfile @@ -4,7 +4,7 @@ FROM node:16.17-bullseye-slim # entrypoint script requires 'netcat' RUN apt-get update \ && apt-get install -y --no-install-recommends \ - python3 make g++ netcat-openbsd \ + python3 make g++ netcat-openbsd iputils-ping\ && rm -rf /var/lib/apt/lists/* # websocket port 8080 diff --git a/test/ping-pong/index.mjs b/test/ping-pong/index.mjs index 11c25fb48..c145576d5 100644 --- a/test/ping-pong/index.mjs +++ b/test/ping-pong/index.mjs @@ -70,7 +70,7 @@ export async function simpleUserTest( const startBalance = await retrieveL2Balance(nf3, ercAddress); console.log(`start balance ${nf3.zkpKeys.compressedZkpPublicKey}`, startBalance); - let offchainTx = true; + const offchainTx = true; const { txTypes } = nf3; @@ -130,7 +130,7 @@ export async function simpleUserTest( to: userAdressTo, value: valueToTransfer, fee, - transactionHashL1: res.transactionHash, + transactionHashL1: res?.transactionHash, blockHash: res.blockHash, onchain: !offchainTx, type: 'transfer', @@ -161,7 +161,7 @@ export async function simpleUserTest( to: userAdressTo, value: valueToTransfer, fee, - transactionHashL1: res.transactionHash, + transactionHashL1: res?.transactionHash, blockHash: res.blockHash, onchain: !offchainTx, type: 'transfer', @@ -171,7 +171,6 @@ export async function simpleUserTest( console.warn('Error transfer', err); } } - offchainTx = !offchainTx; try { const res = await nf3.deposit( @@ -206,7 +205,7 @@ export async function simpleUserTest( try { const res = await nf3.withdraw( txTypes[i * 3 + 2], - offchainTx, + !offchainTx, ercAddress, tokenType, valueToTransfer, From 9fd09176a65d6e1a6ca9734c697c00c662775064 Mon Sep 17 00:00:00 2001 From: Westlad Date: Fri, 31 Mar 2023 11:20:29 +0100 Subject: [PATCH 06/11] fix: remove console.log --- cli/lib/nf3.mjs | 1 - 1 file changed, 1 deletion(-) diff --git a/cli/lib/nf3.mjs b/cli/lib/nf3.mjs index e995e649e..5f2f6a109 100644 --- a/cli/lib/nf3.mjs +++ b/cli/lib/nf3.mjs @@ -1319,7 +1319,6 @@ class Nf3 { { transaction }, { timeout: 3600000 }, ); - console.log(`FORWARDING TO ${this.optimistBaseUrl}/proposer/offchain-transaction`); return res; } From 2ea531da5d53c90981b86410e4446a943857361a Mon Sep 17 00:00:00 2001 From: Westlad Date: Mon, 27 Mar 2023 15:14:49 +0100 Subject: [PATCH 07/11] feat: 401 if users are not allowed to be annonymous and no signature is provided --- cli/lib/nf3.mjs | 7 ++++++- nightfall-optimist/src/routes/proposer.mjs | 16 +++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/cli/lib/nf3.mjs b/cli/lib/nf3.mjs index 5f2f6a109..0b277d813 100644 --- a/cli/lib/nf3.mjs +++ b/cli/lib/nf3.mjs @@ -1357,9 +1357,14 @@ class Nf3 { logger.debug( `offchain transaction - calling ${peerList[address]}/proposer/offchain-transaction`, ); + // sign the transaction if we're required to identify ourself + const signature = process.env.ANONYMOUS_USER + ? null + : this.web3.eth.accounts.sign(JSON.stringify(transaction), this.ethereumSigningKey) + .signature; return axios.post( `${peerList[address]}/proposer/offchain-transaction`, - { transaction }, + { transaction, signature }, { timeout: 3600000 }, ); }), diff --git a/nightfall-optimist/src/routes/proposer.mjs b/nightfall-optimist/src/routes/proposer.mjs index 540dfefb4..69b1e0eba 100644 --- a/nightfall-optimist/src/routes/proposer.mjs +++ b/nightfall-optimist/src/routes/proposer.mjs @@ -5,6 +5,7 @@ */ import express from 'express'; import config from 'config'; +import Web3 from 'web3'; import Timber from '@polygon-nightfall/common-files/classes/timber.mjs'; import logger from '@polygon-nightfall/common-files/utils/logger.mjs'; import { @@ -32,6 +33,7 @@ import transactionSubmittedEventHandler from '../event-handlers/transaction-subm const router = express.Router(); const { TIMBER_HEIGHT, HASH_TYPE } = config; const { STATE_CONTRACT_NAME, PROPOSERS_CONTRACT_NAME, SHIELD_CONTRACT_NAME, ZERO } = constants; +const web3 = new Web3(); let proposer; export function setProposer(p) { @@ -405,7 +407,19 @@ router.post('/encode', async (req, res, next) => { }); router.post('/offchain-transaction', async (req, res) => { - const { transaction } = req.body; + const { transaction, signature } = req.body; + // the first thing we'll do is check that the sender is whitelisted (if required by our config) + if (!process.env.ANONYMOUS_USER) { + const address = web3.eth.accounts.recover(JSON.stringify(transaction), signature); + const x509Instance = await getContractInstance('X509'); + const isWhitelisted = await x509Instance.x509Check(address); + if (!isWhitelisted) { + logger.warn('Attempted transaction by a user who is not whitelisted'); + res.sendStatus(401); + return; + } + } + /* When a transaction is built by client, they are generalised into hex(32) interfacing with web3 The response from on-chain events converts them to saner string values (e.g. uint64 etc). From 3221219f72f8238b3cdab43631d3ce8d6ba9932a Mon Sep 17 00:00:00 2001 From: Westlad Date: Mon, 27 Mar 2023 16:39:45 +0100 Subject: [PATCH 08/11] fix: enable setting of ANONYMOUS_USER in optimist --- docker/docker-compose.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index b19e22b6d..19b0b2d48 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -153,6 +153,7 @@ services: PROPOSER_MAX_BLOCK_PERIOD_MILIS: ${PROPOSER_MAX_BLOCK_PERIOD_MILIS:-0} USE_EXTERNAL_NODE: ${USE_EXTERNAL_NODE} WEBSOCKET_PORT: ${WEBSOCKET_PORT:-8080} + ANONYMOUS_USER: ${ANONYMOUS_USER} command: ['npm', 'run', 'dev'] rabbitmq: From 8b0f8640a8513beafc7969275d37f0fd88c18c8d Mon Sep 17 00:00:00 2001 From: Westlad Date: Fri, 31 Mar 2023 16:25:37 +0100 Subject: [PATCH 09/11] fix: minor bugs --- apps/proposer/src/routes/proposer.mjs | 4 ++-- cli/lib/nf3.mjs | 4 ++-- nightfall-optimist/src/routes/proposer.mjs | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/proposer/src/routes/proposer.mjs b/apps/proposer/src/routes/proposer.mjs index 37ea7f585..6d944253b 100644 --- a/apps/proposer/src/routes/proposer.mjs +++ b/apps/proposer/src/routes/proposer.mjs @@ -14,7 +14,7 @@ const router = express.Router(); router.post('/offchain-transaction', async (req, res, next) => { const nf3 = req.app.get('nf3'); - const { transaction } = req.body; + const { transaction, signature } = req.body; if (!transaction) { res.sendStatus(404); return; @@ -34,7 +34,7 @@ router.post('/offchain-transaction', async (req, res, next) => { } try { - const res2 = await nf3.forwardOffchainTransaction(transaction); + const res2 = await nf3.forwardOffchainTransaction(transaction, signature); res.sendStatus(res2.status); } catch (error) { next(error); diff --git a/cli/lib/nf3.mjs b/cli/lib/nf3.mjs index 0b277d813..37138f223 100644 --- a/cli/lib/nf3.mjs +++ b/cli/lib/nf3.mjs @@ -1313,10 +1313,10 @@ class Nf3 { @param {object} transaction @returns {object} A promise that resolves to the API call status */ - async forwardOffchainTransaction(transaction) { + async forwardOffchainTransaction(transaction, signature) { const res = await axios.post( `${this.optimistBaseUrl}/proposer/offchain-transaction`, - { transaction }, + { transaction, signature }, { timeout: 3600000 }, ); return res; diff --git a/nightfall-optimist/src/routes/proposer.mjs b/nightfall-optimist/src/routes/proposer.mjs index 69b1e0eba..5ad5c3f16 100644 --- a/nightfall-optimist/src/routes/proposer.mjs +++ b/nightfall-optimist/src/routes/proposer.mjs @@ -411,8 +411,9 @@ router.post('/offchain-transaction', async (req, res) => { // the first thing we'll do is check that the sender is whitelisted (if required by our config) if (!process.env.ANONYMOUS_USER) { const address = web3.eth.accounts.recover(JSON.stringify(transaction), signature); + logger.debug(`Recovered address ${address}`); const x509Instance = await getContractInstance('X509'); - const isWhitelisted = await x509Instance.x509Check(address); + const isWhitelisted = await x509Instance.methods.x509Check(address).call(); if (!isWhitelisted) { logger.warn('Attempted transaction by a user who is not whitelisted'); res.sendStatus(401); From 60bc907abeba134f66f5a18d478d8bddae7bd5c9 Mon Sep 17 00:00:00 2001 From: Westlad Date: Tue, 11 Apr 2023 13:58:52 +0100 Subject: [PATCH 10/11] docs: document anonymous user environment variable --- doc/whitelist.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/whitelist.md b/doc/whitelist.md index ca694e1f0..611e0297e 100644 --- a/doc/whitelist.md +++ b/doc/whitelist.md @@ -1,6 +1,6 @@ # Nightfall Whitelisting adaptions -Nightfall now incorporates the ability to manage a whitelist of accounts. It is an abstract contract, intended to be subclassed by a form of Whitelist Manager contract (currentyl `X509.sol` performs this role). When whitelisting is enabled, only accounts that are added to the whitelist are able to move funds from Layer 1 to Layer 2 and to withdraw Layer 1 funds from the Shield contract. +Nightfall now incorporates the ability to manage a whitelist of accounts. It is an abstract contract, intended to be subclassed by a form of Whitelist Manager contract (currentyl `X509.sol` performs this role). When whitelisting is enabled, only accounts that are added to the whitelist are able to move funds from Layer 1 to Layer 2 and to withdraw Layer 1 funds from the Shield contract. Further, only whitelisted accounts may act as Proposers or Challengers. ## Enabling Whitelisting @@ -9,3 +9,7 @@ To enable whitelisting, the deployer container should have its `WHITELISTING` en ## Operating Whitelisting All whitelisting functionality is managed by the contract `Whitelist.sol`, the functions therein are self-explanatory. + +## Identifying users to the Proposer + +The Proposer may require that all users for whom it accepts transactions must be whitelisted. This is in fact the default unless the environment variable ANONYMOUS_USER is set in the Proposer container. Unless this variable is set, the Proposer will expect the user to sign the submitted off-chain transaction wirh their Ethereum signing key. The Proposer will do an ecrrecover on the signature and require that the recovered address is whitelisted before processing the transaction. The user's nf3 class will automatically sign offchain transactions unless the ANNONYMOUS_USER environment variable is set there. From e7093dbfdf05049dde9b975a549155ef27df2af0 Mon Sep 17 00:00:00 2001 From: Westlad Date: Wed, 19 Apr 2023 11:45:36 +0100 Subject: [PATCH 11/11] fix: backport changes from polygon PoS deployment --- .eslintignore | 2 ++ .gitignore | 2 ++ bin/polygonpos-deployment.env | 6 +++--- nightfall-deployer/migrations/3_test_tokens_migration.js | 3 +-- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/.eslintignore b/.eslintignore index 6d3b75fc7..edf47ed29 100644 --- a/.eslintignore +++ b/.eslintignore @@ -3,6 +3,8 @@ node_modules/* **/migrations/* **/doc/* mumbai/ +polygonpos/ +proving_files/ cli/build/* wallet/cli/* mumbai/ diff --git a/.gitignore b/.gitignore index f6620bf5f..1fe154dde 100644 --- a/.gitignore +++ b/.gitignore @@ -7,8 +7,10 @@ mumbai/ .*swp .vscode/* .openzeppelin/ +proving_files/ *.log mumbai/ +polygonpos/ # wallet wallet/build wallet/cli diff --git a/bin/polygonpos-deployment.env b/bin/polygonpos-deployment.env index 3c855981c..dd38dd564 100755 --- a/bin/polygonpos-deployment.env +++ b/bin/polygonpos-deployment.env @@ -7,9 +7,9 @@ MULTISIG_APPROVERS='0x0000000000000000000000000000000000000001,0x000000000000000 WHITELISTING=enable NF_SERVICES_TO_START='deployer,worker' DEPLOY_MOCK_TOKENS=false -ENVIRONMENT=mumbai +ENVIRONMENT=polygonPos FEE_L2_TOKEN_ID=WMATIC -DEPLOY_MOCKED_SANCTIONS_CONTRACT=true -GAS_PRICE=500000000000 +DEPLOY_MOCKED_SANCTIONS_CONTRACT=false +GAS_PRICE=400000000000 RESTRICT_TOKENS=disable set +o allexport \ No newline at end of file diff --git a/nightfall-deployer/migrations/3_test_tokens_migration.js b/nightfall-deployer/migrations/3_test_tokens_migration.js index 36cdd9e52..de54e892c 100644 --- a/nightfall-deployer/migrations/3_test_tokens_migration.js +++ b/nightfall-deployer/migrations/3_test_tokens_migration.js @@ -16,12 +16,11 @@ const ERC1155Mock = artifacts.require('ERC1155Mock.sol'); const nERC721 = 35; module.exports = function (deployer, _, accounts) { + if (DEPLOY_MOCK_TOKENS === 'false') return; deployer.then(async () => { const shield = await Shield.deployed(); const state = await State.deployed(); - if (DEPLOY_MOCK_TOKENS === 'false') return; - await deployer.deploy(ERC20Mock, 1001010000000000); // initialSupply const ERC20deployed = await ERC20Mock.deployed();