Merge pull request #14 from 0xProject/implementFirstExchangeMethod
Implement first exchange method
This commit is contained in:
commit
b897bdab79
2
.gitignore
vendored
2
.gitignore
vendored
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
28
package.json
28
package.json
@ -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"
|
||||
}
|
||||
}
|
||||
|
339
src/artifacts/EtherToken.json
Normal file
339
src/artifacts/EtherToken.json
Normal 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
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
189
src/artifacts/Mintable.json
Normal 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
267
src/artifacts/Proxy.json
Normal 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
176
src/artifacts/Token.json
Normal 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
|
||||
}
|
1002
src/artifacts/TokenRegistry.json
Normal file
1002
src/artifacts/TokenRegistry.json
Normal file
File diff suppressed because one or more lines are too long
@ -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);
|
||||
}
|
||||
}
|
||||
|
48
src/ts/contract_wrappers/contract_wrapper.ts
Normal file
48
src/ts/contract_wrappers/contract_wrapper.ts
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
37
src/ts/contract_wrappers/exchange_wrapper.ts
Normal file
37
src/ts/contract_wrappers/exchange_wrapper.ts
Normal 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
33
src/ts/globals.d.ts
vendored
@ -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' {
|
||||
|
@ -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',
|
||||
|
@ -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}`;
|
||||
},
|
||||
};
|
||||
|
@ -1,3 +1,3 @@
|
||||
export const constants = {
|
||||
NULL_ADDRESS: '0x0000000000000000000000000000000000000000',
|
||||
}
|
||||
};
|
||||
|
7
src/ts/utils/utils.ts
Normal file
7
src/ts/utils/utils.ts
Normal 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
69
src/ts/web3_wrapper.ts
Normal 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;
|
||||
}
|
||||
}
|
98
test/contract_wrapper_test.ts
Normal file
98
test/contract_wrapper_test.ts
Normal 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;
|
||||
});
|
||||
});
|
||||
});
|
20
test/utils/blockchain_lifecycle.ts
Normal file
20
test/utils/blockchain_lifecycle.ts
Normal 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
5
test/utils/constants.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export const constants = {
|
||||
NULL_ADDRESS: '0x0000000000000000000000000000000000000000',
|
||||
RPC_HOST: 'localhost',
|
||||
RPC_PORT: 8545,
|
||||
};
|
48
test/utils/rpc.ts
Normal file
48
test/utils/rpc.ts
Normal 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;
|
||||
}
|
||||
}
|
23
test/utils/web3_factory.ts
Normal file
23
test/utils/web3_factory.ts
Normal 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;
|
||||
},
|
||||
};
|
@ -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',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user