mirror of
https://github.com/tornadocash/tornado-nova
synced 2024-02-02 14:53:56 +01:00
initial
This commit is contained in:
commit
33dddba57e
9
.editorconfig
Normal file
9
.editorconfig
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
node_modules
|
||||||
|
build
|
54
circuits/merkleTree.circom
Normal file
54
circuits/merkleTree.circom
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
include "../node_modules/circomlib/circuits/mimcsponge.circom";
|
||||||
|
|
||||||
|
// Computes MiMC([left, right])
|
||||||
|
template HashLeftRight() {
|
||||||
|
signal input left;
|
||||||
|
signal input right;
|
||||||
|
signal output hash;
|
||||||
|
|
||||||
|
component hasher = MiMCSponge(2, 220, 1);
|
||||||
|
hasher.ins[0] <== left;
|
||||||
|
hasher.ins[1] <== right;
|
||||||
|
hasher.k <== 0;
|
||||||
|
hash <== hasher.outs[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// if s == 0 returns [in[0], in[1]]
|
||||||
|
// if s == 1 returns [in[1], in[0]]
|
||||||
|
template DualMux() {
|
||||||
|
signal input in[2];
|
||||||
|
signal input s;
|
||||||
|
signal output out[2];
|
||||||
|
|
||||||
|
s * (1 - s) === 0
|
||||||
|
out[0] <== (in[1] - in[0])*s + in[0];
|
||||||
|
out[1] <== (in[0] - in[1])*s + in[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verifies that merkle proof is correct for given merkle root and a leaf
|
||||||
|
// pathIndices input is an array of 0/1 selectors telling whether given pathElement is on the left or right side of merkle path
|
||||||
|
template MerkleTree(levels) {
|
||||||
|
signal input leaf;
|
||||||
|
signal input root;
|
||||||
|
signal input pathElements[levels];
|
||||||
|
signal input pathIndices;
|
||||||
|
|
||||||
|
component selectors[levels];
|
||||||
|
component hashers[levels];
|
||||||
|
|
||||||
|
component indexBits = Num2Bits(levels);
|
||||||
|
indexBits.in <== pathIndices;
|
||||||
|
|
||||||
|
for (var i = 0; i < levels; i++) {
|
||||||
|
selectors[i] = DualMux();
|
||||||
|
selectors[i].in[0] <== i == 0 ? leaf : hashers[i - 1].hash;
|
||||||
|
selectors[i].in[1] <== pathElements[i];
|
||||||
|
selectors[i].s <== indexBits.out[i];
|
||||||
|
|
||||||
|
hashers[i] = HashLeftRight();
|
||||||
|
hashers[i].left <== selectors[i].out[0];
|
||||||
|
hashers[i].right <== selectors[i].out[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
root === hashers[levels - 1].hash;
|
||||||
|
}
|
123
circuits/transaction.circom
Normal file
123
circuits/transaction.circom
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
include "./merkleTree.circom"
|
||||||
|
include "./treeUpdater.circom"
|
||||||
|
include "./utils.circom"
|
||||||
|
|
||||||
|
/*
|
||||||
|
Utxo structure:
|
||||||
|
{
|
||||||
|
amount,
|
||||||
|
blinding, // random number
|
||||||
|
pubkey,
|
||||||
|
}
|
||||||
|
|
||||||
|
commitment = hash(amount, blinding, pubKey)
|
||||||
|
nullifier = hash(commitment, privKey, merklePath)
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Universal JoinSplit transaction with 2 inputs and 2 outputs
|
||||||
|
template Transaction(levels, zeroLeaf) {
|
||||||
|
signal input root;
|
||||||
|
signal input newRoot;
|
||||||
|
signal input inputNullifier[2];
|
||||||
|
signal input outputCommitment[2];
|
||||||
|
// external amount used for deposits and withdrawals
|
||||||
|
// correct extAmount range is enforced on the smart contract
|
||||||
|
signal input extAmount;
|
||||||
|
signal input fee;
|
||||||
|
signal input recipient;
|
||||||
|
signal input relayer;
|
||||||
|
|
||||||
|
signal private input privateKey;
|
||||||
|
|
||||||
|
// data for 2 transaction inputs
|
||||||
|
signal private input inAmount[2];
|
||||||
|
signal private input inBlinding[2];
|
||||||
|
signal private input inPathIndices[2];
|
||||||
|
signal private input inPathElements[2][levels];
|
||||||
|
|
||||||
|
// data for 2 transaction outputs
|
||||||
|
signal private input outAmount[2];
|
||||||
|
signal private input outBlinding[2];
|
||||||
|
signal private input outPathIndices;
|
||||||
|
signal private input outPathElements[levels - 1];
|
||||||
|
|
||||||
|
component inUtxoHasher[2];
|
||||||
|
component outUtxoHasher[2];
|
||||||
|
component nullifierHasher[2];
|
||||||
|
component checkRoot[2]
|
||||||
|
component tree[2];
|
||||||
|
component inAmountCheck[2];
|
||||||
|
component outAmountCheck[2];
|
||||||
|
|
||||||
|
component keypair = Keypair();
|
||||||
|
keypair.privateKey <== privateKey;
|
||||||
|
|
||||||
|
// verify correctness of transaction inputs
|
||||||
|
for (var tx = 0; tx < 2; tx++) {
|
||||||
|
inUtxoHasher[tx] = TransactionHasher();
|
||||||
|
inUtxoHasher[tx].amount <== inAmount[tx];
|
||||||
|
inUtxoHasher[tx].blinding <== inBlinding[tx];
|
||||||
|
inUtxoHasher[tx].publicKey <== keypair.publicKey;
|
||||||
|
|
||||||
|
nullifierHasher[tx] = NullifierHasher();
|
||||||
|
nullifierHasher[tx].commitment <== inUtxoHasher[tx].commitment;
|
||||||
|
nullifierHasher[tx].merklePath <== inPathIndices[tx];
|
||||||
|
nullifierHasher[tx].privateKey <== keypair.privateKey;
|
||||||
|
nullifierHasher[tx].nullifier === inputNullifier[tx];
|
||||||
|
|
||||||
|
tree[tx] = MerkleTree(levels);
|
||||||
|
tree[tx].leaf <== inUtxoHasher[tx].commitment;
|
||||||
|
tree[tx].pathIndices <== inPathIndices[tx];
|
||||||
|
for (var i = 0; i < levels; i++) {
|
||||||
|
tree[tx].pathElements[i] <== inPathElements[tx][i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// check merkle proof only if amount is non-zero
|
||||||
|
checkRoot[tx] = ForceEqualIfEnabled();
|
||||||
|
checkRoot[tx].in[0] <== root;
|
||||||
|
checkRoot[tx].in[1] <== tree[tx].root;
|
||||||
|
checkRoot[tx].enabled <== inAmount[tx];
|
||||||
|
|
||||||
|
// Check that amount fits into 248 bits to prevent overflow
|
||||||
|
inAmountCheck[tx] = Num2Bits(248);
|
||||||
|
inAmountCheck[tx].in <== inAmount[tx];
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify correctness of transaction outputs
|
||||||
|
for (var tx = 0; tx < 2; tx++) {
|
||||||
|
outUtxoHasher[tx] = TransactionHasher();
|
||||||
|
outUtxoHasher[tx].amount <== outAmount[tx];
|
||||||
|
outUtxoHasher[tx].blinding <== outBlinding[tx];
|
||||||
|
outUtxoHasher[tx].publicKey <== keypair.publicKey;
|
||||||
|
outUtxoHasher[tx].commitment === outputCommitment[tx];
|
||||||
|
|
||||||
|
// Check that amount fits into 248 bits to prevent overflow
|
||||||
|
outAmountCheck[tx] = Num2Bits(248);
|
||||||
|
outAmountCheck[tx].in <== outAmount[tx];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that fee fits into 248 bits to prevent overflow
|
||||||
|
component feeCheck = Num2Bits(248);
|
||||||
|
feeCheck.in <== fee;
|
||||||
|
|
||||||
|
component sameNullifiers = IsEqual();
|
||||||
|
sameNullifiers.in[0] <== inputNullifier[0];
|
||||||
|
sameNullifiers.in[1] <== inputNullifier[1];
|
||||||
|
sameNullifiers.out === 0;
|
||||||
|
|
||||||
|
// verify amount invariant
|
||||||
|
inAmount[0] + inAmount[1] + extAmount === outAmount[0] + outAmount[1] + fee;
|
||||||
|
|
||||||
|
// Check merkle tree update with inserted transaction outputs
|
||||||
|
component treeUpdater = TreeUpdater(levels, zeroLeaf);
|
||||||
|
treeUpdater.oldRoot <== root;
|
||||||
|
treeUpdater.newRoot <== newRoot;
|
||||||
|
treeUpdater.leaf[0] <== outputCommitment[0];
|
||||||
|
treeUpdater.leaf[1] <== outputCommitment[1];
|
||||||
|
treeUpdater.pathIndices <== outPathIndices;
|
||||||
|
for (var i = 0; i < levels - 1; i++) {
|
||||||
|
treeUpdater.pathElements[i] <== outPathElements[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component main = Transaction(20, 3193090221241211970002919215846211184824251841300455796635909287157453409439);
|
32
circuits/treeUpdater.circom
Normal file
32
circuits/treeUpdater.circom
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
include "./merkleTree.circom";
|
||||||
|
|
||||||
|
// inserts a pair of leaves into a tree
|
||||||
|
// checks that tree previously contained zeroes is same positions
|
||||||
|
// zeroLeaf is a second level leaf: `hash(0, 0)`
|
||||||
|
template TreeUpdater(n, zeroLeaf) {
|
||||||
|
signal input oldRoot;
|
||||||
|
signal input newRoot;
|
||||||
|
signal input leaf[2];
|
||||||
|
signal input pathIndices;
|
||||||
|
signal private input pathElements[n - 1];
|
||||||
|
|
||||||
|
component leafPair = HashLeftRight();
|
||||||
|
leafPair.left <== leaf[0];
|
||||||
|
leafPair.right <== leaf[1];
|
||||||
|
|
||||||
|
component treeBefore = MerkleTree(n - 1);
|
||||||
|
for(var i = 0; i < n - 1; i++) {
|
||||||
|
treeBefore.pathElements[i] <== pathElements[i];
|
||||||
|
}
|
||||||
|
treeBefore.pathIndices <== pathIndices;
|
||||||
|
treeBefore.leaf <== zeroLeaf;
|
||||||
|
treeBefore.root === oldRoot;
|
||||||
|
|
||||||
|
component treeAfter = MerkleTree(n - 1);
|
||||||
|
for(var i = 0; i < n - 1; i++) {
|
||||||
|
treeAfter.pathElements[i] <== pathElements[i];
|
||||||
|
}
|
||||||
|
treeAfter.pathIndices <== pathIndices;
|
||||||
|
treeAfter.leaf <== leafPair.hash;
|
||||||
|
treeAfter.root === newRoot;
|
||||||
|
}
|
44
circuits/utils.circom
Normal file
44
circuits/utils.circom
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
include "../node_modules/circomlib/circuits/pointbits.circom";
|
||||||
|
include "../node_modules/circomlib/circuits/compconstant.circom";
|
||||||
|
include "../node_modules/circomlib/circuits/mimcsponge.circom";
|
||||||
|
|
||||||
|
|
||||||
|
template Keypair() {
|
||||||
|
signal input privateKey;
|
||||||
|
signal output publicKey;
|
||||||
|
|
||||||
|
publicKey <== privateKey;
|
||||||
|
// todo
|
||||||
|
}
|
||||||
|
|
||||||
|
template TransactionHasher() {
|
||||||
|
signal input amount;
|
||||||
|
signal input blinding;
|
||||||
|
signal input publicKey;
|
||||||
|
|
||||||
|
signal output commitment;
|
||||||
|
|
||||||
|
component hasher = MiMCSponge(3, 220, 1);
|
||||||
|
hasher.ins[0] <== amount;
|
||||||
|
hasher.ins[1] <== blinding;
|
||||||
|
hasher.ins[2] <== publicKey;
|
||||||
|
hasher.k <== 0;
|
||||||
|
|
||||||
|
commitment <== hasher.outs[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
template NullifierHasher() {
|
||||||
|
signal input privateKey;
|
||||||
|
signal input merklePath;
|
||||||
|
signal input commitment;
|
||||||
|
|
||||||
|
signal output nullifier;
|
||||||
|
|
||||||
|
component hasher = MiMCSponge(3, 220, 1);
|
||||||
|
hasher.ins[0] <== commitment;
|
||||||
|
hasher.ins[1] <== merklePath;
|
||||||
|
hasher.ins[2] <== privateKey;
|
||||||
|
hasher.k <== 0;
|
||||||
|
|
||||||
|
nullifier <== hasher.outs[0];
|
||||||
|
}
|
123
contracts/Tornado.sol
Normal file
123
contracts/Tornado.sol
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
// https://tornado.cash
|
||||||
|
/*
|
||||||
|
* d888888P dP a88888b. dP
|
||||||
|
* 88 88 d8' `88 88
|
||||||
|
* 88 .d8888b. 88d888b. 88d888b. .d8888b. .d888b88 .d8888b. 88 .d8888b. .d8888b. 88d888b.
|
||||||
|
* 88 88' `88 88' `88 88' `88 88' `88 88' `88 88' `88 88 88' `88 Y8ooooo. 88' `88
|
||||||
|
* 88 88. .88 88 88 88 88. .88 88. .88 88. .88 dP Y8. .88 88. .88 88 88 88
|
||||||
|
* dP `88888P' dP dP dP `88888P8 `88888P8 `88888P' 88 Y88888P' `88888P8 `88888P' dP dP
|
||||||
|
* ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.5.8;
|
||||||
|
|
||||||
|
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; // todo: maybe remove?
|
||||||
|
|
||||||
|
contract IVerifier {
|
||||||
|
function verifyProof(bytes memory _proof, uint256[10] memory _input) public returns(bool);
|
||||||
|
}
|
||||||
|
|
||||||
|
contract TornadoPool is ReentrancyGuard {
|
||||||
|
uint256 public constant FIELD_SIZE = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
|
||||||
|
uint256 public constant MAX_EXT_AMOUNT = 2**248 - 1;
|
||||||
|
|
||||||
|
mapping(bytes32 => bool) public nullifierHashes;
|
||||||
|
bytes32 public currentRoot;
|
||||||
|
IVerifier public verifier;
|
||||||
|
|
||||||
|
// todo: event Transaction();
|
||||||
|
event NewCommitment(bytes32 commitment);
|
||||||
|
event NewNullifier(bytes32 nullifier);
|
||||||
|
|
||||||
|
/**
|
||||||
|
@dev The constructor
|
||||||
|
@param _verifier the address of SNARK verifier for this contract
|
||||||
|
*/
|
||||||
|
constructor(IVerifier _verifier) public {
|
||||||
|
verifier = _verifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
function transaction(
|
||||||
|
bytes calldata _proof,
|
||||||
|
bytes32 _root,
|
||||||
|
bytes32 _newRoot,
|
||||||
|
bytes32[2] calldata _inputNullifiers,
|
||||||
|
bytes32[2] calldata _outputCommitments,
|
||||||
|
uint256 _extAmount,
|
||||||
|
uint256 _fee,
|
||||||
|
address payable _recipient,
|
||||||
|
address payable _relayer
|
||||||
|
)
|
||||||
|
external payable nonReentrant
|
||||||
|
{
|
||||||
|
require(currentRoot == _root, "Invalid merkle root");
|
||||||
|
require(!isSpent(_inputNullifiers[0]), "Input 0 is already spent");
|
||||||
|
require(!isSpent(_inputNullifiers[1]), "Input 1 is already spent");
|
||||||
|
require(verifier.verifyProof(_proof, [
|
||||||
|
uint256(_root),
|
||||||
|
uint256(_newRoot),
|
||||||
|
uint256(_inputNullifiers[0]),
|
||||||
|
uint256(_inputNullifiers[1]),
|
||||||
|
uint256(_outputCommitments[0]),
|
||||||
|
uint256(_outputCommitments[1]),
|
||||||
|
_extAmount,
|
||||||
|
_fee,
|
||||||
|
uint256(_relayer),
|
||||||
|
uint256(_recipient)
|
||||||
|
]), "Invalid transaction proof");
|
||||||
|
|
||||||
|
currentRoot = _newRoot;
|
||||||
|
nullifierHashes[_inputNullifiers[0]] = true;
|
||||||
|
nullifierHashes[_inputNullifiers[1]] = true;
|
||||||
|
|
||||||
|
int256 extAmount = calculateExternalAmount(_extAmount);
|
||||||
|
if (extAmount > 0) {
|
||||||
|
require(msg.value == uint256(extAmount), "Incorrect amount of ETH sent on deposit");
|
||||||
|
} else {
|
||||||
|
require(msg.value == 0, "Sent ETH amount should be 0 for withdrawal");
|
||||||
|
transfer(_recipient, uint256(-extAmount));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_fee > 0) {
|
||||||
|
transfer(_relayer, _fee);
|
||||||
|
}
|
||||||
|
|
||||||
|
emit NewCommitment(_outputCommitments[0]);
|
||||||
|
emit NewCommitment(_outputCommitments[1]);
|
||||||
|
emit NewNullifier(_inputNullifiers[0]);
|
||||||
|
emit NewNullifier(_inputNullifiers[1]);
|
||||||
|
// emit Transaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculateExternalAmount(uint256 _extAmount) public pure returns(int256) {
|
||||||
|
// -MAX_EXT_AMOUNT < extAmount < MAX_EXT_AMOUNT
|
||||||
|
if (_extAmount < MAX_EXT_AMOUNT) {
|
||||||
|
return int256(_extAmount);
|
||||||
|
} else if (_extAmount > FIELD_SIZE - MAX_EXT_AMOUNT) {
|
||||||
|
// FIELD_SIZE - MAX_EXT_AMOUNT < _extAmount < FIELD_SIZE
|
||||||
|
return -(int256(FIELD_SIZE) - int256(_extAmount));
|
||||||
|
} else {
|
||||||
|
revert("Invalid extAmount value");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function transfer(address payable to, uint256 amount) internal {
|
||||||
|
(bool success, ) = to.call.value(amount)("");
|
||||||
|
require(success, "payment did not go through");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @dev whether a note is already spent */
|
||||||
|
function isSpent(bytes32 _nullifierHash) public view returns(bool) {
|
||||||
|
return nullifierHashes[_nullifierHash];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @dev whether an array of notes is already spent */
|
||||||
|
function isSpentArray(bytes32[] calldata _nullifierHashes) external view returns(bool[] memory spent) {
|
||||||
|
spent = new bool[](_nullifierHashes.length);
|
||||||
|
for(uint i = 0; i < _nullifierHashes.length; i++) {
|
||||||
|
if (isSpent(_nullifierHashes[i])) {
|
||||||
|
spent[i] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
5
migrations/1_initial_migration.js
Normal file
5
migrations/1_initial_migration.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const Migrations = artifacts.require("Migrations");
|
||||||
|
|
||||||
|
module.exports = function(deployer) {
|
||||||
|
deployer.deploy(Migrations);
|
||||||
|
};
|
3915
package-lock.json
generated
Normal file
3915
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
19
package.json
Normal file
19
package.json
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "tornado-pool",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "truffle-config.js",
|
||||||
|
"directories": {
|
||||||
|
"test": "test"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"@openzeppelin/contracts": "^2.5.0",
|
||||||
|
"circomlib": "0.0.21"
|
||||||
|
}
|
||||||
|
}
|
99
truffle-config.js
Normal file
99
truffle-config.js
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
/**
|
||||||
|
* Use this file to configure your truffle project. It's seeded with some
|
||||||
|
* common settings for different networks and features like migrations,
|
||||||
|
* compilation and testing. Uncomment the ones you need or modify
|
||||||
|
* them to suit your project as necessary.
|
||||||
|
*
|
||||||
|
* More information about configuration can be found at:
|
||||||
|
*
|
||||||
|
* truffleframework.com/docs/advanced/configuration
|
||||||
|
*
|
||||||
|
* To deploy via Infura you'll need a wallet provider (like @truffle/hdwallet-provider)
|
||||||
|
* to sign your transactions before they're sent to a remote public node. Infura accounts
|
||||||
|
* are available for free at: infura.io/register.
|
||||||
|
*
|
||||||
|
* You'll also need a mnemonic - the twelve word phrase the wallet uses to generate
|
||||||
|
* public/private key pairs. If you're publishing your code to GitHub make sure you load this
|
||||||
|
* phrase from a file you've .gitignored so it doesn't accidentally become public.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// const HDWalletProvider = require('@truffle/hdwallet-provider');
|
||||||
|
// const infuraKey = "fj4jll3k.....";
|
||||||
|
//
|
||||||
|
// const fs = require('fs');
|
||||||
|
// const mnemonic = fs.readFileSync(".secret").toString().trim();
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
/**
|
||||||
|
* Networks define how you connect to your ethereum client and let you set the
|
||||||
|
* defaults web3 uses to send transactions. If you don't specify one truffle
|
||||||
|
* will spin up a development blockchain for you on port 9545 when you
|
||||||
|
* run `develop` or `test`. You can ask a truffle command to use a specific
|
||||||
|
* network from the command line, e.g
|
||||||
|
*
|
||||||
|
* $ truffle test --network <network-name>
|
||||||
|
*/
|
||||||
|
|
||||||
|
networks: {
|
||||||
|
// Useful for testing. The `development` name is special - truffle uses it by default
|
||||||
|
// if it's defined here and no other network is specified at the command line.
|
||||||
|
// You should run a client (like ganache-cli, geth or parity) in a separate terminal
|
||||||
|
// tab if you use this network and you must also set the `host`, `port` and `network_id`
|
||||||
|
// options below to some value.
|
||||||
|
//
|
||||||
|
// development: {
|
||||||
|
// host: "127.0.0.1", // Localhost (default: none)
|
||||||
|
// port: 8545, // Standard Ethereum port (default: none)
|
||||||
|
// network_id: "*", // Any network (default: none)
|
||||||
|
// },
|
||||||
|
|
||||||
|
// Another network with more advanced options...
|
||||||
|
// advanced: {
|
||||||
|
// port: 8777, // Custom port
|
||||||
|
// network_id: 1342, // Custom network
|
||||||
|
// gas: 8500000, // Gas sent with each transaction (default: ~6700000)
|
||||||
|
// gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei)
|
||||||
|
// from: <address>, // Account to send txs from (default: accounts[0])
|
||||||
|
// websockets: true // Enable EventEmitter interface for web3 (default: false)
|
||||||
|
// },
|
||||||
|
|
||||||
|
// Useful for deploying to a public network.
|
||||||
|
// NB: It's important to wrap the provider as a function.
|
||||||
|
// ropsten: {
|
||||||
|
// provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`),
|
||||||
|
// network_id: 3, // Ropsten's id
|
||||||
|
// gas: 5500000, // Ropsten has a lower block limit than mainnet
|
||||||
|
// confirmations: 2, // # of confs to wait between deployments. (default: 0)
|
||||||
|
// timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50)
|
||||||
|
// skipDryRun: true // Skip dry run before migrations? (default: false for public nets )
|
||||||
|
// },
|
||||||
|
|
||||||
|
// Useful for private networks
|
||||||
|
// private: {
|
||||||
|
// provider: () => new HDWalletProvider(mnemonic, `https://network.io`),
|
||||||
|
// network_id: 2111, // This network is yours, in the cloud.
|
||||||
|
// production: true // Treats this network as if it was a public net. (default: false)
|
||||||
|
// }
|
||||||
|
},
|
||||||
|
|
||||||
|
// Set default mocha options here, use special reporters etc.
|
||||||
|
mocha: {
|
||||||
|
// timeout: 100000
|
||||||
|
},
|
||||||
|
|
||||||
|
// Configure your compilers
|
||||||
|
compilers: {
|
||||||
|
solc: {
|
||||||
|
// version: "0.5.1", // Fetch exact version from solc-bin (default: truffle's version)
|
||||||
|
// docker: true, // Use "0.5.1" you've installed locally with docker (default: false)
|
||||||
|
// settings: { // See the solidity docs for advice about optimization and evmVersion
|
||||||
|
// optimizer: {
|
||||||
|
// enabled: false,
|
||||||
|
// runs: 200
|
||||||
|
// },
|
||||||
|
// evmVersion: "byzantium"
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user