Merge pull request #14 from 0xProject/implementFirstExchangeMethod

Implement first exchange method
This commit is contained in:
Fabio Berger 2017-05-26 18:54:56 +02:00 committed by GitHub
commit b897bdab79
25 changed files with 3439 additions and 40 deletions

2
.gitignore vendored
View File

@ -59,8 +59,6 @@ typings/
# built library using in commonjs module syntax
lib
# built library using es6 module syntax to enable webpack and rollup tree shaking
lib-esm
# UMD bundles that export the global variable
_bundles

View File

@ -4,4 +4,10 @@ machine:
test:
override:
- node node_modules/ethereumjs-testrpc/bin/testrpc:
background: true
- git clone git@github.com:0xProject/contracts.git ../contracts
- cd ../contracts; git checkout 38c2b4c; npm install && npm run migrate
- npm run update_contracts
- npm run test:coverage
- npm run lint

View File

@ -10,17 +10,21 @@
"exchange"
],
"scripts": {
"clean": "shx rm -rf _bundles lib lib-esm",
"clean": "shx rm -rf _bundles lib",
"build:bundle": "webpack",
"build:commonjs": "tsc",
"build:es6": "tsc -m es6 --outDir lib-esm",
"build:commonjs": "tsc; copyfiles -u 2 ./src/artifacts/*.json ../0x.js/lib/src/artifacts;",
"build": "npm run clean && run-p build:*",
"lint": "tslint src/ts/**/*",
"test": "run-s clean build:commonjs && mocha lib/test/**/*.js",
"test": "run-s clean build:commonjs && mocha lib/test/**/*_test.js",
"test:coverage": "nyc npm run test --all",
"docs:json": "typedoc --json docs/index.json .",
"docs:generate": "typedoc --out docs .",
"docs:open": "opn docs/index.html"
"docs:open": "opn docs/index.html",
"update_contracts": "for i in ${npm_package_config_artifacts}; do copyfiles -u 4 ../contracts/build/contracts/$i.json ../0x.js/src/artifacts; done;",
"testrpc": "testrpc -p 8545 --networkId 50"
},
"config": {
"artifacts": "Proxy Exchange TokenRegistry Token Mintable EtherToken"
},
"repository": {
"type": "git",
@ -33,31 +37,43 @@
"devDependencies": {
"@types/bignumber.js": "^4.0.2",
"@types/chai": "^3.5.2",
"@types/chai-as-promised": "0.0.30",
"@types/jsonschema": "^1.1.1",
"@types/lodash": "^4.14.64",
"@types/mocha": "^2.2.41",
"@types/node": "^7.0.22",
"awesome-typescript-loader": "^3.1.3",
"bignumber.js": "^4.0.2",
"chai": "^3.5.0",
"chai-as-promised": "^6.0.0",
"chai-bignumber": "^2.0.0",
"copyfiles": "^1.2.0",
"ethereumjs-testrpc": "^3.0.5",
"json-loader": "^0.5.4",
"mocha": "^3.4.1",
"npm-run-all": "^4.0.2",
"nyc": "^10.3.2",
"opn-cli": "^3.1.0",
"request": "^2.81.0",
"request-promise-native": "^1.0.4",
"shx": "^0.2.2",
"source-map-support": "^0.4.15",
"tslint": "^5.3.2",
"tslint-config-0xproject": "^0.0.2",
"typedoc": "^0.7.1",
"typescript": "^2.3.3",
"web3-typescript-typings": "0.0.3",
"web3-provider-engine": "^12.1.0",
"web3-typescript-typings": "0.0.8",
"webpack": "^2.6.0"
},
"dependencies": {
"bignumber.js": "^4.0.2",
"es6-promisify": "^5.0.0",
"ethereumjs-abi": "^0.6.4",
"ethereumjs-util": "^5.1.1",
"jsonschema": "^1.1.1",
"lodash": "^4.17.4",
"truffle-contract": "^2.0.0",
"web3": "^0.19.0"
}
}

View File

