Add smart contract tests
This commit is contained in:
parent
9a4e1f396d
commit
6e0fe64937
|
@ -1,24 +0,0 @@
|
|||
{
|
||||
"manifestVersion": "2.2",
|
||||
"contracts": {
|
||||
"Wormhole": "Wormhole"
|
||||
},
|
||||
"dependencies": {},
|
||||
"name": "wormhole",
|
||||
"version": "0.1.0",
|
||||
"compiler": {
|
||||
"compilerSettings": {
|
||||
"optimizer": {
|
||||
"enabled": false,
|
||||
"runs": "200"
|
||||
}
|
||||
},
|
||||
"typechain": {
|
||||
"enabled": false
|
||||
},
|
||||
"manager": "openzeppelin",
|
||||
"solcVersion": "0.6.12",
|
||||
"artifactsDir": "build/contracts",
|
||||
"contractsDir": "contracts"
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@ wrapped non-ETH assets that are currently held on ETH.
|
|||
### Deploying
|
||||
|
||||
To deploy the bridge on Ethereum you first need to compile all smart contracts:
|
||||
`npx oz compile`
|
||||
`npx truffle compile`
|
||||
|
||||
To deploy you can either use the bytecode from the `build/contracts` folder or the oz cli `oz deploy <Contract>`
|
||||
([Documentation](https://docs.openzeppelin.com/learn/deploying-and-interacting)).
|
||||
|
@ -22,6 +22,14 @@ Then deploy the `Wormhole` using the initial guardian key (`key_x,y_parity,0`) a
|
|||
`WrappedAsset`. The wrapped asset contract will be used as proxy library to all the creation of cheap proxy wrapped
|
||||
assets.
|
||||
|
||||
### Testing
|
||||
|
||||
For each test run:
|
||||
|
||||
Run `npx ganache-cli --deterministic --time "1970-01-01T00:00:00+00:00"` to start a chain.
|
||||
|
||||
Run the tests using `npm test`
|
||||
|
||||
### User methods
|
||||
|
||||
`submitVAA(bytes vaa)` can be used to execute a VAA.
|
||||
|
|
|
@ -53,7 +53,7 @@ contract Wormhole {
|
|||
);
|
||||
|
||||
// Mapping of guardian_set_index => guardian set
|
||||
mapping(uint32 => GuardianSet) private guardian_sets;
|
||||
mapping(uint32 => GuardianSet) public guardian_sets;
|
||||
// Current active guardian set
|
||||
uint32 public guardian_set_index;
|
||||
|
||||
|
@ -67,10 +67,11 @@ contract Wormhole {
|
|||
mapping(bytes32 => address) wrappedAssets;
|
||||
mapping(address => bool) isWrappedAsset;
|
||||
|
||||
constructor(GuardianSet memory initial_guardian_set, address wrapped_asset_master) public {
|
||||
constructor(GuardianSet memory initial_guardian_set, address wrapped_asset_master, uint32 _vaa_expiry) public {
|
||||
guardian_sets[0] = initial_guardian_set;
|
||||
// Explicitly set for doc purposes
|
||||
guardian_set_index = 0;
|
||||
vaa_expiry = _vaa_expiry;
|
||||
|
||||
wrappedAssetMaster = wrapped_asset_master;
|
||||
}
|
||||
|
@ -91,8 +92,7 @@ contract Wormhole {
|
|||
uint32 timestamp = vaa.toUint32(57);
|
||||
|
||||
// Verify that the VAA is still valid
|
||||
// TODO: the clock on Solana can't be trusted
|
||||
require(timestamp + vaa_expiry < block.timestamp, "VAA has expired");
|
||||
require(timestamp + vaa_expiry > block.timestamp, "VAA has expired");
|
||||
|
||||
// Hash the body
|
||||
bytes32 hash = keccak256(vaa.slice(57, vaa.length - 57));
|
||||
|
@ -129,16 +129,17 @@ contract Wormhole {
|
|||
|
||||
function vaaUpdateGuardianSet(bytes memory data) private {
|
||||
uint256 new_key_x = data.toUint256(0);
|
||||
uint256 new_key_y = data.toUint256(32);
|
||||
uint32 new_guardian_set_index = data.toUint32(64);
|
||||
uint256 y_parity = data.toUint8(32);
|
||||
uint32 new_guardian_set_index = data.toUint32(33);
|
||||
|
||||
require(new_guardian_set_index > guardian_set_index, "index of new guardian set must be > current");
|
||||
require(new_key_x < Schnorr.HALF_Q, "invalid key for fast Schnorr verification");
|
||||
require(y_parity <= 1, "invalid y parity");
|
||||
|
||||
uint32 old_guardian_set_index = guardian_set_index;
|
||||
guardian_set_index = new_guardian_set_index;
|
||||
|
||||
GuardianSet memory new_guardian_set = GuardianSet(new_key_x, uint8(new_key_y % 2), 0);
|
||||
GuardianSet memory new_guardian_set = GuardianSet(new_key_x, uint8(y_parity), 0);
|
||||
guardian_sets[guardian_set_index] = new_guardian_set;
|
||||
guardian_sets[old_guardian_set_index].expiration_time = uint32(block.timestamp) + vaa_expiry;
|
||||
|
||||
|
@ -226,7 +227,7 @@ contract Wormhole {
|
|||
asset_address = bytes32(uint256(asset));
|
||||
}
|
||||
|
||||
emit LogTokensLocked(target_chain, asset_chain, asset_address, recipient, bytes32(uint256(msg.sender)), amount);
|
||||
emit LogTokensLocked(target_chain, asset_chain, asset_address, bytes32(uint256(msg.sender)), recipient, amount);
|
||||
}
|
||||
|
||||
function lockETH(
|
||||
|
@ -239,7 +240,7 @@ contract Wormhole {
|
|||
WETH(WETHAddress).deposit{value : msg.value}();
|
||||
|
||||
// Log deposit of WETH
|
||||
emit LogTokensLocked(target_chain, CHAIN_ID, bytes32(uint256(WETHAddress)), recipient, bytes32(uint256(msg.sender)), msg.value);
|
||||
emit LogTokensLocked(target_chain, CHAIN_ID, bytes32(uint256(WETHAddress)), bytes32(uint256(msg.sender)), recipient, msg.value);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
const Schnorr = artifacts.require("Schnorr");
|
||||
const WrappedAsset = artifacts.require("WrappedAsset");
|
||||
const Wormhole = artifacts.require("Wormhole");
|
||||
|
||||
module.exports = async function (deployer) {
|
||||
await deployer.deploy(Schnorr);
|
||||
await deployer.deploy(WrappedAsset);
|
||||
await deployer.link(Schnorr, Wormhole);
|
||||
await deployer.deploy(Wormhole, {
|
||||
x: "15420174358166353706216094226583628565375637765325964030087969534155416299009",
|
||||
parity: 1,
|
||||
expiration_time: 0
|
||||
}, WrappedAsset.address, 1000);
|
||||
};
|
|
@ -1,12 +0,0 @@
|
|||
module.exports = {
|
||||
networks: {
|
||||
development: {
|
||||
protocol: 'http',
|
||||
host: 'localhost',
|
||||
port: 8545,
|
||||
gas: 5000000,
|
||||
gasPrice: 5e9,
|
||||
networkId: '*',
|
||||
},
|
||||
},
|
||||
};
|
File diff suppressed because it is too large
Load Diff
|
@ -5,12 +5,21 @@
|
|||
"main": "networks.js",
|
||||
"devDependencies": {
|
||||
"@openzeppelin/cli": "^2.8.2",
|
||||
"@openzeppelin/contracts": "^3.1.0"
|
||||
"@openzeppelin/contracts": "^3.1.0",
|
||||
"@openzeppelin/test-environment": "^0.1.4",
|
||||
"@openzeppelin/test-helpers": "^0.5.6",
|
||||
"chai": "^4.2.0",
|
||||
"mocha": "^8.1.1",
|
||||
"truffle-assertions": "^0.9.2",
|
||||
"truffle": "^5.1.37"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "openzeppelin compile",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
"build": "truffle compile",
|
||||
"test": "cp node_modules/@openzeppelin/contracts/build/contracts/* build/contracts/ && truffle test"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"truffle": "^5.1.37"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,179 @@
|
|||
const Schnorr = artifacts.require("Schnorr");
|
||||
const Wormhole = artifacts.require("Wormhole");
|
||||
const WrappedAsset = artifacts.require("WrappedAsset");
|
||||
const ERC20 = artifacts.require("ERC20PresetMinterPauser");
|
||||
|
||||
advanceTimeAndBlock = async (time) => {
|
||||
await advanceTime(time);
|
||||
await advanceBlock();
|
||||
|
||||
return Promise.resolve(web3.eth.getBlock('latest'));
|
||||
}
|
||||
|
||||
advanceTime = (time) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
web3.currentProvider.send({
|
||||
jsonrpc: "2.0",
|
||||
method: "evm_increaseTime",
|
||||
params: [time],
|
||||
id: new Date().getTime()
|
||||
}, (err, result) => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
return resolve(result);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
advanceBlock = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
web3.currentProvider.send({
|
||||
jsonrpc: "2.0",
|
||||
method: "evm_mine",
|
||||
id: new Date().getTime()
|
||||
}, (err, result) => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
const newBlockHash = web3.eth.getBlock('latest').hash;
|
||||
|
||||
return resolve(newBlockHash)
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
contract("Wormhole", function () {
|
||||
it("should use master wrapped asset", async function () {
|
||||
let bridge = await Wormhole.deployed();
|
||||
let wa = await bridge.wrappedAssetMaster.call();
|
||||
assert.equal(wa, WrappedAsset.address)
|
||||
});
|
||||
|
||||
it("should transfer tokens in on valid VAA", async function () {
|
||||
let bridge = await Wormhole.deployed();
|
||||
|
||||
await bridge.submitVAA("0x0100000000008df1ef2b367213cf591e6f6a8de37dd5a4ca771590f6f964a2c4a63b44c1e8532c0e595f4e6e0e784314724c85038af6576de0000007d01087000000330102020104000000000000000000000000000000000000000000000000000000000000000000000000000000000090f8bf6a479f320ead074411a4b0e7944ea8c9c1010000000000000000000000000347ef34687bdc9f189e87a9200658d9c40e99880000000000000000000000000000000000000000000000004563918244f40000")
|
||||
// Expect user to have a balance of a new wrapped asset
|
||||
let wa = new WrappedAsset("0x79183957Be84C0F4dA451E534d5bA5BA3FB9c696");
|
||||
assert.equal(await wa.assetChain(), 1)
|
||||
assert.equal(await wa.assetAddress(), "0x0000000000000000000000000347ef34687bdc9f189e87a9200658d9c40e9988")
|
||||
let balance = await wa.balanceOf("0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1");
|
||||
assert.equal(balance, "5000000000000000000");
|
||||
});
|
||||
|
||||
it("should not accept the same VAA twice", async function () {
|
||||
let bridge = await Wormhole.deployed();
|
||||
try {
|
||||
await bridge.submitVAA("0x0100000000008df1ef2b367213cf591e6f6a8de37dd5a4ca771590f6f964a2c4a63b44c1e8532c0e595f4e6e0e784314724c85038af6576de0000007d01087000000330102020104000000000000000000000000000000000000000000000000000000000000000000000000000000000090f8bf6a479f320ead074411a4b0e7944ea8c9c1010000000000000000000000000347ef34687bdc9f189e87a9200658d9c40e99880000000000000000000000000000000000000000000000004563918244f40000");
|
||||
} catch (e) {
|
||||
return
|
||||
}
|
||||
assert.fail("did not fail")
|
||||
});
|
||||
|
||||
it("should burn tokens on lock", async function () {
|
||||
let bridge = await Wormhole.deployed();
|
||||
// Expect user to have a balance
|
||||
let wa = new WrappedAsset("0x79183957Be84C0F4dA451E534d5bA5BA3FB9c696")
|
||||
|
||||
await bridge.lockAssets(wa.address, "4000000000000000000", "0x0", 2);
|
||||
let balance = await wa.balanceOf("0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1");
|
||||
|
||||
// Expect user balance to decrease
|
||||
assert.equal(balance, "1000000000000000000");
|
||||
|
||||
// Expect contract balance to be 0 since tokens have been burned
|
||||
balance = await wa.balanceOf(bridge.address);
|
||||
assert.equal(balance, "0");
|
||||
});
|
||||
|
||||
it("should transfer tokens in and out", async function () {
|
||||
let bridge = await Wormhole.deployed();
|
||||
let token = await ERC20.new("Test Token", "TKN");
|
||||
|
||||
await token.mint("0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1", "1000000000000000000");
|
||||
// Expect user to have a balance
|
||||
assert.equal(await token.balanceOf("0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1"), "1000000000000000000");
|
||||
|
||||
// Approve bridge
|
||||
await token.approve(bridge.address, "1000000000000000000");
|
||||
|
||||
// Transfer of that token out of the contract should not work
|
||||
let threw = false;
|
||||
try {
|
||||
await bridge.submitVAA("0x0100000000636e71c9cb08d64b6388a39d28779fab9dd42edad20331d022c9e90a43b78b1bfc737f2973136230a9e323fbd5d2f7d6cb599c2bfffff82f1087000000310102020104000000000000000000000000000000000000000000000000000000000000000000000000000000000090f8bf6a479f320ead074411a4b0e7944ea8c9c1020000000000000000000000009561c133dd8580860b6b7e504bc5aa500f0f06a70000000000000000000000000000000000000000000000000de0b6b3a7640000");
|
||||
} catch (e) {
|
||||
threw = true;
|
||||
}
|
||||
assert.isTrue(threw);
|
||||
|
||||
// Lock assets
|
||||
let ev = await bridge.lockAssets(token.address, "1000000000000000000", "0x1230000000000000000000000000000000000000000000000000000000000000", 3);
|
||||
|
||||
// Check that the lock event was emitted correctly
|
||||
assert.lengthOf(ev.logs, 1)
|
||||
assert.equal(ev.logs[0].event, "LogTokensLocked")
|
||||
assert.equal(ev.logs[0].args.target_chain, "3")
|
||||
assert.equal(ev.logs[0].args.token_chain, "2")
|
||||
assert.equal(ev.logs[0].args.token, "0x0000000000000000000000009561c133dd8580860b6b7e504bc5aa500f0f06a7")
|
||||
assert.equal(ev.logs[0].args.sender, "0x00000000000000000000000090f8bf6a479f320ead074411a4b0e7944ea8c9c1")
|
||||
assert.equal(ev.logs[0].args.recipient, "0x1230000000000000000000000000000000000000000000000000000000000000")
|
||||
assert.equal(ev.logs[0].args.amount, "1000000000000000000")
|
||||
|
||||
// Check that the tokens were transferred to the bridge
|
||||
assert.equal(await token.balanceOf("0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1"), "0");
|
||||
assert.equal(await token.balanceOf(bridge.address), "1000000000000000000");
|
||||
|
||||
// Transfer this token back
|
||||
await bridge.submitVAA("0x0100000000636e71c9cb08d64b6388a39d28779fab9dd42edad20331d022c9e90a43b78b1bfc737f2973136230a9e323fbd5d2f7d6cb599c2bfffff82f1087000000310102020104000000000000000000000000000000000000000000000000000000000000000000000000000000000090f8bf6a479f320ead074411a4b0e7944ea8c9c1020000000000000000000000009561c133dd8580860b6b7e504bc5aa500f0f06a70000000000000000000000000000000000000000000000000de0b6b3a7640000");
|
||||
assert.equal(await token.balanceOf("0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1"), "1000000000000000000");
|
||||
assert.equal(await token.balanceOf(bridge.address), "0");
|
||||
});
|
||||
|
||||
it("should accept validator set change", async function () {
|
||||
let bridge = await Wormhole.deployed();
|
||||
|
||||
// Push time by 1000
|
||||
await advanceTimeAndBlock(1000);
|
||||
await bridge.submitVAA("0x0100000000fe60d5766a84300effedd5362dcf6ff8f4ed75ab3dbe4c1ae07151ab48bc8cbf767b4aa42cf768477dc5bb45367044bd2de6d6b3000003e801253e2f87d126ef42ac22d284de7619d2c87437198a32887efeddb4debfd016747f0000000001")
|
||||
// Expect user to have a balance of a new wrapped asset
|
||||
assert.equal(await bridge.guardian_set_index(), 1);
|
||||
assert.equal((await bridge.guardian_sets(1)).x, "28127375798693063422362909717576839343810687066240716944661469189277081826431");
|
||||
|
||||
// Test VAA from guardian set 0; timestamp 1000
|
||||
await bridge.submitVAA("0x01000000004f871da18c25af540bf7ea0ef28df13ff8945903fa1b82aa5d11ff749f33dba57b6064666dfe07b627e5e1da1f4bf620f92c15c2000003e81087000000340102020104000000000000000000000000000000000000000000000000000000000000000000000000000000000090f8bf6a479f320ead074411a4b0e7944ea8c9c1010000000000000000000000000347ef34687bdc9f189e87a9200658d9c40e99880000000000000000000000000000000000000000000000004563918244f40000")
|
||||
|
||||
await advanceTimeAndBlock(1000);
|
||||
|
||||
// Test VAA from guardian set 0; timestamp 2000 - should not work anymore
|
||||
let threw = false;
|
||||
try {
|
||||
await bridge.submitVAA("0x01000000004629dc39ea4b284d31f9c7d5350013aeed4b1c38a80fc65fb21e6c7da5ebd0eb13b46039f40a0ddd7c94c3e974b51cacf9eaa1bb000007d01087000000340102020104000000000000000000000000000000000000000000000000000000000000000000000000000000000090f8bf6a479f320ead074411a4b0e7944ea8c9c1010000000000000000000000000347ef34687bdc9f189e87a9200658d9c40e99880000000000000000000000000000000000000000000000004563918244f40000")
|
||||
} catch (e) {
|
||||
threw = true;
|
||||
assert.equal(e.reason, "guardian set has expired")
|
||||
}
|
||||
assert.isTrue(threw, "guardian set did not expire")
|
||||
|
||||
// Test same transaction with guardian set 1; timestamp 2000
|
||||
await bridge.submitVAA("0x01000000011322402df3ec812a145aa2d9b0f627ff3654c9b3ca471622a1439e81da62ec384ad14db65ae4bee55a23b8082628590902e3d778000007d01087000000340102020104000000000000000000000000000000000000000000000000000000000000000000000000000000000090f8bf6a479f320ead074411a4b0e7944ea8c9c1010000000000000000000000000347ef34687bdc9f189e87a9200658d9c40e99880000000000000000000000000000000000000000000000004563918244f40000")
|
||||
});
|
||||
|
||||
it("should expire VAA", async function () {
|
||||
let bridge = await Wormhole.deployed();
|
||||
|
||||
// Push time by 1000
|
||||
await advanceTimeAndBlock(1000);
|
||||
|
||||
// Test same transaction with guardian set 1; timestamp 2000
|
||||
let threw = false;
|
||||
try {
|
||||
await bridge.submitVAA("0x01000000013faebdc02d6427d1e8d33919fbaa519ca402323723922c772e4e2da7fedc820c15b24aa5e4c99bec6a9f4c9b612970590ea3acd1000007d01087000000350102020104000000000000000000000000000000000000000000000000000000000000000000000000000000000090f8bf6a479f320ead074411a4b0e7944ea8c9c1010000000000000000000000000347ef34687bdc9f189e87a9200658d9c40e99880000000000000000000000000000000000000000000000004563918244f40000")
|
||||
} catch (e) {
|
||||
threw = true;
|
||||
assert.equal(e.reason, "VAA has expired")
|
||||
}
|
||||
assert.isTrue(threw, "VAA did not expire")
|
||||
});
|
||||
});
|
|
@ -0,0 +1,96 @@
|
|||
/**
|
||||
* 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.6.12", // 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