@ -0,0 +1,339 @@
{
"contract_name": "EtherToken",
"abi": [
{
"constant": true,
"inputs": [],
"name": "name",
"outputs": [
{
"name": "",
"type": "string"
}
],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_spender",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "approve",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "totalSupply",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_from",
"type": "address"
},
{
"name": "_to",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "transferFrom",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "amount",
"type": "uint256"
}
],
"name": "withdraw",
"outputs": [],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "decimals",
"outputs": [
{
"name": "",
"type": "uint8"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_owner",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "symbol",
"outputs": [
{
"name": "",
"type": "string"
}
],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_to",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "transfer",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [],
"name": "deposit",
"outputs": [],
"payable": true,
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_owner",
"type": "address"
},
{
"name": "_spender",
"type": "address"
}
],
"name": "allowance",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"type": "function"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "_from",
"type": "address"
},
{
"indexed": true,
"name": "_to",
"type": "address"
},
{
"indexed": false,
"name": "_value",
"type": "uint256"
}
],
"name": "Transfer",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "_owner",
"type": "address"
},
{
"indexed": true,
"name": "_spender",
"type": "address"
},
{
"indexed": false,
"name": "_value",
"type": "uint256"
}
],
"name": "Approval",
"type": "event"
}
],
"unlinked_binary": "0x606060405234610000575b61072d806100196000396000f300606060405236156100935763ffffffff60e060020a60003504166306fdde038114610098578063095ea7b31461012557806318160ddd1461015557806323b872dd146101745780632e1a7d4d146101aa578063313ce567146101bc57806370a08231146101df57806395d89b411461020a578063a9059cbb14610297578063d0e30db0146102c7578063dd62ed3e146102d1575b610000565b34610000576100a5610302565b6040805160208082528351818301528351919283929083019185019080838382156100eb575b8051825260208311156100eb57601f1990920191602091820191016100cb565b505050905090810190601f1680156101175780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3461000057610141600160a060020a0360043516602435610339565b604080519115158252519081900360200190f35b34610000576101626103a4565b60408051918252519081900360200190f35b3461000057610141600160a060020a03600435811690602435166044356103aa565b604080519115158252519081900360200190f35b34610000576101ba6004356104a7565b005b34610000576101c9610527565b6040805160ff9092168252519081900360200190f35b3461000057610162600160a060020a036004351661052c565b60408051918252519081900360200190f35b34610000576100a561054b565b6040805160208082528351818301528351919283929083019185019080838382156100eb575b8051825260208311156100eb57601f1990920191602091820191016100cb565b505050905090810190601f1680156101175780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3461000057610141600160a060020a0360043516602435610582565b604080519115158252519081900360200190f35b6101ba610634565b005b3461000057610162600160a060020a0360043581169060243516610683565b60408051918252519081900360200190f35b60408051808201909152600b81527f457468657220546f6b656e000000000000000000000000000000000000000000602082015281565b600160a060020a03338116600081815260016020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b60025481565b600160a060020a0383166000908152602081905260408120546103cd90836106b0565b600160a060020a03808616600090815260208181526040808320949094556001815283822033909316825291909152205461040890836106b0565b600160a060020a0380861660009081526001602090815260408083203385168452825280832094909455918616815290819052205461044790836106c9565b600160a060020a038085166000818152602081815260409182902094909455805186815290519193928816927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a35060015b9392505050565b600160a060020a0333166000908152602081905260409020546104ca90826106b0565b600160a060020a0333166000908152602081905260409020556002546104f090826106b0565b600255604051600160a060020a0333169082156108fc029083906000818181858888f19350505050151561052357610000565b5b50565b601281565b600160a060020a0381166000908152602081905260409020545b919050565b60408051808201909152600481527f5745544800000000000000000000000000000000000000000000000000000000602082015281565b600160a060020a0333166000908152602081905260408120546105a590836106b0565b600160a060020a0333811660009081526020819052604080822093909355908516815220546105d490836106c9565b600160a060020a03808516600081815260208181526040918290209490945580518681529051919333909316927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a35060015b92915050565b600160a060020a03331660009081526020819052604090205461065790346106c9565b600160a060020a03331660009081526020819052604090205560025461067d90346106c9565b6002555b565b600160a060020a038083166000908152600160209081526040808320938516835292905220545b92915050565b60006106be838311156106f1565b508082035b92915050565b60008282016106e68482108015906106e15750838210155b6106f1565b8091505b5092915050565b80151561052357610000565b5b505600a165627a7a72305820b28cd5acca9bda15cda19b84401b1834ed21ef11cbefcfb3b7a366fe2680aa8e0029",
"networks": {
"42": {
"links": {},
"events": {
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef": {
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "_from",
"type": "address"
},
{
"indexed": true,
"name": "_to",
"type": "address"
},
{
"indexed": false,
"name": "_value",
"type": "uint256"
}
],
"name": "Transfer",
"type": "event"
},
"0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925": {
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "_owner",
"type": "address"
},
{
"indexed": true,
"name": "_spender",
"type": "address"
},
{
"indexed": false,
"name": "_value",
"type": "uint256"
}
],
"name": "Approval",
"type": "event"
}
},
"updated_at": 1495042008609,
"address": "0xd5cbb5c0d14718a844b1e4cd141878a0e2a71760"
},
"50": {
"links": {},
"events": {
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef": {
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "_from",
"type": "address"
},
{
"indexed": true,
"name": "_to",
"type": "address"
},
{
"indexed": false,
"name": "_value",
"type": "uint256"
}
],
"name": "Transfer",
"type": "event"
},
"0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925": {
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "_owner",
"type": "address"
},
{
"indexed": true,
"name": "_spender",
"type": "address"
},
{
"indexed": false,
"name": "_value",
"type": "uint256"
}
],
"name": "Approval",
"type": "event"
}
},
"updated_at": 1495030736786,
"address": "0x48bacb9266a570d521063ef5dd96e61686dbe788"
}
},
"schema_version": "0.0.5",
"updated_at": 1495042008609
}

985
src/artifacts/Exchange.json Normal file

File diff suppressed because one or more lines are too long

189
src/artifacts/Mintable.json Normal file
View File

@ -0,0 +1,189 @@
{
"contract_name": "Mintable",
"abi": [
{
"constant": false,
"inputs": [
{
"name": "_spender",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "approve",
"outputs": [
{
"name": "success",
"type": "bool"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "totalSupply",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_from",
"type": "address"
},
{
"name": "_to",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "transferFrom",
"outputs": [
{
"name": "success",
"type": "bool"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_owner",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"name": "balance",
"type": "uint256"
}
],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_value",
"type": "uint256"
}
],
"name": "mint",
"outputs": [],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_to",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "transfer",
"outputs": [
{
"name": "success",
"type": "bool"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_owner",
"type": "address"
},
{
"name": "_spender",
"type": "address"
}
],
"name": "allowance",
"outputs": [
{
"name": "remaining",
"type": "uint256"
}
],
"payable": false,
"type": "function"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "_from",
"type": "address"
},
{
"indexed": true,
"name": "_to",
"type": "address"
},
{
"indexed": false,
"name": "_value",
"type": "uint256"
}
],
"name": "Transfer",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "_owner",
"type": "address"
},
{
"indexed": true,
"name": "_spender",
"type": "address"
},
{
"indexed": false,
"name": "_value",
"type": "uint256"
}
],
"name": "Approval",
"type": "event"
}
],
"unlinked_binary": "0x606060405234610000575b6104e7806100196000396000f300606060405236156100675763ffffffff60e060020a600035041663095ea7b3811461006c57806318160ddd1461009c57806323b872dd146100bb57806370a08231146100f1578063a0712d681461011c578063a9059cbb1461012e578063dd62ed3e1461015e575b610000565b3461000057610088600160a060020a036004351660243561018f565b604080519115158252519081900360200190f35b34610000576100a96101fa565b60408051918252519081900360200190f35b3461000057610088600160a060020a0360043581169060243516604435610200565b604080519115158252519081900360200190f35b34610000576100a9600160a060020a036004351661030d565b60408051918252519081900360200190f35b346100005761012c60043561032c565b005b3461000057610088600160a060020a0360043516602435610393565b604080519115158252519081900360200190f35b34610000576100a9600160a060020a0360043581169060243516610456565b60408051918252519081900360200190f35b600160a060020a03338116600081815260016020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b60025481565b600160a060020a0383166000908152602081905260408120548290108015906102505750600160a060020a0380851660009081526001602090815260408083203390941683529290522054829010155b80156102755750600160a060020a038316600090815260208190526040902054828101115b1561030157600160a060020a0380841660008181526020818152604080832080548801905588851680845281842080548990039055600183528184203390961684529482529182902080548790039055815186815291519293927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a3506001610305565b5060005b5b9392505050565b600160a060020a0381166000908152602081905260409020545b919050565b68056bc75e2d6310000081111561034257610000565b600160a060020a033316600090815260208190526040902054610366908290610483565b600160a060020a03331660009081526020819052604090205560025461038c9082610483565b6002555b50565b600160a060020a0333166000908152602081905260408120548290108015906103d55750600160a060020a038316600090815260208190526040902054828101115b1561044757600160a060020a0333811660008181526020818152604080832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a35060016101f4565b5060006101f4565b5b92915050565b600160a060020a038083166000908152600160209081526040808320938516835292905220545b92915050565b60008282016104a084821080159061049b5750838210155b6104ab565b8091505b5092915050565b80151561039057610000565b5b505600a165627a7a72305820cf19b2935b2a852369d6ff6508a8c5c3b184b660a7d117af9fd1c7224bdb1d2f0029",
"networks": {},
"schema_version": "0.0.5",
"updated_at": 1495030728122
}

267
src/artifacts/Proxy.json Normal file
View File

@ -0,0 +1,267 @@
{
"contract_name": "Proxy",
"abi": [
{
"constant": false,
"inputs": [
{
"name": "token",
"type": "address"
},
{
"name": "from",
"type": "address"
},
{
"name": "to",
"type": "address"
},
{
"name": "value",
"type": "uint256"
}
],
"name": "transferFrom",
"outputs": [
{
"name": "success",
"type": "bool"
}
],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "target",
"type": "address"
}
],
"name": "addAuthorizedAddress",
"outputs": [
{
"name": "success",
"type": "bool"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "",
"type": "uint256"
}
],
"name": "authorities",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "target",
"type": "address"
}
],
"name": "removeAuthorizedAddress",
"outputs": [
{
"name": "success",
"type": "bool"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "owner",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "",
"type": "address"
}
],
"name": "authorized",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getAuthorizedAddresses",
"outputs": [
{
"name": "",
"type": "address[]"
}
],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "newOwner",
"type": "address"
}
],
"name": "transferOwnership",
"outputs": [],
"payable": false,
"type": "function"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "target",
"type": "address"
},
{
"indexed": true,
"name": "caller",
"type": "address"
}
],
"name": "LogAuthorizedAddressAdded",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "target",
"type": "address"
},
{
"indexed": true,
"name": "caller",
"type": "address"
}
],
"name": "LogAuthorizedAddressRemoved",
"type": "event"
}
],
"unlinked_binary": "0x60606040525b60008054600160a060020a03191633600160a060020a03161790555b5b610701806100316000396000f300606060405236156100725763ffffffff60e060020a60003504166315dacbea811461007757806342f1181e146100b3578063494503d4146100e0578063707129391461010c5780638da5cb5b14610139578063b918161114610162578063d39de6e91461018f578063f2fde38b146101f7575b610000565b346100005761009f600160a060020a0360043581169060243581169060443516606435610212565b604080519115158252519081900360200190f35b346100005761009f600160a060020a03600435166102d8565b604080519115158252519081900360200190f35b34610000576100f06004356103f5565b60408051600160a060020a039092168252519081900360200190f35b346100005761009f600160a060020a0360043516610425565b604080519115158252519081900360200190f35b34610000576100f06105ee565b60408051600160a060020a039092168252519081900360200190f35b346100005761009f600160a060020a03600435166105fd565b604080519115158252519081900360200190f35b346100005761019c610612565b60408051602080825283518183015283519192839290830191858101910280838382156101e4575b8051825260208311156101e457601f1990920191602091820191016101c4565b5050509050019250505060405180910390f35b3461000057610210600160a060020a036004351661067d565b005b600160a060020a03331660009081526001602052604081205460ff16151561023957610000565b604080516000602091820181905282517f23b872dd000000000000000000000000000000000000000000000000000000008152600160a060020a0388811660048301528781166024830152604482018790529351938916936323b872dd9360648084019491938390030190829087803b156100005760325a03f11561000057505060405151151590506102cb57610000565b5060015b5b949350505050565b6000805433600160a060020a039081169116146102f457610000565b600160a060020a038216600090815260016020526040902054829060ff161561031c57610000565b600160a060020a0383166000908152600160208190526040909120805460ff191682179055600280549182018082559091908281838015829011610385576000838152602090206103859181019083015b80821115610381576000815560010161036d565b5090565b5b505050916000526020600020900160005b81546101009190910a600160a060020a0381810219909216878316918202179092556040513390911692507f94bb87f4c15c4587ff559a7584006fa01ddf9299359be6b512b94527aa961aca90600090a3600191505b5b505b919050565b600281815481101561000057906000526020600020900160005b915054906101000a9004600160a060020a031681565b60008054819033600160a060020a0390811691161461044357610000565b600160a060020a038316600090815260016020526040902054839060ff16151561046c57610000565b600160a060020a0384166000908152600160205260408120805460ff1916905591505b6002548210156105a75783600160a060020a0316600283815481101561000057906000526020600020900160005b9054906101000a9004600160a060020a0316600160a060020a0316141561059b576002805460001981019081101561000057906000526020600020900160005b9054906101000a9004600160a060020a0316600283815481101561000057906000526020600020900160005b6101000a815481600160a060020a030219169083600160a060020a031602179055506001600281818054905003915081815481835581811511610591576000838152602090206105919181019083015b80821115610381576000815560010161036d565b5090565b5b505050506105a7565b5b60019091019061048f565b604051600160a060020a0333811691908616907ff5b347a1e40749dd050f5f07fbdbeb7e3efa9756903044dd29401fd1d4bb4a1c90600090a3600192505b5b505b50919050565b600054600160a060020a031681565b60016020526000908152604090205460ff1681565b60408051602081810183526000825260028054845181840281018401909552808552929392909183018282801561067257602002820191906000526020600020905b8154600160a060020a03168152600190910190602001808311610654575b505050505090505b90565b60005433600160a060020a0390811691161461069857610000565b600160a060020a038116156106d0576000805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0383161790555b5b5b505600a165627a7a723058209cd95460fca24868b66555c9516a21cd9ea580df9649543a663b057f4de4808b0029",
"networks": {
"42": {
"links": {},
"events": {
"0x94bb87f4c15c4587ff559a7584006fa01ddf9299359be6b512b94527aa961aca": {
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "target",
"type": "address"
},
{
"indexed": true,
"name": "caller",
"type": "address"
}
],
"name": "LogAuthorizedAddressAdded",
"type": "event"
},
"0xf5b347a1e40749dd050f5f07fbdbeb7e3efa9756903044dd29401fd1d4bb4a1c": {
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "target",
"type": "address"
},
{
"indexed": true,
"name": "caller",
"type": "address"
}
],
"name": "LogAuthorizedAddressRemoved",
"type": "event"
}
},
"updated_at": 1495042008598,
"address": "0x72a2820f45b3e977897a63f2a726c21754f3730d"
},
"50": {
"links": {},
"events": {
"0x94bb87f4c15c4587ff559a7584006fa01ddf9299359be6b512b94527aa961aca": {
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "target",
"type": "address"
},
{
"indexed": true,
"name": "caller",
"type": "address"
}
],
"name": "LogAuthorizedAddressAdded",
"type": "event"
},
"0xf5b347a1e40749dd050f5f07fbdbeb7e3efa9756903044dd29401fd1d4bb4a1c": {
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "target",
"type": "address"
},
{
"indexed": true,
"name": "caller",
"type": "address"
}
],
"name": "LogAuthorizedAddressRemoved",
"type": "event"
}
},
"updated_at": 1495030736781,
"address": "0x871dd7c2b4b25e1aa18728e9d5f2af4c4e431f5c"
}
},
"schema_version": "0.0.5",
"updated_at": 1495042008598
}

176
src/artifacts/Token.json Normal file
View File

@ -0,0 +1,176 @@
{
"contract_name": "Token",
"abi": [
{
"constant": false,
"inputs": [
{
"name": "_spender",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "approve",
"outputs": [
{
"name": "success",
"type": "bool"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "totalSupply",
"outputs": [
{
"name": "supply",
"type": "uint256"
}
],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_from",
"type": "address"
},
{
"name": "_to",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "transferFrom",
"outputs": [
{
"name": "success",
"type": "bool"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_owner",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"name": "balance",
"type": "uint256"
}
],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_to",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "transfer",
"outputs": [
{
"name": "success",
"type": "bool"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_owner",
"type": "address"
},
{
"name": "_spender",
"type": "address"
}
],
"name": "allowance",
"outputs": [
{
"name": "remaining",
"type": "uint256"
}
],
"payable": false,
"type": "function"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "_from",
"type": "address"
},
{
"indexed": true,
"name": "_to",
"type": "address"
},
{
"indexed": false,
"name": "_value",
"type": "uint256"
}
],
"name": "Transfer",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "_owner",
"type": "address"
},
{
"indexed": true,
"name": "_spender",
"type": "address"
},
{
"indexed": false,
"name": "_value",
"type": "uint256"
}
],
"name": "Approval",
"type": "event"
}
],
"unlinked_binary": "0x606060405234610000575b6101d1806100196000396000f3006060604052361561005c5763ffffffff60e060020a600035041663095ea7b3811461006157806318160ddd1461009157806323b872dd146100b057806370a08231146100e6578063a9059cbb14610061578063dd62ed3e14610141575b610000565b346100005761007d600160a060020a0360043516602435610172565b604080519115158252519081900360200190f35b346100005761009e61017b565b60408051918252519081900360200190f35b346100005761007d600160a060020a0360043581169060243516604435610181565b604080519115158252519081900360200190f35b346100005761009e600160a060020a036004351661018b565b60408051918252519081900360200190f35b346100005761007d600160a060020a0360043516602435610172565b604080519115158252519081900360200190f35b346100005761009e600160a060020a0360043581169060243516610172565b60408051918252519081900360200190f35b60005b92915050565b60005b90565b60005b9392505050565b60005b919050565b60005b92915050565b60005b929150505600a165627a7a7230582031ad84562e693d05c7c6f36cc87a07055903923d08faf214a07c4e7c3b2d4a8f0029",
"networks": {},
"schema_version": "0.0.5",
"updated_at": 1495030728125
}

File diff suppressed because one or more lines are too long

View File

@ -1,25 +1,22 @@
import * as _ from 'lodash';
import * as BigNumber from 'bignumber.js';
import * as BN from 'bn.js';
import * as ethUtil from 'ethereumjs-util';
import contract = require('truffle-contract');
import * as Web3 from 'web3';
import * as ethABI from 'ethereumjs-abi';
import * as _ from 'lodash';
import {Web3Wrapper} from './web3_wrapper';
import {constants} from './utils/constants';
import {assert} from './utils/assert';
import {ExchangeWrapper} from './contract_wrappers/exchange_wrapper';
import {ECSignatureSchema} from './schemas/ec_signature_schema';
import {SolidityTypes} from './types';
/**
* Elliptic Curve signature
*/
export interface ECSignature {
v: number;
r: string;
s: string;
}
import {SolidityTypes, ECSignature} from './types';
const MAX_DIGITS_IN_UNSIGNED_256_INT = 78;
export class ZeroEx {
public web3Wrapper: Web3Wrapper;
public exchange: ExchangeWrapper;
/**
* Computes the orderHash given the order parameters and returns it as a hex encoded string.
*/
@ -74,7 +71,8 @@ export class ZeroEx {
const dataBuff = ethUtil.toBuffer(dataHex);
const msgHashBuff = ethUtil.hashPersonalMessage(dataBuff);
try {
const pubKey = ethUtil.ecrecover(msgHashBuff,
const pubKey = ethUtil.ecrecover(
msgHashBuff,
signature.v,
ethUtil.toBuffer(signature.r),
ethUtil.toBuffer(signature.s));
@ -129,7 +127,6 @@ export class ZeroEx {
const baseUnitAmount = amount.times(unit);
return baseUnitAmount;
}
/**
* Converts BigNumber instance to BN
* The only we convert to BN is to remain compatible with `ethABI. soliditySHA3 ` that
@ -139,4 +136,8 @@ export class ZeroEx {
private static bigNumberToBN(value: BigNumber.BigNumber) {
return new BN(value.toString(), 10);
}
constructor(web3: Web3) {
this.web3Wrapper = new Web3Wrapper(web3);
this.exchange = new ExchangeWrapper(this.web3Wrapper);
}
}

View File

@ -0,0 +1,48 @@
import * as _ from 'lodash';
import contract = require('truffle-contract');
import {Web3Wrapper} from '../web3_wrapper';
import {ZeroExError} from '../types';
import {utils} from '../utils/utils';
export class ContractWrapper {
public web3Wrapper: Web3Wrapper;
constructor(web3Wrapper: Web3Wrapper) {
this.web3Wrapper = web3Wrapper;
}
protected async instantiateContractIfExistsAsync(artifact: Artifact, address?: string): Promise<ContractInstance> {
const c = await contract(artifact);
const providerObj = this.web3Wrapper.getCurrentProvider();
c.setProvider(providerObj);
const networkIdIfExists = await this.web3Wrapper.getNetworkIdIfExistsAsync();
const artifactNetworkConfigs = _.isUndefined(networkIdIfExists) ?
undefined :
artifact.networks[networkIdIfExists];
let contractAddress;
if (!_.isUndefined(address)) {
contractAddress = address;
} else if (!_.isUndefined(artifactNetworkConfigs)) {
contractAddress = artifactNetworkConfigs.address;
}
if (!_.isUndefined(contractAddress)) {
const doesContractExist = await this.web3Wrapper.doesContractExistAtAddressAsync(contractAddress);
if (!doesContractExist) {
throw new Error(ZeroExError.CONTRACT_DOES_NOT_EXIST);
}
}
try {
const contractInstance = _.isUndefined(address) ? await c.deployed() : await c.at(address);
return contractInstance;
} catch (err) {
const errMsg = `${err}`;
if (_.includes(errMsg, 'not been deployed to detected network')) {
throw new Error(ZeroExError.CONTRACT_DOES_NOT_EXIST);
} else {
utils.consoleLog(`Notice: Error encountered: ${err} ${err.stack}`);
throw new Error(ZeroExError.UNHANDLED_ERROR);
}
}
}
}

View File

@ -0,0 +1,37 @@
import * as _ from 'lodash';
import {Web3Wrapper} from '../web3_wrapper';
import {ECSignature, ZeroExError, ExchangeContract} from '../types';
import {assert} from '../utils/assert';
import {ContractWrapper} from './contract_wrapper';
import * as ExchangeArtifacts from '../../artifacts/Exchange.json';
import {ECSignatureSchema} from '../schemas/ec_signature_schema';
export class ExchangeWrapper extends ContractWrapper {
constructor(web3Wrapper: Web3Wrapper) {
super(web3Wrapper);
}
public async isValidSignatureAsync(dataHex: string, ecSignature: ECSignature,
signerAddressHex: string): Promise<boolean> {
assert.isHexString('dataHex', dataHex);
assert.doesConformToSchema('ecSignature', ecSignature, ECSignatureSchema);
assert.isETHAddressHex('signerAddressHex', signerAddressHex);
const senderAddressIfExists = await this.web3Wrapper.getSenderAddressIfExistsAsync();
assert.assert(!_.isUndefined(senderAddressIfExists), ZeroExError.USER_HAS_NO_ASSOCIATED_ADDRESSES);
const contractInstance = await this.instantiateContractIfExistsAsync((ExchangeArtifacts as any));
const exchangeInstance = contractInstance as ExchangeContract;
const isValidSignature = await exchangeInstance.isValidSignature.call(
signerAddressHex,
dataHex,
ecSignature.v,
ecSignature.r,
ecSignature.s,
{
from: senderAddressIfExists,
},
);
return isValidSignature;
}
}

33
src/ts/globals.d.ts vendored
View File

@ -1,5 +1,8 @@
declare module 'chai-bignumber';
declare module 'bn.js';
declare module 'request-promise-native';
declare module 'web3-provider-engine';
declare module 'web3-provider-engine/subproviders/rpc';
declare interface Schema {
id: string;
@ -12,10 +15,18 @@ declare interface Schema {
declare namespace Chai {
interface Assertion {
bignumber: Assertion;
eventually: Assertion;
}
}
/* tslint:enable */
declare module '*.json' {
const json: any;
/* tslint:disable */
export default json;
/* tslint:enable */
}
declare module 'ethereumjs-util' {
const toBuffer: (dataHex: string) => Buffer;
const hashPersonalMessage: (msg: Buffer) => Buffer;
@ -23,6 +34,28 @@ declare module 'ethereumjs-util' {
const ecrecover: (msgHashBuff: Buffer, v: number, r: Buffer, s: Buffer) => string;
const pubToAddress: (pubKey: string) => Buffer;
const isValidAddress: (address: string) => boolean;
const bufferToInt: (buffer: Buffer) => number;
}
// truffle-contract declarations
declare interface ContractInstance {}
declare interface ContractFactory {
setProvider: (providerObj: any) => void;
deployed: () => ContractInstance;
at: (address: string) => ContractInstance;
}
declare interface Artifact {
networks: {[networkId: number]: any};
}
declare function contract(artifacts: Artifact): ContractFactory;
declare module 'truffle-contract' {
export = contract;
}
// es6-promisify declarations
declare function promisify(original: any, settings?: any): ((...arg: any[]) => Promise<any>);
declare module 'es6-promisify' {
export = promisify;
}
declare module 'ethereumjs-abi' {

View File

@ -1,5 +1,4 @@
import * as _ from 'lodash';
import * as BigNumber from 'bignumber.js';
// Utility function to create a K:V from a list of strings
// Adapted from: https://basarat.gitbooks.io/typescript/content/docs/types/literal-types.html
@ -10,6 +9,26 @@ function strEnum(values: string[]): {[key: string]: string} {
}, Object.create(null));
}
export const ZeroExError = strEnum([
'CONTRACT_DOES_NOT_EXIST',
'UNHANDLED_ERROR',
'USER_HAS_NO_ASSOCIATED_ADDRESSES',
]);
export type ZeroExError = keyof typeof ZeroExError;
/**
* Elliptic Curve signature
*/
export interface ECSignature {
v: number;
r: string;
s: string;
}
export interface ExchangeContract {
isValidSignature: any;
}
export const SolidityTypes = strEnum([
'address',
'uint256',

View File

@ -1,30 +1,33 @@
import * as _ from 'lodash';
import * as BigNumber from 'bignumber.js';
import Web3 = require('web3');
import * as Web3 from 'web3';
import {SchemaValidator} from './schema_validator';
const HEX_REGEX = /^0x[0-9A-F]*$/i;
export const assert = {
isBigNumber(variableName: string, value: BigNumber.BigNumber) {
isBigNumber(variableName: string, value: BigNumber.BigNumber): void {
const isBigNumber = _.isObject(value) && value.isBigNumber;
this.assert(isBigNumber, this.typeAssertionMessage(variableName, 'BigNumber', value));
},
isString(variableName: string, value: string) {
isUndefined(value: any, variableName?: string): void {
this.assert(_.isUndefined(value), this.typeAssertionMessage(variableName, 'undefined', value));
},
isString(variableName: string, value: string): void {
this.assert(_.isString(value), this.typeAssertionMessage(variableName, 'string', value));
},
isHexString(variableName: string, value: string) {
isHexString(variableName: string, value: string): void {
this.assert(_.isString(value) && HEX_REGEX.test(value),
this.typeAssertionMessage(variableName, 'HexString', value));
},
isETHAddressHex(variableName: string, value: string) {
isETHAddressHex(variableName: string, value: string): void {
const web3 = new Web3();
this.assert(web3.isAddress(value), this.typeAssertionMessage(variableName, 'ETHAddressHex', value));
},
isNumber(variableName: string, value: number) {
isNumber(variableName: string, value: number): void {
this.assert(_.isFinite(value), this.typeAssertionMessage(variableName, 'number', value));
},
doesConformToSchema(variableName: string, value: object, schema: Schema) {
doesConformToSchema(variableName: string, value: object, schema: Schema): void {
const schemaValidator = new SchemaValidator();
const validationResult = schemaValidator.validate(value, schema);
const hasValidationErrors = validationResult.errors.length > 0;
@ -33,12 +36,12 @@ Encountered: ${JSON.stringify(value, null, '\t')}
Validation errors: ${validationResult.errors.join(', ')}`;
this.assert(!hasValidationErrors, msg);
},
assert(condition: boolean, message: string) {
assert(condition: boolean, message: string): void {
if (!condition) {
throw new Error(message);
}
},
typeAssertionMessage(variableName: string, type: string, value: any) {
typeAssertionMessage(variableName: string, type: string, value: any): string {
return `Expected ${variableName} to be of type ${type}, encountered: ${value}`;
},
};

View File

@ -1,3 +1,3 @@
export const constants = {
NULL_ADDRESS: '0x0000000000000000000000000000000000000000',
}
};

7
src/ts/utils/utils.ts Normal file
View File

@ -0,0 +1,7 @@
export const utils = {
consoleLog(message: string): void {
/* tslint:disable */
console.log(message);
/* tslint:enable */
},
};

69
src/ts/web3_wrapper.ts Normal file
View File

@ -0,0 +1,69 @@
import * as _ from 'lodash';
import * as Web3 from 'web3';
import * as BigNumber from 'bignumber.js';
import promisify = require('es6-promisify');
export class Web3Wrapper {
private web3: Web3;
constructor(web3: Web3) {
this.web3 = new Web3();
this.web3.setProvider(web3.currentProvider);
}
public isAddress(address: string): boolean {
return this.web3.isAddress(address);
}
public async getSenderAddressIfExistsAsync(): Promise<string|undefined> {
const defaultAccount = this.web3.eth.defaultAccount;
if (!_.isUndefined(defaultAccount)) {
return defaultAccount;
}
const firstAccount = await this.getFirstAddressIfExistsAsync();
return firstAccount;
}
public async getFirstAddressIfExistsAsync(): Promise<string|undefined> {
const addresses = await promisify(this.web3.eth.getAccounts)();
if (_.isEmpty(addresses)) {
return undefined;
}
return (addresses as string[])[0];
}
public async getNodeVersionAsync(): Promise<string> {
const nodeVersion = await promisify(this.web3.version.getNode)();
return nodeVersion;
}
public getCurrentProvider(): Web3.Provider {
return this.web3.currentProvider;
}
public async getNetworkIdIfExistsAsync(): Promise<number|undefined> {
try {
const networkId = await this.getNetworkAsync();
return Number(networkId);
} catch (err) {
return undefined;
}
}
public async getBalanceInEthAsync(owner: string): Promise<BigNumber.BigNumber> {
const balanceInWei = await promisify(this.web3.eth.getBalance)(owner);
const balanceEth = this.web3.fromWei(balanceInWei, 'ether');
return balanceEth;
}
public async doesContractExistAtAddressAsync(address: string): Promise<boolean> {
const code = await promisify(this.web3.eth.getCode)(address);
// Regex matches 0x0, 0x00, 0x in order to accomodate poorly implemented clients
const zeroHexAddressRegex = /^0x0\{0,40\}$/i;
const didFindCode = _.isNull(code.match(zeroHexAddressRegex));
return didFindCode;
}
public async signTransactionAsync(address: string, message: string): Promise<string> {
const signData = await promisify(this.web3.eth.sign)(address, message);
return signData;
}
public async getBlockTimestampAsync(blockHash: string): Promise<number> {
const {timestamp} = await promisify(this.web3.eth.getBlock)(blockHash);
return timestamp;
}
private async getNetworkAsync(): Promise<number> {
const networkId = await promisify(this.web3.version.getNetwork)();
return networkId;
}
}

View File

@ -0,0 +1,98 @@
import 'mocha';
import * as chai from 'chai';
import chaiAsPromised = require('chai-as-promised');
import * as Web3 from 'web3';
import {web3Factory} from './utils/web3_factory';
import {ExchangeWrapper} from '../src/ts/contract_wrappers/exchange_wrapper';
import {BlockchainLifecycle} from './utils/blockchain_lifecycle';
import {Web3Wrapper} from './../src/ts/web3_wrapper';
const expect = chai.expect;
chai.use(chaiAsPromised);
const blockchainLifecycle = new BlockchainLifecycle();
describe('ExchangeWrapper', () => {
let web3Wrapper: Web3Wrapper;
let exchangeWrapper: ExchangeWrapper;
before(async () => {
const web3 = web3Factory.create();
web3Wrapper = new Web3Wrapper(web3);
exchangeWrapper = new ExchangeWrapper(web3Wrapper);
});
beforeEach(async () => {
await blockchainLifecycle.startAsync();
});
afterEach(async () => {
await blockchainLifecycle.revertAsync();
});
describe('#isValidSignatureAsync', () => {
// The Exchange smart contract `isValidSignature` method only validates orderHashes and assumes
// the length of the data is exactly 32 bytes. Thus for these tests, we use data of this size.
const dataHex = '0x6927e990021d23b1eb7b8789f6a6feaf98fe104bb0cf8259421b79f9a34222b0';
const signature = {
v: 27,
r: '0x61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33',
s: '0x40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254',
};
const address = '0x5409ed021d9299bf6814279a6a1411a7e866a631';
describe('should throw if passed a malformed signature', () => {
it('malformed v', async () => {
const malformedSignature = {
v: 34,
r: signature.r,
s: signature.s,
};
expect(exchangeWrapper.isValidSignatureAsync(dataHex, malformedSignature, address))
.to.be.rejected;
});
it('r lacks 0x prefix', () => {
const malformedR = signature.r.replace('0x', '');
const malformedSignature = {
v: signature.v,
r: malformedR,
s: signature.s,
};
expect(exchangeWrapper.isValidSignatureAsync(dataHex, malformedSignature, address))
.to.be.rejected;
});
it('r is too short', () => {
const malformedR = signature.r.substr(10);
const malformedSignature = {
v: signature.v,
r: malformedR,
s: signature.s.replace('0', 'z'),
};
expect(exchangeWrapper.isValidSignatureAsync(dataHex, malformedSignature, address))
.to.be.rejected;
});
it('s is not hex', () => {
const malformedS = signature.s.replace('0', 'z');
const malformedSignature = {
v: signature.v,
r: signature.r,
s: malformedS,
};
expect(exchangeWrapper.isValidSignatureAsync(dataHex, malformedSignature, address))
.to.be.rejected;
});
});
it('should return false if the data doesn\'t pertain to the signature & address', async () => {
const isValid = await exchangeWrapper.isValidSignatureAsync('0x0', signature, address);
expect(isValid).to.be.false;
});
it('should return false if the address doesn\'t pertain to the signature & dataHex', async () => {
const validUnrelatedAddress = '0x8b0292B11a196601eD2ce54B665CaFEca0347D42';
const isValid = await exchangeWrapper.isValidSignatureAsync(dataHex, signature, validUnrelatedAddress);
expect(isValid).to.be.false;
});
it('should return false if the signature doesn\'t pertain to the dataHex & address', async () => {
const wrongSignature = Object.assign({}, signature, {v: 28});
const isValid = await exchangeWrapper.isValidSignatureAsync(dataHex, wrongSignature, address);
expect(isValid).to.be.false;
});
it('should return true if the signature does pertain to the dataHex & address', async () => {
const isValid = await exchangeWrapper.isValidSignatureAsync(dataHex, signature, address);
expect(isValid).to.be.true;
});
});
});

View File

@ -0,0 +1,20 @@
import {RPC} from './rpc';
export class BlockchainLifecycle {
private rpc: RPC;
private snapshotId: number;
constructor() {
this.rpc = new RPC();
}
// TODO: In order to run these tests on an actual node, we should check if we are running against
// TestRPC, if so, use snapshots, otherwise re-deploy contracts before every test
public async startAsync(): Promise<void> {
this.snapshotId = await this.rpc.takeSnapshotAsync();
}
public async revertAsync(): Promise<void> {
const didRevert = await this.rpc.revertSnapshotAsync(this.snapshotId);
if (!didRevert) {
throw new Error(`Snapshot with id #${this.snapshotId} failed to revert`);
}
}
};

5
test/utils/constants.ts Normal file
View File

@ -0,0 +1,5 @@
export const constants = {
NULL_ADDRESS: '0x0000000000000000000000000000000000000000',
RPC_HOST: 'localhost',
RPC_PORT: 8545,
};

48
test/utils/rpc.ts Normal file
View File

@ -0,0 +1,48 @@
import * as ethUtil from 'ethereumjs-util';
import * as request from 'request-promise-native';
import {constants} from './constants';
export class RPC {
private host: string;
private port: number;
private id: number;
constructor() {
this.host = constants.RPC_HOST;
this.port = constants.RPC_PORT;
this.id = 0;
}
public async takeSnapshotAsync(): Promise<number> {
const method = 'evm_snapshot';
const params: any[] = [];
const payload = this.toPayload(method, params);
const snapshotIdHex = await this.sendAsync(payload);
const snapshotId = ethUtil.bufferToInt(ethUtil.toBuffer(snapshotIdHex));
return snapshotId;
}
public async revertSnapshotAsync(snapshotId: number): Promise<boolean> {
const method = 'evm_revert';
const params = [snapshotId];
const payload = this.toPayload(method, params);
const didRevert = await this.sendAsync(payload);
return didRevert;
}
private toPayload(method: string, params: any[] = []): string {
const payload = JSON.stringify({
id: this.id,
method,
params,
});
this.id += 1;
return payload;
}
private async sendAsync(payload: string): Promise<any> {
const opts = {
method: 'POST',
uri: `http://${this.host}:${this.port}`,
body: payload,
};
const bodyString = await request(opts);
const body = JSON.parse(bodyString);
return body.result;
}
}

View File

@ -0,0 +1,23 @@
// HACK: web3 injects XMLHttpRequest into the global scope and ProviderEngine checks XMLHttpRequest
// to know whether it is running in a browser or node environment. We need it to be undefined since
// we are not running in a browser env.
// Filed issue: https://github.com/ethereum/web3.js/issues/844
(global as any).XMLHttpRequest = undefined;
import ProviderEngine = require('web3-provider-engine');
import RpcSubprovider = require('web3-provider-engine/subproviders/rpc');
import * as Web3 from 'web3';
import {constants} from './constants';
export const web3Factory = {
create(): Web3 {
const provider = new ProviderEngine();
const rpcUrl = `http://${constants.RPC_HOST}:${constants.RPC_PORT}`;
provider.addProvider(new RpcSubprovider({
rpcUrl,
}));
provider.start();
const web3 = new Web3();
web3.setProvider(provider);
return web3;
},
};

View File

@ -17,7 +17,7 @@ module.exports = {
umdNamedDefine: true,
},
resolve: {
extensions: ['.ts', '.js'],
extensions: ['.ts', '.js', '.json'],
},
devtool: 'source-map',
plugins: [
@ -28,13 +28,23 @@ module.exports = {
}),
],
module: {
loaders: [{
test: /\.ts$/,
loader: 'awesome-typescript-loader',
exclude: /node_modules/,
query: {
declaration: false,
rules: [
{
test: /\.ts$/,
use: [
{
loader: 'awesome-typescript-loader',
query: {
declaration: false,
},
},
],
exclude: /node_modules/,
},
}],
{
test: /\.json$/,
loader: 'json-loader',
},
],
},
};