Ui 2 packages (#6169)
* Ensure all internal dapps have package.json * Update compilation rules # Conflicts: # js/src/redux/providers/balancesActions.js # js/src/ui/Form/TypedInput/typedInput.js * Remove SignerIcon * Cleanup providers * Enable request of new token from app * Queue when no token (yet) * Add location & token request * Cleanup send logic * Request token * Request comms token * Remove yarn.lock (not updated) * Update version to 1.99.99 (publish prepare) * Move jsonrpc to seperate repo * Update jsonrpc references * Update repo info * Update repo info * Additional debugging * Update repo references * Move ABI to js-abi repo * Move webWorker to shared * Fix package reference * Worker location * Move js-ui & js-shared components * Update file references * Update package repo locations * Remove debugging info * Cleanup debug * Split api into own repo * Update api local references * Update app loading * Update dependencies * Allow serving of /parity-utils * Error when EthereumProvider has not been attached * Use inject.js * Correct appId retrieval
This commit is contained in:
parent
5830767273
commit
a1b8fabd99
1
js/.gitignore
vendored
1
js/.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
|
yarn.lock
|
||||||
node_modules
|
node_modules
|
||||||
npm-debug.log
|
npm-debug.log
|
||||||
build
|
build
|
||||||
|
14
js/package-lock.json
generated
14
js/package-lock.json
generated
@ -5,17 +5,17 @@
|
|||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@parity/abi": {
|
"@parity/abi": {
|
||||||
"version": "file:packages/abi",
|
"version": "github:paritytech/js-abi#a1021ca5b7550e1e24e4767a22ef3f0d95ead19a",
|
||||||
"requires": {
|
"requires": {
|
||||||
"bignumber.js": "3.0.1",
|
"bignumber.js": "3.0.1",
|
||||||
"js-sha3": "0.5.5"
|
"js-sha3": "0.5.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@parity/api": {
|
"@parity/api": {
|
||||||
"version": "file:packages/api",
|
"version": "github:paritytech/js-api#418ee49849a5361ad3c416b224fd9bb6dbabc1d1",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@parity/abi": "file:packages/abi",
|
"@parity/abi": "github:paritytech/js-abi#a1021ca5b7550e1e24e4767a22ef3f0d95ead19a",
|
||||||
"@parity/jsonrpc": "file:packages/jsonrpc",
|
"@parity/jsonrpc": "github:paritytech/js-jsonrpc#ac545573880212a27cf4cc6bb32a37fdab6dc26d",
|
||||||
"bignumber.js": "3.0.1",
|
"bignumber.js": "3.0.1",
|
||||||
"blockies": "0.0.2",
|
"blockies": "0.0.2",
|
||||||
"es6-error": "4.0.0",
|
"es6-error": "4.0.0",
|
||||||
@ -73,7 +73,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@parity/jsonrpc": {
|
"@parity/jsonrpc": {
|
||||||
"version": "file:packages/jsonrpc"
|
"version": "github:paritytech/js-jsonrpc#ac545573880212a27cf4cc6bb32a37fdab6dc26d"
|
||||||
},
|
},
|
||||||
"@parity/ledger": {
|
"@parity/ledger": {
|
||||||
"version": "file:packages/ledger"
|
"version": "file:packages/ledger"
|
||||||
@ -102,7 +102,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@parity/shared": {
|
"@parity/shared": {
|
||||||
"version": "file:packages/shared",
|
"version": "github:paritytech/js-shared#a83c71946d30d5b3bf976860a676add29c48ee24",
|
||||||
"requires": {
|
"requires": {
|
||||||
"mobx": "2.6.4",
|
"mobx": "2.6.4",
|
||||||
"mobx-react": "4.0.3",
|
"mobx-react": "4.0.3",
|
||||||
@ -117,7 +117,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@parity/ui": {
|
"@parity/ui": {
|
||||||
"version": "file:packages/ui",
|
"version": "github:paritytech/js-ui#164c08e1aec4a009dcd559764a746b1cc06c4b22",
|
||||||
"requires": {
|
"requires": {
|
||||||
"bignumber.js": "3.0.1",
|
"bignumber.js": "3.0.1",
|
||||||
"brace": "0.9.0",
|
"brace": "0.9.0",
|
||||||
|
@ -160,17 +160,13 @@
|
|||||||
"yargs": "6.6.0"
|
"yargs": "6.6.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@parity/abi": "file:packages/abi",
|
"@parity/api": "paritytech/js-api#418ee49849a5361ad3c416b224fd9bb6dbabc1d1",
|
||||||
"@parity/api": "file:packages/api",
|
|
||||||
"@parity/dapp-account": "file:packages/dapp-account",
|
|
||||||
"@parity/dapp-develop": "file:packages/dapp-develop",
|
|
||||||
"@parity/dapps": "file:packages/dapps",
|
"@parity/dapps": "file:packages/dapps",
|
||||||
"@parity/etherscan": "file:packages/etherscan",
|
"@parity/etherscan": "file:packages/etherscan",
|
||||||
"@parity/jsonrpc": "file:packages/jsonrpc",
|
|
||||||
"@parity/ledger": "file:packages/ledger",
|
"@parity/ledger": "file:packages/ledger",
|
||||||
"@parity/shapeshift": "file:packages/shapeshift",
|
"@parity/shapeshift": "file:packages/shapeshift",
|
||||||
"@parity/shared": "file:packages/shared",
|
"@parity/shared": "paritytech/js-shared#a83c71946d30d5b3bf976860a676add29c48ee24",
|
||||||
"@parity/ui": "file:packages/ui",
|
"@parity/ui": "paritytech/js-ui#164c08e1aec4a009dcd559764a746b1cc06c4b22",
|
||||||
"@parity/wordlist": "1.0.1",
|
"@parity/wordlist": "1.0.1",
|
||||||
"es6-error": "4.0.0",
|
"es6-error": "4.0.0",
|
||||||
"es6-promise": "4.0.5",
|
"es6-promise": "4.0.5",
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
# ethabi-js
|
|
||||||
|
|
||||||
A very early, very POC-type port of [https://github.com/paritytech/ethabi](https://github.com/paritytech/ethabi) to JavaScript
|
|
||||||
|
|
||||||
[![Build Status](https://travis-ci.org/jacogr/ethabi-js.svg?branch=master)](https://travis-ci.org/jacogr/ethabi-js)
|
|
||||||
[![Coverage Status](https://coveralls.io/repos/github/jacogr/ethabi-js/badge.svg?branch=master)](https://coveralls.io/github/jacogr/ethabi-js?branch=master)
|
|
||||||
[![Dependency Status](https://david-dm.org/jacogr/ethabi-js.svg)](https://david-dm.org/jacogr/ethabi-js)
|
|
||||||
[![devDependency Status](https://david-dm.org/jacogr/ethabi-js/dev-status.svg)](https://david-dm.org/jacogr/ethabi-js#info=devDependencies)
|
|
||||||
|
|
||||||
## contributing
|
|
||||||
|
|
||||||
Clone the repo and install dependencies via `npm install`. Tests can be executed via
|
|
||||||
|
|
||||||
- `npm run testOnce` (100% covered unit tests)
|
|
||||||
|
|
||||||
## installation
|
|
||||||
|
|
||||||
Install the package with `npm install --save ethabi-js` from the [npm registry ethabi-js](https://www.npmjs.com/package/ethabi-js)
|
|
||||||
|
|
||||||
|
|
||||||
## implementation
|
|
||||||
### approach
|
|
||||||
|
|
||||||
- this version tries to stay as close to the original Rust version in intent, function names & purpose
|
|
||||||
- it is a basic port of the Rust version, relying on effectively the same test-suite (expanded where deemed appropriate)
|
|
||||||
- it is meant as a library to be used in other projects, i.e. [ethapi-js](https://www.npmjs.com/package/ethapi-js)
|
|
||||||
|
|
||||||
### differences to original Rust version
|
|
||||||
|
|
||||||
- internally the library operates on string binary representations as opposed to Vector bytes, lengths are therefore 64 bytes as opposed to 32 bytes
|
|
||||||
- function names are adapted from the Rust standard snake_case to the JavaScript standard camelCase
|
|
||||||
- due to the initial library focus, the cli component (as implemented by the original) is not supported nor mplemented
|
|
@ -1,20 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import Interface from './spec/interface';
|
|
||||||
|
|
||||||
export default class Abi extends Interface {
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
export default class BytesTaken {
|
|
||||||
constructor (bytes, newOffset) {
|
|
||||||
this._bytes = bytes;
|
|
||||||
this._newOffset = newOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
get bytes () {
|
|
||||||
return this._bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
get newOffset () {
|
|
||||||
return this._newOffset;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import BytesTaken from './bytesTaken';
|
|
||||||
|
|
||||||
describe('abi/decoder/BytesTaken', () => {
|
|
||||||
describe('constructor', () => {
|
|
||||||
it('sets the bytes of the object', () => {
|
|
||||||
expect((new BytesTaken(1, 2)).bytes).to.equal(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sets the newOffset of the object', () => {
|
|
||||||
expect((new BytesTaken(3, 4)).newOffset).to.equal(4);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,30 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
export default class DecodeResult {
|
|
||||||
constructor (token, newOffset) {
|
|
||||||
this._token = token;
|
|
||||||
this._newOffset = newOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
get token () {
|
|
||||||
return this._token;
|
|
||||||
}
|
|
||||||
|
|
||||||
get newOffset () {
|
|
||||||
return this._newOffset;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import DecodeResult from './decodeResult';
|
|
||||||
|
|
||||||
describe('abi/decoder/DecodeResult', () => {
|
|
||||||
describe('constructor', () => {
|
|
||||||
it('sets the token of the object', () => {
|
|
||||||
expect((new DecodeResult('token', 2)).token).to.equal('token');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sets the newOffset of the object', () => {
|
|
||||||
expect((new DecodeResult('baz', 4)).newOffset).to.equal(4);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,156 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import utf8 from 'utf8';
|
|
||||||
|
|
||||||
import Token from '../token/token';
|
|
||||||
import BytesTaken from './bytesTaken';
|
|
||||||
import DecodeResult from './decodeResult';
|
|
||||||
import ParamType from '../spec/paramType/paramType';
|
|
||||||
import { sliceData } from '../util/slice';
|
|
||||||
import { asAddress, asBool, asI32, asU32 } from '../util/sliceAs';
|
|
||||||
import { isArray, isInstanceOf } from '../util/types';
|
|
||||||
|
|
||||||
const NULL = '0000000000000000000000000000000000000000000000000000000000000000';
|
|
||||||
|
|
||||||
export default class Decoder {
|
|
||||||
static decode (params, data) {
|
|
||||||
if (!isArray(params)) {
|
|
||||||
throw new Error('Parameters should be array of ParamType');
|
|
||||||
}
|
|
||||||
|
|
||||||
const slices = sliceData(data);
|
|
||||||
let offset = 0;
|
|
||||||
|
|
||||||
return params.map((param) => {
|
|
||||||
const result = Decoder.decodeParam(param, slices, offset);
|
|
||||||
|
|
||||||
offset = result.newOffset;
|
|
||||||
return result.token;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static peek (slices, position) {
|
|
||||||
if (!slices || !slices[position]) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return slices[position];
|
|
||||||
}
|
|
||||||
|
|
||||||
static takeBytes (slices, position, length) {
|
|
||||||
const slicesLength = Math.floor((length + 31) / 32);
|
|
||||||
let bytesStr = '';
|
|
||||||
|
|
||||||
for (let idx = 0; idx < slicesLength; idx++) {
|
|
||||||
bytesStr = `${bytesStr}${Decoder.peek(slices, position + idx)}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const bytes = (bytesStr.substr(0, length * 2).match(/.{1,2}/g) || []).map((code) => parseInt(code, 16));
|
|
||||||
|
|
||||||
return new BytesTaken(bytes, position + slicesLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
static decodeParam (param, slices, offset) {
|
|
||||||
if (!isInstanceOf(param, ParamType)) {
|
|
||||||
throw new Error('param should be instanceof ParamType');
|
|
||||||
}
|
|
||||||
|
|
||||||
const tokens = [];
|
|
||||||
let taken;
|
|
||||||
let lengthOffset;
|
|
||||||
let length;
|
|
||||||
let newOffset;
|
|
||||||
|
|
||||||
switch (param.type) {
|
|
||||||
case 'address':
|
|
||||||
return new DecodeResult(new Token(param.type, asAddress(Decoder.peek(slices, offset))), offset + 1);
|
|
||||||
|
|
||||||
case 'bool':
|
|
||||||
return new DecodeResult(new Token(param.type, asBool(Decoder.peek(slices, offset))), offset + 1);
|
|
||||||
|
|
||||||
case 'int':
|
|
||||||
return new DecodeResult(new Token(param.type, asI32(Decoder.peek(slices, offset))), offset + 1);
|
|
||||||
|
|
||||||
case 'uint':
|
|
||||||
return new DecodeResult(new Token(param.type, asU32(Decoder.peek(slices, offset))), offset + 1);
|
|
||||||
|
|
||||||
case 'fixedBytes':
|
|
||||||
taken = Decoder.takeBytes(slices, offset, param.length);
|
|
||||||
|
|
||||||
return new DecodeResult(new Token(param.type, taken.bytes), taken.newOffset);
|
|
||||||
|
|
||||||
case 'bytes':
|
|
||||||
lengthOffset = asU32(Decoder.peek(slices, offset)).div(32).toNumber();
|
|
||||||
length = asU32(Decoder.peek(slices, lengthOffset)).toNumber();
|
|
||||||
taken = Decoder.takeBytes(slices, lengthOffset + 1, length);
|
|
||||||
|
|
||||||
return new DecodeResult(new Token(param.type, taken.bytes), offset + 1);
|
|
||||||
|
|
||||||
case 'string':
|
|
||||||
if (param.indexed) {
|
|
||||||
taken = Decoder.takeBytes(slices, offset, 32);
|
|
||||||
|
|
||||||
return new DecodeResult(new Token('fixedBytes', taken.bytes), offset + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
lengthOffset = asU32(Decoder.peek(slices, offset)).div(32).toNumber();
|
|
||||||
length = asU32(Decoder.peek(slices, lengthOffset)).toNumber();
|
|
||||||
taken = Decoder.takeBytes(slices, lengthOffset + 1, length);
|
|
||||||
|
|
||||||
const str = taken.bytes.map((code) => String.fromCharCode(code)).join('');
|
|
||||||
|
|
||||||
let decoded;
|
|
||||||
|
|
||||||
try {
|
|
||||||
decoded = utf8.decode(str);
|
|
||||||
} catch (error) {
|
|
||||||
decoded = str;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new DecodeResult(new Token(param.type, decoded), offset + 1);
|
|
||||||
|
|
||||||
case 'array':
|
|
||||||
lengthOffset = asU32(Decoder.peek(slices, offset)).div(32).toNumber();
|
|
||||||
length = asU32(Decoder.peek(slices, lengthOffset)).toNumber();
|
|
||||||
newOffset = lengthOffset + 1;
|
|
||||||
|
|
||||||
for (let idx = 0; idx < length; idx++) {
|
|
||||||
const result = Decoder.decodeParam(param.subtype, slices, newOffset);
|
|
||||||
|
|
||||||
newOffset = result.newOffset;
|
|
||||||
tokens.push(result.token);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new DecodeResult(new Token(param.type, tokens), offset + 1);
|
|
||||||
|
|
||||||
case 'fixedArray':
|
|
||||||
newOffset = offset;
|
|
||||||
|
|
||||||
for (let idx = 0; idx < param.length; idx++) {
|
|
||||||
const result = Decoder.decodeParam(param.subtype, slices, newOffset);
|
|
||||||
|
|
||||||
newOffset = result.newOffset;
|
|
||||||
tokens.push(result.token);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new DecodeResult(new Token(param.type, tokens), newOffset);
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new Error(`Invalid param type ${param.type} in decodeParam`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,319 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import BigNumber from 'bignumber.js';
|
|
||||||
|
|
||||||
import Decoder from './decoder';
|
|
||||||
import ParamType from '../spec/paramType';
|
|
||||||
import Token from '../token';
|
|
||||||
import { padU32 } from '../util/pad';
|
|
||||||
|
|
||||||
describe('abi/decoder/Decoder', () => {
|
|
||||||
const stringToBytes = function (str) {
|
|
||||||
return str.match(/.{1,2}/g).map((code) => parseInt(code, 16));
|
|
||||||
};
|
|
||||||
|
|
||||||
const address1 = '0000000000000000000000001111111111111111111111111111111111111111';
|
|
||||||
const address2 = '0000000000000000000000002222222222222222222222222222222222222222';
|
|
||||||
const address3 = '0000000000000000000000003333333333333333333333333333333333333333';
|
|
||||||
const address4 = '0000000000000000000000004444444444444444444444444444444444444444';
|
|
||||||
const bool1 = '0000000000000000000000000000000000000000000000000000000000000001';
|
|
||||||
const bytes1 = '1234000000000000000000000000000000000000000000000000000000000000';
|
|
||||||
const bytes2 = '1000000000000000000000000000000000000000000000000000000000000000';
|
|
||||||
const bytes3 = '10000000000000000000000000000000000000000000000000000000000002';
|
|
||||||
const bytes4 = '0010000000000000000000000000000000000000000000000000000000000002';
|
|
||||||
const int1 = '0111111111111111111111111111111111111111111111111111111111111111';
|
|
||||||
const intn = 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85';
|
|
||||||
const string1 = '6761766f66796f726b0000000000000000000000000000000000000000000000';
|
|
||||||
const string2 = '4665726ee16e64657a0000000000000000000000000000000000000000000000';
|
|
||||||
const tokenAddress1 = new Token('address', `0x${address1.slice(-40)}`);
|
|
||||||
const tokenAddress2 = new Token('address', `0x${address2.slice(-40)}`);
|
|
||||||
const tokenAddress3 = new Token('address', `0x${address3.slice(-40)}`);
|
|
||||||
const tokenAddress4 = new Token('address', `0x${address4.slice(-40)}`);
|
|
||||||
const tokenBool1 = new Token('bool', true);
|
|
||||||
const tokenFixedBytes1 = new Token('fixedBytes', [0x12, 0x34]);
|
|
||||||
const tokenBytes1 = new Token('bytes', [0x12, 0x34]);
|
|
||||||
const tokenBytes2 = new Token('bytes', stringToBytes(bytes2).concat(stringToBytes(bytes2)));
|
|
||||||
const tokenBytes3 = new Token('bytes', stringToBytes(bytes3));
|
|
||||||
const tokenBytes4 = new Token('bytes', stringToBytes(bytes4));
|
|
||||||
const tokenInt1 = new Token('int', new BigNumber(int1, 16));
|
|
||||||
const tokenIntn = new Token('int', new BigNumber(-123));
|
|
||||||
const tokenUint1 = new Token('uint', new BigNumber(int1, 16));
|
|
||||||
const tokenUintn = new Token('uint', new BigNumber(intn, 16));
|
|
||||||
const tokenString1 = new Token('string', 'gavofyork');
|
|
||||||
const tokenString2 = new Token('string', 'Fernández');
|
|
||||||
const slices = [ address1, address2, address3, address4 ];
|
|
||||||
|
|
||||||
describe('peek', () => {
|
|
||||||
it('returns the slice at the correct position', () => {
|
|
||||||
expect(Decoder.peek(slices, 1)).to.equal(slices[1]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns empty on invalid slices', () => {
|
|
||||||
expect(Decoder.peek(null, 4)).to.equal('0000000000000000000000000000000000000000000000000000000000000000');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('takeBytes', () => {
|
|
||||||
it('returns a single slice', () => {
|
|
||||||
expect(Decoder.takeBytes(slices, 0, 32).bytes).to.deep.equal(stringToBytes(slices[0]));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns a single partial slice', () => {
|
|
||||||
expect(Decoder.takeBytes(slices, 0, 20).bytes).to.deep.equal(stringToBytes(slices[0].substr(0, 40)));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns multiple slices', () => {
|
|
||||||
expect(Decoder.takeBytes(slices, 0, 64).bytes).to.deep.equal(stringToBytes(`${slices[0]}${slices[1]}`));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns a single offset slice', () => {
|
|
||||||
expect(Decoder.takeBytes(slices, 1, 32).bytes).to.deep.equal(stringToBytes(slices[1]));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns multiple offset slices', () => {
|
|
||||||
expect(Decoder.takeBytes(slices, 1, 64).bytes).to.deep.equal(stringToBytes(`${slices[1]}${slices[2]}`));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns the requires length from slices', () => {
|
|
||||||
expect(
|
|
||||||
Decoder.takeBytes(slices, 1, 75).bytes
|
|
||||||
).to.deep.equal(stringToBytes(`${slices[1]}${slices[2]}${slices[3]}`.substr(0, 150)));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('decodeParam', () => {
|
|
||||||
it('throws an error on non ParamType param', () => {
|
|
||||||
expect(() => Decoder.decodeParam({})).to.throw(/ParamType/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('throws an error on invalid param type', () => {
|
|
||||||
const pt = new ParamType('address');
|
|
||||||
|
|
||||||
pt._type = 'noMatch';
|
|
||||||
|
|
||||||
expect(() => Decoder.decodeParam(pt)).to.throw(/noMatch/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('decodes an address', () => {
|
|
||||||
expect(
|
|
||||||
Decoder.decodeParam(new ParamType('address'), [address1], 0).token
|
|
||||||
).to.deep.equal(tokenAddress1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('decodes a bool', () => {
|
|
||||||
expect(
|
|
||||||
Decoder.decodeParam(new ParamType('bool'), [bool1], 0).token
|
|
||||||
).to.deep.equal(tokenBool1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('decodes an int', () => {
|
|
||||||
expect(
|
|
||||||
Decoder.decodeParam(new ParamType('int'), [int1], 0).token
|
|
||||||
).to.deep.equal(tokenInt1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('decodes a negative int', () => {
|
|
||||||
expect(
|
|
||||||
Decoder.decodeParam(new ParamType('int'), [intn], 0).token
|
|
||||||
).to.deep.equal(tokenIntn);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('decodes an uint', () => {
|
|
||||||
expect(
|
|
||||||
Decoder.decodeParam(new ParamType('uint'), [int1], 0).token
|
|
||||||
).to.deep.equal(tokenUint1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('decodes an uint (negative as int)', () => {
|
|
||||||
expect(
|
|
||||||
Decoder.decodeParam(new ParamType('uint'), [intn], 0).token
|
|
||||||
).to.deep.equal(tokenUintn);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('decodes fixedBytes', () => {
|
|
||||||
expect(
|
|
||||||
Decoder.decodeParam(new ParamType('fixedBytes', null, 2), [bytes1], 0).token
|
|
||||||
).to.deep.equal(tokenFixedBytes1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('decodes bytes', () => {
|
|
||||||
expect(
|
|
||||||
Decoder.decodeParam(new ParamType('bytes'), [padU32(0x20), padU32(2), bytes1], 0).token
|
|
||||||
).to.deep.equal(tokenBytes1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('decodes string', () => {
|
|
||||||
expect(
|
|
||||||
Decoder.decodeParam(new ParamType('string'), [padU32(0x20), padU32(9), string1], 0).token
|
|
||||||
).to.deep.equal(tokenString1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('decodes utf8-invalid string', () => {
|
|
||||||
expect(
|
|
||||||
Decoder.decodeParam(new ParamType('string'), [padU32(0x20), padU32(9), string2], 0).token
|
|
||||||
).to.deep.equal(tokenString2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('decodes string (indexed)', () => {
|
|
||||||
expect(
|
|
||||||
Decoder.decodeParam(new ParamType('string', null, 0, true), [bytes1], 0)
|
|
||||||
).to.deep.equal(Decoder.decodeParam(new ParamType('fixedBytes', null, 32, true), [bytes1], 0));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('decode', () => {
|
|
||||||
it('throws an error on invalid params', () => {
|
|
||||||
expect(() => Decoder.decode(null, '123')).to.throw(/array/);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('address', () => {
|
|
||||||
it('decodes an address', () => {
|
|
||||||
expect(
|
|
||||||
Decoder.decode(
|
|
||||||
[new ParamType('address')],
|
|
||||||
`${address1}`
|
|
||||||
)
|
|
||||||
).to.deep.equal([tokenAddress1]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('decodes 2 addresses', () => {
|
|
||||||
expect(
|
|
||||||
Decoder.decode(
|
|
||||||
[new ParamType('address'), new ParamType('address')],
|
|
||||||
`${address1}${address2}`
|
|
||||||
)
|
|
||||||
).to.deep.equal([tokenAddress1, tokenAddress2]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('decodes a fixedArray of addresses', () => {
|
|
||||||
expect(
|
|
||||||
Decoder.decode(
|
|
||||||
[new ParamType('fixedArray', new ParamType('address'), 2)],
|
|
||||||
`${address1}${address2}`
|
|
||||||
)
|
|
||||||
).to.deep.equal([new Token('fixedArray', [tokenAddress1, tokenAddress2])]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('decodes a dynamic array of addresses', () => {
|
|
||||||
expect(
|
|
||||||
Decoder.decode(
|
|
||||||
[new ParamType('array', new ParamType('address'))],
|
|
||||||
`${padU32(0x20)}${padU32(2)}${address1}${address2}`
|
|
||||||
)
|
|
||||||
).to.deep.equal([new Token('array', [tokenAddress1, tokenAddress2])]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('decodes a dynamic array of fixed arrays', () => {
|
|
||||||
expect(
|
|
||||||
Decoder.decode(
|
|
||||||
[new ParamType('array', new ParamType('fixedArray', new ParamType('address'), 2))],
|
|
||||||
`${padU32(0x20)}${padU32(2)}${address1}${address2}${address3}${address4}`
|
|
||||||
)
|
|
||||||
).to.deep.equal([
|
|
||||||
new Token('array', [
|
|
||||||
new Token('fixedArray', [tokenAddress1, tokenAddress2]),
|
|
||||||
new Token('fixedArray', [tokenAddress3, tokenAddress4])
|
|
||||||
])
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('int', () => {
|
|
||||||
it('decodes an int', () => {
|
|
||||||
expect(
|
|
||||||
Decoder.decode(
|
|
||||||
[new ParamType('int')],
|
|
||||||
`${int1}`
|
|
||||||
)
|
|
||||||
).to.deep.equal([tokenInt1]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('uint', () => {
|
|
||||||
it('decodes an uint', () => {
|
|
||||||
expect(
|
|
||||||
Decoder.decode(
|
|
||||||
[new ParamType('uint')],
|
|
||||||
`${int1}`
|
|
||||||
)
|
|
||||||
).to.deep.equal([tokenUint1]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('fixedBytes', () => {
|
|
||||||
it('decodes fixedBytes', () => {
|
|
||||||
expect(
|
|
||||||
Decoder.decode(
|
|
||||||
[new ParamType('fixedBytes', null, 2)],
|
|
||||||
`${bytes1}`
|
|
||||||
)
|
|
||||||
).to.deep.equal([tokenFixedBytes1]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('bytes', () => {
|
|
||||||
it('decodes bytes', () => {
|
|
||||||
expect(
|
|
||||||
Decoder.decode(
|
|
||||||
[new ParamType('bytes')],
|
|
||||||
`${padU32(0x20)}${padU32(2)}${bytes1}`
|
|
||||||
)
|
|
||||||
).to.deep.equal([tokenBytes1]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('decodes bytes sequence', () => {
|
|
||||||
expect(
|
|
||||||
Decoder.decode(
|
|
||||||
[new ParamType('bytes')],
|
|
||||||
`${padU32(0x20)}${padU32(0x40)}${bytes2}${bytes2}`
|
|
||||||
)
|
|
||||||
).to.deep.equal([tokenBytes2]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('decodes bytes seuence (2)', () => {
|
|
||||||
expect(
|
|
||||||
Decoder.decode(
|
|
||||||
[new ParamType('bytes'), new ParamType('bytes')],
|
|
||||||
`${padU32(0x40)}${padU32(0x80)}${padU32(0x1f)}${bytes3}00${padU32(0x20)}${bytes4}`
|
|
||||||
)
|
|
||||||
).to.deep.equal([tokenBytes3, tokenBytes4]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('bool', () => {
|
|
||||||
it('decodes a single bool', () => {
|
|
||||||
expect(
|
|
||||||
Decoder.decode(
|
|
||||||
[new ParamType('bool')],
|
|
||||||
bool1
|
|
||||||
)
|
|
||||||
).to.deep.equal([tokenBool1]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('string', () => {
|
|
||||||
it('decodes a string', () => {
|
|
||||||
expect(
|
|
||||||
Decoder.decode(
|
|
||||||
[new ParamType('string')],
|
|
||||||
`${padU32(0x20)}${padU32(9)}${string1}`
|
|
||||||
)
|
|
||||||
).to.deep.equal([tokenString1]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,17 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
export default from './decoder';
|
|
@ -1,75 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import { padAddress, padBool, padBytes, padFixedBytes, padU32, padString } from '../util/pad';
|
|
||||||
import Mediate from './mediate';
|
|
||||||
import Token from '../token/token';
|
|
||||||
import { isArray, isInstanceOf } from '../util/types';
|
|
||||||
|
|
||||||
export default class Encoder {
|
|
||||||
static encode (tokens) {
|
|
||||||
if (!isArray(tokens)) {
|
|
||||||
throw new Error('tokens should be array of Token');
|
|
||||||
}
|
|
||||||
|
|
||||||
const mediates = tokens.map((token, index) => Encoder.encodeToken(token, index));
|
|
||||||
const inits = mediates
|
|
||||||
.map((mediate, idx) => mediate.init(Mediate.offsetFor(mediates, idx)))
|
|
||||||
.join('');
|
|
||||||
const closings = mediates
|
|
||||||
.map((mediate, idx) => mediate.closing(Mediate.offsetFor(mediates, idx)))
|
|
||||||
.join('');
|
|
||||||
|
|
||||||
return `${inits}${closings}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static encodeToken (token, index = 0) {
|
|
||||||
if (!isInstanceOf(token, Token)) {
|
|
||||||
throw new Error('token should be instanceof Token');
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
switch (token.type) {
|
|
||||||
case 'address':
|
|
||||||
return new Mediate('raw', padAddress(token.value));
|
|
||||||
|
|
||||||
case 'int':
|
|
||||||
case 'uint':
|
|
||||||
return new Mediate('raw', padU32(token.value));
|
|
||||||
|
|
||||||
case 'bool':
|
|
||||||
return new Mediate('raw', padBool(token.value));
|
|
||||||
|
|
||||||
case 'fixedBytes':
|
|
||||||
return new Mediate('raw', padFixedBytes(token.value));
|
|
||||||
|
|
||||||
case 'bytes':
|
|
||||||
return new Mediate('prefixed', padBytes(token.value));
|
|
||||||
|
|
||||||
case 'string':
|
|
||||||
return new Mediate('prefixed', padString(token.value));
|
|
||||||
|
|
||||||
case 'fixedArray':
|
|
||||||
case 'array':
|
|
||||||
return new Mediate(token.type, token.value.map((token) => Encoder.encodeToken(token)));
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
throw new Error(`Cannot encode token #${index} [${token.type}: ${token.value}]. ${e.message}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error(`Invalid token type ${token.type} in encodeToken`);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,291 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import Encoder from './encoder';
|
|
||||||
import Token from '../token';
|
|
||||||
import { padAddress, padFixedBytes, padU32 } from '../util/pad';
|
|
||||||
|
|
||||||
describe('abi/encoder/Encoder', () => {
|
|
||||||
describe('encodeToken', () => {
|
|
||||||
it('requires token as Token', () => {
|
|
||||||
expect(() => Encoder.encodeToken()).to.throw(/Token/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('encodes address tokens in Mediate(raw)', () => {
|
|
||||||
const mediate = Encoder.encodeToken(new Token('address', '123'));
|
|
||||||
|
|
||||||
expect(mediate.type).to.equal('raw');
|
|
||||||
expect(mediate.value).to.be.ok;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('encodes bool tokens in Mediate(raw)', () => {
|
|
||||||
const mediatet = Encoder.encodeToken(new Token('bool', true));
|
|
||||||
const mediatef = Encoder.encodeToken(new Token('bool', false));
|
|
||||||
|
|
||||||
expect(mediatet.type).to.equal('raw');
|
|
||||||
expect(mediatet.value).to.be.ok;
|
|
||||||
|
|
||||||
expect(mediatef.type).to.equal('raw');
|
|
||||||
expect(mediatef.value).to.be.ok;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('encodes int tokens in Mediate(raw)', () => {
|
|
||||||
const mediate = Encoder.encodeToken(new Token('int', '123'));
|
|
||||||
|
|
||||||
expect(mediate.type).to.equal('raw');
|
|
||||||
expect(mediate.value).to.be.ok;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('encodes uint tokens in Mediate(raw)', () => {
|
|
||||||
const mediate = Encoder.encodeToken(new Token('uint', '123'));
|
|
||||||
|
|
||||||
expect(mediate.type).to.equal('raw');
|
|
||||||
expect(mediate.value).to.be.ok;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('encodes fixedBytes tokens in Mediate(raw)', () => {
|
|
||||||
const mediate = Encoder.encodeToken(new Token('fixedBytes', '123'));
|
|
||||||
|
|
||||||
expect(mediate.type).to.equal('raw');
|
|
||||||
expect(mediate.value).to.be.ok;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('encodes bytes tokens in Mediate(prefixed)', () => {
|
|
||||||
const mediate = Encoder.encodeToken(new Token('bytes', '123'));
|
|
||||||
|
|
||||||
expect(mediate.type).to.equal('prefixed');
|
|
||||||
expect(mediate.value).to.be.ok;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('encodes string tokens in Mediate(prefixed)', () => {
|
|
||||||
const mediate = Encoder.encodeToken(new Token('string', '123'));
|
|
||||||
|
|
||||||
expect(mediate.type).to.equal('prefixed');
|
|
||||||
expect(mediate.value).to.be.ok;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('encodes fixedArray tokens in Mediate(fixedArray)', () => {
|
|
||||||
const mediate = Encoder.encodeToken(new Token('fixedArray', [new Token('uint', '123')]));
|
|
||||||
|
|
||||||
expect(mediate.type).to.equal('fixedArray');
|
|
||||||
expect(mediate.value).to.be.ok;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('encodes array tokens in Mediate(array)', () => {
|
|
||||||
const mediate = Encoder.encodeToken(new Token('array', [new Token('uint', '123')]));
|
|
||||||
|
|
||||||
expect(mediate.type).to.equal('array');
|
|
||||||
expect(mediate.value).to.be.ok;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('throws an Error on invalid tokens', () => {
|
|
||||||
const token = new Token('address');
|
|
||||||
|
|
||||||
token._type = 'noMatch';
|
|
||||||
|
|
||||||
expect(() => Encoder.encodeToken(token)).to.throw(/noMatch/);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('encode', () => {
|
|
||||||
it('requires tokens array', () => {
|
|
||||||
expect(() => Encoder.encode()).to.throw(/array/);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('addresses', () => {
|
|
||||||
const address1 = '1111111111111111111111111111111111111111';
|
|
||||||
const address2 = '2222222222222222222222222222222222222222';
|
|
||||||
const address3 = '3333333333333333333333333333333333333333';
|
|
||||||
const address4 = '4444444444444444444444444444444444444444';
|
|
||||||
const encAddress1 = padAddress(address1);
|
|
||||||
const encAddress2 = padAddress(address2);
|
|
||||||
const encAddress3 = padAddress(address3);
|
|
||||||
const encAddress4 = padAddress(address4);
|
|
||||||
const tokenAddress1 = new Token('address', address1);
|
|
||||||
const tokenAddress2 = new Token('address', address2);
|
|
||||||
const tokenAddress3 = new Token('address', address3);
|
|
||||||
const tokenAddress4 = new Token('address', address4);
|
|
||||||
|
|
||||||
it('encodes an address', () => {
|
|
||||||
const token = tokenAddress1;
|
|
||||||
|
|
||||||
expect(Encoder.encode([token])).to.equal(encAddress1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('encodes an array of addresses', () => {
|
|
||||||
const expected = `${padU32(0x20)}${padU32(2)}${encAddress1}${encAddress2}`;
|
|
||||||
const token = new Token('array', [tokenAddress1, tokenAddress2]);
|
|
||||||
|
|
||||||
expect(Encoder.encode([token])).to.equal(expected);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('encodes an fixedArray of addresses', () => {
|
|
||||||
const expected = `${encAddress1}${encAddress2}`;
|
|
||||||
const token = new Token('fixedArray', [tokenAddress1, tokenAddress2]);
|
|
||||||
|
|
||||||
expect(Encoder.encode([token])).to.equal(expected);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('encodes two addresses', () => {
|
|
||||||
const expected = `${encAddress1}${encAddress2}`;
|
|
||||||
const tokens = [tokenAddress1, tokenAddress2];
|
|
||||||
|
|
||||||
expect(Encoder.encode(tokens)).to.equal(expected);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('encodes fixed array of dynamic array addresses', () => {
|
|
||||||
const tokens1 = new Token('array', [tokenAddress1, tokenAddress2]);
|
|
||||||
const tokens2 = new Token('array', [tokenAddress3, tokenAddress4]);
|
|
||||||
const fixed = new Token('fixedArray', [tokens1, tokens2]);
|
|
||||||
const expected = `${padU32(0x40)}${padU32(0xa0)}${padU32(2)}${encAddress1}${encAddress2}${padU32(2)}${encAddress3}${encAddress4}`;
|
|
||||||
|
|
||||||
expect(Encoder.encode([fixed])).to.equal(expected);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('encodes dynamic array of fixed array addresses', () => {
|
|
||||||
const tokens1 = new Token('fixedArray', [tokenAddress1, tokenAddress2]);
|
|
||||||
const tokens2 = new Token('fixedArray', [tokenAddress3, tokenAddress4]);
|
|
||||||
const dynamic = new Token('array', [tokens1, tokens2]);
|
|
||||||
const expected = `${padU32(0x20)}${padU32(2)}${encAddress1}${encAddress2}${encAddress3}${encAddress4}`;
|
|
||||||
|
|
||||||
expect(Encoder.encode([dynamic])).to.equal(expected);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('encodes dynamic array of dynamic array addresses', () => {
|
|
||||||
const tokens1 = new Token('array', [tokenAddress1]);
|
|
||||||
const tokens2 = new Token('array', [tokenAddress2]);
|
|
||||||
const dynamic = new Token('array', [tokens1, tokens2]);
|
|
||||||
const expected = `${padU32(0x20)}${padU32(2)}${padU32(0x80)}${padU32(0xc0)}${padU32(1)}${encAddress1}${padU32(1)}${encAddress2}`;
|
|
||||||
|
|
||||||
expect(Encoder.encode([dynamic])).to.equal(expected);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('encodes dynamic array of dynamic array addresses (2)', () => {
|
|
||||||
const tokens1 = new Token('array', [tokenAddress1, tokenAddress2]);
|
|
||||||
const tokens2 = new Token('array', [tokenAddress3, tokenAddress4]);
|
|
||||||
const dynamic = new Token('array', [tokens1, tokens2]);
|
|
||||||
const expected = `${padU32(0x20)}${padU32(2)}${padU32(0x80)}${padU32(0xe0)}${padU32(2)}${encAddress1}${encAddress2}${padU32(2)}${encAddress3}${encAddress4}`;
|
|
||||||
|
|
||||||
expect(Encoder.encode([dynamic])).to.equal(expected);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('encodes fixed array of fixed array addresses', () => {
|
|
||||||
const tokens1 = new Token('fixedArray', [tokenAddress1, tokenAddress2]);
|
|
||||||
const tokens2 = new Token('fixedArray', [tokenAddress3, tokenAddress4]);
|
|
||||||
const dynamic = new Token('fixedArray', [tokens1, tokens2]);
|
|
||||||
const expected = `${encAddress1}${encAddress2}${encAddress3}${encAddress4}`;
|
|
||||||
|
|
||||||
expect(Encoder.encode([dynamic])).to.equal(expected);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('bytes', () => {
|
|
||||||
const bytes1 = '0x1234';
|
|
||||||
const bytes2 = '0x10000000000000000000000000000000000000000000000000000000000002';
|
|
||||||
const bytes3 = '0x1000000000000000000000000000000000000000000000000000000000000000';
|
|
||||||
|
|
||||||
it('encodes fixed bytes', () => {
|
|
||||||
const token = new Token('fixedBytes', bytes1);
|
|
||||||
|
|
||||||
expect(Encoder.encode([token])).to.equal(padFixedBytes(bytes1));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('encodes bytes', () => {
|
|
||||||
const token = new Token('bytes', bytes1);
|
|
||||||
|
|
||||||
expect(Encoder.encode([token])).to.equal(`${padU32(0x20)}${padU32(2)}${padFixedBytes(bytes1)}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('encodes bytes (short of boundary)', () => {
|
|
||||||
const token = new Token('bytes', bytes2);
|
|
||||||
|
|
||||||
expect(Encoder.encode([token])).to.equal(`${padU32(0x20)}${padU32(0x1f)}${padFixedBytes(bytes2)}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('encodes bytes (two blocks)', () => {
|
|
||||||
const input = `${bytes3}${bytes3.slice(-64)}`;
|
|
||||||
const token = new Token('bytes', input);
|
|
||||||
|
|
||||||
expect(Encoder.encode([token])).to.equal(`${padU32(0x20)}${padU32(0x40)}${padFixedBytes(input)}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('encodes two consecutive bytes', () => {
|
|
||||||
const in1 = '0x10000000000000000000000000000000000000000000000000000000000002';
|
|
||||||
const in2 = '0x0010000000000000000000000000000000000000000000000000000000000002';
|
|
||||||
const tokens = [new Token('bytes', in1), new Token('bytes', in2)];
|
|
||||||
|
|
||||||
expect(Encoder.encode(tokens)).to.equal(`${padU32(0x40)}${padU32(0x80)}${padU32(0x1f)}${padFixedBytes(in1)}${padU32(0x20)}${padFixedBytes(in2)}`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('string', () => {
|
|
||||||
it('encodes a string', () => {
|
|
||||||
const string = 'gavofyork';
|
|
||||||
const stringEnc = padFixedBytes('0x6761766f66796f726b');
|
|
||||||
const token = new Token('string', string);
|
|
||||||
|
|
||||||
expect(Encoder.encode([token])).to.equal(`${padU32(0x20)}${padU32(string.length.toString(16))}${stringEnc}`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('uint', () => {
|
|
||||||
it('encodes a uint', () => {
|
|
||||||
const token = new Token('uint', 4);
|
|
||||||
|
|
||||||
expect(Encoder.encode([token])).to.equal(padU32(4));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('int', () => {
|
|
||||||
it('encodes a int', () => {
|
|
||||||
const token = new Token('int', 4);
|
|
||||||
|
|
||||||
expect(Encoder.encode([token])).to.equal(padU32(4));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('bool', () => {
|
|
||||||
it('encodes a bool (true)', () => {
|
|
||||||
const token = new Token('bool', true);
|
|
||||||
|
|
||||||
expect(Encoder.encode([token])).to.equal(padU32(1));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('encodes a bool (false)', () => {
|
|
||||||
const token = new Token('bool', false);
|
|
||||||
|
|
||||||
expect(Encoder.encode([token])).to.equal(padU32(0));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('comprehensive test', () => {
|
|
||||||
it('encodes a complex sequence', () => {
|
|
||||||
const bytes = '0x131a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b131a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b';
|
|
||||||
const tokens = [new Token('int', 5), new Token('bytes', bytes), new Token('int', 3), new Token('bytes', bytes)];
|
|
||||||
|
|
||||||
expect(Encoder.encode(tokens)).to.equal(`${padU32(5)}${padU32(0x80)}${padU32(3)}${padU32(0xe0)}${padU32(0x40)}${bytes.substr(2)}${padU32(0x40)}${bytes.substr(2)}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('encodes a complex sequence (nested)', () => {
|
|
||||||
const array = [new Token('int', 5), new Token('int', 6), new Token('int', 7)];
|
|
||||||
const tokens = [new Token('int', 1), new Token('string', 'gavofyork'), new Token('int', 2), new Token('int', 3), new Token('int', 4), new Token('array', array)];
|
|
||||||
const stringEnc = padFixedBytes('0x6761766f66796f726b');
|
|
||||||
|
|
||||||
expect(Encoder.encode(tokens)).to.equal(`${padU32(1)}${padU32(0xc0)}${padU32(2)}${padU32(3)}${padU32(4)}${padU32(0x100)}${padU32(9)}${stringEnc}${padU32(3)}${padU32(5)}${padU32(6)}${padU32(7)}`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,17 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
export default from './encoder';
|
|
@ -1,142 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
const TYPES = ['raw', 'prefixed', 'fixedArray', 'array'];
|
|
||||||
|
|
||||||
import { padU32 } from '../util/pad';
|
|
||||||
|
|
||||||
export default class Mediate {
|
|
||||||
constructor (type, value) {
|
|
||||||
Mediate.validateType(type);
|
|
||||||
|
|
||||||
this._type = type;
|
|
||||||
this._value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
initLength () {
|
|
||||||
switch (this._type) {
|
|
||||||
case 'raw':
|
|
||||||
return this._value.length / 2;
|
|
||||||
|
|
||||||
case 'array':
|
|
||||||
case 'prefixed':
|
|
||||||
return 32;
|
|
||||||
|
|
||||||
case 'fixedArray':
|
|
||||||
return this._value
|
|
||||||
.reduce((total, mediate) => {
|
|
||||||
return total + mediate.initLength();
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
closingLength () {
|
|
||||||
switch (this._type) {
|
|
||||||
case 'raw':
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case 'prefixed':
|
|
||||||
return this._value.length / 2;
|
|
||||||
|
|
||||||
case 'array':
|
|
||||||
return this._value
|
|
||||||
.reduce((total, mediate) => {
|
|
||||||
return total + mediate.initLength();
|
|
||||||
}, 32);
|
|
||||||
|
|
||||||
case 'fixedArray':
|
|
||||||
return this._value
|
|
||||||
.reduce((total, mediate) => {
|
|
||||||
return total + mediate.initLength() + mediate.closingLength();
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
init (suffixOffset) {
|
|
||||||
switch (this._type) {
|
|
||||||
case 'raw':
|
|
||||||
return this._value;
|
|
||||||
|
|
||||||
case 'fixedArray':
|
|
||||||
return this._value
|
|
||||||
.map((mediate, idx) => mediate.init(Mediate.offsetFor(this._value, idx)).toString(16))
|
|
||||||
.join('');
|
|
||||||
|
|
||||||
case 'prefixed':
|
|
||||||
case 'array':
|
|
||||||
return padU32(suffixOffset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
closing (offset) {
|
|
||||||
switch (this._type) {
|
|
||||||
case 'raw':
|
|
||||||
return '';
|
|
||||||
|
|
||||||
case 'prefixed':
|
|
||||||
return this._value;
|
|
||||||
|
|
||||||
case 'fixedArray':
|
|
||||||
return this._value
|
|
||||||
.map((mediate, idx) => mediate.closing(Mediate.offsetFor(this._value, idx)).toString(16))
|
|
||||||
.join('');
|
|
||||||
|
|
||||||
case 'array':
|
|
||||||
const prefix = padU32(this._value.length);
|
|
||||||
const inits = this._value
|
|
||||||
.map((mediate, idx) => mediate.init(offset + Mediate.offsetFor(this._value, idx) + 32).toString(16))
|
|
||||||
.join('');
|
|
||||||
const closings = this._value
|
|
||||||
.map((mediate, idx) => mediate.closing(offset + Mediate.offsetFor(this._value, idx)).toString(16))
|
|
||||||
.join('');
|
|
||||||
|
|
||||||
return `${prefix}${inits}${closings}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get type () {
|
|
||||||
return this._type;
|
|
||||||
}
|
|
||||||
|
|
||||||
get value () {
|
|
||||||
return this._value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static offsetFor (mediates, position) {
|
|
||||||
if (position < 0 || position >= mediates.length) {
|
|
||||||
throw new Error(`Invalid position ${position} specified for Mediate.offsetFor`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const initLength = mediates
|
|
||||||
.reduce((total, mediate) => {
|
|
||||||
return total + mediate.initLength();
|
|
||||||
}, 0);
|
|
||||||
|
|
||||||
return mediates
|
|
||||||
.slice(0, position)
|
|
||||||
.reduce((total, mediate) => {
|
|
||||||
return total + mediate.closingLength();
|
|
||||||
}, initLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
static validateType (type) {
|
|
||||||
if (TYPES.filter((_type) => type === _type).length) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error(`Invalid type ${type} received for Mediate.validateType`);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,105 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import Mediate from './mediate';
|
|
||||||
|
|
||||||
describe('abi/encoder/Mediate', () => {
|
|
||||||
const LONG15 = '1234567890abcdef000000000000000000000000000000000000000000000000';
|
|
||||||
const DOUBLE15 = `${LONG15}${LONG15}`;
|
|
||||||
const ARRAY = [new Mediate('raw', DOUBLE15), new Mediate('raw', LONG15)];
|
|
||||||
|
|
||||||
describe('validateType', () => {
|
|
||||||
it('validates raw', () => {
|
|
||||||
expect(Mediate.validateType('raw')).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('validates prefixed', () => {
|
|
||||||
expect(Mediate.validateType('prefixed')).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('validates fixedArray', () => {
|
|
||||||
expect(Mediate.validateType('fixedArray')).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('validates array', () => {
|
|
||||||
expect(Mediate.validateType('array')).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('throws an error on invalid types', () => {
|
|
||||||
expect(() => Mediate.validateType('noMatch')).to.throw(/noMatch/);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('offsetFor', () => {
|
|
||||||
it('thows an error when offset < 0', () => {
|
|
||||||
expect(() => Mediate.offsetFor([1], -1)).to.throw(/Invalid position/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('throws an error when offset >= length', () => {
|
|
||||||
expect(() => Mediate.offsetFor([1], 1)).to.throw(/Invalid position/);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('constructor', () => {
|
|
||||||
it('throws an error on invalid types', () => {
|
|
||||||
expect(() => new Mediate('noMatch', '1')).to.throw(/noMatch/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sets the type of the object', () => {
|
|
||||||
expect((new Mediate('raw', '1')).type).to.equal('raw');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sets the value of the object', () => {
|
|
||||||
expect((new Mediate('raw', '1')).value).to.equal('1');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('initLength', () => {
|
|
||||||
it('returns correct variable byte length for raw', () => {
|
|
||||||
expect(new Mediate('raw', DOUBLE15).initLength()).to.equal(64);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns correct fixed byte length for array', () => {
|
|
||||||
expect(new Mediate('array', [1, 2, 3, 4]).initLength()).to.equal(32);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns correct fixed byte length for prefixed', () => {
|
|
||||||
expect(new Mediate('prefixed', 0).initLength()).to.equal(32);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns correct variable byte length for fixedArray', () => {
|
|
||||||
expect(new Mediate('fixedArray', ARRAY).initLength()).to.equal(96);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('closingLength', () => {
|
|
||||||
it('returns 0 byte length for raw', () => {
|
|
||||||
expect(new Mediate('raw', DOUBLE15).closingLength()).to.equal(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns prefix + size for prefixed', () => {
|
|
||||||
expect(new Mediate('prefixed', DOUBLE15).closingLength()).to.equal(64);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns prefix + size for array', () => {
|
|
||||||
expect(new Mediate('array', ARRAY).closingLength()).to.equal(128);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns total length for fixedArray', () => {
|
|
||||||
expect(new Mediate('fixedArray', ARRAY).closingLength()).to.equal(96);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,17 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
export default from './abi';
|
|
@ -1,30 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@parity/abi",
|
|
||||||
"description": "The Parity ABI library",
|
|
||||||
"version": "0.0.0",
|
|
||||||
"main": "index.js",
|
|
||||||
"author": "Parity Team <admin@parity.io>",
|
|
||||||
"maintainers": [
|
|
||||||
"Jaco Greeff",
|
|
||||||
"Nicolas Gotchac"
|
|
||||||
],
|
|
||||||
"contributors": [],
|
|
||||||
"license": "GPL-3.0",
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git+https://github.com/paritytech/parity.git"
|
|
||||||
},
|
|
||||||
"keywords": [
|
|
||||||
"Ethereum",
|
|
||||||
"ABI",
|
|
||||||
"Parity"
|
|
||||||
],
|
|
||||||
"scripts": {
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"bignumber.js": "3.0.1",
|
|
||||||
"js-sha3": "0.5.5"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import Encoder from '../encoder/encoder';
|
|
||||||
import Param from './param';
|
|
||||||
|
|
||||||
export default class Constructor {
|
|
||||||
constructor (abi) {
|
|
||||||
this._inputs = Param.toParams(abi.inputs || []);
|
|
||||||
}
|
|
||||||
|
|
||||||
get inputs () {
|
|
||||||
return this._inputs;
|
|
||||||
}
|
|
||||||
|
|
||||||
inputParamTypes () {
|
|
||||||
return this._inputs.map((input) => input.kind);
|
|
||||||
}
|
|
||||||
|
|
||||||
encodeCall (tokens) {
|
|
||||||
return Encoder.encode(tokens);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,52 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import Constructor from './constructor';
|
|
||||||
import Param from './param';
|
|
||||||
import Token from '../token';
|
|
||||||
|
|
||||||
describe('abi/spec/Constructor', () => {
|
|
||||||
const inputsArr = [{ name: 'boolin', type: 'bool' }, { name: 'stringin', type: 'string' }];
|
|
||||||
const bool = new Param('boolin', 'bool');
|
|
||||||
const string = new Param('stringin', 'string');
|
|
||||||
|
|
||||||
const inputs = [bool, string];
|
|
||||||
const cr = new Constructor({ inputs: inputsArr });
|
|
||||||
|
|
||||||
describe('constructor', () => {
|
|
||||||
it('stores the inputs as received', () => {
|
|
||||||
expect(cr.inputs).to.deep.equal(inputs);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('matches empty inputs with []', () => {
|
|
||||||
expect(new Constructor({}).inputs).to.deep.equal([]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('inputParamTypes', () => {
|
|
||||||
it('retrieves the input types as received', () => {
|
|
||||||
expect(cr.inputParamTypes()).to.deep.equal([bool.kind, string.kind]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('encodeCall', () => {
|
|
||||||
it('encodes correctly', () => {
|
|
||||||
const result = cr.encodeCall([new Token('bool', true), new Token('string', 'jacogr')]);
|
|
||||||
|
|
||||||
expect(result).to.equal('0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000066a61636f67720000000000000000000000000000000000000000000000000000');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,30 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
export default class DecodedLog {
|
|
||||||
constructor (params, address) {
|
|
||||||
this._params = params;
|
|
||||||
this._address = address;
|
|
||||||
}
|
|
||||||
|
|
||||||
get address () {
|
|
||||||
return this._address;
|
|
||||||
}
|
|
||||||
|
|
||||||
get params () {
|
|
||||||
return this._params;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import DecodedLog from './decodedLog';
|
|
||||||
|
|
||||||
const log = new DecodedLog('someParams', 'someAddress');
|
|
||||||
|
|
||||||
describe('abi/spec/event/DecodedLog', () => {
|
|
||||||
describe('constructor', () => {
|
|
||||||
it('sets internal state', () => {
|
|
||||||
expect(log.params).to.equal('someParams');
|
|
||||||
expect(log.address).to.equal('someAddress');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,45 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import ParamType from '../paramType/paramType';
|
|
||||||
import Token from '../../token/token';
|
|
||||||
import { isInstanceOf } from '../../util/types';
|
|
||||||
|
|
||||||
export default class DecodedLogParam {
|
|
||||||
constructor (name, kind, token) {
|
|
||||||
if (!isInstanceOf(kind, ParamType)) {
|
|
||||||
throw new Error('kind not instanceof ParamType');
|
|
||||||
} else if (!isInstanceOf(token, Token)) {
|
|
||||||
throw new Error('token not instanceof Token');
|
|
||||||
}
|
|
||||||
|
|
||||||
this._name = name;
|
|
||||||
this._kind = kind;
|
|
||||||
this._token = token;
|
|
||||||
}
|
|
||||||
|
|
||||||
get name () {
|
|
||||||
return this._name;
|
|
||||||
}
|
|
||||||
|
|
||||||
get kind () {
|
|
||||||
return this._kind;
|
|
||||||
}
|
|
||||||
|
|
||||||
get token () {
|
|
||||||
return this._token;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import DecodedLogParam from './decodedLogParam';
|
|
||||||
import ParamType from '../paramType';
|
|
||||||
import Token from '../../token';
|
|
||||||
|
|
||||||
describe('abi/spec/event/DecodedLogParam', () => {
|
|
||||||
describe('constructor', () => {
|
|
||||||
const pt = new ParamType('bool');
|
|
||||||
const tk = new Token('bool');
|
|
||||||
|
|
||||||
it('disallows kind not instanceof ParamType', () => {
|
|
||||||
expect(() => new DecodedLogParam('test', 'param')).to.throw(/ParamType/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('disallows token not instanceof Token', () => {
|
|
||||||
expect(() => new DecodedLogParam('test', pt, 'token')).to.throw(/Token/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('stores all parameters received', () => {
|
|
||||||
const log = new DecodedLogParam('test', pt, tk);
|
|
||||||
|
|
||||||
expect(log.name).to.equal('test');
|
|
||||||
expect(log.kind).to.equal(pt);
|
|
||||||
expect(log.token).to.equal(tk);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,114 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import Decoder from '../../decoder/decoder';
|
|
||||||
import DecodedLog from './decodedLog';
|
|
||||||
import DecodedLogParam from './decodedLogParam';
|
|
||||||
import EventParam from './eventParam';
|
|
||||||
import { asAddress } from '../../util/sliceAs';
|
|
||||||
import { eventSignature } from '../../util/signature';
|
|
||||||
|
|
||||||
export default class Event {
|
|
||||||
constructor (abi) {
|
|
||||||
this._inputs = EventParam.toEventParams(abi.inputs || []);
|
|
||||||
this._anonymous = !!abi.anonymous;
|
|
||||||
|
|
||||||
const { id, name, signature } = eventSignature(abi.name, this.inputParamTypes());
|
|
||||||
|
|
||||||
this._id = id;
|
|
||||||
this._name = name;
|
|
||||||
this._signature = signature;
|
|
||||||
}
|
|
||||||
|
|
||||||
get name () {
|
|
||||||
return this._name;
|
|
||||||
}
|
|
||||||
|
|
||||||
get id () {
|
|
||||||
return this._id;
|
|
||||||
}
|
|
||||||
|
|
||||||
get inputs () {
|
|
||||||
return this._inputs;
|
|
||||||
}
|
|
||||||
|
|
||||||
get anonymous () {
|
|
||||||
return this._anonymous;
|
|
||||||
}
|
|
||||||
|
|
||||||
get signature () {
|
|
||||||
return this._signature;
|
|
||||||
}
|
|
||||||
|
|
||||||
inputParamTypes () {
|
|
||||||
return this._inputs.map((input) => input.kind);
|
|
||||||
}
|
|
||||||
|
|
||||||
inputParamNames () {
|
|
||||||
return this._inputs.map((input) => input.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
indexedParams (indexed) {
|
|
||||||
return this._inputs.filter((input) => input.indexed === indexed);
|
|
||||||
}
|
|
||||||
|
|
||||||
decodeLog (topics, data) {
|
|
||||||
const topicParams = this.indexedParams(true);
|
|
||||||
const dataParams = this.indexedParams(false);
|
|
||||||
|
|
||||||
let address;
|
|
||||||
let toSkip;
|
|
||||||
|
|
||||||
if (!this.anonymous) {
|
|
||||||
address = asAddress(topics[0]);
|
|
||||||
toSkip = 1;
|
|
||||||
} else {
|
|
||||||
toSkip = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const topicTypes = topicParams.map((param) => param.kind);
|
|
||||||
const flatTopics = topics
|
|
||||||
.filter((topic, idx) => idx >= toSkip)
|
|
||||||
.map((topic) => {
|
|
||||||
return (topic.substr(0, 2) === '0x')
|
|
||||||
? topic.substr(2)
|
|
||||||
: topic;
|
|
||||||
}).join('');
|
|
||||||
const topicTokens = Decoder.decode(topicTypes, flatTopics);
|
|
||||||
|
|
||||||
if (topicTokens.length !== (topics.length - toSkip)) {
|
|
||||||
throw new Error('Invalid topic data');
|
|
||||||
}
|
|
||||||
|
|
||||||
const dataTypes = dataParams.map((param) => param.kind);
|
|
||||||
const dataTokens = Decoder.decode(dataTypes, data);
|
|
||||||
|
|
||||||
const namedTokens = {};
|
|
||||||
|
|
||||||
topicParams.forEach((param, idx) => {
|
|
||||||
namedTokens[param.name || idx] = topicTokens[idx];
|
|
||||||
});
|
|
||||||
dataParams.forEach((param, idx) => {
|
|
||||||
namedTokens[param.name || idx] = dataTokens[idx];
|
|
||||||
});
|
|
||||||
|
|
||||||
const inputParamTypes = this.inputParamTypes();
|
|
||||||
const decodedParams = this.inputParamNames()
|
|
||||||
.map((name, idx) => new DecodedLogParam(name, inputParamTypes[idx], namedTokens[name || idx]));
|
|
||||||
|
|
||||||
return new DecodedLog(decodedParams, address);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,111 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import BigNumber from 'bignumber.js';
|
|
||||||
|
|
||||||
import Event from './event';
|
|
||||||
import EventParam from './eventParam';
|
|
||||||
import DecodedLogParam from './decodedLogParam';
|
|
||||||
import ParamType from '../paramType';
|
|
||||||
import Token from '../../token';
|
|
||||||
|
|
||||||
describe('abi/spec/event/Event', () => {
|
|
||||||
const inputArr = [{ name: 'a', type: 'bool' }, { name: 'b', type: 'uint', indexed: true }];
|
|
||||||
const inputs = [new EventParam('a', 'bool', false), new EventParam('b', 'uint', true)];
|
|
||||||
const event = new Event({ name: 'test', inputs: inputArr, anonymous: true });
|
|
||||||
|
|
||||||
describe('constructor', () => {
|
|
||||||
it('stores the parameters as received', () => {
|
|
||||||
expect(event.name).to.equal('test');
|
|
||||||
expect(event.inputs).to.deep.equal(inputs);
|
|
||||||
expect(event.anonymous).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('matches empty inputs with []', () => {
|
|
||||||
expect(new Event({ name: 'test' }).inputs).to.deep.equal([]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sets the event signature', () => {
|
|
||||||
expect(new Event({ name: 'baz' }).signature)
|
|
||||||
.to.equal('a7916fac4f538170f7cd12c148552e2cba9fcd72329a2dd5b07a6fa906488ddf');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('inputParamTypes', () => {
|
|
||||||
it('returns all the types', () => {
|
|
||||||
expect(event.inputParamTypes()).to.deep.equal([new ParamType('bool'), new ParamType('uint', null, 256, true)]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('inputParamNames', () => {
|
|
||||||
it('returns all the names', () => {
|
|
||||||
expect(event.inputParamNames()).to.deep.equal(['a', 'b']);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('indexedParams', () => {
|
|
||||||
it('returns all indexed parameters (indexed)', () => {
|
|
||||||
expect(event.indexedParams(true)).to.deep.equal([inputs[1]]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns all indexed parameters (non-indexed)', () => {
|
|
||||||
expect(event.indexedParams(false)).to.deep.equal([inputs[0]]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('decodeLog', () => {
|
|
||||||
it('decodes an event', () => {
|
|
||||||
const event = new Event({
|
|
||||||
name: 'foo',
|
|
||||||
inputs: [
|
|
||||||
{ name: 'a', type: 'int' },
|
|
||||||
{ name: 'b', type: 'int', indexed: true },
|
|
||||||
{ name: 'c', type: 'address' },
|
|
||||||
{ name: 'd', type: 'address', indexed: true }
|
|
||||||
]
|
|
||||||
});
|
|
||||||
const decoded = event.decodeLog([
|
|
||||||
'0000000000000000000000004444444444444444444444444444444444444444',
|
|
||||||
'0000000000000000000000000000000000000000000000000000000000000002',
|
|
||||||
'0000000000000000000000001111111111111111111111111111111111111111' ],
|
|
||||||
'00000000000000000000000000000000000000000000000000000000000000030000000000000000000000002222222222222222222222222222222222222222');
|
|
||||||
|
|
||||||
expect(decoded.address).to.equal('0x4444444444444444444444444444444444444444');
|
|
||||||
expect(decoded.params).to.deep.equal([
|
|
||||||
new DecodedLogParam('a', new ParamType('int', null, 256), new Token('int', new BigNumber(3))),
|
|
||||||
new DecodedLogParam('b', new ParamType('int', null, 256, true), new Token('int', new BigNumber(2))),
|
|
||||||
new DecodedLogParam('c', new ParamType('address'), new Token('address', '0x2222222222222222222222222222222222222222')),
|
|
||||||
new DecodedLogParam('d', new ParamType('address', null, 0, true), new Token('address', '0x1111111111111111111111111111111111111111'))
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('decodes an anonymous event', () => {
|
|
||||||
const event = new Event({ name: 'foo', inputs: [{ name: 'a', type: 'int' }], anonymous: true });
|
|
||||||
const decoded = event.decodeLog([], '0000000000000000000000000000000000000000000000000000000000000003');
|
|
||||||
|
|
||||||
expect(decoded.address).to.not.be.ok;
|
|
||||||
expect(decoded.params).to.deep.equal([
|
|
||||||
new DecodedLogParam('a', new ParamType('int', null, 256), new Token('int', new BigNumber(3)))
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('throws on invalid topics', () => {
|
|
||||||
const event = new Event({ name: 'foo', inputs: [{ name: 'a', type: 'int' }], anonymous: true });
|
|
||||||
|
|
||||||
expect(() => event.decodeLog(['0000000000000000000000004444444444444444444444444444444444444444'], '0000000000000000000000000000000000000000000000000000000000000003')).to.throw(/Invalid/);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,41 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import { toParamType } from '../paramType/format';
|
|
||||||
|
|
||||||
export default class EventParam {
|
|
||||||
constructor (name, type, indexed = false) {
|
|
||||||
this._name = name;
|
|
||||||
this._indexed = indexed;
|
|
||||||
this._kind = toParamType(type, indexed);
|
|
||||||
}
|
|
||||||
|
|
||||||
get name () {
|
|
||||||
return this._name;
|
|
||||||
}
|
|
||||||
|
|
||||||
get kind () {
|
|
||||||
return this._kind;
|
|
||||||
}
|
|
||||||
|
|
||||||
get indexed () {
|
|
||||||
return this._indexed;
|
|
||||||
}
|
|
||||||
|
|
||||||
static toEventParams (params) {
|
|
||||||
return params.map((param) => new EventParam(param.name, param.type, param.indexed));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,44 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import EventParam from './eventParam';
|
|
||||||
|
|
||||||
describe('abi/spec/event/EventParam', () => {
|
|
||||||
describe('constructor', () => {
|
|
||||||
it('sets the properties', () => {
|
|
||||||
const param = new EventParam('foo', 'uint', true);
|
|
||||||
|
|
||||||
expect(param.name).to.equal('foo');
|
|
||||||
expect(param.kind.type).to.equal('uint');
|
|
||||||
expect(param.indexed).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('uses defaults for indexed', () => {
|
|
||||||
expect(new EventParam('foo', 'uint').indexed).to.be.false;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('toEventParams', () => {
|
|
||||||
it('maps an array of params', () => {
|
|
||||||
const params = EventParam.toEventParams([{ name: 'foo', type: 'uint' }]);
|
|
||||||
|
|
||||||
expect(params.length).to.equal(1);
|
|
||||||
expect(params[0].indexed).to.be.false;
|
|
||||||
expect(params[0].name).to.equal('foo');
|
|
||||||
expect(params[0].kind.type).to.equal('uint');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,17 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
export default from './event';
|
|
@ -1,88 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import Decoder from '../decoder/decoder';
|
|
||||||
import Encoder from '../encoder/encoder';
|
|
||||||
import Param from './param';
|
|
||||||
import { methodSignature } from '../util/signature';
|
|
||||||
|
|
||||||
export default class Func {
|
|
||||||
constructor (abi) {
|
|
||||||
this._abi = abi;
|
|
||||||
this._constant = !!abi.constant;
|
|
||||||
this._payable = abi.payable;
|
|
||||||
this._inputs = Param.toParams(abi.inputs || []);
|
|
||||||
this._outputs = Param.toParams(abi.outputs || []);
|
|
||||||
|
|
||||||
const { id, name, signature } = methodSignature(abi.name, this.inputParamTypes());
|
|
||||||
|
|
||||||
this._id = id;
|
|
||||||
this._name = name;
|
|
||||||
this._signature = signature;
|
|
||||||
}
|
|
||||||
|
|
||||||
get abi () {
|
|
||||||
return this._abi;
|
|
||||||
}
|
|
||||||
|
|
||||||
get constant () {
|
|
||||||
return this._constant;
|
|
||||||
}
|
|
||||||
|
|
||||||
get name () {
|
|
||||||
return this._name;
|
|
||||||
}
|
|
||||||
|
|
||||||
get id () {
|
|
||||||
return this._id;
|
|
||||||
}
|
|
||||||
|
|
||||||
get payable () {
|
|
||||||
return this._payable;
|
|
||||||
}
|
|
||||||
|
|
||||||
get inputs () {
|
|
||||||
return this._inputs;
|
|
||||||
}
|
|
||||||
|
|
||||||
get outputs () {
|
|
||||||
return this._outputs;
|
|
||||||
}
|
|
||||||
|
|
||||||
get signature () {
|
|
||||||
return this._signature;
|
|
||||||
}
|
|
||||||
|
|
||||||
inputParamTypes () {
|
|
||||||
return this._inputs.map((input) => input.kind);
|
|
||||||
}
|
|
||||||
|
|
||||||
outputParamTypes () {
|
|
||||||
return this._outputs.map((output) => output.kind);
|
|
||||||
}
|
|
||||||
|
|
||||||
encodeCall (tokens) {
|
|
||||||
return `${this._signature}${Encoder.encode(tokens)}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
decodeInput (data) {
|
|
||||||
return Decoder.decode(this.inputParamTypes(), data);
|
|
||||||
}
|
|
||||||
|
|
||||||
decodeOutput (data) {
|
|
||||||
return Decoder.decode(this.outputParamTypes(), data);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,101 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import Func from './function';
|
|
||||||
import Param from './param';
|
|
||||||
import Token from '../token';
|
|
||||||
|
|
||||||
describe('abi/spec/Function', () => {
|
|
||||||
const inputsArr = [{ name: 'boolin', type: 'bool' }, { name: 'stringin', type: 'string' }];
|
|
||||||
const outputsArr = [{ name: 'output', type: 'uint' }];
|
|
||||||
|
|
||||||
const uint = new Param('output', 'uint');
|
|
||||||
const bool = new Param('boolin', 'bool');
|
|
||||||
const string = new Param('stringin', 'string');
|
|
||||||
const inputs = [bool, string];
|
|
||||||
const outputs = [uint];
|
|
||||||
|
|
||||||
const func = new Func({
|
|
||||||
name: 'test',
|
|
||||||
inputs: inputsArr,
|
|
||||||
outputs: outputsArr
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('constructor', () => {
|
|
||||||
it('returns signature correctly if name already contains it', () => {
|
|
||||||
const func = new Func({
|
|
||||||
name: 'test(bool,string)',
|
|
||||||
inputs: inputsArr,
|
|
||||||
outputs: outputsArr
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(func.name).to.equal('test');
|
|
||||||
expect(func.id).to.equal('test(bool,string)');
|
|
||||||
expect(func.signature).to.equal('02356205');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('stores the parameters as received', () => {
|
|
||||||
expect(func.name).to.equal('test');
|
|
||||||
expect(func.constant).to.be.false;
|
|
||||||
expect(func.inputs).to.deep.equal(inputs);
|
|
||||||
expect(func.outputs).to.deep.equal(outputs);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('matches empty inputs with []', () => {
|
|
||||||
expect(new Func({ name: 'test', outputs: outputsArr }).inputs).to.deep.equal([]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('matches empty outputs with []', () => {
|
|
||||||
expect(new Func({ name: 'test', inputs: inputsArr }).outputs).to.deep.equal([]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sets the method signature', () => {
|
|
||||||
expect(new Func({ name: 'baz' }).signature).to.equal('a7916fac');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('allows constant functions', () => {
|
|
||||||
expect(new Func({ name: 'baz', constant: true }).constant).to.be.true;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('inputParamTypes', () => {
|
|
||||||
it('retrieves the input types as received', () => {
|
|
||||||
expect(func.inputParamTypes()).to.deep.equal([bool.kind, string.kind]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('outputParamTypes', () => {
|
|
||||||
it('retrieves the output types as received', () => {
|
|
||||||
expect(func.outputParamTypes()).to.deep.equal([uint.kind]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('encodeCall', () => {
|
|
||||||
it('encodes the call correctly', () => {
|
|
||||||
const result = func.encodeCall([new Token('bool', true), new Token('string', 'jacogr')]);
|
|
||||||
|
|
||||||
expect(result).to.equal('023562050000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000066a61636f67720000000000000000000000000000000000000000000000000000');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('decodeOutput', () => {
|
|
||||||
it('decodes the result correctly', () => {
|
|
||||||
const result = func.decodeOutput('1111111111111111111111111111111111111111111111111111111111111111');
|
|
||||||
|
|
||||||
expect(result[0].value.toString(16)).to.equal('1111111111111111111111111111111111111111111111111111111111111111');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,17 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
export default from './interface';
|
|
@ -1,77 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import Constructor from './constructor';
|
|
||||||
import Event from './event/event';
|
|
||||||
import Func from './function';
|
|
||||||
import Token from '../token';
|
|
||||||
|
|
||||||
export default class Interface {
|
|
||||||
constructor (abi) {
|
|
||||||
this._interface = Interface.parseABI(abi);
|
|
||||||
}
|
|
||||||
|
|
||||||
get interface () {
|
|
||||||
return this._interface;
|
|
||||||
}
|
|
||||||
|
|
||||||
get constructors () {
|
|
||||||
return this._interface.filter((item) => item instanceof Constructor);
|
|
||||||
}
|
|
||||||
|
|
||||||
get events () {
|
|
||||||
return this._interface.filter((item) => item instanceof Event);
|
|
||||||
}
|
|
||||||
|
|
||||||
get functions () {
|
|
||||||
return this._interface.filter((item) => item instanceof Func);
|
|
||||||
}
|
|
||||||
|
|
||||||
encodeTokens (paramTypes, values) {
|
|
||||||
return Interface.encodeTokens(paramTypes, values);
|
|
||||||
}
|
|
||||||
|
|
||||||
static encodeTokens (paramTypes, values) {
|
|
||||||
const createToken = function (paramType, value) {
|
|
||||||
if (paramType.subtype) {
|
|
||||||
return new Token(paramType.type, value.map((entry) => createToken(paramType.subtype, entry)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Token(paramType.type, value);
|
|
||||||
};
|
|
||||||
|
|
||||||
return paramTypes.map((paramType, idx) => createToken(paramType, values[idx]));
|
|
||||||
}
|
|
||||||
|
|
||||||
static parseABI (abi) {
|
|
||||||
return abi.map((item) => {
|
|
||||||
switch (item.type) {
|
|
||||||
case 'constructor':
|
|
||||||
return new Constructor(item);
|
|
||||||
|
|
||||||
case 'event':
|
|
||||||
return new Event(item);
|
|
||||||
|
|
||||||
case 'function':
|
|
||||||
case 'fallback':
|
|
||||||
return new Func(item);
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new Error(`Unknown ABI type ${item.type}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,126 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import Interface from './interface';
|
|
||||||
import ParamType from './paramType';
|
|
||||||
import Token from '../token';
|
|
||||||
|
|
||||||
describe('abi/spec/Interface', () => {
|
|
||||||
const construct = {
|
|
||||||
type: 'constructor',
|
|
||||||
inputs: []
|
|
||||||
};
|
|
||||||
const event = {
|
|
||||||
type: 'event',
|
|
||||||
name: 'Event2',
|
|
||||||
anonymous: false,
|
|
||||||
inputs: [{ name: 'a', type: 'uint256', indexed: true }, { name: 'b', type: 'bytes32', indexed: false }]
|
|
||||||
};
|
|
||||||
const func = {
|
|
||||||
type: 'function',
|
|
||||||
name: 'foo',
|
|
||||||
inputs: [{ name: 'a', type: 'uint256' }],
|
|
||||||
outputs: []
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('parseABI', () => {
|
|
||||||
it('throws on invalid types', () => {
|
|
||||||
expect(() => Interface.parseABI([{ type: 'noMatch' }])).to.throw(/noMatch/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('creates constructors', () => {
|
|
||||||
expect(Interface.parseABI([ construct ])).to.deep.equal([{ _inputs: [] }]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('creates events', () => {
|
|
||||||
expect(Interface.parseABI([ event ])[0].name).to.equal('Event2');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('creates functions', () => {
|
|
||||||
expect(Interface.parseABI([ func ])[0].name).to.equal('foo');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('parse complex interfaces', () => {
|
|
||||||
expect(Interface.parseABI([ construct, event, func ]).length).to.equal(3);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('constructor', () => {
|
|
||||||
const int = new Interface([ construct, event, func ]);
|
|
||||||
|
|
||||||
it('contains the full interface', () => {
|
|
||||||
expect(int.interface.length).to.equal(3);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('contains the constructors', () => {
|
|
||||||
expect(int.constructors.length).to.equal(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('contains the events', () => {
|
|
||||||
expect(int.events.length).to.equal(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('contains the functions', () => {
|
|
||||||
expect(int.functions.length).to.equal(1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('encodeTokens', () => {
|
|
||||||
const int = new Interface([ construct, event, func ]);
|
|
||||||
|
|
||||||
it('encodes simple types', () => {
|
|
||||||
expect(
|
|
||||||
int.encodeTokens(
|
|
||||||
[new ParamType('bool'), new ParamType('string'), new ParamType('int'), new ParamType('uint')],
|
|
||||||
[true, 'gavofyork', -123, 123]
|
|
||||||
)
|
|
||||||
).to.deep.equal([
|
|
||||||
new Token('bool', true), new Token('string', 'gavofyork'), new Token('int', -123), new Token('uint', 123)
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('encodes array', () => {
|
|
||||||
expect(
|
|
||||||
int.encodeTokens(
|
|
||||||
[new ParamType('array', new ParamType('bool'))],
|
|
||||||
[[true, false, true]]
|
|
||||||
)
|
|
||||||
).to.deep.equal([
|
|
||||||
new Token('array', [
|
|
||||||
new Token('bool', true), new Token('bool', false), new Token('bool', true)
|
|
||||||
])
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('encodes simple with array of array', () => {
|
|
||||||
expect(
|
|
||||||
int.encodeTokens(
|
|
||||||
[
|
|
||||||
new ParamType('bool'),
|
|
||||||
new ParamType('fixedArray', new ParamType('array', new ParamType('uint')), 2)
|
|
||||||
],
|
|
||||||
[true, [[0, 1], [2, 3]]]
|
|
||||||
)
|
|
||||||
).to.deep.equal([
|
|
||||||
new Token('bool', true),
|
|
||||||
new Token('fixedArray', [
|
|
||||||
new Token('array', [new Token('uint', 0), new Token('uint', 1)]),
|
|
||||||
new Token('array', [new Token('uint', 2), new Token('uint', 3)])
|
|
||||||
])
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,42 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import { toParamType } from './paramType/format';
|
|
||||||
|
|
||||||
export default class Param {
|
|
||||||
constructor (name, type) {
|
|
||||||
this._name = name;
|
|
||||||
this._kind = toParamType(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
get name () {
|
|
||||||
return this._name;
|
|
||||||
}
|
|
||||||
|
|
||||||
get kind () {
|
|
||||||
return this._kind;
|
|
||||||
}
|
|
||||||
|
|
||||||
static toParams (params) {
|
|
||||||
return params.map((param) => {
|
|
||||||
if (param instanceof Param) {
|
|
||||||
return param;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Param(param.name, param.type);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,47 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import Param from './param';
|
|
||||||
|
|
||||||
describe('abi/spec/Param', () => {
|
|
||||||
describe('constructor', () => {
|
|
||||||
const param = new Param('foo', 'uint');
|
|
||||||
|
|
||||||
it('sets the properties', () => {
|
|
||||||
expect(param.name).to.equal('foo');
|
|
||||||
expect(param.kind.type).to.equal('uint');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('toParams', () => {
|
|
||||||
it('maps an array of params', () => {
|
|
||||||
const params = Param.toParams([{ name: 'foo', type: 'uint' }]);
|
|
||||||
|
|
||||||
expect(params.length).to.equal(1);
|
|
||||||
expect(params[0].name).to.equal('foo');
|
|
||||||
expect(params[0].kind.type).to.equal('uint');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('converts only if needed', () => {
|
|
||||||
const _params = Param.toParams([{ name: 'foo', type: 'uint' }]);
|
|
||||||
const params = Param.toParams(_params);
|
|
||||||
|
|
||||||
expect(params.length).to.equal(1);
|
|
||||||
expect(params[0].name).to.equal('foo');
|
|
||||||
expect(params[0].kind.type).to.equal('uint');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,80 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import ParamType from './paramType';
|
|
||||||
|
|
||||||
export function toParamType (type, indexed) {
|
|
||||||
if (type[type.length - 1] === ']') {
|
|
||||||
const last = type.lastIndexOf('[');
|
|
||||||
const length = type.substr(last + 1, type.length - last - 2);
|
|
||||||
const subtype = toParamType(type.substr(0, last));
|
|
||||||
|
|
||||||
if (length.length === 0) {
|
|
||||||
return new ParamType('array', subtype, 0, indexed);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ParamType('fixedArray', subtype, parseInt(length, 10), indexed);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case 'address':
|
|
||||||
case 'bool':
|
|
||||||
case 'bytes':
|
|
||||||
case 'string':
|
|
||||||
return new ParamType(type, null, 0, indexed);
|
|
||||||
|
|
||||||
case 'int':
|
|
||||||
case 'uint':
|
|
||||||
return new ParamType(type, null, 256, indexed);
|
|
||||||
|
|
||||||
default:
|
|
||||||
if (type.indexOf('uint') === 0) {
|
|
||||||
return new ParamType('uint', null, parseInt(type.substr(4), 10), indexed);
|
|
||||||
} else if (type.indexOf('int') === 0) {
|
|
||||||
return new ParamType('int', null, parseInt(type.substr(3), 10), indexed);
|
|
||||||
} else if (type.indexOf('bytes') === 0) {
|
|
||||||
return new ParamType('fixedBytes', null, parseInt(type.substr(5), 10), indexed);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error(`Cannot convert ${type} to valid ParamType`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fromParamType (paramType) {
|
|
||||||
switch (paramType.type) {
|
|
||||||
case 'address':
|
|
||||||
case 'bool':
|
|
||||||
case 'bytes':
|
|
||||||
case 'string':
|
|
||||||
return paramType.type;
|
|
||||||
|
|
||||||
case 'int':
|
|
||||||
case 'uint':
|
|
||||||
return `${paramType.type}${paramType.length}`;
|
|
||||||
|
|
||||||
case 'fixedBytes':
|
|
||||||
return `bytes${paramType.length}`;
|
|
||||||
|
|
||||||
case 'fixedArray':
|
|
||||||
return `${fromParamType(paramType.subtype)}[${paramType.length}]`;
|
|
||||||
|
|
||||||
case 'array':
|
|
||||||
return `${fromParamType(paramType.subtype)}[]`;
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new Error(`Cannot convert from ParamType ${paramType.type}`);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,228 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import ParamType from './paramType';
|
|
||||||
import { fromParamType, toParamType } from './format';
|
|
||||||
|
|
||||||
describe('abi/spec/paramType/format', () => {
|
|
||||||
describe('fromParamType', () => {
|
|
||||||
it('errors on invalid types', () => {
|
|
||||||
expect(() => fromParamType({ type: 'noMatch' })).to.throw(/noMatch/);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('simple types', () => {
|
|
||||||
it('converts address to address', () => {
|
|
||||||
const pt = new ParamType('address');
|
|
||||||
|
|
||||||
expect(fromParamType(pt)).to.equal('address');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('converts bool to bool', () => {
|
|
||||||
const pt = new ParamType('bool');
|
|
||||||
|
|
||||||
expect(fromParamType(pt)).to.equal('bool');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('converts bytes to bytes', () => {
|
|
||||||
const pt = new ParamType('bytes');
|
|
||||||
|
|
||||||
expect(fromParamType(pt)).to.equal('bytes');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('converts string to string', () => {
|
|
||||||
const pt = new ParamType('string');
|
|
||||||
|
|
||||||
expect(fromParamType(pt)).to.equal('string');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('length types', () => {
|
|
||||||
it('converts int32 to int32', () => {
|
|
||||||
const pt = new ParamType('int', null, 32);
|
|
||||||
|
|
||||||
expect(fromParamType(pt)).to.equal('int32');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('converts uint64 to int64', () => {
|
|
||||||
const pt = new ParamType('uint', null, 64);
|
|
||||||
|
|
||||||
expect(fromParamType(pt)).to.equal('uint64');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('converts fixedBytes8 to bytes8', () => {
|
|
||||||
const pt = new ParamType('fixedBytes', null, 8);
|
|
||||||
|
|
||||||
expect(fromParamType(pt)).to.equal('bytes8');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('arrays', () => {
|
|
||||||
it('converts string[2] to string[2]', () => {
|
|
||||||
const pt = new ParamType('fixedArray', new ParamType('string'), 2);
|
|
||||||
|
|
||||||
expect(fromParamType(pt)).to.equal('string[2]');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('converts bool[] to bool[]', () => {
|
|
||||||
const pt = new ParamType('array', new ParamType('bool'));
|
|
||||||
|
|
||||||
expect(fromParamType(pt)).to.equal('bool[]');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('converts bool[][2] to bool[][2]', () => {
|
|
||||||
const pt = new ParamType('fixedArray', new ParamType('array', new ParamType('bool')), 2);
|
|
||||||
|
|
||||||
expect(fromParamType(pt)).to.equal('bool[][2]');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('converts bool[2][] to bool[2][]', () => {
|
|
||||||
const pt = new ParamType('array', new ParamType('fixedArray', new ParamType('bool'), 2));
|
|
||||||
|
|
||||||
expect(fromParamType(pt)).to.equal('bool[2][]');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('toParamType', () => {
|
|
||||||
it('errors on invalid types', () => {
|
|
||||||
expect(() => toParamType('noMatch')).to.throw(/noMatch/);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('simple mapping', () => {
|
|
||||||
it('converts address to address', () => {
|
|
||||||
const pt = toParamType('address');
|
|
||||||
|
|
||||||
expect(pt.type).to.equal('address');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('converts bool to bool', () => {
|
|
||||||
const pt = toParamType('bool');
|
|
||||||
|
|
||||||
expect(pt.type).to.equal('bool');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('converts bytes to bytes', () => {
|
|
||||||
const pt = toParamType('bytes');
|
|
||||||
|
|
||||||
expect(pt.type).to.equal('bytes');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('converts string to string', () => {
|
|
||||||
const pt = toParamType('string');
|
|
||||||
|
|
||||||
expect(pt.type).to.equal('string');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('number', () => {
|
|
||||||
it('converts int to int256', () => {
|
|
||||||
const pt = toParamType('int');
|
|
||||||
|
|
||||||
expect(pt.type).to.equal('int');
|
|
||||||
expect(pt.length).to.equal(256);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('converts uint to uint256', () => {
|
|
||||||
const pt = toParamType('uint');
|
|
||||||
|
|
||||||
expect(pt.type).to.equal('uint');
|
|
||||||
expect(pt.length).to.equal(256);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('sized types', () => {
|
|
||||||
it('converts int32 to int32', () => {
|
|
||||||
const pt = toParamType('int32');
|
|
||||||
|
|
||||||
expect(pt.type).to.equal('int');
|
|
||||||
expect(pt.length).to.equal(32);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('converts uint16 to uint16', () => {
|
|
||||||
const pt = toParamType('uint32');
|
|
||||||
|
|
||||||
expect(pt.type).to.equal('uint');
|
|
||||||
expect(pt.length).to.equal(32);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('converts bytes8 to fixedBytes8', () => {
|
|
||||||
const pt = toParamType('bytes8');
|
|
||||||
|
|
||||||
expect(pt.type).to.equal('fixedBytes');
|
|
||||||
expect(pt.length).to.equal(8);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('arrays', () => {
|
|
||||||
describe('fixed arrays', () => {
|
|
||||||
it('creates fixed array', () => {
|
|
||||||
const pt = toParamType('bytes[8]');
|
|
||||||
|
|
||||||
expect(pt.type).to.equal('fixedArray');
|
|
||||||
expect(pt.subtype.type).to.equal('bytes');
|
|
||||||
expect(pt.length).to.equal(8);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('creates fixed arrays of fixed arrays', () => {
|
|
||||||
const pt = toParamType('bytes[45][3]');
|
|
||||||
|
|
||||||
expect(pt.type).to.equal('fixedArray');
|
|
||||||
expect(pt.length).to.equal(3);
|
|
||||||
expect(pt.subtype.type).to.equal('fixedArray');
|
|
||||||
expect(pt.subtype.length).to.equal(45);
|
|
||||||
expect(pt.subtype.subtype.type).to.equal('bytes');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('dynamic arrays', () => {
|
|
||||||
it('creates a dynamic array', () => {
|
|
||||||
const pt = toParamType('bytes[]');
|
|
||||||
|
|
||||||
expect(pt.type).to.equal('array');
|
|
||||||
expect(pt.subtype.type).to.equal('bytes');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('creates a dynamic array of dynamic arrays', () => {
|
|
||||||
const pt = toParamType('bool[][]');
|
|
||||||
|
|
||||||
expect(pt.type).to.equal('array');
|
|
||||||
expect(pt.subtype.type).to.equal('array');
|
|
||||||
expect(pt.subtype.subtype.type).to.equal('bool');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('mixed arrays', () => {
|
|
||||||
it('creates a fixed dynamic array', () => {
|
|
||||||
const pt = toParamType('bool[][3]');
|
|
||||||
|
|
||||||
expect(pt.type).to.equal('fixedArray');
|
|
||||||
expect(pt.length).to.equal(3);
|
|
||||||
expect(pt.subtype.type).to.equal('array');
|
|
||||||
expect(pt.subtype.subtype.type).to.equal('bool');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('creates a dynamic fixed array', () => {
|
|
||||||
const pt = toParamType('bool[3][]');
|
|
||||||
|
|
||||||
expect(pt.type).to.equal('array');
|
|
||||||
expect(pt.subtype.type).to.equal('fixedArray');
|
|
||||||
expect(pt.subtype.length).to.equal(3);
|
|
||||||
expect(pt.subtype.subtype.type).to.equal('bool');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,17 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
export default from './paramType';
|
|
@ -1,52 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import TYPES from './types';
|
|
||||||
|
|
||||||
export default class ParamType {
|
|
||||||
constructor (type, subtype = null, length = 0, indexed = false) {
|
|
||||||
ParamType.validateType(type);
|
|
||||||
|
|
||||||
this._type = type;
|
|
||||||
this._subtype = subtype;
|
|
||||||
this._length = length;
|
|
||||||
this._indexed = indexed;
|
|
||||||
}
|
|
||||||
|
|
||||||
get type () {
|
|
||||||
return this._type;
|
|
||||||
}
|
|
||||||
|
|
||||||
get subtype () {
|
|
||||||
return this._subtype;
|
|
||||||
}
|
|
||||||
|
|
||||||
get length () {
|
|
||||||
return this._length;
|
|
||||||
}
|
|
||||||
|
|
||||||
get indexed () {
|
|
||||||
return this._indexed;
|
|
||||||
}
|
|
||||||
|
|
||||||
static validateType (type) {
|
|
||||||
if (TYPES.filter((_type) => type === _type).length) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error(`Invalid type ${type} received for ParamType`);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,87 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import ParamType from './paramType';
|
|
||||||
|
|
||||||
describe('abi/spec/paramType/ParamType', () => {
|
|
||||||
describe('validateType', () => {
|
|
||||||
it('validates address', () => {
|
|
||||||
expect(ParamType.validateType('address')).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('validates fixedArray', () => {
|
|
||||||
expect(ParamType.validateType('fixedArray')).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('validates array', () => {
|
|
||||||
expect(ParamType.validateType('array')).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('validates fixedBytes', () => {
|
|
||||||
expect(ParamType.validateType('fixedBytes')).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('validates bytes', () => {
|
|
||||||
expect(ParamType.validateType('bytes')).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('validates bool', () => {
|
|
||||||
expect(ParamType.validateType('bool')).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('validates int', () => {
|
|
||||||
expect(ParamType.validateType('int')).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('validates uint', () => {
|
|
||||||
expect(ParamType.validateType('uint')).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('validates string', () => {
|
|
||||||
expect(ParamType.validateType('string')).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('throws an error on invalid types', () => {
|
|
||||||
expect(() => ParamType.validateType('noMatch')).to.throw(/noMatch/);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('constructor', () => {
|
|
||||||
it('throws an error on invalid types', () => {
|
|
||||||
expect(() => new ParamType('noMatch')).to.throw(/noMatch/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sets the type of the object', () => {
|
|
||||||
expect((new ParamType('bool', null, 1)).type).to.equal('bool');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sets the subtype of the object', () => {
|
|
||||||
expect((new ParamType('array', 'bool', 1)).subtype).to.equal('bool');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sets the length of the object', () => {
|
|
||||||
expect((new ParamType('array', 'bool', 1)).length).to.equal(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sets the index of the object', () => {
|
|
||||||
expect((new ParamType('array', 'bool', 1, true)).indexed).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sets default values where none supplied', () => {
|
|
||||||
expect(Object.values(new ParamType('string'))).to.deep.equal(['string', null, 0, false]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,19 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
const TYPES = ['address', 'bytes', 'int', 'uint', 'bool', 'string', 'array', 'fixedBytes', 'fixedArray'];
|
|
||||||
|
|
||||||
export default TYPES;
|
|
@ -1,17 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
export default from './token';
|
|
@ -1,42 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import TYPES from '../spec/paramType/types';
|
|
||||||
|
|
||||||
export default class Token {
|
|
||||||
constructor (type, value) {
|
|
||||||
Token.validateType(type);
|
|
||||||
|
|
||||||
this._type = type;
|
|
||||||
this._value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
get type () {
|
|
||||||
return this._type;
|
|
||||||
}
|
|
||||||
|
|
||||||
get value () {
|
|
||||||
return this._value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static validateType (type) {
|
|
||||||
if (TYPES.filter((_type) => type === _type).length) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error(`Invalid type ${type} received for Token`);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,75 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import Token from './token';
|
|
||||||
|
|
||||||
describe('abi/token/token', () => {
|
|
||||||
describe('validateType', () => {
|
|
||||||
it('validates address', () => {
|
|
||||||
expect(Token.validateType('address')).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('validates fixedArray', () => {
|
|
||||||
expect(Token.validateType('fixedArray')).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('validates array', () => {
|
|
||||||
expect(Token.validateType('array')).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('validates fixedBytes', () => {
|
|
||||||
expect(Token.validateType('fixedBytes')).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('validates bytes', () => {
|
|
||||||
expect(Token.validateType('bytes')).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('validates bool', () => {
|
|
||||||
expect(Token.validateType('bool')).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('validates int', () => {
|
|
||||||
expect(Token.validateType('int')).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('validates uint', () => {
|
|
||||||
expect(Token.validateType('uint')).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('validates string', () => {
|
|
||||||
expect(Token.validateType('string')).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('throws an error on invalid types', () => {
|
|
||||||
expect(() => Token.validateType('noMatch')).to.throw(/noMatch/);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('constructor', () => {
|
|
||||||
it('throws an error on invalid types', () => {
|
|
||||||
expect(() => new Token('noMatch', '1')).to.throw(/noMatch/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sets the type of the object', () => {
|
|
||||||
expect((new Token('bool', '1')).type).to.equal('bool');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sets the value of the object', () => {
|
|
||||||
expect((new Token('bool', '1')).value).to.equal('1');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,66 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import { keccak_256 } from 'js-sha3'; // eslint-disable-line camelcase
|
|
||||||
|
|
||||||
export function isChecksumValid (_address) {
|
|
||||||
const address = _address.replace('0x', '');
|
|
||||||
const hash = keccak_256(address.toLowerCase());
|
|
||||||
|
|
||||||
for (let n = 0; n < 40; n++) {
|
|
||||||
const char = address[n];
|
|
||||||
const isLower = char !== char.toUpperCase();
|
|
||||||
const isUpper = char !== char.toLowerCase();
|
|
||||||
const hashval = parseInt(hash[n], 16);
|
|
||||||
|
|
||||||
if ((hashval > 7 && isLower) || (hashval <= 7 && isUpper)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isAddress (address) {
|
|
||||||
if (address && address.length === 42) {
|
|
||||||
if (!/^(0x)?[0-9a-f]{40}$/i.test(address)) {
|
|
||||||
return false;
|
|
||||||
} else if (/^(0x)?[0-9a-f]{40}$/.test(address) || /^(0x)?[0-9A-F]{40}$/.test(address)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return isChecksumValid(address);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function toChecksumAddress (_address) {
|
|
||||||
const address = (_address || '').toLowerCase();
|
|
||||||
|
|
||||||
if (!isAddress(address)) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
const hash = keccak_256(address.slice(-40));
|
|
||||||
let result = '0x';
|
|
||||||
|
|
||||||
for (let n = 0; n < 40; n++) {
|
|
||||||
result = `${result}${parseInt(hash[n], 16) > 7 ? address[n + 2].toUpperCase() : address[n + 2]}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
@ -1,100 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import { isChecksumValid, isAddress, toChecksumAddress } from './address';
|
|
||||||
|
|
||||||
describe('abi/util/address', () => {
|
|
||||||
const value = '63Cf90D3f0410092FC0fca41846f596223979195';
|
|
||||||
const address = `0x${value}`;
|
|
||||||
const lowercase = `0x${value.toLowerCase()}`;
|
|
||||||
const uppercase = `0x${value.toUpperCase()}`;
|
|
||||||
const invalid = '0x' + value.split('').map((char) => {
|
|
||||||
if (char >= 'a' && char <= 'f') {
|
|
||||||
return char.toUpperCase();
|
|
||||||
} else if (char >= 'A' && char <= 'F') {
|
|
||||||
return char.toLowerCase();
|
|
||||||
}
|
|
||||||
|
|
||||||
return char;
|
|
||||||
}).join('');
|
|
||||||
const invalidhex = '0x01234567890123456789012345678901234567gh';
|
|
||||||
|
|
||||||
describe('isChecksumValid', () => {
|
|
||||||
it('returns false when fully lowercase', () => {
|
|
||||||
expect(isChecksumValid(lowercase)).to.be.false;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns false when fully uppercase', () => {
|
|
||||||
expect(isChecksumValid(uppercase)).to.be.false;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns false on a mixed-case address', () => {
|
|
||||||
expect(isChecksumValid(invalid)).to.be.false;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns true on a checksummed address', () => {
|
|
||||||
expect(isChecksumValid(address)).to.be.true;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('isAddress', () => {
|
|
||||||
it('returns true when fully lowercase', () => {
|
|
||||||
expect(isAddress(lowercase)).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns true when fully uppercase', () => {
|
|
||||||
expect(isAddress(uppercase)).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns true when checksummed', () => {
|
|
||||||
expect(isAddress(address)).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns false when invalid checksum', () => {
|
|
||||||
expect(isAddress(invalid)).to.be.false;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns false on valid length, non-hex', () => {
|
|
||||||
expect(isAddress(invalidhex)).to.be.false;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('toChecksumAddress', () => {
|
|
||||||
it('returns empty when no address specified', () => {
|
|
||||||
expect(toChecksumAddress()).to.equal('');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns empty on invalid address structure', () => {
|
|
||||||
expect(toChecksumAddress('0xnotaddress')).to.equal('');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns formatted address on checksum input', () => {
|
|
||||||
expect(toChecksumAddress(address)).to.equal(address);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns formatted address on lowercase input', () => {
|
|
||||||
expect(toChecksumAddress(lowercase)).to.equal(address);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns formatted address on uppercase input', () => {
|
|
||||||
expect(toChecksumAddress(uppercase)).to.equal(address);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns formatted address on mixed input', () => {
|
|
||||||
expect(toChecksumAddress(invalid)).to.equal(address);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,77 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import BigNumber from 'bignumber.js';
|
|
||||||
import utf8 from 'utf8';
|
|
||||||
|
|
||||||
import { isArray } from './types';
|
|
||||||
|
|
||||||
const ZERO_64 = '0000000000000000000000000000000000000000000000000000000000000000';
|
|
||||||
|
|
||||||
export function padAddress (_input) {
|
|
||||||
const input = _input.substr(0, 2) === '0x' ? _input.substr(2) : _input;
|
|
||||||
|
|
||||||
return `${ZERO_64}${input}`.slice(-64);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function padBool (input) {
|
|
||||||
return `${ZERO_64}${input ? '1' : '0'}`.slice(-64);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function padU32 (input) {
|
|
||||||
let bn = new BigNumber(input);
|
|
||||||
|
|
||||||
if (bn.lessThan(0)) {
|
|
||||||
bn = new BigNumber('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 16)
|
|
||||||
.plus(bn).plus(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return `${ZERO_64}${bn.toString(16)}`.slice(-64);
|
|
||||||
}
|
|
||||||
|
|
||||||
function stringToBytes (input) {
|
|
||||||
if (isArray(input)) {
|
|
||||||
return input;
|
|
||||||
} else if (input.substr(0, 2) === '0x') {
|
|
||||||
const matches = input.substr(2).toLowerCase().match(/.{1,2}/g) || [];
|
|
||||||
|
|
||||||
return matches.map((value) => parseInt(value, 16));
|
|
||||||
} else {
|
|
||||||
return input.split('').map((char) => char.charCodeAt(0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function padBytes (_input) {
|
|
||||||
const input = stringToBytes(_input);
|
|
||||||
|
|
||||||
return `${padU32(input.length)}${padFixedBytes(input)}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function padFixedBytes (_input) {
|
|
||||||
const input = stringToBytes(_input);
|
|
||||||
const sinput = input.map((code) => `0${code.toString(16)}`.slice(-2)).join('');
|
|
||||||
const max = Math.floor((sinput.length + 63) / 64) * 64;
|
|
||||||
|
|
||||||
return `${sinput}${ZERO_64}`.substr(0, max);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function padString (input) {
|
|
||||||
const array = utf8.encode(input)
|
|
||||||
.split('')
|
|
||||||
.map((char) => char.charCodeAt(0));
|
|
||||||
|
|
||||||
return padBytes(array);
|
|
||||||
}
|
|
@ -1,124 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import BigNumber from 'bignumber.js';
|
|
||||||
import { padAddress, padBool, padBytes, padFixedBytes, padString, padU32 } from './pad';
|
|
||||||
|
|
||||||
describe('abi/util/pad', () => {
|
|
||||||
const SHORT15 = '1234567890abcdef';
|
|
||||||
const BYTES15 = [0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef];
|
|
||||||
const LONG15 = `${SHORT15}000000000000000000000000000000000000000000000000`;
|
|
||||||
const PAD123 = '0000000000000000000000000000000000000000000000000000000000000123';
|
|
||||||
|
|
||||||
describe('padAddress', () => {
|
|
||||||
it('pads to 64 characters', () => {
|
|
||||||
expect(padAddress('123')).to.equal(PAD123);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('strips leading 0x when passed in', () => {
|
|
||||||
expect(padFixedBytes(`0x${PAD123}`)).to.equal(PAD123);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('padBool', () => {
|
|
||||||
const TRUE = '0000000000000000000000000000000000000000000000000000000000000001';
|
|
||||||
const FALSE = '0000000000000000000000000000000000000000000000000000000000000000';
|
|
||||||
|
|
||||||
it('pads true to 64 characters', () => {
|
|
||||||
expect(padBool(true)).to.equal(TRUE);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('pads false to 64 characters', () => {
|
|
||||||
expect(padBool(false)).to.equal(FALSE);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('padU32', () => {
|
|
||||||
it('left pads length < 64 bytes to 64 bytes', () => {
|
|
||||||
expect(padU32(1)).to.equal('0000000000000000000000000000000000000000000000000000000000000001');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('pads hex representation', () => {
|
|
||||||
expect(padU32(0x123)).to.equal(PAD123);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('pads decimal representation', () => {
|
|
||||||
expect(padU32(291)).to.equal(PAD123);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('pads string representation', () => {
|
|
||||||
expect(padU32('0x123')).to.equal(PAD123);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('pads BigNumber representation', () => {
|
|
||||||
expect(padU32(new BigNumber(0x123))).to.equal(PAD123);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('converts negative numbers to 2s complement', () => {
|
|
||||||
expect(padU32(-123)).to.equal('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('padFixedBytes', () => {
|
|
||||||
it('right pads length < 64 bytes to 64 bytes (string)', () => {
|
|
||||||
expect(padFixedBytes(`0x${SHORT15}`)).to.equal(LONG15);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('right pads length < 64 bytes to 64 bytes (array)', () => {
|
|
||||||
expect(padFixedBytes(BYTES15)).to.equal(LONG15);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('right pads length > 64 bytes (64 byte multiples)', () => {
|
|
||||||
expect(padFixedBytes(`0x${LONG15}${SHORT15}`)).to.equal(`${LONG15}${LONG15}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('strips leading 0x when passed in', () => {
|
|
||||||
expect(padFixedBytes(`0x${SHORT15}`)).to.equal(LONG15);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('padBytes', () => {
|
|
||||||
it('right pads length < 64, adding the length (string)', () => {
|
|
||||||
const result = padBytes(`0x${SHORT15}`);
|
|
||||||
|
|
||||||
expect(result.length).to.equal(128);
|
|
||||||
expect(result).to.equal(`${padU32(8)}${LONG15}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('right pads length < 64, adding the length (array)', () => {
|
|
||||||
const result = padBytes(BYTES15);
|
|
||||||
|
|
||||||
expect(result.length).to.equal(128);
|
|
||||||
expect(result).to.equal(`${padU32(8)}${LONG15}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('right pads length > 64, adding the length', () => {
|
|
||||||
const result = padBytes(`0x${LONG15}${SHORT15}`);
|
|
||||||
|
|
||||||
expect(result.length).to.equal(192);
|
|
||||||
expect(result).to.equal(`${padU32(0x28)}${LONG15}${LONG15}`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('padString', () => {
|
|
||||||
it('correctly converts & pads strings', () => {
|
|
||||||
const result = padString('gavofyork');
|
|
||||||
|
|
||||||
expect(result.length).to.equal(128);
|
|
||||||
expect(result).to.equal(padBytes('0x6761766f66796f726b'));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,49 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import { keccak_256 } from 'js-sha3'; // eslint-disable-line camelcase
|
|
||||||
import { fromParamType } from '../spec/paramType/format';
|
|
||||||
|
|
||||||
export function eventSignature (eventName, params) {
|
|
||||||
const { strName, name } = parseName(eventName);
|
|
||||||
const types = (params || []).map(fromParamType).join(',');
|
|
||||||
const id = `${strName}(${types})`;
|
|
||||||
const signature = strName ? keccak_256(id) : '';
|
|
||||||
|
|
||||||
return { id, name, signature };
|
|
||||||
}
|
|
||||||
|
|
||||||
export function methodSignature (methodName, params) {
|
|
||||||
const { id, name, signature } = eventSignature(methodName, params);
|
|
||||||
|
|
||||||
return { id, name, signature: signature.substr(0, 8) };
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseName (name) {
|
|
||||||
const strName = `${name || ''}`;
|
|
||||||
const idx = strName.indexOf('(');
|
|
||||||
|
|
||||||
if (idx === -1) {
|
|
||||||
return { strName, name };
|
|
||||||
}
|
|
||||||
|
|
||||||
const trimmedName = strName.slice(0, idx);
|
|
||||||
|
|
||||||
return {
|
|
||||||
strName: trimmedName,
|
|
||||||
name: trimmedName
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,111 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import { eventSignature, methodSignature } from './signature';
|
|
||||||
|
|
||||||
describe('abi/util/signature', () => {
|
|
||||||
describe('eventSignature', () => {
|
|
||||||
it('encodes signature baz() correctly', () => {
|
|
||||||
expect(eventSignature('baz', [])).to.deep.equal({
|
|
||||||
id: 'baz()',
|
|
||||||
name: 'baz',
|
|
||||||
signature: 'a7916fac4f538170f7cd12c148552e2cba9fcd72329a2dd5b07a6fa906488ddf'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('encodes signature baz(uint32) correctly', () => {
|
|
||||||
expect(eventSignature('baz', [{ type: 'uint', length: 32 }])).to.deep.equal({
|
|
||||||
id: 'baz(uint32)',
|
|
||||||
name: 'baz',
|
|
||||||
signature: '7d68785e8fc871be024b75964bd86d093511d4bc2dc7cf7bea32c48a0efaecb1'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('encodes signature baz(uint32, bool) correctly', () => {
|
|
||||||
expect(eventSignature('baz', [{ type: 'uint', length: 32 }, { type: 'bool' }])).to.deep.equal({
|
|
||||||
id: 'baz(uint32,bool)',
|
|
||||||
name: 'baz',
|
|
||||||
signature: 'cdcd77c0992ec5bbfc459984220f8c45084cc24d9b6efed1fae540db8de801d2'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('encodes no-name signature correctly as ()', () => {
|
|
||||||
expect(eventSignature(undefined, [])).to.deep.equal({
|
|
||||||
id: '()',
|
|
||||||
name: undefined,
|
|
||||||
signature: ''
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('encodes no-params signature correctly as ()', () => {
|
|
||||||
expect(eventSignature(undefined, undefined)).to.deep.equal({
|
|
||||||
id: '()',
|
|
||||||
name: undefined,
|
|
||||||
signature: ''
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('methodSignature', () => {
|
|
||||||
it('encodes signature baz() correctly', () => {
|
|
||||||
expect(methodSignature('baz', [])).to.deep.equal({
|
|
||||||
id: 'baz()',
|
|
||||||
name: 'baz',
|
|
||||||
signature: 'a7916fac'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('encodes signature baz(uint32) correctly', () => {
|
|
||||||
expect(methodSignature('baz', [{ type: 'uint', length: 32 }])).to.deep.equal({
|
|
||||||
id: 'baz(uint32)',
|
|
||||||
name: 'baz',
|
|
||||||
signature: '7d68785e'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('encodes signature baz(uint32, bool) correctly', () => {
|
|
||||||
expect(methodSignature('baz', [{ type: 'uint', length: 32 }, { type: 'bool' }])).to.deep.equal({
|
|
||||||
id: 'baz(uint32,bool)',
|
|
||||||
name: 'baz',
|
|
||||||
signature: 'cdcd77c0'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('encodes signature in name correctly', () => {
|
|
||||||
expect(methodSignature('baz(uint32,bool)', [{ type: 'uint', length: 32 }, { type: 'bool' }])).to.deep.equal({
|
|
||||||
id: 'baz(uint32,bool)',
|
|
||||||
name: 'baz',
|
|
||||||
signature: 'cdcd77c0'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('encodes no-name signature correctly as ()', () => {
|
|
||||||
expect(methodSignature(undefined, [])).to.deep.equal({
|
|
||||||
id: '()',
|
|
||||||
name: undefined,
|
|
||||||
signature: ''
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('encodes no-params signature correctly as ()', () => {
|
|
||||||
expect(methodSignature(undefined, undefined)).to.deep.equal({
|
|
||||||
id: '()',
|
|
||||||
name: undefined,
|
|
||||||
signature: ''
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,31 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import { padAddress } from './pad';
|
|
||||||
|
|
||||||
export function sliceData (_data) {
|
|
||||||
if (!_data || !_data.length) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
let data = (_data.substr(0, 2) === '0x') ? _data.substr(2) : _data;
|
|
||||||
|
|
||||||
if (!data.length) {
|
|
||||||
data = padAddress('');
|
|
||||||
}
|
|
||||||
|
|
||||||
return data.match(/.{1,64}/g);
|
|
||||||
}
|
|
@ -1,44 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import { sliceData } from './slice';
|
|
||||||
|
|
||||||
describe('abi/util/slice', () => {
|
|
||||||
describe('sliceData', () => {
|
|
||||||
const slice1 = '131a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b';
|
|
||||||
const slice2 = '2124768576358735263578356373526387638357635873563586353756358763';
|
|
||||||
|
|
||||||
it('returns an empty array when length === 0', () => {
|
|
||||||
expect(sliceData('')).to.deep.equal([]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns an array with the slices otherwise', () => {
|
|
||||||
const sliced = sliceData(`${slice1}${slice2}`);
|
|
||||||
|
|
||||||
expect(sliced.length).to.equal(2);
|
|
||||||
expect(sliced[0]).to.equal(slice1);
|
|
||||||
expect(sliced[1]).to.equal(slice2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('removes leading 0x when passed in', () => {
|
|
||||||
const sliced = sliceData(`0x${slice1}${slice2}`);
|
|
||||||
|
|
||||||
expect(sliced.length).to.equal(2);
|
|
||||||
expect(sliced[0]).to.equal(slice1);
|
|
||||||
expect(sliced[1]).to.equal(slice2);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,47 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import BigNumber from 'bignumber.js';
|
|
||||||
|
|
||||||
import { toChecksumAddress } from './address';
|
|
||||||
|
|
||||||
export function asU32 (slice) {
|
|
||||||
// TODO: validation
|
|
||||||
|
|
||||||
return new BigNumber(slice, 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function asI32 (slice) {
|
|
||||||
if (new BigNumber(slice.substr(0, 1), 16).toString(2)[0] === '1') {
|
|
||||||
return new BigNumber(slice, 16)
|
|
||||||
.minus(new BigNumber('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 16))
|
|
||||||
.minus(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new BigNumber(slice, 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function asAddress (slice) {
|
|
||||||
// TODO: address validation?
|
|
||||||
|
|
||||||
return toChecksumAddress(`0x${slice.slice(-40)}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function asBool (slice) {
|
|
||||||
// TODO: everything else should be 0
|
|
||||||
|
|
||||||
return new BigNumber(slice[63]).eq(1);
|
|
||||||
}
|
|
@ -1,55 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import { asAddress, asBool, asI32, asU32 } from './sliceAs';
|
|
||||||
|
|
||||||
describe('abi/util/sliceAs', () => {
|
|
||||||
const MAX_INT = 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';
|
|
||||||
|
|
||||||
describe('asAddress', () => {
|
|
||||||
it('correctly returns the last 0x40 characters', () => {
|
|
||||||
const address = '1111111111222222222233333333334444444444';
|
|
||||||
|
|
||||||
expect(asAddress(`000000000000000000000000${address}`)).to.equal(`0x${address}`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('asBool', () => {
|
|
||||||
it('correctly returns true', () => {
|
|
||||||
expect(asBool('0000000000000000000000000000000000000000000000000000000000000001')).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('correctly returns false', () => {
|
|
||||||
expect(asBool('0000000000000000000000000000000000000000000000000000000000000000')).to.be.false;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('asI32', () => {
|
|
||||||
it('correctly decodes positive numbers', () => {
|
|
||||||
expect(asI32('000000000000000000000000000000000000000000000000000000000000007b').toString()).to.equal('123');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('correctly decodes negative numbers', () => {
|
|
||||||
expect(asI32('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85').toString()).to.equal('-123');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('asU32', () => {
|
|
||||||
it('returns a maxium U32', () => {
|
|
||||||
expect(asU32(MAX_INT).toString(16)).to.equal(MAX_INT);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,27 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
export function isArray (test) {
|
|
||||||
return Object.prototype.toString.call(test) === '[object Array]';
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isString (test) {
|
|
||||||
return Object.prototype.toString.call(test) === '[object String]';
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isInstanceOf (test, clazz) {
|
|
||||||
return test instanceof clazz;
|
|
||||||
}
|
|
@ -1,62 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import { isArray, isString, isInstanceOf } from './types';
|
|
||||||
import Token from '../token';
|
|
||||||
|
|
||||||
describe('abi/util/types', () => {
|
|
||||||
describe('isArray', () => {
|
|
||||||
it('correctly identifies empty arrays as Array', () => {
|
|
||||||
expect(isArray([])).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('correctly identifies non-empty arrays as Array', () => {
|
|
||||||
expect(isArray([1, 2, 3])).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('correctly identifies strings as non-Array', () => {
|
|
||||||
expect(isArray('not an array')).to.be.false;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('correctly identifies objects as non-Array', () => {
|
|
||||||
expect(isArray({})).to.be.false;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('isString', () => {
|
|
||||||
it('correctly identifies empty string as string', () => {
|
|
||||||
expect(isString('')).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('correctly identifies string as string', () => {
|
|
||||||
expect(isString('123')).to.be.true;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('isInstanceOf', () => {
|
|
||||||
it('correctly identifies build-in instanceof', () => {
|
|
||||||
expect(isInstanceOf(new String('123'), String)).to.be.true; // eslint-disable-line no-new-wrappers
|
|
||||||
});
|
|
||||||
|
|
||||||
it('correctly identifies own instanceof', () => {
|
|
||||||
expect(isInstanceOf(new Token('int', 123), Token)).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('correctly reports false for own', () => {
|
|
||||||
expect(isInstanceOf({ type: 'int' }, Token)).to.be.false;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,83 +0,0 @@
|
|||||||
# @parity/parity.js
|
|
||||||
|
|
||||||
Parity.js is a thin, fast, Promise-based wrapper around the Ethereum APIs.
|
|
||||||
|
|
||||||
[https://github.com/paritytech/parity/tree/master/js/src/api](https://github.com/paritytech/parity/tree/master/js/src/api)
|
|
||||||
|
|
||||||
## installation
|
|
||||||
|
|
||||||
Install the package with `npm install --save @parity/parity.js`
|
|
||||||
|
|
||||||
## usage
|
|
||||||
|
|
||||||
### initialisation
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// import the actual Api class
|
|
||||||
import { Api } from '@parity/parity.js';
|
|
||||||
|
|
||||||
// do the setup
|
|
||||||
const provider = new Api.Provider.Http('http://localhost:8545');
|
|
||||||
const api = new Api(provider);
|
|
||||||
```
|
|
||||||
|
|
||||||
### making calls
|
|
||||||
|
|
||||||
perform a call
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
api.eth
|
|
||||||
.coinbase()
|
|
||||||
.then((coinbase) => {
|
|
||||||
console.log(`The coinbase is ${coinbase}`);
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
multiple promises
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
Promise
|
|
||||||
.all([
|
|
||||||
api.eth.coinbase(),
|
|
||||||
api.net.listening()
|
|
||||||
])
|
|
||||||
.then(([coinbase, listening]) => {
|
|
||||||
// do stuff here
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
chaining promises
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
api.eth
|
|
||||||
.newFilter({...})
|
|
||||||
.then((filterId) => api.eth.getFilterChanges(filterId))
|
|
||||||
.then((changes) => {
|
|
||||||
console.log(changes);
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### contracts
|
|
||||||
|
|
||||||
attach contract
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
const abi = [{ name: 'callMe', inputs: [{ type: 'bool', ...}, { type: 'string', ...}]}, ...abi...];
|
|
||||||
const address = '0x123456...9abc';
|
|
||||||
const contract = new api.newContract(abi, address);
|
|
||||||
```
|
|
||||||
|
|
||||||
find & call a function
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
contract.instance
|
|
||||||
.callMe
|
|
||||||
.call({ gas: 21000 }, [true, 'someString']) // or estimateGas or postTransaction
|
|
||||||
.then((result) => {
|
|
||||||
console.log(`the result was ${result}`);
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
## apis
|
|
||||||
|
|
||||||
APIs implement the calls as exposed in the [Ethcore JSON Ethereum RPC](https://github.com/paritytech/ethereum-rpc-json/) definitions. Mapping follows the naming conventions of the originals, i.e. `eth_call` becomes `eth.call`, `personal_accounts` becomes `personal.accounts`, etc.
|
|
@ -1,206 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import EventEmitter from 'eventemitter3';
|
|
||||||
|
|
||||||
import Contract from './contract';
|
|
||||||
import { PromiseProvider, Http as HttpProvider, PostMessage as PostMessageProvider, Ws as WsProvider, WsSecure as WsSecureProvider } from './provider';
|
|
||||||
import { Http as HttpTransport, Ws as WsTransport, WsSecure as WsSecureTransport } from './transport';
|
|
||||||
|
|
||||||
import { Db, Eth, Parity, Net, Personal, Shell, Shh, Signer, Trace, Web3 } from './rpc';
|
|
||||||
import Subscriptions from './subscriptions';
|
|
||||||
import Pubsub from './pubsub';
|
|
||||||
import util from './util';
|
|
||||||
import { isFunction } from './util/types';
|
|
||||||
|
|
||||||
import LocalAccountsMiddleware from '~/packages/api/local';
|
|
||||||
|
|
||||||
export default class Api extends EventEmitter {
|
|
||||||
constructor (provider, allowSubscriptions = true) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
if (!provider || !isFunction(provider.send)) {
|
|
||||||
console.log(provider);
|
|
||||||
console.warn(new Error('deprecated: Api needs provider with send() function, old-style Transport found instead'));
|
|
||||||
}
|
|
||||||
// does use new provider interface (not promiseProvider)
|
|
||||||
if (provider && isFunction(provider.subscribe)) {
|
|
||||||
this._pubsub = new Pubsub(provider);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._provider = new PromiseProvider(provider);
|
|
||||||
|
|
||||||
this._db = new Db(this._provider);
|
|
||||||
this._eth = new Eth(this._provider);
|
|
||||||
this._net = new Net(this._provider);
|
|
||||||
this._parity = new Parity(this._provider);
|
|
||||||
this._personal = new Personal(this._provider);
|
|
||||||
this._shell = new Shell(this._provider);
|
|
||||||
this._shh = new Shh(this._provider);
|
|
||||||
this._signer = new Signer(this._provider);
|
|
||||||
this._trace = new Trace(this._provider);
|
|
||||||
this._web3 = new Web3(this._provider);
|
|
||||||
|
|
||||||
if (allowSubscriptions) {
|
|
||||||
this._subscriptions = new Subscriptions(this);
|
|
||||||
}
|
|
||||||
// Doing a request here in test env would cause an error
|
|
||||||
if (LocalAccountsMiddleware && process.env.NODE_ENV !== 'test') {
|
|
||||||
const middleware = this.parity
|
|
||||||
.nodeKind()
|
|
||||||
.then((nodeKind) => {
|
|
||||||
if (nodeKind.availability === 'public') {
|
|
||||||
return LocalAccountsMiddleware;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
})
|
|
||||||
.catch(() => null);
|
|
||||||
|
|
||||||
provider.addMiddleware(middleware);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get isConnected () {
|
|
||||||
const isConnected = this.provider.isConnected;
|
|
||||||
|
|
||||||
return isConnected || typeof isConnected === 'undefined';
|
|
||||||
}
|
|
||||||
|
|
||||||
get pubsub () {
|
|
||||||
if (!this._pubsub) {
|
|
||||||
throw Error('Pubsub is only available with a subscribing-supported transport injected!');
|
|
||||||
}
|
|
||||||
|
|
||||||
return this._pubsub;
|
|
||||||
}
|
|
||||||
|
|
||||||
get db () {
|
|
||||||
return this._db;
|
|
||||||
}
|
|
||||||
|
|
||||||
get eth () {
|
|
||||||
return this._eth;
|
|
||||||
}
|
|
||||||
|
|
||||||
get parity () {
|
|
||||||
return this._parity;
|
|
||||||
}
|
|
||||||
|
|
||||||
get net () {
|
|
||||||
return this._net;
|
|
||||||
}
|
|
||||||
|
|
||||||
get personal () {
|
|
||||||
return this._personal;
|
|
||||||
}
|
|
||||||
|
|
||||||
get provider () {
|
|
||||||
return this._provider.provider;
|
|
||||||
}
|
|
||||||
|
|
||||||
get shell () {
|
|
||||||
return this._shell;
|
|
||||||
}
|
|
||||||
|
|
||||||
get shh () {
|
|
||||||
return this._shh;
|
|
||||||
}
|
|
||||||
|
|
||||||
get signer () {
|
|
||||||
return this._signer;
|
|
||||||
}
|
|
||||||
|
|
||||||
get trace () {
|
|
||||||
return this._trace;
|
|
||||||
}
|
|
||||||
|
|
||||||
get transport () {
|
|
||||||
return this.provider;
|
|
||||||
}
|
|
||||||
|
|
||||||
get web3 () {
|
|
||||||
return this._web3;
|
|
||||||
}
|
|
||||||
|
|
||||||
get util () {
|
|
||||||
return util;
|
|
||||||
}
|
|
||||||
|
|
||||||
newContract (abi, address) {
|
|
||||||
return new Contract(this, abi).at(address);
|
|
||||||
}
|
|
||||||
|
|
||||||
subscribe (subscriptionName, callback) {
|
|
||||||
if (!this._subscriptions) {
|
|
||||||
return Promise.resolve(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this._subscriptions.subscribe(subscriptionName, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsubscribe (subscriptionId) {
|
|
||||||
if (!this._subscriptions) {
|
|
||||||
return Promise.resolve(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this._subscriptions.unsubscribe(subscriptionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
pollMethod (method, input, validate) {
|
|
||||||
const [_group, endpoint] = method.split('_');
|
|
||||||
const group = `_${_group}`;
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const timeout = () => {
|
|
||||||
this[group][endpoint](input)
|
|
||||||
.then((result) => {
|
|
||||||
if (validate ? validate(result) : result) {
|
|
||||||
resolve(result);
|
|
||||||
} else {
|
|
||||||
setTimeout(timeout, 500);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
// Don't print if the request is rejected: that's ok
|
|
||||||
if (error.type !== 'REQUEST_REJECTED') {
|
|
||||||
console.error('pollMethod', error);
|
|
||||||
}
|
|
||||||
|
|
||||||
reject(error);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
timeout();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static util = util
|
|
||||||
|
|
||||||
static Provider = {
|
|
||||||
Http: HttpProvider,
|
|
||||||
PostMessage: PostMessageProvider,
|
|
||||||
Ws: WsProvider,
|
|
||||||
WsSecure: WsSecureProvider
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: kept for backwards compatibility
|
|
||||||
static Transport = {
|
|
||||||
Http: HttpTransport,
|
|
||||||
Ws: WsTransport,
|
|
||||||
WsSecure: WsSecureTransport
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,47 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import ethereumRpc from '@parity/jsonrpc';
|
|
||||||
|
|
||||||
import { TEST_HTTP_URL, endpointTest } from '../../test/mockRpc';
|
|
||||||
|
|
||||||
import util from './util';
|
|
||||||
import Api from './api';
|
|
||||||
|
|
||||||
describe('api/Api', () => {
|
|
||||||
describe('interface', () => {
|
|
||||||
const api = new Api(new Api.Provider.Http(TEST_HTTP_URL, -1));
|
|
||||||
const ignored = [
|
|
||||||
'eth_subscribe', 'eth_unsubscribe',
|
|
||||||
'parity_subscribe', 'parity_unsubscribe',
|
|
||||||
'signer_subscribePending', 'signer_unsubscribePending'
|
|
||||||
];
|
|
||||||
|
|
||||||
Object.keys(ethereumRpc).sort().forEach((endpoint) => {
|
|
||||||
describe(endpoint, () => {
|
|
||||||
Object.keys(ethereumRpc[endpoint]).sort()
|
|
||||||
.filter(method => ignored.indexOf(method) !== -1)
|
|
||||||
.forEach((method) => {
|
|
||||||
endpointTest(api, endpoint, method);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('exposes util as static property', () => {
|
|
||||||
expect(Api.util).to.equal(util);
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,561 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import Abi from '@parity/abi';
|
|
||||||
|
|
||||||
let nextSubscriptionId = 0;
|
|
||||||
|
|
||||||
export default class Contract {
|
|
||||||
constructor (api, abi) {
|
|
||||||
if (!api) {
|
|
||||||
throw new Error('API instance needs to be provided to Contract');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!abi) {
|
|
||||||
throw new Error('ABI needs to be provided to Contract instance');
|
|
||||||
}
|
|
||||||
|
|
||||||
this._api = api;
|
|
||||||
this._abi = new Abi(abi);
|
|
||||||
|
|
||||||
this._subscriptions = {};
|
|
||||||
this._constructors = this._abi.constructors.map(this._bindFunction);
|
|
||||||
this._functions = this._abi.functions.map(this._bindFunction);
|
|
||||||
this._events = this._abi.events.map(this._bindEvent);
|
|
||||||
|
|
||||||
this._instance = {};
|
|
||||||
|
|
||||||
this._events.forEach((evt) => {
|
|
||||||
this._instance[evt.name] = evt;
|
|
||||||
this._instance[evt.signature] = evt;
|
|
||||||
});
|
|
||||||
|
|
||||||
this._functions.forEach((fn) => {
|
|
||||||
this._instance[fn.name] = fn;
|
|
||||||
this._instance[fn.signature] = fn;
|
|
||||||
});
|
|
||||||
|
|
||||||
this._subscribedToPendings = false;
|
|
||||||
this._pendingsSubscriptionId = null;
|
|
||||||
|
|
||||||
this._subscribedToBlock = false;
|
|
||||||
this._blockSubscriptionId = null;
|
|
||||||
|
|
||||||
if (api && api.patch && api.patch.contract) {
|
|
||||||
api.patch.contract(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get address () {
|
|
||||||
return this._address;
|
|
||||||
}
|
|
||||||
|
|
||||||
get constructors () {
|
|
||||||
return this._constructors;
|
|
||||||
}
|
|
||||||
|
|
||||||
get events () {
|
|
||||||
return this._events;
|
|
||||||
}
|
|
||||||
|
|
||||||
get functions () {
|
|
||||||
return this._functions;
|
|
||||||
}
|
|
||||||
|
|
||||||
get receipt () {
|
|
||||||
return this._receipt;
|
|
||||||
}
|
|
||||||
|
|
||||||
get instance () {
|
|
||||||
this._instance.address = this._address;
|
|
||||||
return this._instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
get api () {
|
|
||||||
return this._api;
|
|
||||||
}
|
|
||||||
|
|
||||||
get abi () {
|
|
||||||
return this._abi;
|
|
||||||
}
|
|
||||||
|
|
||||||
at (address) {
|
|
||||||
this._address = address;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
deployEstimateGas (options, values) {
|
|
||||||
const _options = this._encodeOptions(this.constructors[0], options, values);
|
|
||||||
|
|
||||||
return this._api.eth
|
|
||||||
.estimateGas(_options)
|
|
||||||
.then((gasEst) => {
|
|
||||||
return [gasEst, gasEst.mul(1.2)];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
deploy (options, values, statecb = () => {}, skipGasEstimate = false) {
|
|
||||||
let gasEstPromise;
|
|
||||||
|
|
||||||
if (skipGasEstimate) {
|
|
||||||
gasEstPromise = Promise.resolve(null);
|
|
||||||
} else {
|
|
||||||
statecb(null, { state: 'estimateGas' });
|
|
||||||
|
|
||||||
gasEstPromise = this.deployEstimateGas(options, values)
|
|
||||||
.then(([gasEst, gas]) => gas);
|
|
||||||
}
|
|
||||||
|
|
||||||
return gasEstPromise
|
|
||||||
.then((_gas) => {
|
|
||||||
if (_gas) {
|
|
||||||
options.gas = _gas.toFixed(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
const gas = _gas || options.gas;
|
|
||||||
|
|
||||||
statecb(null, { state: 'postTransaction', gas });
|
|
||||||
|
|
||||||
const encodedOptions = this._encodeOptions(this.constructors[0], options, values);
|
|
||||||
|
|
||||||
return this._api.parity
|
|
||||||
.postTransaction(encodedOptions)
|
|
||||||
.then((requestId) => {
|
|
||||||
statecb(null, { state: 'checkRequest', requestId });
|
|
||||||
return this._pollCheckRequest(requestId);
|
|
||||||
})
|
|
||||||
.then((txhash) => {
|
|
||||||
statecb(null, { state: 'getTransactionReceipt', txhash });
|
|
||||||
return this._pollTransactionReceipt(txhash, gas);
|
|
||||||
})
|
|
||||||
.then((receipt) => {
|
|
||||||
if (receipt.gasUsed.eq(gas)) {
|
|
||||||
throw new Error(`Contract not deployed, gasUsed == ${gas.toFixed(0)}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
statecb(null, { state: 'hasReceipt', receipt });
|
|
||||||
this._receipt = receipt;
|
|
||||||
this._address = receipt.contractAddress;
|
|
||||||
return this._address;
|
|
||||||
})
|
|
||||||
.then((address) => {
|
|
||||||
statecb(null, { state: 'getCode' });
|
|
||||||
return this._api.eth.getCode(this._address);
|
|
||||||
})
|
|
||||||
.then((code) => {
|
|
||||||
if (code === '0x') {
|
|
||||||
throw new Error('Contract not deployed, getCode returned 0x');
|
|
||||||
}
|
|
||||||
|
|
||||||
statecb(null, { state: 'completed' });
|
|
||||||
return this._address;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
parseEventLogs (logs) {
|
|
||||||
return logs
|
|
||||||
.map((log) => {
|
|
||||||
const signature = log.topics[0].substr(2);
|
|
||||||
const event = this.events.find((evt) => evt.signature === signature);
|
|
||||||
|
|
||||||
if (!event) {
|
|
||||||
console.warn(`Unable to find event matching signature ${signature}`);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const decoded = event.decodeLog(log.topics, log.data);
|
|
||||||
|
|
||||||
log.params = {};
|
|
||||||
log.event = event.name;
|
|
||||||
|
|
||||||
decoded.params.forEach((param, index) => {
|
|
||||||
const { type, value } = param.token;
|
|
||||||
const key = param.name || index;
|
|
||||||
|
|
||||||
log.params[key] = { type, value };
|
|
||||||
});
|
|
||||||
|
|
||||||
return log;
|
|
||||||
} catch (error) {
|
|
||||||
console.warn('Error decoding log', log);
|
|
||||||
console.warn(error);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.filter((log) => log);
|
|
||||||
}
|
|
||||||
|
|
||||||
parseTransactionEvents (receipt) {
|
|
||||||
receipt.logs = this.parseEventLogs(receipt.logs);
|
|
||||||
|
|
||||||
return receipt;
|
|
||||||
}
|
|
||||||
|
|
||||||
_pollCheckRequest = (requestId) => {
|
|
||||||
return this._api.pollMethod('parity_checkRequest', requestId);
|
|
||||||
}
|
|
||||||
|
|
||||||
_pollTransactionReceipt = (txhash, gas) => {
|
|
||||||
return this.api.pollMethod('eth_getTransactionReceipt', txhash, (receipt) => {
|
|
||||||
if (!receipt || !receipt.blockNumber || receipt.blockNumber.eq(0)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getCallData = (func, options, values) => {
|
|
||||||
let data = options.data;
|
|
||||||
|
|
||||||
const tokens = func ? Abi.encodeTokens(func.inputParamTypes(), values) : null;
|
|
||||||
const call = tokens ? func.encodeCall(tokens) : null;
|
|
||||||
|
|
||||||
if (data && data.substr(0, 2) === '0x') {
|
|
||||||
data = data.substr(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
return `0x${data || ''}${call || ''}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
_encodeOptions (func, options, values) {
|
|
||||||
const data = this.getCallData(func, options, values);
|
|
||||||
|
|
||||||
return {
|
|
||||||
...options,
|
|
||||||
data
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
_addOptionsTo (options = {}) {
|
|
||||||
return {
|
|
||||||
to: this._address,
|
|
||||||
...options
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
_bindFunction = (func) => {
|
|
||||||
func.contract = this;
|
|
||||||
|
|
||||||
func.call = (_options = {}, values = []) => {
|
|
||||||
const rawTokens = !!_options.rawTokens;
|
|
||||||
const options = {
|
|
||||||
..._options
|
|
||||||
};
|
|
||||||
|
|
||||||
delete options.rawTokens;
|
|
||||||
|
|
||||||
let callParams;
|
|
||||||
|
|
||||||
try {
|
|
||||||
callParams = this._encodeOptions(func, this._addOptionsTo(options), values);
|
|
||||||
} catch (error) {
|
|
||||||
return Promise.reject(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this._api.eth
|
|
||||||
.call(callParams)
|
|
||||||
.then((encoded) => func.decodeOutput(encoded))
|
|
||||||
.then((tokens) => {
|
|
||||||
if (rawTokens) {
|
|
||||||
return tokens;
|
|
||||||
}
|
|
||||||
|
|
||||||
return tokens.map((token) => token.value);
|
|
||||||
})
|
|
||||||
.then((returns) => returns.length === 1 ? returns[0] : returns)
|
|
||||||
.catch((error) => {
|
|
||||||
console.warn(`${func.name}.call`, values, error);
|
|
||||||
throw error;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!func.constant) {
|
|
||||||
func.postTransaction = (options, values = []) => {
|
|
||||||
let _options;
|
|
||||||
|
|
||||||
try {
|
|
||||||
_options = this._encodeOptions(func, this._addOptionsTo(options), values);
|
|
||||||
} catch (error) {
|
|
||||||
return Promise.reject(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this._api.parity
|
|
||||||
.postTransaction(_options)
|
|
||||||
.catch((error) => {
|
|
||||||
console.warn(`${func.name}.postTransaction`, values, error);
|
|
||||||
throw error;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
func.estimateGas = (options, values = []) => {
|
|
||||||
const _options = this._encodeOptions(func, this._addOptionsTo(options), values);
|
|
||||||
|
|
||||||
return this._api.eth
|
|
||||||
.estimateGas(_options)
|
|
||||||
.catch((error) => {
|
|
||||||
console.warn(`${func.name}.estimateGas`, values, error);
|
|
||||||
throw error;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return func;
|
|
||||||
}
|
|
||||||
|
|
||||||
_bindEvent = (event) => {
|
|
||||||
event.subscribe = (options = {}, callback, autoRemove) => {
|
|
||||||
return this._subscribe(event, options, callback, autoRemove);
|
|
||||||
};
|
|
||||||
|
|
||||||
event.unsubscribe = (subscriptionId) => {
|
|
||||||
return this.unsubscribe(subscriptionId);
|
|
||||||
};
|
|
||||||
|
|
||||||
event.getAllLogs = (options = {}) => {
|
|
||||||
return this.getAllLogs(event);
|
|
||||||
};
|
|
||||||
|
|
||||||
return event;
|
|
||||||
}
|
|
||||||
|
|
||||||
getAllLogs (event, _options) {
|
|
||||||
// Options as first parameter
|
|
||||||
if (!_options && event && event.topics) {
|
|
||||||
return this.getAllLogs(null, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
const options = this._getFilterOptions(event, _options);
|
|
||||||
|
|
||||||
options.fromBlock = 0;
|
|
||||||
options.toBlock = 'latest';
|
|
||||||
|
|
||||||
return this._api.eth
|
|
||||||
.getLogs(options)
|
|
||||||
.then((logs) => this.parseEventLogs(logs));
|
|
||||||
}
|
|
||||||
|
|
||||||
_findEvent (eventName = null) {
|
|
||||||
const event = eventName
|
|
||||||
? this._events.find((evt) => evt.name === eventName)
|
|
||||||
: null;
|
|
||||||
|
|
||||||
if (eventName && !event) {
|
|
||||||
const events = this._events.map((evt) => evt.name).join(', ');
|
|
||||||
|
|
||||||
throw new Error(`${eventName} is not a valid eventName, subscribe using one of ${events} (or null to include all)`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return event;
|
|
||||||
}
|
|
||||||
|
|
||||||
_getFilterOptions (event = null, _options = {}) {
|
|
||||||
const optionTopics = _options.topics || [];
|
|
||||||
const signature = event && event.signature || null;
|
|
||||||
|
|
||||||
// If event provided, remove the potential event signature
|
|
||||||
// as the first element of the topics
|
|
||||||
const topics = signature
|
|
||||||
? [ signature ].concat(optionTopics.filter((t, idx) => idx > 0 || t !== signature))
|
|
||||||
: optionTopics;
|
|
||||||
|
|
||||||
const options = Object.assign({}, _options, {
|
|
||||||
address: this._address,
|
|
||||||
topics
|
|
||||||
});
|
|
||||||
|
|
||||||
return options;
|
|
||||||
}
|
|
||||||
|
|
||||||
_createEthFilter (event = null, _options) {
|
|
||||||
const options = this._getFilterOptions(event, _options);
|
|
||||||
|
|
||||||
return this._api.eth.newFilter(options);
|
|
||||||
}
|
|
||||||
|
|
||||||
subscribe (eventName = null, options = {}, callback, autoRemove) {
|
|
||||||
try {
|
|
||||||
const event = this._findEvent(eventName);
|
|
||||||
|
|
||||||
return this._subscribe(event, options, callback, autoRemove);
|
|
||||||
} catch (e) {
|
|
||||||
return Promise.reject(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_sendData (subscriptionId, error, logs) {
|
|
||||||
const { autoRemove, callback } = this._subscriptions[subscriptionId];
|
|
||||||
let result = true;
|
|
||||||
|
|
||||||
try {
|
|
||||||
result = callback(error, logs);
|
|
||||||
} catch (error) {
|
|
||||||
console.warn('_sendData', subscriptionId, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (autoRemove && result && typeof result === 'boolean') {
|
|
||||||
this.unsubscribe(subscriptionId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_subscribe (event = null, _options, callback, autoRemove = false) {
|
|
||||||
const subscriptionId = nextSubscriptionId++;
|
|
||||||
const { skipInitFetch } = _options;
|
|
||||||
|
|
||||||
delete _options['skipInitFetch'];
|
|
||||||
|
|
||||||
return this
|
|
||||||
._createEthFilter(event, _options)
|
|
||||||
.then((filterId) => {
|
|
||||||
this._subscriptions[subscriptionId] = {
|
|
||||||
options: _options,
|
|
||||||
autoRemove,
|
|
||||||
callback,
|
|
||||||
filterId,
|
|
||||||
id: subscriptionId
|
|
||||||
};
|
|
||||||
|
|
||||||
if (skipInitFetch) {
|
|
||||||
this._subscribeToChanges();
|
|
||||||
return subscriptionId;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this._api.eth
|
|
||||||
.getFilterLogs(filterId)
|
|
||||||
.then((logs) => {
|
|
||||||
this._sendData(subscriptionId, null, this.parseEventLogs(logs));
|
|
||||||
this._subscribeToChanges();
|
|
||||||
return subscriptionId;
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.warn('subscribe', event, _options, error);
|
|
||||||
throw error;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
unsubscribe (subscriptionId) {
|
|
||||||
return this._api.eth
|
|
||||||
.uninstallFilter(this._subscriptions[subscriptionId].filterId)
|
|
||||||
.catch((error) => {
|
|
||||||
console.error('unsubscribe', error);
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
delete this._subscriptions[subscriptionId];
|
|
||||||
this._unsubscribeFromChanges();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
_subscribeToChanges = () => {
|
|
||||||
const subscriptions = Object.values(this._subscriptions);
|
|
||||||
|
|
||||||
const pendingSubscriptions = subscriptions
|
|
||||||
.filter((s) => s.options.toBlock && s.options.toBlock === 'pending');
|
|
||||||
|
|
||||||
const otherSubscriptions = subscriptions
|
|
||||||
.filter((s) => !(s.options.toBlock && s.options.toBlock === 'pending'));
|
|
||||||
|
|
||||||
if (pendingSubscriptions.length > 0 && !this._subscribedToPendings) {
|
|
||||||
this._subscribedToPendings = true;
|
|
||||||
this._subscribeToPendings();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (otherSubscriptions.length > 0 && !this._subscribedToBlock) {
|
|
||||||
this._subscribedToBlock = true;
|
|
||||||
this._subscribeToBlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_unsubscribeFromChanges = () => {
|
|
||||||
const subscriptions = Object.values(this._subscriptions);
|
|
||||||
|
|
||||||
const pendingSubscriptions = subscriptions
|
|
||||||
.filter((s) => s.options.toBlock && s.options.toBlock === 'pending');
|
|
||||||
|
|
||||||
const otherSubscriptions = subscriptions
|
|
||||||
.filter((s) => !(s.options.toBlock && s.options.toBlock === 'pending'));
|
|
||||||
|
|
||||||
if (pendingSubscriptions.length === 0 && this._subscribedToPendings) {
|
|
||||||
this._subscribedToPendings = false;
|
|
||||||
clearTimeout(this._pendingsSubscriptionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (otherSubscriptions.length === 0 && this._subscribedToBlock) {
|
|
||||||
this._subscribedToBlock = false;
|
|
||||||
this._api.unsubscribe(this._blockSubscriptionId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_subscribeToBlock = () => {
|
|
||||||
this._api
|
|
||||||
.subscribe('eth_blockNumber', (error) => {
|
|
||||||
if (error) {
|
|
||||||
console.error('::_subscribeToBlock', error, error && error.stack);
|
|
||||||
}
|
|
||||||
|
|
||||||
const subscriptions = Object.values(this._subscriptions)
|
|
||||||
.filter((s) => !(s.options.toBlock && s.options.toBlock === 'pending'));
|
|
||||||
|
|
||||||
this._sendSubscriptionChanges(subscriptions);
|
|
||||||
})
|
|
||||||
.then((blockSubId) => {
|
|
||||||
this._blockSubscriptionId = blockSubId;
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
console.error('::_subscribeToBlock', e, e && e.stack);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
_subscribeToPendings = () => {
|
|
||||||
const subscriptions = Object.values(this._subscriptions)
|
|
||||||
.filter((s) => s.options.toBlock && s.options.toBlock === 'pending');
|
|
||||||
|
|
||||||
const timeout = () => setTimeout(() => this._subscribeToPendings(), 1000);
|
|
||||||
|
|
||||||
this._sendSubscriptionChanges(subscriptions)
|
|
||||||
.then(() => {
|
|
||||||
this._pendingsSubscriptionId = timeout();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
_sendSubscriptionChanges = (subscriptions) => {
|
|
||||||
return Promise
|
|
||||||
.all(
|
|
||||||
subscriptions.map((subscription) => {
|
|
||||||
return this._api.eth.getFilterChanges(subscription.filterId);
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.then((logsArray) => {
|
|
||||||
logsArray.forEach((logs, index) => {
|
|
||||||
if (!logs || !logs.length) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
this._sendData(subscriptions[index].id, null, this.parseEventLogs(logs));
|
|
||||||
} catch (error) {
|
|
||||||
console.error('_sendSubscriptionChanges', error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error('_sendSubscriptionChanges', error);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,598 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import BigNumber from 'bignumber.js';
|
|
||||||
import sinon from 'sinon';
|
|
||||||
|
|
||||||
import Abi from '@parity/abi';
|
|
||||||
|
|
||||||
import { TEST_HTTP_URL, mockHttp } from '../../../test/mockRpc';
|
|
||||||
|
|
||||||
import { sha3 } from '../util/sha3';
|
|
||||||
|
|
||||||
import Api from '../api';
|
|
||||||
import Contract from './contract';
|
|
||||||
import { isInstanceOf, isFunction } from '../util/types';
|
|
||||||
|
|
||||||
const provider = new Api.Provider.Http(TEST_HTTP_URL, -1);
|
|
||||||
const eth = new Api(provider);
|
|
||||||
|
|
||||||
describe('api/contract/Contract', () => {
|
|
||||||
const ADDR = '0x0123456789';
|
|
||||||
|
|
||||||
const ABI = [
|
|
||||||
{
|
|
||||||
type: 'function', name: 'test',
|
|
||||||
inputs: [{ name: 'boolin', type: 'bool' }, { name: 'stringin', type: 'string' }],
|
|
||||||
outputs: [{ type: 'uint' }]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'function', name: 'test2',
|
|
||||||
outputs: [{ type: 'uint' }, { type: 'uint' }]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'constructor',
|
|
||||||
inputs: [{ name: 'boolin', type: 'bool' }, { name: 'stringin', type: 'string' }]
|
|
||||||
},
|
|
||||||
{ type: 'event', name: 'baz' },
|
|
||||||
{ type: 'event', name: 'foo' }
|
|
||||||
];
|
|
||||||
|
|
||||||
const ABI_NO_PARAMS = [
|
|
||||||
{
|
|
||||||
type: 'function', name: 'test',
|
|
||||||
inputs: [{ name: 'boolin', type: 'bool' }, { name: 'stringin', type: 'string' }],
|
|
||||||
outputs: [{ type: 'uint' }]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'function', name: 'test2',
|
|
||||||
outputs: [{ type: 'uint' }, { type: 'uint' }]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'constructor'
|
|
||||||
},
|
|
||||||
{ type: 'event', name: 'baz' },
|
|
||||||
{ type: 'event', name: 'foo' }
|
|
||||||
];
|
|
||||||
|
|
||||||
const VALUES = [ true, 'jacogr' ];
|
|
||||||
const CALLDATA = `
|
|
||||||
0000000000000000000000000000000000000000000000000000000000000001
|
|
||||||
0000000000000000000000000000000000000000000000000000000000000040
|
|
||||||
0000000000000000000000000000000000000000000000000000000000000006
|
|
||||||
6a61636f67720000000000000000000000000000000000000000000000000000
|
|
||||||
`.replace(/\s/g, '');
|
|
||||||
const SIGNATURE = '02356205';
|
|
||||||
|
|
||||||
const ENCODED = `0x${SIGNATURE}${CALLDATA}`;
|
|
||||||
|
|
||||||
const RETURN1 = '0000000000000000000000000000000000000000000000000000000000123456';
|
|
||||||
const RETURN2 = '0000000000000000000000000000000000000000000000000000000000456789';
|
|
||||||
let scope;
|
|
||||||
|
|
||||||
describe('constructor', () => {
|
|
||||||
it('needs an EthAbi instance', () => {
|
|
||||||
expect(() => new Contract()).to.throw(/API instance needs to be provided to Contract/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('needs an ABI', () => {
|
|
||||||
expect(() => new Contract(eth)).to.throw(/ABI needs to be provided to Contract instance/);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('internal setup', () => {
|
|
||||||
const contract = new Contract(eth, ABI);
|
|
||||||
|
|
||||||
it('sets EthApi & parsed interface', () => {
|
|
||||||
expect(contract.address).to.not.be.ok;
|
|
||||||
expect(contract.api).to.deep.equal(eth);
|
|
||||||
expect(isInstanceOf(contract.abi, Abi)).to.be.ok;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('attaches functions', () => {
|
|
||||||
expect(contract.functions.length).to.equal(2);
|
|
||||||
expect(contract.functions[0].name).to.equal('test');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('attaches constructors', () => {
|
|
||||||
expect(contract.constructors.length).to.equal(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('attaches events', () => {
|
|
||||||
expect(contract.events.length).to.equal(2);
|
|
||||||
expect(contract.events[0].name).to.equal('baz');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('at', () => {
|
|
||||||
it('sets returns the functions, events & sets the address', () => {
|
|
||||||
const contract = new Contract(eth, [
|
|
||||||
{
|
|
||||||
constant: true,
|
|
||||||
inputs: [{
|
|
||||||
name: '_who',
|
|
||||||
type: 'address'
|
|
||||||
}],
|
|
||||||
name: 'balanceOf',
|
|
||||||
outputs: [{
|
|
||||||
name: '',
|
|
||||||
type: 'uint256'
|
|
||||||
}],
|
|
||||||
type: 'function'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
anonymous: false,
|
|
||||||
inputs: [{
|
|
||||||
indexed: false,
|
|
||||||
name: 'amount',
|
|
||||||
type: 'uint256'
|
|
||||||
}],
|
|
||||||
name: 'Drained',
|
|
||||||
type: 'event'
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
|
|
||||||
contract.at('6789');
|
|
||||||
|
|
||||||
expect(Object.keys(contract.instance)).to.deep.equal([
|
|
||||||
'Drained',
|
|
||||||
/^(?:0x)(.+)$/.exec(sha3('Drained(uint256)'))[1],
|
|
||||||
'balanceOf',
|
|
||||||
/^(?:0x)(.+)$/.exec(sha3('balanceOf(address)'))[1].substr(0, 8),
|
|
||||||
'address'
|
|
||||||
]);
|
|
||||||
expect(contract.address).to.equal('6789');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('parseTransactionEvents', () => {
|
|
||||||
it('parses a transaction log into the data', () => {
|
|
||||||
const contract = new Contract(eth, [
|
|
||||||
{
|
|
||||||
anonymous: false, name: 'Message', type: 'event',
|
|
||||||
inputs: [
|
|
||||||
{ indexed: true, name: 'postId', type: 'uint256' },
|
|
||||||
{ indexed: false, name: 'parentId', type: 'uint256' },
|
|
||||||
{ indexed: false, name: 'sender', type: 'address' },
|
|
||||||
{ indexed: false, name: 'at', type: 'uint256' },
|
|
||||||
{ indexed: false, name: 'messageId', type: 'uint256' },
|
|
||||||
{ indexed: false, name: 'message', type: 'string' }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
const decoded = contract.parseTransactionEvents({
|
|
||||||
blockHash: '0xa9280530a3b47bee2fc80f2862fd56502ae075350571d724d6442ea4c597347b',
|
|
||||||
blockNumber: '0x4fcd',
|
|
||||||
cumulativeGasUsed: '0xb57f',
|
|
||||||
gasUsed: '0xb57f',
|
|
||||||
logs: [{
|
|
||||||
address: '0x22bff18ec62281850546a664bb63a5c06ac5f76c',
|
|
||||||
blockHash: '0xa9280530a3b47bee2fc80f2862fd56502ae075350571d724d6442ea4c597347b',
|
|
||||||
blockNumber: '0x4fcd',
|
|
||||||
data: '0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000063cf90d3f0410092fc0fca41846f5962239791950000000000000000000000000000000000000000000000000000000056e6c85f0000000000000000000000000000000000000000000000000001000000004fcd00000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000d706f7374286d6573736167652900000000000000000000000000000000000000',
|
|
||||||
logIndex: '0x0',
|
|
||||||
topics: [
|
|
||||||
'0x954ba6c157daf8a26539574ffa64203c044691aa57251af95f4b48d85ec00dd5',
|
|
||||||
'0x0000000000000000000000000000000000000000000000000001000000004fe0'
|
|
||||||
],
|
|
||||||
transactionHash: '0xca16f537d761d13e4e80953b754e2b15541f267d6cad9381f750af1bae1e4917',
|
|
||||||
transactionIndex: '0x0'
|
|
||||||
}],
|
|
||||||
to: '0x22bff18ec62281850546a664bb63a5c06ac5f76c',
|
|
||||||
transactionHash: '0xca16f537d761d13e4e80953b754e2b15541f267d6cad9381f750af1bae1e4917',
|
|
||||||
transactionIndex: '0x0'
|
|
||||||
});
|
|
||||||
const log = decoded.logs[0];
|
|
||||||
|
|
||||||
expect(log.event).to.equal('Message');
|
|
||||||
expect(log.address).to.equal('0x22bff18ec62281850546a664bb63a5c06ac5f76c');
|
|
||||||
expect(log.params).to.deep.equal({
|
|
||||||
at: { type: 'uint', value: new BigNumber('1457965151') },
|
|
||||||
message: { type: 'string', value: 'post(message)' },
|
|
||||||
messageId: { type: 'uint', value: new BigNumber('281474976731085') },
|
|
||||||
parentId: { type: 'uint', value: new BigNumber(0) },
|
|
||||||
postId: { type: 'uint', value: new BigNumber('281474976731104') },
|
|
||||||
sender: { type: 'address', value: '0x63Cf90D3f0410092FC0fca41846f596223979195' }
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('_pollTransactionReceipt', () => {
|
|
||||||
const contract = new Contract(eth, ABI);
|
|
||||||
const ADDRESS = '0xD337e80eEdBdf86eDBba021797d7e4e00Bb78351';
|
|
||||||
const BLOCKNUMBER = '555000';
|
|
||||||
const RECEIPT = { contractAddress: ADDRESS.toLowerCase(), blockNumber: BLOCKNUMBER };
|
|
||||||
const EXPECT = { contractAddress: ADDRESS, blockNumber: new BigNumber(BLOCKNUMBER) };
|
|
||||||
|
|
||||||
let scope;
|
|
||||||
let receipt;
|
|
||||||
|
|
||||||
describe('success', () => {
|
|
||||||
before(() => {
|
|
||||||
scope = mockHttp([
|
|
||||||
{ method: 'eth_getTransactionReceipt', reply: { result: null } },
|
|
||||||
{ method: 'eth_getTransactionReceipt', reply: { result: null } },
|
|
||||||
{ method: 'eth_getTransactionReceipt', reply: { result: RECEIPT } }
|
|
||||||
]);
|
|
||||||
|
|
||||||
return contract
|
|
||||||
._pollTransactionReceipt('0x123')
|
|
||||||
.then((_receipt) => {
|
|
||||||
receipt = _receipt;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sends multiple getTransactionReceipt calls', () => {
|
|
||||||
expect(scope.isDone()).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('passes the txhash through', () => {
|
|
||||||
expect(scope.body.eth_getTransactionReceipt.params[0]).to.equal('0x123');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('receives the final receipt', () => {
|
|
||||||
expect(receipt).to.deep.equal(EXPECT);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('error', () => {
|
|
||||||
before(() => {
|
|
||||||
scope = mockHttp([{ method: 'eth_getTransactionReceipt', reply: { error: { code: -1, message: 'failure' } } }]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns the errors', () => {
|
|
||||||
return contract
|
|
||||||
._pollTransactionReceipt('0x123')
|
|
||||||
.catch((error) => {
|
|
||||||
expect(error.message).to.match(/failure/);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('deploy without parameters', () => {
|
|
||||||
const contract = new Contract(eth, ABI_NO_PARAMS);
|
|
||||||
const CODE = '0x123';
|
|
||||||
const ADDRESS = '0xD337e80eEdBdf86eDBba021797d7e4e00Bb78351';
|
|
||||||
const RECEIPT_DONE = { contractAddress: ADDRESS.toLowerCase(), gasUsed: 50, blockNumber: 2500 };
|
|
||||||
|
|
||||||
let scope;
|
|
||||||
|
|
||||||
describe('success', () => {
|
|
||||||
before(() => {
|
|
||||||
scope = mockHttp([
|
|
||||||
{ method: 'eth_estimateGas', reply: { result: 1000 } },
|
|
||||||
{ method: 'parity_postTransaction', reply: { result: '0x678' } },
|
|
||||||
{ method: 'parity_checkRequest', reply: { result: '0x890' } },
|
|
||||||
{ method: 'eth_getTransactionReceipt', reply: { result: RECEIPT_DONE } },
|
|
||||||
{ method: 'eth_getCode', reply: { result: CODE } }
|
|
||||||
]);
|
|
||||||
|
|
||||||
return contract.deploy({ data: CODE }, []);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('passes the options through to postTransaction (incl. gas calculation)', () => {
|
|
||||||
expect(scope.body.parity_postTransaction.params[0].data).to.equal(CODE);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('deploy', () => {
|
|
||||||
const contract = new Contract(eth, ABI);
|
|
||||||
const ADDRESS = '0xD337e80eEdBdf86eDBba021797d7e4e00Bb78351';
|
|
||||||
const RECEIPT_PEND = { contractAddress: ADDRESS.toLowerCase(), gasUsed: 50, blockNumber: 0 };
|
|
||||||
const RECEIPT_DONE = { contractAddress: ADDRESS.toLowerCase(), gasUsed: 50, blockNumber: 2500 };
|
|
||||||
const RECEIPT_EXCP = { contractAddress: ADDRESS.toLowerCase(), gasUsed: 1200, blockNumber: 2500 };
|
|
||||||
|
|
||||||
let scope;
|
|
||||||
|
|
||||||
describe('success', () => {
|
|
||||||
before(() => {
|
|
||||||
scope = mockHttp([
|
|
||||||
{ method: 'eth_estimateGas', reply: { result: 1000 } },
|
|
||||||
{ method: 'parity_postTransaction', reply: { result: '0x678' } },
|
|
||||||
{ method: 'parity_checkRequest', reply: { result: null } },
|
|
||||||
{ method: 'parity_checkRequest', reply: { result: '0x890' } },
|
|
||||||
{ method: 'eth_getTransactionReceipt', reply: { result: null } },
|
|
||||||
{ method: 'eth_getTransactionReceipt', reply: { result: RECEIPT_PEND } },
|
|
||||||
{ method: 'eth_getTransactionReceipt', reply: { result: RECEIPT_DONE } },
|
|
||||||
{ method: 'eth_getCode', reply: { result: '0x456' } }
|
|
||||||
]);
|
|
||||||
|
|
||||||
return contract.deploy({ data: '0x123' }, VALUES);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('calls estimateGas, postTransaction, checkRequest, getTransactionReceipt & getCode in order', () => {
|
|
||||||
expect(scope.isDone()).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('passes the options through to postTransaction (incl. gas calculation)', () => {
|
|
||||||
expect(scope.body.parity_postTransaction.params).to.deep.equal([
|
|
||||||
{ data: `0x123${CALLDATA}`, gas: '0x4b0' }
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sets the address of the contract', () => {
|
|
||||||
expect(contract.address).to.equal(ADDRESS);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('error', () => {
|
|
||||||
it('fails when gasUsed == gas', () => {
|
|
||||||
mockHttp([
|
|
||||||
{ method: 'eth_estimateGas', reply: { result: 1000 } },
|
|
||||||
{ method: 'parity_postTransaction', reply: { result: '0x678' } },
|
|
||||||
{ method: 'parity_checkRequest', reply: { result: '0x789' } },
|
|
||||||
{ method: 'eth_getTransactionReceipt', reply: { result: RECEIPT_EXCP } }
|
|
||||||
]);
|
|
||||||
|
|
||||||
return contract
|
|
||||||
.deploy({ data: '0x123' }, VALUES)
|
|
||||||
.catch((error) => {
|
|
||||||
expect(error.message).to.match(/not deployed, gasUsed/);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fails when no code was deployed', () => {
|
|
||||||
mockHttp([
|
|
||||||
{ method: 'eth_estimateGas', reply: { result: 1000 } },
|
|
||||||
{ method: 'parity_postTransaction', reply: { result: '0x678' } },
|
|
||||||
{ method: 'parity_checkRequest', reply: { result: '0x789' } },
|
|
||||||
{ method: 'eth_getTransactionReceipt', reply: { result: RECEIPT_DONE } },
|
|
||||||
{ method: 'eth_getCode', reply: { result: '0x' } }
|
|
||||||
]);
|
|
||||||
|
|
||||||
return contract
|
|
||||||
.deploy({ data: '0x123' }, VALUES)
|
|
||||||
.catch((error) => {
|
|
||||||
expect(error.message).to.match(/not deployed, getCode/);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('bindings', () => {
|
|
||||||
let contract;
|
|
||||||
let cons;
|
|
||||||
let func;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
contract = new Contract(eth, ABI);
|
|
||||||
contract.at(ADDR);
|
|
||||||
cons = contract.constructors[0];
|
|
||||||
func = contract.functions.find((fn) => fn.name === 'test');
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('_addOptionsTo', () => {
|
|
||||||
it('works on no object specified', () => {
|
|
||||||
expect(contract._addOptionsTo()).to.deep.equal({ to: ADDR });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('uses the contract address when none specified', () => {
|
|
||||||
expect(contract._addOptionsTo({ from: 'me' })).to.deep.equal({ to: ADDR, from: 'me' });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('overrides the contract address when specified', () => {
|
|
||||||
expect(contract._addOptionsTo({ to: 'you', from: 'me' })).to.deep.equal({ to: 'you', from: 'me' });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('attachments', () => {
|
|
||||||
it('attaches .call, .postTransaction & .estimateGas to constructors', () => {
|
|
||||||
expect(isFunction(cons.call)).to.be.true;
|
|
||||||
expect(isFunction(cons.postTransaction)).to.be.true;
|
|
||||||
expect(isFunction(cons.estimateGas)).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('attaches .call, .postTransaction & .estimateGas to functions', () => {
|
|
||||||
expect(isFunction(func.call)).to.be.true;
|
|
||||||
expect(isFunction(func.postTransaction)).to.be.true;
|
|
||||||
expect(isFunction(func.estimateGas)).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('attaches .call only to constant functions', () => {
|
|
||||||
func = (new Contract(eth, [{ type: 'function', name: 'test', constant: true }])).functions[0];
|
|
||||||
|
|
||||||
expect(isFunction(func.call)).to.be.true;
|
|
||||||
expect(isFunction(func.postTransaction)).to.be.false;
|
|
||||||
expect(isFunction(func.estimateGas)).to.be.false;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('postTransaction', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
scope = mockHttp([{ method: 'parity_postTransaction', reply: { result: ['hashId'] } }]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('encodes options and mades an parity_postTransaction call', () => {
|
|
||||||
return func
|
|
||||||
.postTransaction({ someExtras: 'foo' }, VALUES)
|
|
||||||
.then(() => {
|
|
||||||
expect(scope.isDone()).to.be.true;
|
|
||||||
expect(scope.body.parity_postTransaction.params[0]).to.deep.equal({
|
|
||||||
someExtras: 'foo',
|
|
||||||
to: ADDR,
|
|
||||||
data: ENCODED
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('estimateGas', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
scope = mockHttp([{ method: 'eth_estimateGas', reply: { result: ['0x123'] } }]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('encodes options and mades an eth_estimateGas call', () => {
|
|
||||||
return func
|
|
||||||
.estimateGas({ someExtras: 'foo' }, VALUES)
|
|
||||||
.then((amount) => {
|
|
||||||
expect(scope.isDone()).to.be.true;
|
|
||||||
expect(amount.toString(16)).to.equal('123');
|
|
||||||
expect(scope.body.eth_estimateGas.params).to.deep.equal([{
|
|
||||||
someExtras: 'foo',
|
|
||||||
to: ADDR,
|
|
||||||
data: ENCODED
|
|
||||||
}]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('call', () => {
|
|
||||||
it('encodes options and mades an eth_call call', () => {
|
|
||||||
scope = mockHttp([{ method: 'eth_call', reply: { result: RETURN1 } }]);
|
|
||||||
|
|
||||||
return func
|
|
||||||
.call({ someExtras: 'foo' }, VALUES)
|
|
||||||
.then((result) => {
|
|
||||||
expect(scope.isDone()).to.be.true;
|
|
||||||
expect(scope.body.eth_call.params).to.deep.equal([{
|
|
||||||
someExtras: 'foo',
|
|
||||||
to: ADDR,
|
|
||||||
data: ENCODED
|
|
||||||
}, 'latest']);
|
|
||||||
expect(result.toString(16)).to.equal('123456');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('encodes options and mades an eth_call call (multiple returns)', () => {
|
|
||||||
scope = mockHttp([{ method: 'eth_call', reply: { result: `${RETURN1}${RETURN2}` } }]);
|
|
||||||
|
|
||||||
return contract.functions[1]
|
|
||||||
.call({}, [])
|
|
||||||
.then((result) => {
|
|
||||||
expect(scope.isDone()).to.be.true;
|
|
||||||
expect(result.length).to.equal(2);
|
|
||||||
expect(result[0].toString(16)).to.equal('123456');
|
|
||||||
expect(result[1].toString(16)).to.equal('456789');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('subscribe', () => {
|
|
||||||
const abi = [
|
|
||||||
{
|
|
||||||
anonymous: false, name: 'Message', type: 'event',
|
|
||||||
inputs: [
|
|
||||||
{ indexed: true, name: 'postId', type: 'uint256' },
|
|
||||||
{ indexed: false, name: 'parentId', type: 'uint256' },
|
|
||||||
{ indexed: false, name: 'sender', type: 'address' },
|
|
||||||
{ indexed: false, name: 'at', type: 'uint256' },
|
|
||||||
{ indexed: false, name: 'messageId', type: 'uint256' },
|
|
||||||
{ indexed: false, name: 'message', type: 'string' }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const logs = [{
|
|
||||||
address: '0x22bff18ec62281850546a664bb63a5c06ac5f76c',
|
|
||||||
blockHash: '0xa9280530a3b47bee2fc80f2862fd56502ae075350571d724d6442ea4c597347b',
|
|
||||||
blockNumber: '0x4fcd',
|
|
||||||
data: '0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000063cf90d3f0410092fc0fca41846f5962239791950000000000000000000000000000000000000000000000000000000056e6c85f0000000000000000000000000000000000000000000000000001000000004fcd00000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000d706f7374286d6573736167652900000000000000000000000000000000000000',
|
|
||||||
logIndex: '0x0',
|
|
||||||
topics: [
|
|
||||||
'0x954ba6c157daf8a26539574ffa64203c044691aa57251af95f4b48d85ec00dd5',
|
|
||||||
'0x0000000000000000000000000000000000000000000000000001000000004fe0'
|
|
||||||
],
|
|
||||||
transactionHash: '0xca16f537d761d13e4e80953b754e2b15541f267d6cad9381f750af1bae1e4917',
|
|
||||||
transactionIndex: '0x0'
|
|
||||||
}];
|
|
||||||
|
|
||||||
const parsed = [{
|
|
||||||
address: '0x22bfF18ec62281850546a664bb63a5C06AC5F76C',
|
|
||||||
blockHash: '0xa9280530a3b47bee2fc80f2862fd56502ae075350571d724d6442ea4c597347b',
|
|
||||||
blockNumber: new BigNumber(20429),
|
|
||||||
data: '0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000063cf90d3f0410092fc0fca41846f5962239791950000000000000000000000000000000000000000000000000000000056e6c85f0000000000000000000000000000000000000000000000000001000000004fcd00000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000d706f7374286d6573736167652900000000000000000000000000000000000000',
|
|
||||||
event: 'Message',
|
|
||||||
logIndex: new BigNumber(0),
|
|
||||||
params: {
|
|
||||||
at: { type: 'uint', value: new BigNumber(1457965151) },
|
|
||||||
message: { type: 'string', value: 'post(message)' },
|
|
||||||
messageId: { type: 'uint', value: new BigNumber(281474976731085) },
|
|
||||||
parentId: { type: 'uint', value: new BigNumber(0) },
|
|
||||||
postId: { type: 'uint', value: new BigNumber(281474976731104) },
|
|
||||||
sender: { type: 'address', value: '0x63Cf90D3f0410092FC0fca41846f596223979195' }
|
|
||||||
},
|
|
||||||
topics: [
|
|
||||||
'0x954ba6c157daf8a26539574ffa64203c044691aa57251af95f4b48d85ec00dd5',
|
|
||||||
'0x0000000000000000000000000000000000000000000000000001000000004fe0'
|
|
||||||
],
|
|
||||||
transactionHash: '0xca16f537d761d13e4e80953b754e2b15541f267d6cad9381f750af1bae1e4917',
|
|
||||||
transactionIndex: new BigNumber(0)
|
|
||||||
}];
|
|
||||||
|
|
||||||
let contract;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
contract = new Contract(eth, abi);
|
|
||||||
contract.at(ADDR);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('invalid events', () => {
|
|
||||||
it('fails to subscribe to an invalid names', () => {
|
|
||||||
return contract
|
|
||||||
.subscribe('invalid')
|
|
||||||
.catch((error) => {
|
|
||||||
expect(error.message).to.match(/invalid is not a valid eventName/);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('valid events', () => {
|
|
||||||
let cbb;
|
|
||||||
let cbe;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
scope = mockHttp([
|
|
||||||
{ method: 'eth_newFilter', reply: { result: '0x123' } },
|
|
||||||
{ method: 'eth_getFilterLogs', reply: { result: logs } },
|
|
||||||
{ method: 'eth_getFilterChanges', reply: { result: logs } },
|
|
||||||
{ method: 'eth_newFilter', reply: { result: '0x123' } },
|
|
||||||
{ method: 'eth_getFilterLogs', reply: { result: logs } }
|
|
||||||
]);
|
|
||||||
cbb = sinon.stub();
|
|
||||||
cbe = sinon.stub();
|
|
||||||
|
|
||||||
return contract.subscribe('Message', { toBlock: 'pending' }, cbb);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sets the subscriptionId returned', () => {
|
|
||||||
return contract
|
|
||||||
.subscribe('Message', { toBlock: 'pending' }, cbe)
|
|
||||||
.then((subscriptionId) => {
|
|
||||||
expect(subscriptionId).to.equal(1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('creates a new filter and retrieves the logs on it', () => {
|
|
||||||
return contract
|
|
||||||
.subscribe('Message', { toBlock: 'pending' }, cbe)
|
|
||||||
.then((subscriptionId) => {
|
|
||||||
expect(scope.isDone()).to.be.true;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns the logs to the callback', () => {
|
|
||||||
return contract
|
|
||||||
.subscribe('Message', { toBlock: 'pending' }, cbe)
|
|
||||||
.then((subscriptionId) => {
|
|
||||||
expect(cbe).to.have.been.calledWith(null, parsed);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,17 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
export default from './contract';
|
|
@ -1,242 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import BigNumber from 'bignumber.js';
|
|
||||||
|
|
||||||
import { isArray, isHex, isInstanceOf, isString } from '../util/types';
|
|
||||||
import { padLeft, toHex } from '../util/format';
|
|
||||||
|
|
||||||
export function inAddress (address) {
|
|
||||||
// TODO: address validation if we have upper-lower addresses
|
|
||||||
return inHex(address);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function inAddresses (addresses) {
|
|
||||||
return (addresses || []).map(inAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function inBlockNumber (blockNumber) {
|
|
||||||
if (isString(blockNumber)) {
|
|
||||||
switch (blockNumber) {
|
|
||||||
case 'earliest':
|
|
||||||
case 'latest':
|
|
||||||
case 'pending':
|
|
||||||
return blockNumber;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return inNumber16(blockNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function inData (data) {
|
|
||||||
if (data && data.length && !isHex(data)) {
|
|
||||||
data = data.split('').map((chr) => {
|
|
||||||
return `0${chr.charCodeAt(0).toString(16)}`.slice(-2);
|
|
||||||
}).join('');
|
|
||||||
}
|
|
||||||
|
|
||||||
return inHex(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function inHash (hash) {
|
|
||||||
return inHex(hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function inTopics (_topics) {
|
|
||||||
let topics = (_topics || [])
|
|
||||||
.filter((topic) => topic === null || topic)
|
|
||||||
.map((topic) => {
|
|
||||||
if (topic === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Array.isArray(topic)) {
|
|
||||||
return inTopics(topic);
|
|
||||||
}
|
|
||||||
|
|
||||||
return padLeft(topic, 32);
|
|
||||||
});
|
|
||||||
|
|
||||||
return topics;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function inFilter (options) {
|
|
||||||
if (options) {
|
|
||||||
Object.keys(options).forEach((key) => {
|
|
||||||
switch (key) {
|
|
||||||
case 'address':
|
|
||||||
if (isArray(options[key])) {
|
|
||||||
options[key] = options[key].map(inAddress);
|
|
||||||
} else {
|
|
||||||
options[key] = inAddress(options[key]);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'fromBlock':
|
|
||||||
case 'toBlock':
|
|
||||||
options[key] = inBlockNumber(options[key]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'limit':
|
|
||||||
options[key] = inNumber10(options[key]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'topics':
|
|
||||||
options[key] = inTopics(options[key]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return options;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function inHex (str) {
|
|
||||||
return toHex(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function inNumber10 (number) {
|
|
||||||
if (isInstanceOf(number, BigNumber)) {
|
|
||||||
return number.toNumber();
|
|
||||||
}
|
|
||||||
|
|
||||||
return (new BigNumber(number || 0)).toNumber();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function inNumber16 (number) {
|
|
||||||
const bn = isInstanceOf(number, BigNumber)
|
|
||||||
? number
|
|
||||||
: (new BigNumber(number || 0));
|
|
||||||
|
|
||||||
if (!bn.isInteger()) {
|
|
||||||
throw new Error(`[format/input::inNumber16] the given number is not an integer: ${bn.toFormat()}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return inHex(bn.toString(16));
|
|
||||||
}
|
|
||||||
|
|
||||||
export function inOptionsCondition (condition) {
|
|
||||||
if (condition) {
|
|
||||||
if (condition.block) {
|
|
||||||
condition.block = condition.block ? inNumber10(condition.block) : null;
|
|
||||||
} else if (condition.time) {
|
|
||||||
condition.time = inNumber10(Math.floor(condition.time.getTime() / 1000));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return condition;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function inOptions (_options = {}) {
|
|
||||||
const options = { ..._options };
|
|
||||||
|
|
||||||
Object.keys(options).forEach((key) => {
|
|
||||||
switch (key) {
|
|
||||||
case 'to':
|
|
||||||
// Don't encode the `to` option if it's empty
|
|
||||||
// (eg. contract deployments)
|
|
||||||
if (options[key]) {
|
|
||||||
options.to = inAddress(options[key]);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'from':
|
|
||||||
options[key] = inAddress(options[key]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'condition':
|
|
||||||
options[key] = inOptionsCondition(options[key]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'gas':
|
|
||||||
case 'gasPrice':
|
|
||||||
options[key] = inNumber16((new BigNumber(options[key])).round());
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'value':
|
|
||||||
case 'nonce':
|
|
||||||
options[key] = inNumber16(options[key]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'data':
|
|
||||||
options[key] = inData(options[key]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return options;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function inTraceFilter (filterObject) {
|
|
||||||
if (filterObject) {
|
|
||||||
Object.keys(filterObject).forEach((key) => {
|
|
||||||
switch (key) {
|
|
||||||
case 'fromAddress':
|
|
||||||
case 'toAddress':
|
|
||||||
filterObject[key] = [].concat(filterObject[key])
|
|
||||||
.map(address => inAddress(address));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'toBlock':
|
|
||||||
case 'fromBlock':
|
|
||||||
filterObject[key] = inBlockNumber(filterObject[key]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return filterObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function inTraceType (whatTrace) {
|
|
||||||
if (isString(whatTrace)) {
|
|
||||||
return [whatTrace];
|
|
||||||
}
|
|
||||||
|
|
||||||
return whatTrace;
|
|
||||||
}
|
|
||||||
|
|
||||||
function inDeriveType (derive) {
|
|
||||||
return derive && derive.type === 'hard' ? 'hard' : 'soft';
|
|
||||||
}
|
|
||||||
|
|
||||||
export function inDeriveHash (derive) {
|
|
||||||
const hash = derive && derive.hash ? derive.hash : derive;
|
|
||||||
const type = inDeriveType(derive);
|
|
||||||
|
|
||||||
return {
|
|
||||||
hash: inHex(hash),
|
|
||||||
type
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function inDeriveIndex (derive) {
|
|
||||||
if (!derive) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isArray(derive)) {
|
|
||||||
derive = [derive];
|
|
||||||
}
|
|
||||||
|
|
||||||
return derive.map(item => {
|
|
||||||
const index = inNumber10(item && item.index ? item.index : item);
|
|
||||||
|
|
||||||
return {
|
|
||||||
index,
|
|
||||||
type: inDeriveType(item)
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
@ -1,341 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import BigNumber from 'bignumber.js';
|
|
||||||
|
|
||||||
import {
|
|
||||||
inAddress, inBlockNumber, inData, inFilter, inHex,
|
|
||||||
inNumber10, inNumber16, inOptions, inTraceType,
|
|
||||||
inDeriveHash, inDeriveIndex
|
|
||||||
} from './input';
|
|
||||||
import { isAddress } from '../../../test/types';
|
|
||||||
|
|
||||||
describe('api/format/input', () => {
|
|
||||||
const address = '0x63cf90d3f0410092fc0fca41846f596223979195';
|
|
||||||
|
|
||||||
describe('inAddress', () => {
|
|
||||||
const address = '63cf90d3f0410092fc0fca41846f596223979195';
|
|
||||||
|
|
||||||
it('adds the leading 0x as required', () => {
|
|
||||||
expect(inAddress(address)).to.equal(`0x${address}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns verified addresses as-is', () => {
|
|
||||||
expect(inAddress(`0x${address}`)).to.equal(`0x${address}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns lowercase equivalents', () => {
|
|
||||||
expect(inAddress(address.toUpperCase())).to.equal(`0x${address}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns 0x on null addresses', () => {
|
|
||||||
expect(inAddress()).to.equal('0x');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('inBlockNumber()', () => {
|
|
||||||
it('returns earliest as-is', () => {
|
|
||||||
expect(inBlockNumber('earliest')).to.equal('earliest');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns latest as-is', () => {
|
|
||||||
expect(inBlockNumber('latest')).to.equal('latest');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns pending as-is', () => {
|
|
||||||
expect(inBlockNumber('pending')).to.equal('pending');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('formats existing BigNumber into hex', () => {
|
|
||||||
expect(inBlockNumber(new BigNumber(0x123456))).to.equal('0x123456');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('formats hex strings into hex', () => {
|
|
||||||
expect(inBlockNumber('0x123456')).to.equal('0x123456');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('formats numbers into hex', () => {
|
|
||||||
expect(inBlockNumber(0x123456)).to.equal('0x123456');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('inData', () => {
|
|
||||||
it('formats to hex', () => {
|
|
||||||
expect(inData('123456')).to.equal('0x123456');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('converts a string to a hex representation', () => {
|
|
||||||
expect(inData('jaco')).to.equal('0x6a61636f');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('inHex', () => {
|
|
||||||
it('leaves leading 0x as-is', () => {
|
|
||||||
expect(inHex('0x123456')).to.equal('0x123456');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('adds a leading 0x', () => {
|
|
||||||
expect(inHex('123456')).to.equal('0x123456');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns uppercase as lowercase (leading 0x)', () => {
|
|
||||||
expect(inHex('0xABCDEF')).to.equal('0xabcdef');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns uppercase as lowercase (no leading 0x)', () => {
|
|
||||||
expect(inHex('ABCDEF')).to.equal('0xabcdef');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('handles empty & null', () => {
|
|
||||||
expect(inHex()).to.equal('0x');
|
|
||||||
expect(inHex('')).to.equal('0x');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('inFilter', () => {
|
|
||||||
['address'].forEach((input) => {
|
|
||||||
it(`formats ${input} address as address`, () => {
|
|
||||||
const block = {};
|
|
||||||
|
|
||||||
block[input] = address;
|
|
||||||
const formatted = inFilter(block)[input];
|
|
||||||
|
|
||||||
expect(isAddress(formatted)).to.be.true;
|
|
||||||
expect(formatted).to.equal(address);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
['fromBlock', 'toBlock'].forEach((input) => {
|
|
||||||
it(`formats ${input} number as blockNumber`, () => {
|
|
||||||
const block = {};
|
|
||||||
|
|
||||||
block[input] = 0x123;
|
|
||||||
const formatted = inFilter(block)[input];
|
|
||||||
|
|
||||||
expect(formatted).to.equal('0x123');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('ignores and passes through unknown keys', () => {
|
|
||||||
expect(inFilter({ someRandom: 'someRandom' })).to.deep.equal({ someRandom: 'someRandom' });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('formats an filter options object with relevant entries converted', () => {
|
|
||||||
expect(
|
|
||||||
inFilter({
|
|
||||||
address: address,
|
|
||||||
fromBlock: 'latest',
|
|
||||||
toBlock: 0x101,
|
|
||||||
extraData: 'someExtraStuffInHere',
|
|
||||||
limit: 0x32
|
|
||||||
})
|
|
||||||
).to.deep.equal({
|
|
||||||
address: address,
|
|
||||||
fromBlock: 'latest',
|
|
||||||
toBlock: '0x101',
|
|
||||||
extraData: 'someExtraStuffInHere',
|
|
||||||
limit: 50
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('inNumber10()', () => {
|
|
||||||
it('formats existing BigNumber into number', () => {
|
|
||||||
expect(inNumber10(new BigNumber(123))).to.equal(123);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('formats hex strings into decimal', () => {
|
|
||||||
expect(inNumber10('0x0a')).to.equal(10);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('formats numbers into number', () => {
|
|
||||||
expect(inNumber10(123)).to.equal(123);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('formats undefined into 0', () => {
|
|
||||||
expect(inNumber10()).to.equal(0);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('inNumber16()', () => {
|
|
||||||
it('formats existing BigNumber into hex', () => {
|
|
||||||
expect(inNumber16(new BigNumber(0x123456))).to.equal('0x123456');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('formats hex strings into hex', () => {
|
|
||||||
expect(inNumber16('0x123456')).to.equal('0x123456');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('formats numbers into hex', () => {
|
|
||||||
expect(inNumber16(0x123456)).to.equal('0x123456');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('formats undefined into 0', () => {
|
|
||||||
expect(inNumber16()).to.equal('0x0');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('inOptions', () => {
|
|
||||||
['data'].forEach((input) => {
|
|
||||||
it(`converts ${input} to hex data`, () => {
|
|
||||||
const block = {};
|
|
||||||
|
|
||||||
block[input] = '1234';
|
|
||||||
const formatted = inData(block[input]);
|
|
||||||
|
|
||||||
expect(formatted).to.equal('0x1234');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
['from', 'to'].forEach((input) => {
|
|
||||||
it(`formats ${input} address as address`, () => {
|
|
||||||
const block = {};
|
|
||||||
|
|
||||||
block[input] = address;
|
|
||||||
const formatted = inOptions(block)[input];
|
|
||||||
|
|
||||||
expect(isAddress(formatted)).to.be.true;
|
|
||||||
expect(formatted).to.equal(address);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not encode an empty `to` value', () => {
|
|
||||||
const options = { to: '' };
|
|
||||||
const formatted = inOptions(options);
|
|
||||||
|
|
||||||
expect(formatted.to).to.equal('');
|
|
||||||
});
|
|
||||||
|
|
||||||
['gas', 'gasPrice', 'value', 'nonce'].forEach((input) => {
|
|
||||||
it(`formats ${input} number as hexnumber`, () => {
|
|
||||||
const block = {};
|
|
||||||
|
|
||||||
block[input] = 0x123;
|
|
||||||
const formatted = inOptions(block)[input];
|
|
||||||
|
|
||||||
expect(formatted).to.equal('0x123');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('passes condition as null when specified as such', () => {
|
|
||||||
expect(inOptions({ condition: null })).to.deep.equal({ condition: null });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('ignores and passes through unknown keys', () => {
|
|
||||||
expect(inOptions({ someRandom: 'someRandom' })).to.deep.equal({ someRandom: 'someRandom' });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('formats an options object with relevant entries converted', () => {
|
|
||||||
expect(
|
|
||||||
inOptions({
|
|
||||||
from: address,
|
|
||||||
to: address,
|
|
||||||
gas: new BigNumber('0x100'),
|
|
||||||
gasPrice: 0x101,
|
|
||||||
value: 258,
|
|
||||||
nonce: '0x104',
|
|
||||||
data: '0123456789',
|
|
||||||
extraData: 'someExtraStuffInHere'
|
|
||||||
})
|
|
||||||
).to.deep.equal({
|
|
||||||
from: address,
|
|
||||||
to: address,
|
|
||||||
gas: '0x100',
|
|
||||||
gasPrice: '0x101',
|
|
||||||
value: '0x102',
|
|
||||||
nonce: '0x104',
|
|
||||||
data: '0x0123456789',
|
|
||||||
extraData: 'someExtraStuffInHere'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('inTraceType', () => {
|
|
||||||
it('returns array of types as is', () => {
|
|
||||||
const types = ['vmTrace', 'trace', 'stateDiff'];
|
|
||||||
|
|
||||||
expect(inTraceType(types)).to.deep.equal(types);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('formats single string type into array', () => {
|
|
||||||
const type = 'vmTrace';
|
|
||||||
|
|
||||||
expect(inTraceType(type)).to.deep.equal([type]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('inDeriveHash', () => {
|
|
||||||
it('returns derive hash', () => {
|
|
||||||
expect(inDeriveHash(1)).to.deep.equal({
|
|
||||||
hash: '0x1',
|
|
||||||
type: 'soft'
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(inDeriveHash(null)).to.deep.equal({
|
|
||||||
hash: '0x',
|
|
||||||
type: 'soft'
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(inDeriveHash({
|
|
||||||
hash: 5
|
|
||||||
})).to.deep.equal({
|
|
||||||
hash: '0x5',
|
|
||||||
type: 'soft'
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(inDeriveHash({
|
|
||||||
hash: 5,
|
|
||||||
type: 'hard'
|
|
||||||
})).to.deep.equal({
|
|
||||||
hash: '0x5',
|
|
||||||
type: 'hard'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('inDeriveIndex', () => {
|
|
||||||
it('returns derive hash', () => {
|
|
||||||
expect(inDeriveIndex(null)).to.deep.equal([]);
|
|
||||||
expect(inDeriveIndex([])).to.deep.equal([]);
|
|
||||||
|
|
||||||
expect(inDeriveIndex([1])).to.deep.equal([{
|
|
||||||
index: 1,
|
|
||||||
type: 'soft'
|
|
||||||
}]);
|
|
||||||
|
|
||||||
expect(inDeriveIndex({
|
|
||||||
index: 1
|
|
||||||
})).to.deep.equal([{
|
|
||||||
index: 1,
|
|
||||||
type: 'soft'
|
|
||||||
}]);
|
|
||||||
|
|
||||||
expect(inDeriveIndex([{
|
|
||||||
index: 1,
|
|
||||||
type: 'hard'
|
|
||||||
}, 5])).to.deep.equal([
|
|
||||||
{
|
|
||||||
index: 1,
|
|
||||||
type: 'hard'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
index: 5,
|
|
||||||
type: 'soft'
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,415 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import BigNumber from 'bignumber.js';
|
|
||||||
|
|
||||||
import { toChecksumAddress } from '@parity/abi/util/address';
|
|
||||||
|
|
||||||
import { isString } from '../util/types';
|
|
||||||
|
|
||||||
export function outAccountInfo (infos) {
|
|
||||||
return Object
|
|
||||||
.keys(infos)
|
|
||||||
.reduce((ret, _address) => {
|
|
||||||
const info = infos[_address];
|
|
||||||
const address = outAddress(_address);
|
|
||||||
|
|
||||||
ret[address] = {
|
|
||||||
name: info.name
|
|
||||||
};
|
|
||||||
|
|
||||||
if (info.meta) {
|
|
||||||
ret[address].uuid = info.uuid;
|
|
||||||
ret[address].meta = JSON.parse(info.meta);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}, {});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function outAddress (address) {
|
|
||||||
return toChecksumAddress(address);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function outAddresses (addresses) {
|
|
||||||
return (addresses || []).map(outAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function outBlock (block) {
|
|
||||||
if (block) {
|
|
||||||
Object.keys(block).forEach((key) => {
|
|
||||||
switch (key) {
|
|
||||||
case 'author':
|
|
||||||
case 'miner':
|
|
||||||
block[key] = outAddress(block[key]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'difficulty':
|
|
||||||
case 'gasLimit':
|
|
||||||
case 'gasUsed':
|
|
||||||
case 'nonce':
|
|
||||||
case 'number':
|
|
||||||
case 'totalDifficulty':
|
|
||||||
block[key] = outNumber(block[key]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'timestamp':
|
|
||||||
block[key] = outDate(block[key]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return block;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function outChainStatus (status) {
|
|
||||||
if (status) {
|
|
||||||
Object.keys(status).forEach((key) => {
|
|
||||||
switch (key) {
|
|
||||||
case 'blockGap':
|
|
||||||
status[key] = status[key]
|
|
||||||
? status[key].map(outNumber)
|
|
||||||
: status[key];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function outDate (date) {
|
|
||||||
if (typeof date.toISOString === 'function') {
|
|
||||||
return date;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (typeof date === 'string' && (new Date(date)).toISOString() === date) {
|
|
||||||
return new Date(date);
|
|
||||||
}
|
|
||||||
} catch (error) {}
|
|
||||||
|
|
||||||
return new Date(outNumber(date).toNumber() * 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function outHistogram (histogram) {
|
|
||||||
if (histogram) {
|
|
||||||
Object.keys(histogram).forEach((key) => {
|
|
||||||
switch (key) {
|
|
||||||
case 'bucketBounds':
|
|
||||||
case 'counts':
|
|
||||||
histogram[key] = histogram[key].map(outNumber);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return histogram;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function outLog (log) {
|
|
||||||
Object.keys(log).forEach((key) => {
|
|
||||||
switch (key) {
|
|
||||||
case 'blockNumber':
|
|
||||||
case 'logIndex':
|
|
||||||
case 'transactionIndex':
|
|
||||||
log[key] = outNumber(log[key]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'address':
|
|
||||||
log[key] = outAddress(log[key]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return log;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function outHwAccountInfo (infos) {
|
|
||||||
return Object
|
|
||||||
.keys(infos)
|
|
||||||
.reduce((ret, _address) => {
|
|
||||||
const address = outAddress(_address);
|
|
||||||
|
|
||||||
ret[address] = infos[_address];
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}, {});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function outNodeKind (info) {
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function outNumber (number) {
|
|
||||||
return new BigNumber(number || 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function outPeer (peer) {
|
|
||||||
const protocols = Object.keys(peer.protocols)
|
|
||||||
.reduce((obj, key) => {
|
|
||||||
if (peer.protocols[key]) {
|
|
||||||
obj[key] = {
|
|
||||||
...peer.protocols[key],
|
|
||||||
difficulty: outNumber(peer.protocols[key].difficulty)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj;
|
|
||||||
}, {});
|
|
||||||
|
|
||||||
return {
|
|
||||||
...peer,
|
|
||||||
protocols
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function outPeers (peers) {
|
|
||||||
return {
|
|
||||||
active: outNumber(peers.active),
|
|
||||||
connected: outNumber(peers.connected),
|
|
||||||
max: outNumber(peers.max),
|
|
||||||
peers: peers.peers.map((peer) => outPeer(peer))
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function outReceipt (receipt) {
|
|
||||||
if (receipt) {
|
|
||||||
Object.keys(receipt).forEach((key) => {
|
|
||||||
switch (key) {
|
|
||||||
case 'blockNumber':
|
|
||||||
case 'cumulativeGasUsed':
|
|
||||||
case 'gasUsed':
|
|
||||||
case 'transactionIndex':
|
|
||||||
receipt[key] = outNumber(receipt[key]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'contractAddress':
|
|
||||||
receipt[key] = outAddress(receipt[key]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return receipt;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function outRecentDapps (recentDapps) {
|
|
||||||
if (recentDapps) {
|
|
||||||
Object.keys(recentDapps).forEach((url) => {
|
|
||||||
recentDapps[url] = outDate(recentDapps[url]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return recentDapps;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function outSignerRequest (request) {
|
|
||||||
if (request) {
|
|
||||||
Object.keys(request).forEach((key) => {
|
|
||||||
switch (key) {
|
|
||||||
case 'id':
|
|
||||||
request[key] = outNumber(request[key]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'payload':
|
|
||||||
request[key].decrypt = outSigningPayload(request[key].decrypt);
|
|
||||||
request[key].sign = outSigningPayload(request[key].sign);
|
|
||||||
request[key].signTransaction = outTransaction(request[key].signTransaction);
|
|
||||||
request[key].sendTransaction = outTransaction(request[key].sendTransaction);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'origin':
|
|
||||||
const type = Object.keys(request[key])[0];
|
|
||||||
const details = request[key][type];
|
|
||||||
|
|
||||||
request[key] = { type, details };
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return request;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function outSyncing (syncing) {
|
|
||||||
if (syncing && syncing !== 'false') {
|
|
||||||
Object.keys(syncing).forEach((key) => {
|
|
||||||
switch (key) {
|
|
||||||
case 'currentBlock':
|
|
||||||
case 'highestBlock':
|
|
||||||
case 'startingBlock':
|
|
||||||
case 'warpChunksAmount':
|
|
||||||
case 'warpChunksProcessed':
|
|
||||||
syncing[key] = outNumber(syncing[key]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'blockGap':
|
|
||||||
syncing[key] = syncing[key] ? syncing[key].map(outNumber) : syncing[key];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return syncing;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function outTransactionCondition (condition) {
|
|
||||||
if (condition) {
|
|
||||||
if (condition.block) {
|
|
||||||
condition.block = outNumber(condition.block);
|
|
||||||
} else if (condition.time) {
|
|
||||||
condition.time = outDate(condition.time);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return condition;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function outTransaction (tx) {
|
|
||||||
if (tx) {
|
|
||||||
Object.keys(tx).forEach((key) => {
|
|
||||||
switch (key) {
|
|
||||||
case 'blockNumber':
|
|
||||||
case 'gasPrice':
|
|
||||||
case 'gas':
|
|
||||||
case 'nonce':
|
|
||||||
case 'transactionIndex':
|
|
||||||
case 'value':
|
|
||||||
tx[key] = outNumber(tx[key]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'condition':
|
|
||||||
tx[key] = outTransactionCondition(tx[key]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'creates':
|
|
||||||
case 'from':
|
|
||||||
case 'to':
|
|
||||||
tx[key] = outAddress(tx[key]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return tx;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function outSigningPayload (payload) {
|
|
||||||
if (payload) {
|
|
||||||
Object.keys(payload).forEach((key) => {
|
|
||||||
switch (key) {
|
|
||||||
case 'address':
|
|
||||||
payload[key] = outAddress(payload[key]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return payload;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function outTrace (trace) {
|
|
||||||
if (trace) {
|
|
||||||
if (trace.action) {
|
|
||||||
Object.keys(trace.action).forEach(key => {
|
|
||||||
switch (key) {
|
|
||||||
case 'gas':
|
|
||||||
case 'value':
|
|
||||||
case 'balance':
|
|
||||||
trace.action[key] = outNumber(trace.action[key]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'from':
|
|
||||||
case 'to':
|
|
||||||
case 'address':
|
|
||||||
case 'refundAddress':
|
|
||||||
trace.action[key] = outAddress(trace.action[key]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (trace.result) {
|
|
||||||
Object.keys(trace.result).forEach(key => {
|
|
||||||
switch (key) {
|
|
||||||
case 'gasUsed':
|
|
||||||
trace.result[key] = outNumber(trace.result[key]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'address':
|
|
||||||
trace.action[key] = outAddress(trace.action[key]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (trace.traceAddress) {
|
|
||||||
trace.traceAddress.forEach((address, index) => {
|
|
||||||
trace.traceAddress[index] = outNumber(address);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.keys(trace).forEach((key) => {
|
|
||||||
switch (key) {
|
|
||||||
case 'subtraces':
|
|
||||||
case 'transactionPosition':
|
|
||||||
case 'blockNumber':
|
|
||||||
trace[key] = outNumber(trace[key]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return trace;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function outTraces (traces) {
|
|
||||||
if (traces) {
|
|
||||||
return traces.map(outTrace);
|
|
||||||
}
|
|
||||||
|
|
||||||
return traces;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function outTraceReplay (trace) {
|
|
||||||
if (trace) {
|
|
||||||
Object.keys(trace).forEach((key) => {
|
|
||||||
switch (key) {
|
|
||||||
case 'trace':
|
|
||||||
trace[key] = outTraces(trace[key]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return trace;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function outVaultMeta (meta) {
|
|
||||||
if (isString(meta)) {
|
|
||||||
try {
|
|
||||||
const obj = JSON.parse(meta);
|
|
||||||
|
|
||||||
return obj;
|
|
||||||
} catch (error) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return meta || {};
|
|
||||||
}
|
|
@ -1,502 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import BigNumber from 'bignumber.js';
|
|
||||||
|
|
||||||
import { outBlock, outAccountInfo, outAddress, outChainStatus, outDate, outHistogram, outHwAccountInfo, outNodeKind, outNumber, outPeer, outPeers, outReceipt, outRecentDapps, outSyncing, outTransaction, outTrace, outVaultMeta } from './output';
|
|
||||||
import { isAddress, isBigNumber, isInstanceOf } from '../../../test/types';
|
|
||||||
|
|
||||||
describe('api/format/output', () => {
|
|
||||||
const address = '0x63cf90d3f0410092fc0fca41846f596223979195';
|
|
||||||
const checksum = '0x63Cf90D3f0410092FC0fca41846f596223979195';
|
|
||||||
|
|
||||||
describe('outAccountInfo', () => {
|
|
||||||
it('returns meta objects parsed', () => {
|
|
||||||
expect(outAccountInfo(
|
|
||||||
{ '0x63cf90d3f0410092fc0fca41846f596223979195': {
|
|
||||||
name: 'name', uuid: 'uuid', meta: '{"name":"456"}' }
|
|
||||||
}
|
|
||||||
)).to.deep.equal({
|
|
||||||
'0x63Cf90D3f0410092FC0fca41846f596223979195': {
|
|
||||||
name: 'name', uuid: 'uuid', meta: { name: '456' }
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns objects without meta & uuid as required', () => {
|
|
||||||
expect(outAccountInfo(
|
|
||||||
{ '0x63cf90d3f0410092fc0fca41846f596223979195': { name: 'name' } }
|
|
||||||
)).to.deep.equal({
|
|
||||||
'0x63Cf90D3f0410092FC0fca41846f596223979195': { name: 'name' }
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('outAddress', () => {
|
|
||||||
it('retuns the address as checksummed', () => {
|
|
||||||
expect(outAddress(address)).to.equal(checksum);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('retuns the checksum as checksummed', () => {
|
|
||||||
expect(outAddress(checksum)).to.equal(checksum);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('outBlock', () => {
|
|
||||||
['author', 'miner'].forEach((input) => {
|
|
||||||
it(`formats ${input} address as address`, () => {
|
|
||||||
const block = {};
|
|
||||||
|
|
||||||
block[input] = address;
|
|
||||||
const formatted = outBlock(block)[input];
|
|
||||||
|
|
||||||
expect(isAddress(formatted)).to.be.true;
|
|
||||||
expect(formatted).to.equal(checksum);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
['difficulty', 'gasLimit', 'gasUsed', 'number', 'nonce', 'totalDifficulty'].forEach((input) => {
|
|
||||||
it(`formats ${input} number as hexnumber`, () => {
|
|
||||||
const block = {};
|
|
||||||
|
|
||||||
block[input] = 0x123;
|
|
||||||
const formatted = outBlock(block)[input];
|
|
||||||
|
|
||||||
expect(isInstanceOf(formatted, BigNumber)).to.be.true;
|
|
||||||
expect(formatted.toString(16)).to.equal('123');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
['timestamp'].forEach((input) => {
|
|
||||||
it(`formats ${input} number as Date`, () => {
|
|
||||||
const block = {};
|
|
||||||
|
|
||||||
block[input] = 0x57513668;
|
|
||||||
const formatted = outBlock(block)[input];
|
|
||||||
|
|
||||||
expect(isInstanceOf(formatted, Date)).to.be.true;
|
|
||||||
expect(formatted.getTime()).to.equal(1464940136000);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('ignores and passes through unknown keys', () => {
|
|
||||||
expect(outBlock({ someRandom: 'someRandom' })).to.deep.equal({ someRandom: 'someRandom' });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('formats a block with all the info converted', () => {
|
|
||||||
expect(
|
|
||||||
outBlock({
|
|
||||||
author: address,
|
|
||||||
miner: address,
|
|
||||||
difficulty: '0x100',
|
|
||||||
gasLimit: '0x101',
|
|
||||||
gasUsed: '0x102',
|
|
||||||
number: '0x103',
|
|
||||||
nonce: '0x104',
|
|
||||||
totalDifficulty: '0x105',
|
|
||||||
timestamp: '0x57513668',
|
|
||||||
extraData: 'someExtraStuffInHere'
|
|
||||||
})
|
|
||||||
).to.deep.equal({
|
|
||||||
author: checksum,
|
|
||||||
miner: checksum,
|
|
||||||
difficulty: new BigNumber('0x100'),
|
|
||||||
gasLimit: new BigNumber('0x101'),
|
|
||||||
gasUsed: new BigNumber('0x102'),
|
|
||||||
number: new BigNumber('0x103'),
|
|
||||||
nonce: new BigNumber('0x104'),
|
|
||||||
totalDifficulty: new BigNumber('0x105'),
|
|
||||||
timestamp: new Date('2016-06-03T07:48:56.000Z'),
|
|
||||||
extraData: 'someExtraStuffInHere'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('outChainStatus', () => {
|
|
||||||
it('formats blockGap values', () => {
|
|
||||||
const status = {
|
|
||||||
blockGap: [0x1234, '0x5678']
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(outChainStatus(status)).to.deep.equal({
|
|
||||||
blockGap: [new BigNumber(0x1234), new BigNumber(0x5678)]
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('handles null blockGap values', () => {
|
|
||||||
const status = {
|
|
||||||
blockGap: null
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(outChainStatus(status)).to.deep.equal(status);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('outDate', () => {
|
|
||||||
it('converts a second date in unix timestamp', () => {
|
|
||||||
expect(outDate(0x57513668)).to.deep.equal(new Date('2016-06-03T07:48:56.000Z'));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('outHistogram', () => {
|
|
||||||
['bucketBounds', 'counts'].forEach((type) => {
|
|
||||||
it(`formats ${type} as number arrays`, () => {
|
|
||||||
expect(
|
|
||||||
outHistogram({ [type]: [0x123, 0x456, 0x789] })
|
|
||||||
).to.deep.equal({
|
|
||||||
[type]: [new BigNumber(0x123), new BigNumber(0x456), new BigNumber(0x789)]
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('outHwAccountInfo', () => {
|
|
||||||
it('returns objects with formatted addresses', () => {
|
|
||||||
expect(outHwAccountInfo(
|
|
||||||
{ '0x63cf90d3f0410092fc0fca41846f596223979195': { manufacturer: 'mfg', name: 'type' } }
|
|
||||||
)).to.deep.equal({
|
|
||||||
'0x63Cf90D3f0410092FC0fca41846f596223979195': { manufacturer: 'mfg', name: 'type' }
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('outNodeKind', () => {
|
|
||||||
it('formats the input as received', () => {
|
|
||||||
const kind = { availability: 'personal', capability: 'full' };
|
|
||||||
|
|
||||||
expect(outNodeKind(kind)).to.deep.equal(kind);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('outNumber', () => {
|
|
||||||
it('returns a BigNumber equalling the value', () => {
|
|
||||||
const bn = outNumber('0x123456');
|
|
||||||
|
|
||||||
expect(isBigNumber(bn)).to.be.true;
|
|
||||||
expect(bn.eq(0x123456)).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('assumes 0 when ivalid input', () => {
|
|
||||||
expect(outNumber().eq(0)).to.be.true;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('outPeer', () => {
|
|
||||||
it('converts all internal numbers to BigNumbers', () => {
|
|
||||||
expect(outPeer({
|
|
||||||
caps: ['par/1'],
|
|
||||||
id: '0x01',
|
|
||||||
name: 'Parity',
|
|
||||||
network: {
|
|
||||||
localAddress: '10.0.0.1',
|
|
||||||
remoteAddress: '10.0.0.1'
|
|
||||||
},
|
|
||||||
protocols: {
|
|
||||||
par: {
|
|
||||||
difficulty: '0x0f',
|
|
||||||
head: '0x02',
|
|
||||||
version: 63
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})).to.deep.equal({
|
|
||||||
caps: ['par/1'],
|
|
||||||
id: '0x01',
|
|
||||||
name: 'Parity',
|
|
||||||
network: {
|
|
||||||
localAddress: '10.0.0.1',
|
|
||||||
remoteAddress: '10.0.0.1'
|
|
||||||
},
|
|
||||||
protocols: {
|
|
||||||
par: {
|
|
||||||
difficulty: new BigNumber(15),
|
|
||||||
head: '0x02',
|
|
||||||
version: 63
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not output null protocols', () => {
|
|
||||||
expect(outPeer({
|
|
||||||
caps: ['par/1'],
|
|
||||||
id: '0x01',
|
|
||||||
name: 'Parity',
|
|
||||||
network: {
|
|
||||||
localAddress: '10.0.0.1',
|
|
||||||
remoteAddress: '10.0.0.1'
|
|
||||||
},
|
|
||||||
protocols: {
|
|
||||||
les: null
|
|
||||||
}
|
|
||||||
})).to.deep.equal({
|
|
||||||
caps: ['par/1'],
|
|
||||||
id: '0x01',
|
|
||||||
name: 'Parity',
|
|
||||||
network: {
|
|
||||||
localAddress: '10.0.0.1',
|
|
||||||
remoteAddress: '10.0.0.1'
|
|
||||||
},
|
|
||||||
protocols: {}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('outPeers', () => {
|
|
||||||
it('converts all internal numbers to BigNumbers', () => {
|
|
||||||
expect(outPeers({
|
|
||||||
active: 789,
|
|
||||||
connected: '456',
|
|
||||||
max: 0x7b,
|
|
||||||
peers: [
|
|
||||||
{
|
|
||||||
caps: ['par/1'],
|
|
||||||
id: '0x01',
|
|
||||||
name: 'Parity',
|
|
||||||
network: {
|
|
||||||
localAddress: '10.0.0.1',
|
|
||||||
remoteAddress: '10.0.0.1'
|
|
||||||
},
|
|
||||||
protocols: {
|
|
||||||
par: {
|
|
||||||
difficulty: '0x0f',
|
|
||||||
head: '0x02',
|
|
||||||
version: 63
|
|
||||||
},
|
|
||||||
les: null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})).to.deep.equal({
|
|
||||||
active: new BigNumber(789),
|
|
||||||
connected: new BigNumber(456),
|
|
||||||
max: new BigNumber(123),
|
|
||||||
peers: [
|
|
||||||
{
|
|
||||||
caps: ['par/1'],
|
|
||||||
id: '0x01',
|
|
||||||
name: 'Parity',
|
|
||||||
network: {
|
|
||||||
localAddress: '10.0.0.1',
|
|
||||||
remoteAddress: '10.0.0.1'
|
|
||||||
},
|
|
||||||
protocols: {
|
|
||||||
par: {
|
|
||||||
difficulty: new BigNumber(15),
|
|
||||||
head: '0x02',
|
|
||||||
version: 63
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('outReceipt', () => {
|
|
||||||
['contractAddress'].forEach((input) => {
|
|
||||||
it(`formats ${input} address as address`, () => {
|
|
||||||
const block = {};
|
|
||||||
|
|
||||||
block[input] = address;
|
|
||||||
const formatted = outReceipt(block)[input];
|
|
||||||
|
|
||||||
expect(isAddress(formatted)).to.be.true;
|
|
||||||
expect(formatted).to.equal(checksum);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
['blockNumber', 'cumulativeGasUsed', 'cumulativeGasUsed', 'gasUsed', 'transactionIndex'].forEach((input) => {
|
|
||||||
it(`formats ${input} number as hexnumber`, () => {
|
|
||||||
const block = {};
|
|
||||||
|
|
||||||
block[input] = 0x123;
|
|
||||||
const formatted = outReceipt(block)[input];
|
|
||||||
|
|
||||||
expect(isInstanceOf(formatted, BigNumber)).to.be.true;
|
|
||||||
expect(formatted.toString(16)).to.equal('123');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('ignores and passes through unknown keys', () => {
|
|
||||||
expect(outReceipt({ someRandom: 'someRandom' })).to.deep.equal({ someRandom: 'someRandom' });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('formats a receipt with all the info converted', () => {
|
|
||||||
expect(
|
|
||||||
outReceipt({
|
|
||||||
contractAddress: address,
|
|
||||||
blockNumber: '0x100',
|
|
||||||
cumulativeGasUsed: '0x101',
|
|
||||||
gasUsed: '0x102',
|
|
||||||
transactionIndex: '0x103',
|
|
||||||
extraData: 'someExtraStuffInHere'
|
|
||||||
})
|
|
||||||
).to.deep.equal({
|
|
||||||
contractAddress: checksum,
|
|
||||||
blockNumber: new BigNumber('0x100'),
|
|
||||||
cumulativeGasUsed: new BigNumber('0x101'),
|
|
||||||
gasUsed: new BigNumber('0x102'),
|
|
||||||
transactionIndex: new BigNumber('0x103'),
|
|
||||||
extraData: 'someExtraStuffInHere'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('outRecentDapps', () => {
|
|
||||||
it('formats the URLs with timestamps', () => {
|
|
||||||
expect(outRecentDapps({ testing: 0x57513668 })).to.deep.equal({
|
|
||||||
testing: new Date('2016-06-03T07:48:56.000Z')
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('outSyncing', () => {
|
|
||||||
['currentBlock', 'highestBlock', 'startingBlock', 'warpChunksAmount', 'warpChunksProcessed'].forEach((input) => {
|
|
||||||
it(`formats ${input} numbers as a number`, () => {
|
|
||||||
expect(outSyncing({ [input]: '0x123' })).to.deep.equal({
|
|
||||||
[input]: new BigNumber('0x123')
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('formats blockGap properly', () => {
|
|
||||||
expect(outSyncing({ blockGap: [0x123, 0x456] })).to.deep.equal({
|
|
||||||
blockGap: [new BigNumber(0x123), new BigNumber(0x456)]
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('outTransaction', () => {
|
|
||||||
['from', 'to'].forEach((input) => {
|
|
||||||
it(`formats ${input} address as address`, () => {
|
|
||||||
const block = {};
|
|
||||||
|
|
||||||
block[input] = address;
|
|
||||||
const formatted = outTransaction(block)[input];
|
|
||||||
|
|
||||||
expect(isAddress(formatted)).to.be.true;
|
|
||||||
expect(formatted).to.equal(checksum);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
['blockNumber', 'gasPrice', 'gas', 'nonce', 'transactionIndex', 'value'].forEach((input) => {
|
|
||||||
it(`formats ${input} number as hexnumber`, () => {
|
|
||||||
const block = {};
|
|
||||||
|
|
||||||
block[input] = 0x123;
|
|
||||||
const formatted = outTransaction(block)[input];
|
|
||||||
|
|
||||||
expect(isInstanceOf(formatted, BigNumber)).to.be.true;
|
|
||||||
expect(formatted.toString(16)).to.equal('123');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('passes condition as null when null', () => {
|
|
||||||
expect(outTransaction({ condition: null })).to.deep.equal({ condition: null });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('ignores and passes through unknown keys', () => {
|
|
||||||
expect(outTransaction({ someRandom: 'someRandom' })).to.deep.equal({ someRandom: 'someRandom' });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('formats a transaction with all the info converted', () => {
|
|
||||||
expect(
|
|
||||||
outTransaction({
|
|
||||||
from: address,
|
|
||||||
to: address,
|
|
||||||
blockNumber: '0x100',
|
|
||||||
gasPrice: '0x101',
|
|
||||||
gas: '0x102',
|
|
||||||
nonce: '0x103',
|
|
||||||
transactionIndex: '0x104',
|
|
||||||
value: '0x105',
|
|
||||||
extraData: 'someExtraStuffInHere'
|
|
||||||
})
|
|
||||||
).to.deep.equal({
|
|
||||||
from: checksum,
|
|
||||||
to: checksum,
|
|
||||||
blockNumber: new BigNumber('0x100'),
|
|
||||||
gasPrice: new BigNumber('0x101'),
|
|
||||||
gas: new BigNumber('0x102'),
|
|
||||||
nonce: new BigNumber('0x103'),
|
|
||||||
transactionIndex: new BigNumber('0x104'),
|
|
||||||
value: new BigNumber('0x105'),
|
|
||||||
extraData: 'someExtraStuffInHere'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('outTrace', () => {
|
|
||||||
it('ignores and passes through unknown keys', () => {
|
|
||||||
expect(outTrace({ someRandom: 'someRandom' })).to.deep.equal({ someRandom: 'someRandom' });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('formats a trace with all the info converted', () => {
|
|
||||||
const formatted = outTrace({
|
|
||||||
type: 'call',
|
|
||||||
action: {
|
|
||||||
from: address,
|
|
||||||
to: address,
|
|
||||||
value: '0x06',
|
|
||||||
gas: '0x07',
|
|
||||||
input: '0x1234',
|
|
||||||
callType: 'call'
|
|
||||||
},
|
|
||||||
result: {
|
|
||||||
gasUsed: '0x08',
|
|
||||||
output: '0x5678'
|
|
||||||
},
|
|
||||||
traceAddress: [ '0x2' ],
|
|
||||||
subtraces: 3,
|
|
||||||
transactionPosition: '0xb',
|
|
||||||
transactionHash: '0x000000000000000000000000000000000000000000000000000000000000000c',
|
|
||||||
blockNumber: '0x0d',
|
|
||||||
blockHash: '0x000000000000000000000000000000000000000000000000000000000000000e'
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(isBigNumber(formatted.action.gas)).to.be.true;
|
|
||||||
expect(formatted.action.gas.toNumber()).to.equal(7);
|
|
||||||
expect(isBigNumber(formatted.action.value)).to.be.true;
|
|
||||||
expect(formatted.action.value.toNumber()).to.equal(6);
|
|
||||||
|
|
||||||
expect(formatted.action.from).to.equal(checksum);
|
|
||||||
expect(formatted.action.to).to.equal(checksum);
|
|
||||||
|
|
||||||
expect(isBigNumber(formatted.blockNumber)).to.be.true;
|
|
||||||
expect(formatted.blockNumber.toNumber()).to.equal(13);
|
|
||||||
expect(isBigNumber(formatted.transactionPosition)).to.be.true;
|
|
||||||
expect(formatted.transactionPosition.toNumber()).to.equal(11);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('outVaultMeta', () => {
|
|
||||||
it('returns an exmpt object on null', () => {
|
|
||||||
expect(outVaultMeta(null)).to.deep.equal({});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns the original value if not string', () => {
|
|
||||||
expect(outVaultMeta({ test: 123 })).to.deep.equal({ test: 123 });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns an object from JSON string', () => {
|
|
||||||
expect(outVaultMeta('{"test":123}')).to.deep.equal({ test: 123 });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns an empty object on invalid JSON', () => {
|
|
||||||
expect(outVaultMeta('{"test"}')).to.deep.equal({});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,17 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
export default from './api';
|
|
@ -1,34 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import es6Promise from 'es6-promise';
|
|
||||||
es6Promise.polyfill();
|
|
||||||
|
|
||||||
const isNode = typeof global !== 'undefined' && typeof global !== 'undefined';
|
|
||||||
const isBrowser = typeof self !== 'undefined' && typeof self.window !== 'undefined';
|
|
||||||
|
|
||||||
if (isBrowser) {
|
|
||||||
require('whatwg-fetch');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isNode) {
|
|
||||||
global.fetch = require('node-fetch');
|
|
||||||
}
|
|
||||||
|
|
||||||
import Abi from '../abi';
|
|
||||||
import Api from './';
|
|
||||||
|
|
||||||
export { Api, Abi };
|
|
@ -1,112 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import { createKeyObject, decryptPrivateKey } from '../ethkey';
|
|
||||||
|
|
||||||
export default class Account {
|
|
||||||
constructor (persist, data = {}) {
|
|
||||||
const {
|
|
||||||
keyObject = null,
|
|
||||||
meta = {},
|
|
||||||
name = ''
|
|
||||||
} = data;
|
|
||||||
|
|
||||||
this._persist = persist;
|
|
||||||
this._keyObject = keyObject;
|
|
||||||
this._name = name;
|
|
||||||
this._meta = meta;
|
|
||||||
}
|
|
||||||
|
|
||||||
isValidPassword (password) {
|
|
||||||
return decryptPrivateKey(this._keyObject, password)
|
|
||||||
.then((privateKey) => {
|
|
||||||
if (!privateKey) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export () {
|
|
||||||
const exported = Object.assign({}, this._keyObject);
|
|
||||||
|
|
||||||
exported.meta = JSON.stringify(this._meta);
|
|
||||||
exported.name = this._name;
|
|
||||||
|
|
||||||
return exported;
|
|
||||||
}
|
|
||||||
|
|
||||||
get address () {
|
|
||||||
return `0x${this._keyObject.address.toLowerCase()}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
get name () {
|
|
||||||
return this._name;
|
|
||||||
}
|
|
||||||
|
|
||||||
set name (name) {
|
|
||||||
this._name = name;
|
|
||||||
|
|
||||||
this._persist();
|
|
||||||
}
|
|
||||||
|
|
||||||
get meta () {
|
|
||||||
return JSON.stringify(this._meta);
|
|
||||||
}
|
|
||||||
|
|
||||||
set meta (meta) {
|
|
||||||
this._meta = JSON.parse(meta);
|
|
||||||
|
|
||||||
this._persist();
|
|
||||||
}
|
|
||||||
|
|
||||||
get uuid () {
|
|
||||||
if (!this._keyObject) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this._keyObject.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
decryptPrivateKey (password) {
|
|
||||||
return decryptPrivateKey(this._keyObject, password);
|
|
||||||
}
|
|
||||||
|
|
||||||
changePassword (key, password) {
|
|
||||||
return createKeyObject(key, password).then((keyObject) => {
|
|
||||||
this._keyObject = keyObject;
|
|
||||||
|
|
||||||
this._persist();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static fromPrivateKey (persist, key, password) {
|
|
||||||
return createKeyObject(key, password).then((keyObject) => {
|
|
||||||
const account = new Account(persist, { keyObject });
|
|
||||||
|
|
||||||
return account;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
toJSON () {
|
|
||||||
return {
|
|
||||||
keyObject: this._keyObject,
|
|
||||||
name: this._name,
|
|
||||||
meta: this._meta
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,223 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import Account from './account';
|
|
||||||
import localStore from 'store';
|
|
||||||
import { debounce } from 'lodash';
|
|
||||||
import { decryptPrivateKey } from '../ethkey';
|
|
||||||
|
|
||||||
const NULL_ADDRESS = '0x0000000000000000000000000000000000000000';
|
|
||||||
const LS_STORE_KEY = '_parity::localAccounts';
|
|
||||||
|
|
||||||
export default class Accounts {
|
|
||||||
persist = debounce(() => {
|
|
||||||
this._lastState = JSON.stringify(this);
|
|
||||||
|
|
||||||
localStore.set(LS_STORE_KEY, this);
|
|
||||||
}, 100);
|
|
||||||
|
|
||||||
constructor (data = localStore.get(LS_STORE_KEY) || {}) {
|
|
||||||
this._lastState = JSON.stringify(data);
|
|
||||||
|
|
||||||
window.addEventListener('storage', ({ key, newValue }) => {
|
|
||||||
if (key !== LS_STORE_KEY) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newValue !== this._lastState) {
|
|
||||||
console.log('Data changed in a second tab, syncing state');
|
|
||||||
|
|
||||||
this.restore(JSON.parse(newValue));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.restore(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
restore (data) {
|
|
||||||
const {
|
|
||||||
last = NULL_ADDRESS,
|
|
||||||
dappsDefault = NULL_ADDRESS,
|
|
||||||
store = {}
|
|
||||||
} = data;
|
|
||||||
|
|
||||||
this._last = last;
|
|
||||||
this._dappsDefaultAddress = dappsDefault;
|
|
||||||
this._store = {};
|
|
||||||
|
|
||||||
if (Array.isArray(store)) {
|
|
||||||
// Recover older version that stored accounts as an array
|
|
||||||
store.forEach((data) => {
|
|
||||||
const account = new Account(this.persist, data);
|
|
||||||
|
|
||||||
this._store[account.address] = account;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
Object.keys(store).forEach((key) => {
|
|
||||||
this._store[key] = new Account(this.persist, store[key]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_addAccount = (account) => {
|
|
||||||
const { address } = account;
|
|
||||||
|
|
||||||
if (address in this._store && this._store[address].uuid) {
|
|
||||||
throw new Error(`Account ${address} already exists!`);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._store[address] = account;
|
|
||||||
this.lastAddress = address;
|
|
||||||
|
|
||||||
this.persist();
|
|
||||||
|
|
||||||
return account.address;
|
|
||||||
}
|
|
||||||
|
|
||||||
create (secret, password) {
|
|
||||||
const privateKey = Buffer.from(secret.slice(2), 'hex');
|
|
||||||
|
|
||||||
return Account
|
|
||||||
.fromPrivateKey(this.persist, privateKey, password)
|
|
||||||
.then(this._addAccount);
|
|
||||||
}
|
|
||||||
|
|
||||||
restoreFromWallet (wallet, password) {
|
|
||||||
return decryptPrivateKey(wallet, password)
|
|
||||||
.then((privateKey) => {
|
|
||||||
if (!privateKey) {
|
|
||||||
throw new Error('Invalid password');
|
|
||||||
}
|
|
||||||
|
|
||||||
return Account.fromPrivateKey(this.persist, privateKey, password);
|
|
||||||
})
|
|
||||||
.then(this._addAccount);
|
|
||||||
}
|
|
||||||
|
|
||||||
set lastAddress (value) {
|
|
||||||
this._last = value.toLowerCase();
|
|
||||||
}
|
|
||||||
|
|
||||||
get lastAddress () {
|
|
||||||
return this._last;
|
|
||||||
}
|
|
||||||
|
|
||||||
get dappsDefaultAddress () {
|
|
||||||
if (this._dappsDefaultAddress === NULL_ADDRESS) {
|
|
||||||
return this._last;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._dappsDefaultAddress in this._store) {
|
|
||||||
return this._dappsDefaultAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL_ADDRESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
set dappsDefaultAddress (value) {
|
|
||||||
this._dappsDefaultAddress = value.toLowerCase();
|
|
||||||
|
|
||||||
this.persist();
|
|
||||||
}
|
|
||||||
|
|
||||||
get (address) {
|
|
||||||
address = address.toLowerCase();
|
|
||||||
|
|
||||||
const account = this._store[address];
|
|
||||||
|
|
||||||
if (!account) {
|
|
||||||
throw new Error(`Account not found: ${address}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.lastAddress = address;
|
|
||||||
|
|
||||||
return account;
|
|
||||||
}
|
|
||||||
|
|
||||||
getLazyCreate (address) {
|
|
||||||
address = address.toLowerCase();
|
|
||||||
|
|
||||||
this.lastAddress = address;
|
|
||||||
|
|
||||||
if (!(address in this._store)) {
|
|
||||||
this._store[address] = new Account(this.persist);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this._store[address];
|
|
||||||
}
|
|
||||||
|
|
||||||
remove (address, password) {
|
|
||||||
address = address.toLowerCase();
|
|
||||||
|
|
||||||
const account = this.get(address);
|
|
||||||
|
|
||||||
if (!account) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return account
|
|
||||||
.isValidPassword(password)
|
|
||||||
.then((isValid) => {
|
|
||||||
if (!isValid) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (address === this.lastAddress) {
|
|
||||||
this.lastAddress = NULL_ADDRESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.removeUnsafe(address);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
removeUnsafe (address) {
|
|
||||||
address = address.toLowerCase();
|
|
||||||
|
|
||||||
delete this._store[address];
|
|
||||||
|
|
||||||
this.persist();
|
|
||||||
}
|
|
||||||
|
|
||||||
allAddresses () {
|
|
||||||
return Object.keys(this._store);
|
|
||||||
}
|
|
||||||
|
|
||||||
accountAddresses () {
|
|
||||||
return Object
|
|
||||||
.keys(this._store)
|
|
||||||
.filter((address) => this._store[address].uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
map (mapper) {
|
|
||||||
const result = {};
|
|
||||||
|
|
||||||
Object.keys(this._store).forEach((key) => {
|
|
||||||
result[key] = mapper(this._store[key]);
|
|
||||||
});
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
toJSON () {
|
|
||||||
return {
|
|
||||||
last: this._last,
|
|
||||||
dappsDefault: this._dappsDefaultAddress,
|
|
||||||
store: this._store
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import Accounts from './accounts';
|
|
||||||
|
|
||||||
const accounts = new Accounts();
|
|
||||||
|
|
||||||
export default accounts;
|
|
@ -1,147 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
/* global WebAssembly */
|
|
||||||
|
|
||||||
import wasmBuffer from './ethkey.wasm.js';
|
|
||||||
|
|
||||||
const NOOP = () => {};
|
|
||||||
|
|
||||||
// WASM memory setup
|
|
||||||
const WASM_PAGE_SIZE = 65536;
|
|
||||||
const STATIC_BASE = 1024;
|
|
||||||
const STATICTOP = STATIC_BASE + WASM_PAGE_SIZE * 2;
|
|
||||||
const STACK_BASE = align(STATICTOP + 16);
|
|
||||||
const STACKTOP = STACK_BASE;
|
|
||||||
const TOTAL_STACK = 5 * 1024 * 1024;
|
|
||||||
const TOTAL_MEMORY = 16777216;
|
|
||||||
const STACK_MAX = STACK_BASE + TOTAL_STACK;
|
|
||||||
const DYNAMIC_BASE = STACK_MAX + 64;
|
|
||||||
const DYNAMICTOP_PTR = STACK_MAX;
|
|
||||||
|
|
||||||
function mockWebAssembly () {
|
|
||||||
function throwWasmError () {
|
|
||||||
throw new Error('Missing WebAssembly support');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Simple mock replacement
|
|
||||||
return {
|
|
||||||
Memory: class { buffer = new ArrayBuffer(2048) },
|
|
||||||
Table: class {},
|
|
||||||
Module: class {},
|
|
||||||
Instance: class {
|
|
||||||
exports = {
|
|
||||||
'_input_ptr': () => 0,
|
|
||||||
'_secret_ptr': () => 0,
|
|
||||||
'_public_ptr': () => 0,
|
|
||||||
'_address_ptr': () => 0,
|
|
||||||
'_ecpointg': NOOP,
|
|
||||||
'_brain': throwWasmError,
|
|
||||||
'_verify_secret': throwWasmError
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const { Memory, Table, Module, Instance } = typeof WebAssembly !== 'undefined' ? WebAssembly : mockWebAssembly();
|
|
||||||
|
|
||||||
const wasmMemory = new Memory({
|
|
||||||
initial: TOTAL_MEMORY / WASM_PAGE_SIZE,
|
|
||||||
maximum: TOTAL_MEMORY / WASM_PAGE_SIZE
|
|
||||||
});
|
|
||||||
|
|
||||||
const wasmTable = new Table({
|
|
||||||
initial: 8,
|
|
||||||
maximum: 8,
|
|
||||||
element: 'anyfunc'
|
|
||||||
});
|
|
||||||
|
|
||||||
// TypedArray views into the memory
|
|
||||||
const wasmMemoryU8 = new Uint8Array(wasmMemory.buffer);
|
|
||||||
const wasmMemoryU32 = new Uint32Array(wasmMemory.buffer);
|
|
||||||
|
|
||||||
// Keep DYNAMIC_BASE in memory
|
|
||||||
wasmMemoryU32[DYNAMICTOP_PTR >> 2] = align(DYNAMIC_BASE);
|
|
||||||
|
|
||||||
function align (mem) {
|
|
||||||
const ALIGN_SIZE = 16;
|
|
||||||
|
|
||||||
return (Math.ceil(mem / ALIGN_SIZE) * ALIGN_SIZE) | 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function slice (ptr, len) {
|
|
||||||
return wasmMemoryU8.subarray(ptr, ptr + len);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Required by emscripten
|
|
||||||
function abort (what) {
|
|
||||||
throw new Error(what || 'WASM abort');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Required by emscripten
|
|
||||||
function abortOnCannotGrowMemory () {
|
|
||||||
abort(`Cannot enlarge memory arrays.`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Required by emscripten
|
|
||||||
function enlargeMemory () {
|
|
||||||
abortOnCannotGrowMemory();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Required by emscripten
|
|
||||||
function getTotalMemory () {
|
|
||||||
return TOTAL_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Required by emscripten - used to perform memcpy on large data
|
|
||||||
function memcpy (dest, src, len) {
|
|
||||||
wasmMemoryU8.set(wasmMemoryU8.subarray(src, src + len), dest);
|
|
||||||
|
|
||||||
return dest;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Synchronously compile WASM from the buffer
|
|
||||||
const module = new Module(wasmBuffer);
|
|
||||||
|
|
||||||
// Instantiated WASM module
|
|
||||||
const instance = new Instance(module, {
|
|
||||||
global: {},
|
|
||||||
env: {
|
|
||||||
DYNAMICTOP_PTR,
|
|
||||||
STACKTOP,
|
|
||||||
STACK_MAX,
|
|
||||||
abort,
|
|
||||||
enlargeMemory,
|
|
||||||
getTotalMemory,
|
|
||||||
abortOnCannotGrowMemory,
|
|
||||||
___lock: NOOP,
|
|
||||||
___syscall6: () => 0,
|
|
||||||
___setErrNo: (no) => no,
|
|
||||||
_abort: abort,
|
|
||||||
___syscall140: () => 0,
|
|
||||||
_emscripten_memcpy_big: memcpy,
|
|
||||||
___syscall54: () => 0,
|
|
||||||
___unlock: NOOP,
|
|
||||||
_llvm_trap: abort,
|
|
||||||
___syscall146: () => 0,
|
|
||||||
'memory': wasmMemory,
|
|
||||||
'table': wasmTable,
|
|
||||||
tableBase: 0,
|
|
||||||
memoryBase: STATIC_BASE
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const extern = instance.exports;
|
|
File diff suppressed because one or more lines are too long
@ -1,47 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import workerPool from './workerPool';
|
|
||||||
|
|
||||||
export function createKeyObject (key, password) {
|
|
||||||
return workerPool.action('createKeyObject', { key, password })
|
|
||||||
.then((obj) => JSON.parse(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
export function decryptPrivateKey (keyObject, password) {
|
|
||||||
return workerPool
|
|
||||||
.action('decryptPrivateKey', { keyObject, password })
|
|
||||||
.then((privateKey) => {
|
|
||||||
if (privateKey) {
|
|
||||||
return Buffer.from(privateKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function phraseToAddress (phrase) {
|
|
||||||
return phraseToWallet(phrase)
|
|
||||||
.then((wallet) => wallet.address);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function phraseToWallet (phrase) {
|
|
||||||
return workerPool.action('phraseToWallet', phrase);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function verifySecret (secret) {
|
|
||||||
return workerPool.action('verifySecret', secret);
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import { randomPhrase } from '@parity/wordlist';
|
|
||||||
import { phraseToAddress, phraseToWallet } from './';
|
|
||||||
|
|
||||||
// TODO: Skipping until Node.js 8.0 comes out and we can test WebAssembly
|
|
||||||
describe.skip('api/local/ethkey', () => {
|
|
||||||
describe('phraseToAddress', function () {
|
|
||||||
this.timeout(30000);
|
|
||||||
|
|
||||||
it('generates a valid address', () => {
|
|
||||||
const phrase = randomPhrase(12);
|
|
||||||
|
|
||||||
return phraseToAddress(phrase).then((address) => {
|
|
||||||
expect(address.length).to.be.equal(42);
|
|
||||||
expect(address.slice(0, 4)).to.be.equal('0x00');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('generates valid address for empty phrase', () => {
|
|
||||||
return phraseToAddress('').then((address) => {
|
|
||||||
expect(address).to.be.equal('0x00a329c0648769a73afac7f9381e08fb43dbea72');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('phraseToWallet', function () {
|
|
||||||
this.timeout(30000);
|
|
||||||
|
|
||||||
it('generates a valid wallet object', () => {
|
|
||||||
const phrase = randomPhrase(12);
|
|
||||||
|
|
||||||
return phraseToWallet(phrase).then((wallet) => {
|
|
||||||
expect(wallet.address.length).to.be.equal(42);
|
|
||||||
expect(wallet.secret.length).to.be.equal(66);
|
|
||||||
expect(wallet.public.length).to.be.equal(130);
|
|
||||||
|
|
||||||
expect(wallet.address.slice(0, 4)).to.be.equal('0x00');
|
|
||||||
expect(wallet.secret.slice(0, 2)).to.be.equal('0x');
|
|
||||||
expect(wallet.public.slice(0, 2)).to.be.equal('0x');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,138 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import { bytesToHex } from '../../util/format';
|
|
||||||
import { extern, slice } from './ethkey.js';
|
|
||||||
|
|
||||||
const isWorker = typeof self !== 'undefined';
|
|
||||||
|
|
||||||
// Stay compatible between environments
|
|
||||||
if (!isWorker) {
|
|
||||||
const scope = typeof global === 'undefined' ? window : global;
|
|
||||||
|
|
||||||
scope.self = scope;
|
|
||||||
}
|
|
||||||
|
|
||||||
// keythereum should never be used outside of the browser
|
|
||||||
let keythereum = require('keythereum');
|
|
||||||
|
|
||||||
if (isWorker) {
|
|
||||||
keythereum = self.keythereum;
|
|
||||||
}
|
|
||||||
|
|
||||||
function route ({ action, payload }) {
|
|
||||||
if (action in actions) {
|
|
||||||
return actions[action](payload);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const input = slice(extern._input_ptr(), 1024);
|
|
||||||
const secret = slice(extern._secret_ptr(), 32);
|
|
||||||
const publicKey = slice(extern._public_ptr(), 64);
|
|
||||||
const address = slice(extern._address_ptr(), 20);
|
|
||||||
|
|
||||||
extern._ecpointg();
|
|
||||||
|
|
||||||
const actions = {
|
|
||||||
phraseToWallet (phrase) {
|
|
||||||
const phraseUtf8 = Buffer.from(phrase, 'utf8');
|
|
||||||
|
|
||||||
if (phraseUtf8.length > input.length) {
|
|
||||||
throw new Error('Phrase is too long!');
|
|
||||||
}
|
|
||||||
|
|
||||||
input.set(phraseUtf8);
|
|
||||||
|
|
||||||
extern._brain(phraseUtf8.length);
|
|
||||||
|
|
||||||
const wallet = {
|
|
||||||
secret: bytesToHex(secret),
|
|
||||||
public: bytesToHex(publicKey),
|
|
||||||
address: bytesToHex(address)
|
|
||||||
};
|
|
||||||
|
|
||||||
return wallet;
|
|
||||||
},
|
|
||||||
|
|
||||||
verifySecret (key) {
|
|
||||||
const keyBuf = Buffer.from(key.slice(2), 'hex');
|
|
||||||
|
|
||||||
secret.set(keyBuf);
|
|
||||||
|
|
||||||
return extern._verify_secret();
|
|
||||||
},
|
|
||||||
|
|
||||||
createKeyObject ({ key, password }) {
|
|
||||||
key = Buffer.from(key);
|
|
||||||
password = Buffer.from(password);
|
|
||||||
|
|
||||||
const iv = keythereum.crypto.randomBytes(16);
|
|
||||||
const salt = keythereum.crypto.randomBytes(32);
|
|
||||||
const keyObject = keythereum.dump(password, key, salt, iv);
|
|
||||||
|
|
||||||
return JSON.stringify(keyObject);
|
|
||||||
},
|
|
||||||
|
|
||||||
decryptPrivateKey ({ keyObject, password }) {
|
|
||||||
password = Buffer.from(password);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const key = keythereum.recover(password, keyObject);
|
|
||||||
|
|
||||||
// Convert to array to safely send from the worker
|
|
||||||
return Array.from(key);
|
|
||||||
} catch (e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.onmessage = function ({ data }) {
|
|
||||||
try {
|
|
||||||
const result = route(data);
|
|
||||||
|
|
||||||
postMessage([null, result]);
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
postMessage([err.toString(), null]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Emulate a web worker in Node.js
|
|
||||||
class KeyWorker {
|
|
||||||
postMessage (data) {
|
|
||||||
// Force async
|
|
||||||
setTimeout(() => {
|
|
||||||
try {
|
|
||||||
const result = route(data);
|
|
||||||
|
|
||||||
this.onmessage({ data: [null, result] });
|
|
||||||
} catch (err) {
|
|
||||||
this.onmessage({ data: [err, null] });
|
|
||||||
}
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
onmessage (event) {
|
|
||||||
// no-op to be overriden
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exports != null) {
|
|
||||||
exports.KeyWorker = KeyWorker;
|
|
||||||
}
|
|
@ -1,105 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
// Allow a web worker in the browser, with a fallback for Node.js
|
|
||||||
const hasWebWorkers = typeof Worker !== 'undefined';
|
|
||||||
const KeyWorker = hasWebWorkers ? require('worker-loader!./worker')
|
|
||||||
: require('./worker').KeyWorker;
|
|
||||||
|
|
||||||
class WorkerContainer {
|
|
||||||
busy = false;
|
|
||||||
_worker = new KeyWorker();
|
|
||||||
|
|
||||||
action (action, payload) {
|
|
||||||
if (this.busy) {
|
|
||||||
throw new Error('Cannot issue an action on a busy worker!');
|
|
||||||
}
|
|
||||||
|
|
||||||
this.busy = true;
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
this._worker.postMessage({ action, payload });
|
|
||||||
this._worker.onmessage = ({ data }) => {
|
|
||||||
const [err, result] = data;
|
|
||||||
|
|
||||||
this.busy = false;
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
// `err` ought to be a String
|
|
||||||
reject(new Error(err));
|
|
||||||
} else {
|
|
||||||
resolve(result);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class WorkerPool {
|
|
||||||
pool = [
|
|
||||||
new WorkerContainer(),
|
|
||||||
new WorkerContainer()
|
|
||||||
];
|
|
||||||
|
|
||||||
queue = [];
|
|
||||||
|
|
||||||
_getContainer () {
|
|
||||||
return this.pool.find((container) => !container.busy);
|
|
||||||
}
|
|
||||||
|
|
||||||
action (action, payload) {
|
|
||||||
let container = this.pool.find((container) => !container.busy);
|
|
||||||
|
|
||||||
let promise;
|
|
||||||
|
|
||||||
// const start = Date.now();
|
|
||||||
|
|
||||||
if (container) {
|
|
||||||
promise = container.action(action, payload);
|
|
||||||
} else {
|
|
||||||
promise = new Promise((resolve, reject) => {
|
|
||||||
this.queue.push([action, payload, resolve]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return promise
|
|
||||||
.catch((err) => {
|
|
||||||
this.processQueue();
|
|
||||||
|
|
||||||
throw err;
|
|
||||||
})
|
|
||||||
.then((result) => {
|
|
||||||
this.processQueue();
|
|
||||||
|
|
||||||
// console.log('Work done in ', Date.now() - start);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
processQueue () {
|
|
||||||
let container = this._getContainer();
|
|
||||||
|
|
||||||
while (container && this.queue.length > 0) {
|
|
||||||
const [action, payload, resolve] = this.queue.shift();
|
|
||||||
|
|
||||||
resolve(container.action(action, payload));
|
|
||||||
container = this._getContainer();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default new WorkerPool();
|
|
@ -1,17 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
export default null;
|
|
@ -1,284 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import EthereumTx from 'ethereumjs-tx';
|
|
||||||
import accounts from './accounts';
|
|
||||||
import transactions from './transactions';
|
|
||||||
import { Middleware } from '../transport';
|
|
||||||
import { inNumber16 } from '../format/input';
|
|
||||||
import { phraseToWallet, phraseToAddress, verifySecret } from './ethkey';
|
|
||||||
import { randomPhrase } from '@parity/wordlist';
|
|
||||||
|
|
||||||
export default class LocalAccountsMiddleware extends Middleware {
|
|
||||||
constructor (transport) {
|
|
||||||
super(transport);
|
|
||||||
|
|
||||||
const register = this.register.bind(this);
|
|
||||||
|
|
||||||
register('eth_accounts', () => {
|
|
||||||
return accounts.accountAddresses();
|
|
||||||
});
|
|
||||||
|
|
||||||
register('eth_coinbase', () => {
|
|
||||||
return accounts.lastAddress;
|
|
||||||
});
|
|
||||||
|
|
||||||
register('parity_accountsInfo', () => {
|
|
||||||
return accounts.map(({ name }) => {
|
|
||||||
return { name };
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
register('parity_allAccountsInfo', () => {
|
|
||||||
return accounts.map(({ name, meta, uuid }) => {
|
|
||||||
return { name, meta, uuid };
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
register('parity_changePassword', ([address, oldPassword, newPassword]) => {
|
|
||||||
const account = accounts.get(address);
|
|
||||||
|
|
||||||
return account
|
|
||||||
.decryptPrivateKey(oldPassword)
|
|
||||||
.then((privateKey) => {
|
|
||||||
if (!privateKey) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
account.changePassword(privateKey, newPassword);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
register('parity_checkRequest', ([id]) => {
|
|
||||||
return transactions.hash(id) || Promise.resolve(null);
|
|
||||||
});
|
|
||||||
|
|
||||||
register('parity_dappsList', () => {
|
|
||||||
return [];
|
|
||||||
});
|
|
||||||
|
|
||||||
register('parity_defaultAccount', () => {
|
|
||||||
return accounts.dappsDefaultAddress;
|
|
||||||
});
|
|
||||||
|
|
||||||
register('parity_exportAccount', ([address, password]) => {
|
|
||||||
const account = accounts.get(address);
|
|
||||||
|
|
||||||
if (!password) {
|
|
||||||
password = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
return account.isValidPassword(password)
|
|
||||||
.then((isValid) => {
|
|
||||||
if (!isValid) {
|
|
||||||
throw new Error('Invalid password');
|
|
||||||
}
|
|
||||||
|
|
||||||
return account.export();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
register('parity_generateSecretPhrase', () => {
|
|
||||||
return randomPhrase(12);
|
|
||||||
});
|
|
||||||
|
|
||||||
register('parity_getNewDappsAddresses', () => {
|
|
||||||
return accounts.accountAddresses();
|
|
||||||
});
|
|
||||||
|
|
||||||
register('parity_getNewDappsDefaultAddress', () => {
|
|
||||||
return accounts.dappsDefaultAddress;
|
|
||||||
});
|
|
||||||
|
|
||||||
register('parity_hardwareAccountsInfo', () => {
|
|
||||||
return {};
|
|
||||||
});
|
|
||||||
|
|
||||||
register('parity_newAccountFromPhrase', ([phrase, password]) => {
|
|
||||||
return phraseToWallet(phrase)
|
|
||||||
.then((wallet) => {
|
|
||||||
return accounts.create(wallet.secret, password);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
register('parity_newAccountFromSecret', ([secret, password]) => {
|
|
||||||
return verifySecret(secret)
|
|
||||||
.then((isValid) => {
|
|
||||||
if (!isValid) {
|
|
||||||
throw new Error('Invalid secret key');
|
|
||||||
}
|
|
||||||
|
|
||||||
return accounts.create(secret, password);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
register('parity_newAccountFromWallet', ([json, password]) => {
|
|
||||||
if (!password) {
|
|
||||||
password = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
return accounts.restoreFromWallet(JSON.parse(json), password);
|
|
||||||
});
|
|
||||||
|
|
||||||
register('parity_setAccountMeta', ([address, meta]) => {
|
|
||||||
accounts.getLazyCreate(address).meta = meta;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
register('parity_setAccountName', ([address, name]) => {
|
|
||||||
accounts.getLazyCreate(address).name = name;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
register('parity_setNewDappsDefaultAddress', ([address]) => {
|
|
||||||
accounts.dappsDefaultAddress = address;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
register('parity_postTransaction', ([tx]) => {
|
|
||||||
if (!tx.from) {
|
|
||||||
tx.from = accounts.lastAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
tx.nonce = null;
|
|
||||||
tx.condition = null;
|
|
||||||
|
|
||||||
return transactions.add(tx);
|
|
||||||
});
|
|
||||||
|
|
||||||
register('parity_phraseToAddress', ([phrase]) => {
|
|
||||||
return phraseToAddress(phrase);
|
|
||||||
});
|
|
||||||
|
|
||||||
register('parity_useLocalAccounts', () => {
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
register('parity_listGethAccounts', () => {
|
|
||||||
return [];
|
|
||||||
});
|
|
||||||
|
|
||||||
register('parity_listOpenedVaults', () => {
|
|
||||||
return [];
|
|
||||||
});
|
|
||||||
|
|
||||||
register('parity_listRecentDapps', () => {
|
|
||||||
return {};
|
|
||||||
});
|
|
||||||
|
|
||||||
register('parity_listVaults', () => {
|
|
||||||
return [];
|
|
||||||
});
|
|
||||||
|
|
||||||
register('parity_wsUrl', () => {
|
|
||||||
// This is a hack, will be replaced by a `hostname` setting on the node itself
|
|
||||||
return `${window.location.hostname}:8546`;
|
|
||||||
});
|
|
||||||
|
|
||||||
register('parity_dappsUrl', () => {
|
|
||||||
// This is a hack, will be replaced by a `hostname` setting on the node itself
|
|
||||||
return `${window.location.hostname}:8545`;
|
|
||||||
});
|
|
||||||
|
|
||||||
register('parity_hashContent', () => {
|
|
||||||
throw new Error('Functionality unavailable on a public wallet.');
|
|
||||||
});
|
|
||||||
|
|
||||||
register('parity_killAccount', ([address, password]) => {
|
|
||||||
return accounts.remove(address, password);
|
|
||||||
});
|
|
||||||
|
|
||||||
register('parity_testPassword', ([address, password]) => {
|
|
||||||
const account = accounts.get(address);
|
|
||||||
|
|
||||||
return account.isValidPassword(password);
|
|
||||||
});
|
|
||||||
|
|
||||||
register('parity_upgradeReady', () => {
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
register('signer_confirmRequest', ([id, modify, password]) => {
|
|
||||||
const {
|
|
||||||
gasPrice,
|
|
||||||
gas: gasLimit,
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
value,
|
|
||||||
data
|
|
||||||
} = Object.assign(transactions.get(id), modify);
|
|
||||||
|
|
||||||
transactions.lock(id);
|
|
||||||
|
|
||||||
const account = accounts.get(from);
|
|
||||||
|
|
||||||
return Promise.all([
|
|
||||||
this.rpcRequest('parity_nextNonce', [from]),
|
|
||||||
account.decryptPrivateKey(password)
|
|
||||||
])
|
|
||||||
.catch((err) => {
|
|
||||||
transactions.unlock(id);
|
|
||||||
|
|
||||||
// transaction got unlocked, can propagate rejection further
|
|
||||||
throw err;
|
|
||||||
})
|
|
||||||
.then(([nonce, privateKey]) => {
|
|
||||||
if (!privateKey) {
|
|
||||||
transactions.unlock(id);
|
|
||||||
|
|
||||||
throw new Error('Invalid password');
|
|
||||||
}
|
|
||||||
|
|
||||||
const tx = new EthereumTx({
|
|
||||||
nonce,
|
|
||||||
to,
|
|
||||||
data,
|
|
||||||
gasLimit: inNumber16(gasLimit),
|
|
||||||
gasPrice: inNumber16(gasPrice),
|
|
||||||
value: inNumber16(value)
|
|
||||||
});
|
|
||||||
|
|
||||||
tx.sign(privateKey);
|
|
||||||
|
|
||||||
const serializedTx = `0x${tx.serialize().toString('hex')}`;
|
|
||||||
|
|
||||||
return this.rpcRequest('eth_sendRawTransaction', [serializedTx]);
|
|
||||||
})
|
|
||||||
.then((hash) => {
|
|
||||||
transactions.confirm(id, hash);
|
|
||||||
|
|
||||||
return {};
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
register('signer_generateAuthorizationToken', () => {
|
|
||||||
return '';
|
|
||||||
});
|
|
||||||
|
|
||||||
register('signer_rejectRequest', ([id]) => {
|
|
||||||
return transactions.reject(id);
|
|
||||||
});
|
|
||||||
|
|
||||||
register('signer_requestsToConfirm', () => {
|
|
||||||
return transactions.requestsToConfirm();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,157 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import LocalAccountsMiddleware from './localAccountsMiddleware';
|
|
||||||
import JsonRpcBase from '../transport/jsonRpcBase';
|
|
||||||
|
|
||||||
const RPC_RESPONSE = Symbol('RPC response');
|
|
||||||
const ADDRESS = '0x00a329c0648769a73afac7f9381e08fb43dbea72';
|
|
||||||
const SECRET = '0x4d5db4107d237df6a3d58ee5f70ae63d73d7658d4026f2eefd2f204c81682cb7';
|
|
||||||
const PASSWORD = 'password';
|
|
||||||
|
|
||||||
const FOO_PHRASE = 'foobar';
|
|
||||||
const FOO_PASSWORD = 'foopass';
|
|
||||||
const FOO_ADDRESS = '0x007ef7ac1058e5955e366ab9d6b6c4ebcc937e7e';
|
|
||||||
|
|
||||||
class MockedTransport extends JsonRpcBase {
|
|
||||||
_execute (method, params) {
|
|
||||||
return RPC_RESPONSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip till all CI runs on Node 8+
|
|
||||||
describe.skip('api/local/LocalAccountsMiddleware', function () {
|
|
||||||
this.timeout(30000);
|
|
||||||
|
|
||||||
let transport;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
transport = new MockedTransport();
|
|
||||||
transport.addMiddleware(LocalAccountsMiddleware);
|
|
||||||
|
|
||||||
// Same as `parity_newAccountFromPhrase` with empty phrase
|
|
||||||
return transport
|
|
||||||
.execute('parity_newAccountFromSecret', [SECRET, PASSWORD])
|
|
||||||
.catch((_err) => {
|
|
||||||
// Ignore the error - all instances of LocalAccountsMiddleware
|
|
||||||
// share account storage
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('registers all necessary methods', () => {
|
|
||||||
return Promise
|
|
||||||
.all([
|
|
||||||
'eth_accounts',
|
|
||||||
'eth_coinbase',
|
|
||||||
'parity_accountsInfo',
|
|
||||||
'parity_allAccountsInfo',
|
|
||||||
'parity_changePassword',
|
|
||||||
'parity_checkRequest',
|
|
||||||
'parity_defaultAccount',
|
|
||||||
'parity_generateSecretPhrase',
|
|
||||||
'parity_getNewDappsAddresses',
|
|
||||||
'parity_hardwareAccountsInfo',
|
|
||||||
'parity_newAccountFromPhrase',
|
|
||||||
'parity_newAccountFromSecret',
|
|
||||||
'parity_setAccountMeta',
|
|
||||||
'parity_setAccountName',
|
|
||||||
'parity_postTransaction',
|
|
||||||
'parity_phraseToAddress',
|
|
||||||
'parity_useLocalAccounts',
|
|
||||||
'parity_listGethAccounts',
|
|
||||||
'parity_listOpenedVaults',
|
|
||||||
'parity_listRecentDapps',
|
|
||||||
'parity_listVaults',
|
|
||||||
'parity_killAccount',
|
|
||||||
'parity_testPassword',
|
|
||||||
'signer_confirmRequest',
|
|
||||||
'signer_rejectRequest',
|
|
||||||
'signer_requestsToConfirm'
|
|
||||||
].map((method) => {
|
|
||||||
return transport
|
|
||||||
.execute(method)
|
|
||||||
.then((result) => {
|
|
||||||
expect(result).not.to.be.equal(RPC_RESPONSE);
|
|
||||||
})
|
|
||||||
// Some errors are expected here since we are calling methods
|
|
||||||
// without parameters.
|
|
||||||
.catch((_) => {});
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('allows non-registered methods through', () => {
|
|
||||||
return transport
|
|
||||||
.execute('eth_getBalance', ['0x407d73d8a49eeb85d32cf465507dd71d507100c1'])
|
|
||||||
.then((result) => {
|
|
||||||
expect(result).to.be.equal(RPC_RESPONSE);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('can handle `eth_accounts`', () => {
|
|
||||||
return transport
|
|
||||||
.execute('eth_accounts')
|
|
||||||
.then((accounts) => {
|
|
||||||
expect(accounts.length).to.be.equal(1);
|
|
||||||
expect(accounts[0]).to.be.equal(ADDRESS);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('can handle `parity_defaultAccount`', () => {
|
|
||||||
return transport
|
|
||||||
.execute('parity_defaultAccount')
|
|
||||||
.then((address) => {
|
|
||||||
expect(address).to.be.equal(ADDRESS);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('can handle `parity_phraseToAddress`', () => {
|
|
||||||
return transport
|
|
||||||
.execute('parity_phraseToAddress', [''])
|
|
||||||
.then((address) => {
|
|
||||||
expect(address).to.be.equal(ADDRESS);
|
|
||||||
|
|
||||||
return transport.execute('parity_phraseToAddress', [FOO_PHRASE]);
|
|
||||||
})
|
|
||||||
.then((address) => {
|
|
||||||
expect(address).to.be.equal(FOO_ADDRESS);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('can create and kill an account', () => {
|
|
||||||
return transport
|
|
||||||
.execute('parity_newAccountFromPhrase', [FOO_PHRASE, FOO_PASSWORD])
|
|
||||||
.then((address) => {
|
|
||||||
expect(address).to.be.equal(FOO_ADDRESS);
|
|
||||||
|
|
||||||
return transport.execute('eth_accounts');
|
|
||||||
})
|
|
||||||
.then((accounts) => {
|
|
||||||
expect(accounts.length).to.be.equal(2);
|
|
||||||
expect(accounts.includes(FOO_ADDRESS)).to.be.true;
|
|
||||||
|
|
||||||
return transport.execute('parity_killAccount', [FOO_ADDRESS, FOO_PASSWORD]);
|
|
||||||
})
|
|
||||||
.then((result) => {
|
|
||||||
expect(result).to.be.true;
|
|
||||||
|
|
||||||
return transport.execute('eth_accounts');
|
|
||||||
})
|
|
||||||
.then((accounts) => {
|
|
||||||
expect(accounts.length).to.be.equal(1);
|
|
||||||
expect(accounts.includes(FOO_ADDRESS)).to.be.false;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,147 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import { toHex } from '../util/format';
|
|
||||||
import { TransportError } from '../transport';
|
|
||||||
|
|
||||||
const AWAITING = Symbol('awaiting');
|
|
||||||
const LOCKED = Symbol('locked');
|
|
||||||
const CONFIRMED = Symbol('confirmed');
|
|
||||||
const REJECTED = Symbol('rejected');
|
|
||||||
|
|
||||||
class Transactions {
|
|
||||||
constructor () {
|
|
||||||
this.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
// should only really be needed in the constructor and tests
|
|
||||||
reset () {
|
|
||||||
this._id = 1;
|
|
||||||
this._states = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
nextId () {
|
|
||||||
return toHex(this._id++);
|
|
||||||
}
|
|
||||||
|
|
||||||
add (tx) {
|
|
||||||
const id = this.nextId();
|
|
||||||
|
|
||||||
this._states[id] = {
|
|
||||||
status: AWAITING,
|
|
||||||
transaction: tx
|
|
||||||
};
|
|
||||||
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
get (id) {
|
|
||||||
const state = this._states[id];
|
|
||||||
|
|
||||||
if (!state || state.status !== AWAITING) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return state.transaction;
|
|
||||||
}
|
|
||||||
|
|
||||||
lock (id) {
|
|
||||||
const state = this._states[id];
|
|
||||||
|
|
||||||
if (!state || state.status !== AWAITING) {
|
|
||||||
throw new Error('Trying to lock an invalid transaction');
|
|
||||||
}
|
|
||||||
|
|
||||||
state.status = LOCKED;
|
|
||||||
}
|
|
||||||
|
|
||||||
unlock (id) {
|
|
||||||
const state = this._states[id];
|
|
||||||
|
|
||||||
if (!state || state.status !== LOCKED) {
|
|
||||||
throw new Error('Trying to unlock an invalid transaction');
|
|
||||||
}
|
|
||||||
|
|
||||||
state.status = AWAITING;
|
|
||||||
}
|
|
||||||
|
|
||||||
hash (id) {
|
|
||||||
const state = this._states[id];
|
|
||||||
|
|
||||||
if (!state) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (state.status) {
|
|
||||||
case REJECTED:
|
|
||||||
throw TransportError.requestRejected();
|
|
||||||
case CONFIRMED:
|
|
||||||
return state.hash;
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
confirm (id, hash) {
|
|
||||||
const state = this._states[id];
|
|
||||||
const status = state ? state.status : null;
|
|
||||||
|
|
||||||
switch (status) {
|
|
||||||
case AWAITING: break;
|
|
||||||
case LOCKED: break;
|
|
||||||
default: throw new Error('Trying to confirm an invalid transaction');
|
|
||||||
}
|
|
||||||
|
|
||||||
state.hash = hash;
|
|
||||||
state.status = CONFIRMED;
|
|
||||||
}
|
|
||||||
|
|
||||||
reject (id) {
|
|
||||||
const state = this._states[id];
|
|
||||||
|
|
||||||
if (!state) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
state.status = REJECTED;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
requestsToConfirm () {
|
|
||||||
const result = [];
|
|
||||||
|
|
||||||
Object.keys(this._states).forEach((id) => {
|
|
||||||
const state = this._states[id];
|
|
||||||
|
|
||||||
if (state.status === AWAITING) {
|
|
||||||
result.push({
|
|
||||||
id,
|
|
||||||
origin: {
|
|
||||||
signer: '0x0'
|
|
||||||
},
|
|
||||||
payload: {
|
|
||||||
sendTransaction: state.transaction
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default new Transactions();
|
|
@ -1,85 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import transactions from './transactions';
|
|
||||||
import { TransportError } from '../transport/error';
|
|
||||||
|
|
||||||
const DUMMY_TX = 'dummy';
|
|
||||||
|
|
||||||
describe('api/local/transactions', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
transactions.reset();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('can store transactions', () => {
|
|
||||||
const id1 = transactions.add(DUMMY_TX);
|
|
||||||
const id2 = transactions.add(DUMMY_TX);
|
|
||||||
const requests = transactions.requestsToConfirm();
|
|
||||||
|
|
||||||
expect(id1).to.be.equal('0x1');
|
|
||||||
expect(id2).to.be.equal('0x2');
|
|
||||||
expect(requests.length).to.be.equal(2);
|
|
||||||
expect(requests[0].id).to.be.equal(id1);
|
|
||||||
expect(requests[1].id).to.be.equal(id2);
|
|
||||||
expect(requests[0].payload.sendTransaction).to.be.equal(DUMMY_TX);
|
|
||||||
expect(requests[1].payload.sendTransaction).to.be.equal(DUMMY_TX);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('can confirm transactions', () => {
|
|
||||||
const id1 = transactions.add(DUMMY_TX);
|
|
||||||
const id2 = transactions.add(DUMMY_TX);
|
|
||||||
|
|
||||||
const hash1 = '0x1111111111111111111111111111111111111111';
|
|
||||||
const hash2 = '0x2222222222222222222222222222222222222222';
|
|
||||||
|
|
||||||
transactions.confirm(id1, hash1);
|
|
||||||
transactions.confirm(id2, hash2);
|
|
||||||
|
|
||||||
const requests = transactions.requestsToConfirm();
|
|
||||||
|
|
||||||
expect(requests.length).to.be.equal(0);
|
|
||||||
expect(transactions.hash(id1)).to.be.equal(hash1);
|
|
||||||
expect(transactions.hash(id2)).to.be.equal(hash2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('can reject transactions', () => {
|
|
||||||
const id = transactions.add(DUMMY_TX);
|
|
||||||
|
|
||||||
transactions.reject(id);
|
|
||||||
|
|
||||||
const requests = transactions.requestsToConfirm();
|
|
||||||
|
|
||||||
expect(requests.length).to.be.equal(0);
|
|
||||||
expect(() => transactions.hash(id)).to.throw(TransportError);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('can lock and confirm transactions', () => {
|
|
||||||
const id = transactions.add(DUMMY_TX);
|
|
||||||
const hash = '0x1111111111111111111111111111111111111111';
|
|
||||||
|
|
||||||
transactions.lock(id);
|
|
||||||
|
|
||||||
const requests = transactions.requestsToConfirm();
|
|
||||||
|
|
||||||
expect(requests.length).to.be.equal(0);
|
|
||||||
expect(transactions.get(id)).to.be.null;
|
|
||||||
expect(transactions.hash(id)).to.be.null;
|
|
||||||
|
|
||||||
transactions.confirm(id, hash);
|
|
||||||
|
|
||||||
expect(transactions.hash(id)).to.be.equal(hash);
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,41 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@parity/api",
|
|
||||||
"description": "The Parity Promise-based API library for interfacing with Ethereum over RPC",
|
|
||||||
"version": "0.0.0",
|
|
||||||
"main": "index.js",
|
|
||||||
"author": "Parity Team <admin@parity.io>",
|
|
||||||
"maintainers": [
|
|
||||||
"Jaco Greeff",
|
|
||||||
"Nicolas Gotchac"
|
|
||||||
],
|
|
||||||
"contributors": [],
|
|
||||||
"license": "GPL-3.0",
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git+https://github.com/paritytech/parity.git"
|
|
||||||
},
|
|
||||||
"keywords": [
|
|
||||||
"Ethereum",
|
|
||||||
"API",
|
|
||||||
"RPC",
|
|
||||||
"Parity",
|
|
||||||
"Promise"
|
|
||||||
],
|
|
||||||
"scripts": {
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@parity/abi": "file:../abi",
|
|
||||||
"@parity/jsonrpc": "file:../jsonrpc",
|
|
||||||
"bignumber.js": "3.0.1",
|
|
||||||
"blockies": "0.0.2",
|
|
||||||
"es6-error": "4.0.0",
|
|
||||||
"ethereumjs-tx": "1.2.5",
|
|
||||||
"eventemitter3": "2.0.2",
|
|
||||||
"js-sha3": "0.5.5",
|
|
||||||
"keythereum": "0.4.6",
|
|
||||||
"node-fetch": "1.6.3",
|
|
||||||
"secp256k1": "3.2.5"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import { Http as Transport } from '../transport';
|
|
||||||
|
|
||||||
export default class Http extends Transport {
|
|
||||||
send = (method, params, callback) => {
|
|
||||||
this
|
|
||||||
._execute(method, params)
|
|
||||||
.then((result) => callback(null, result))
|
|
||||||
.catch((error) => callback(error));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import Ws from './ws';
|
|
||||||
|
|
||||||
export Http from './http';
|
|
||||||
export PostMessage from './postMessage';
|
|
||||||
export PromiseProvider from './promise';
|
|
||||||
|
|
||||||
const WsSecure = Ws;
|
|
||||||
|
|
||||||
export {
|
|
||||||
Ws,
|
|
||||||
WsSecure
|
|
||||||
};
|
|
@ -1,102 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
export default class PostMessage {
|
|
||||||
id = 0;
|
|
||||||
_messages = {};
|
|
||||||
|
|
||||||
constructor (token, destination) {
|
|
||||||
this._token = token;
|
|
||||||
this._destination = destination;
|
|
||||||
|
|
||||||
window.addEventListener('message', this.receiveMessage, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
addMiddleware () {
|
|
||||||
}
|
|
||||||
|
|
||||||
_send (data) {
|
|
||||||
this._destination.postMessage(data, '*');
|
|
||||||
}
|
|
||||||
|
|
||||||
send = (method, params, callback) => {
|
|
||||||
const id = ++this.id;
|
|
||||||
|
|
||||||
this._messages[id] = { callback };
|
|
||||||
this._send({
|
|
||||||
id,
|
|
||||||
from: this._token,
|
|
||||||
method,
|
|
||||||
params,
|
|
||||||
token: this._token
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
subscribe = (api, callback, params) => {
|
|
||||||
// console.log('paritySubscribe', JSON.stringify(params), api, callback);
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const id = ++this.id;
|
|
||||||
|
|
||||||
this._messages[id] = { callback, resolve, reject, subscription: true, initial: true };
|
|
||||||
this._send({
|
|
||||||
id,
|
|
||||||
from: this._token,
|
|
||||||
api,
|
|
||||||
params,
|
|
||||||
token: this._token
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
unsubscribe = (subId) => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const id = ++this.id;
|
|
||||||
|
|
||||||
this._messages[id] = { callback: (e, v) => e ? reject(e) : resolve(v) };
|
|
||||||
this._send({
|
|
||||||
id,
|
|
||||||
from: this._token,
|
|
||||||
subId,
|
|
||||||
token: this._token
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
unsubscribeAll () {
|
|
||||||
return this.unsubscribe('*');
|
|
||||||
}
|
|
||||||
|
|
||||||
receiveMessage = ({ data: { id, error, from, token, result }, origin, source }) => {
|
|
||||||
if (from !== 'shell' || token !== this._token) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
console.error(from, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._messages[id].subscription) {
|
|
||||||
// console.log('subscription', result, 'initial?', this._messages[id].initial);
|
|
||||||
this._messages[id].initial
|
|
||||||
? this._messages[id].resolve(result)
|
|
||||||
: this._messages[id].callback(error && new Error(error), result);
|
|
||||||
this._messages[id].initial = false;
|
|
||||||
} else {
|
|
||||||
this._messages[id].callback(error && new Error(error), result);
|
|
||||||
this._messages[id] = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
export default class PromiseProvider {
|
|
||||||
constructor (provider) {
|
|
||||||
this.provider = provider;
|
|
||||||
}
|
|
||||||
|
|
||||||
send = (method, ...params) => {
|
|
||||||
if (!this.provider.send) {
|
|
||||||
// old-style transport interface for backwards compatibility
|
|
||||||
return this.provider.execute(method, params);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
this.provider.send(method, params, (error, result) => {
|
|
||||||
if (error) {
|
|
||||||
reject(error);
|
|
||||||
} else {
|
|
||||||
resolve(result);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import { Ws as Transport } from '../transport';
|
|
||||||
|
|
||||||
export default class Ws extends Transport {
|
|
||||||
send = (method, params, callback) => {
|
|
||||||
this
|
|
||||||
._execute(method, params)
|
|
||||||
.then((result) => callback(null, result))
|
|
||||||
.catch((error) => callback(error));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,227 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
import PubsubBase from '../pubsubBase';
|
|
||||||
|
|
||||||
import { inAddress, inBlockNumber, inHex, inNumber16, inOptions, inFilter } from '../../format/input';
|
|
||||||
import { outAddress, outBlock, outNumber, outTransaction, outSyncing, outReceipt, outLog } from '../../format/output';
|
|
||||||
|
|
||||||
export default class Eth extends PubsubBase {
|
|
||||||
constructor (provider) {
|
|
||||||
super(provider);
|
|
||||||
this._api = 'parity';
|
|
||||||
}
|
|
||||||
|
|
||||||
newHeads (callback) {
|
|
||||||
return this.addListener('eth', 'newHeads', callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
logs (callback) {
|
|
||||||
throw Error('not supported yet');
|
|
||||||
}
|
|
||||||
|
|
||||||
// eth API
|
|
||||||
protocolVersion (callback) {
|
|
||||||
return this.addListener(this._api, 'eth_protocolVersion', callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
syncing (callback) {
|
|
||||||
return this.addListener(this._api, 'eth_syncing', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outSyncing(data));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
hashrate (callback) {
|
|
||||||
return this.addListener(this._api, 'eth_hashrate', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outNumber(data));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
coinbase (callback) {
|
|
||||||
return this.addListener(this._api, 'eth_coinbase', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outAddress(data));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
mining (callback) {
|
|
||||||
return this.addListener(this._api, 'eth_mining', callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
gasPrice (callback) {
|
|
||||||
return this.addListener(this._api, 'eth_gasPrice', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outNumber(data));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
accounts (callback) {
|
|
||||||
return this.addListener(this._api, 'eth_accounts', (error, accounts) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, (accounts || []).map(outAddress));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
blockNumber (callback) {
|
|
||||||
return this.addListener(this._api, 'eth_blockNumber', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outNumber(data));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getBalance (callback, address, blockNumber = 'latest') {
|
|
||||||
return this.addListener(this._api, 'eth_getBalance', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outNumber(data));
|
|
||||||
}, [inAddress(address), inBlockNumber(blockNumber)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
getStorageAt (callback, address, index = 0, blockNumber = 'latest') {
|
|
||||||
return this.addListener(this._api, 'eth_getStorageAt', callback, [inAddress(address), inNumber16(index), inBlockNumber(blockNumber)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
getBlockByHash (callback, hash, full = false) {
|
|
||||||
return this.addListener(this._api, 'eth_getBlockByHash', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outBlock(data));
|
|
||||||
}, [inHex(hash), full]);
|
|
||||||
}
|
|
||||||
|
|
||||||
getBlockByNumber (callback, blockNumber = 'latest', full = false) {
|
|
||||||
return this.addListener(this._api, 'eth_getBlockByNumber', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outBlock(data));
|
|
||||||
}, [inBlockNumber(blockNumber), full]);
|
|
||||||
}
|
|
||||||
|
|
||||||
getTransactionCount (callback, address, blockNumber = 'latest') {
|
|
||||||
return this.addListener(this._api, 'eth_getTransactionCount', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outNumber(data));
|
|
||||||
}, [inAddress(address), inBlockNumber(blockNumber)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
getBlockTransactionCountByHash (callback, hash) {
|
|
||||||
return this.addListener(this._api, 'eth_getBlockTransactionCountByHash', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outNumber(data));
|
|
||||||
}, [inHex(hash)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
getBlockTransactionCountByNumber (callback, blockNumber = 'latest') {
|
|
||||||
return this.addListener(this._api, 'eth_getBlockTransactionCountByNumber', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outNumber(data));
|
|
||||||
}, [inBlockNumber(blockNumber)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
getUncleCountByBlockHash (callback, hash) {
|
|
||||||
return this.addListener(this._api, 'eth_getUncleCountByBlockHash', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outNumber(data));
|
|
||||||
}, [inHex(hash)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
getUncleCountByBlockNumber (callback, blockNumber = 'latest') {
|
|
||||||
return this.addListener(this._api, 'eth_getUncleCountByBlockNumber', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outNumber(data));
|
|
||||||
}, [inBlockNumber(blockNumber)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
getCode (callback, address, blockNumber = 'latest') {
|
|
||||||
return this.addListener(this._api, 'eth_getCode', callback, [inAddress(address), inBlockNumber(blockNumber)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
call (callback, options, blockNumber = 'latest') {
|
|
||||||
return this.addListener(this._api, 'eth_call', callback, [inOptions(options), inBlockNumber(blockNumber)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
estimateGas (callback, options) {
|
|
||||||
return this.addListener(this._api, 'eth_estimateGas', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outNumber(data));
|
|
||||||
}, [inOptions(options)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
getTransactionByHash (callback, hash) {
|
|
||||||
return this.addListener(this._api, 'eth_getTransactionByHash', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outTransaction(data));
|
|
||||||
}, [inHex(hash)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
getTransactionByBlockHashAndIndex (callback, hash, index = 0) {
|
|
||||||
return this.addListener(this._api, 'eth_getTransactionByBlockHashAndIndex', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outTransaction(data));
|
|
||||||
}, [inHex(hash), inNumber16(index)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
getTransactionByBlockNumberAndIndex (callback, blockNumber = 'latest', index = 0) {
|
|
||||||
return this.addListener(this._api, 'eth_getTransactionByBlockNumberAndIndex', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outTransaction(data));
|
|
||||||
}, [inBlockNumber(blockNumber), inNumber16(index)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
getTransactionReceipt (callback, txhash) {
|
|
||||||
return this.addListener(this._api, 'eth_getTransactionReceipt', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outReceipt(data));
|
|
||||||
}, [inHex(txhash)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
getUncleByBlockHashAndIndex (callback, hash, index = 0) {
|
|
||||||
return this.addListener(this._api, 'eth_getUncleByBlockHashAndIndex', callback, [inHex(hash), inNumber16(index)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
getUncleByBlockNumberAndIndex (callback, blockNumber = 'latest', index = 0) {
|
|
||||||
return this.addListener(this._api, 'eth_getUncleByBlockNumberAndIndex', callback, [inBlockNumber(blockNumber), inNumber16(index)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
getLogs (callback, options) {
|
|
||||||
return this.addListener(this._api, 'eth_getLogs', (error, logs) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, (logs) => logs.map(outLog));
|
|
||||||
}, [inFilter(options)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
getWork (callback) {
|
|
||||||
return this.addListener(this._api, 'eth_getWork', callback);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
export default from './eth';
|
|
@ -1,16 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
export default from './pubsub';
|
|
@ -1,16 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
export default from './net';
|
|
@ -1,42 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
import PubsubBase from '../pubsubBase';
|
|
||||||
|
|
||||||
import { outNumber } from '../../format/output';
|
|
||||||
|
|
||||||
export default class Net extends PubsubBase {
|
|
||||||
constructor (provider) {
|
|
||||||
super(provider);
|
|
||||||
this._api = 'parity';
|
|
||||||
}
|
|
||||||
|
|
||||||
// net API
|
|
||||||
version (callback) {
|
|
||||||
return this.addListener(this._api, 'net_version', callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
peerCount (callback) {
|
|
||||||
return this.addListener(this._api, 'net_peerCount', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outNumber(data));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
listening (callback) {
|
|
||||||
return this.addListener(this._api, 'net_listening', callback);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
export default from './parity';
|
|
@ -1,355 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import PubsubBase from '../pubsubBase';
|
|
||||||
import { inAddress, inBlockNumber, inData, inHex, inDeriveHash, inDeriveIndex } from '../../format/input';
|
|
||||||
import { outAccountInfo, outAddress, outBlock, outChainStatus, outHistogram, outHwAccountInfo, outNodeKind, outNumber, outPeers, outTransaction, outAddresses, outRecentDapps, outVaultMeta } from '../../format/output';
|
|
||||||
|
|
||||||
export default class Parity extends PubsubBase {
|
|
||||||
constructor (provider) {
|
|
||||||
super(provider);
|
|
||||||
this._api = 'parity';
|
|
||||||
}
|
|
||||||
|
|
||||||
// parity API
|
|
||||||
accountsInfo (callback) {
|
|
||||||
return this.addListener(this._api, 'parity_accountsInfo', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outAccountInfo(data));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
hardwareAccountsInfo (callback) {
|
|
||||||
return this.addListener(this._api, 'parity_hardwareAccountsInfo', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outHwAccountInfo(data));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultAccount (callback) {
|
|
||||||
return this.addListener(this._api, 'parity_defaultAccount', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outAddress(data));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
transactionsLimit (callback) {
|
|
||||||
return this.addListener(this._api, 'parity_transactionsLimit', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outNumber(data));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
extraData (callback) {
|
|
||||||
return this.addListener(this._api, 'parity_extraData', callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
gasFloorTarget (callback) {
|
|
||||||
return this.addListener(this._api, 'parity_gasFloorTarget', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outNumber(data));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
gasCeilTarget (callback) {
|
|
||||||
return this.addListener(this._api, 'parity_gasCeilTarget', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outNumber(data));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
minGasPrice (callback) {
|
|
||||||
return this.addListener(this._api, 'parity_minGasPrice', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outNumber(data));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
devLogs (callback) {
|
|
||||||
return this.addListener(this._api, 'parity_devLogs', callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
devLogsLevels (callback) {
|
|
||||||
return this.addListener(this._api, 'parity_devLogsLevels', callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
netChain (callback) {
|
|
||||||
return this.addListener(this._api, 'parity_netChain', callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
netPeers (callback) {
|
|
||||||
return this.addListener(this._api, 'parity_netPeers', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outPeers(data));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
netPort (callback) {
|
|
||||||
return this.addListener(this._api, 'parity_netPort', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outNumber(data));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
rpcSettings (callback) {
|
|
||||||
return this.addListener(this._api, 'parity_rpcSettings', callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
nodeName (callback) {
|
|
||||||
return this.addListener(this._api, 'parity_nodeName', callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultExtraData (callback) {
|
|
||||||
return this.addListener(this._api, 'parity_defaultExtraData', callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
gasPriceHistogram (callback) {
|
|
||||||
return this.addListener(this._api, 'parity_gasPriceHistogram', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outHistogram(data));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
unsignedTransactionsCount (callback) {
|
|
||||||
return this.addListener(this._api, 'parity_unsignedTransactionsCount', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outNumber(data));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
registryAddress (callback) {
|
|
||||||
return this.addListener(this._api, 'parity_registryAddress', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outAddress(data));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
listAccounts (callback, count, offset = null, blockNumber = 'latest') {
|
|
||||||
return this.addListener(this._api, 'parity_listAccounts', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, (data) => (data || []).map(outAddress));
|
|
||||||
}, [count, inAddress(offset), inBlockNumber(blockNumber)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
listStorageKeys (callback, address, count, hash = null, blockNumber = 'latest') {
|
|
||||||
return this.addListener(this._api, 'parity_listStorageKeys', callback, [inAddress(address), count, inHex(hash), inBlockNumber(blockNumber)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
pendingTransactions (callback) {
|
|
||||||
return this.addListener(this._api, 'parity_pendingTransactions', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outTransaction(data));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
futureTransactions (callback) {
|
|
||||||
return this.addListener(this._api, 'parity_futureTransactions', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outTransaction(data));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pendingTransactionsStats (callback) {
|
|
||||||
return this.addListener(this._api, 'parity_pendingTransactionsStats', callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
localTransactions (callback) {
|
|
||||||
return this.addListener(this._api, 'parity_localTransactions', (error, transactions) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, transactions => {
|
|
||||||
Object.values(transactions)
|
|
||||||
.filter(tx => tx.transaction)
|
|
||||||
.map(tx => {
|
|
||||||
tx.transaction = outTransaction(tx.transaction);
|
|
||||||
});
|
|
||||||
return transactions;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
dappsUrl (callback) {
|
|
||||||
return this.addListener(this._api, 'parity_dappsUrl', callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
wsUrl (callback) {
|
|
||||||
return this.addListener(this._api, 'parity_wsUrl', callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
nextNonce (callback, account) {
|
|
||||||
return this.addListener(this._api, 'parity_nextNonce', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outNumber(data));
|
|
||||||
}, [inAddress(account)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
mode (callback) {
|
|
||||||
return this.addListener(this._api, 'parity_mode', callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
chain (callback) {
|
|
||||||
return this.addListener(this._api, 'parity_chain', callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
enode (callback) {
|
|
||||||
return this.addListener(this._api, 'parity_enode', callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
consensusCapability (callback) {
|
|
||||||
return this.addListener(this._api, 'parity_consensusCapability', callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
versionInfo (callback) {
|
|
||||||
return this.addListener(this._api, 'parity_versionInfo', callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
releasesInfo (callback) {
|
|
||||||
return this.addListener(this._api, 'parity_releasesInfo', callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
chainStatus (callback) {
|
|
||||||
return this.addListener(this._api, 'parity_chainStatus', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outChainStatus(data));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
nodeKind (callback) {
|
|
||||||
return this.addListener(this._api, 'parity_nodeKind', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outNodeKind(data));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getBlockHeaderByNumber (callback, blockNumber = 'latest') {
|
|
||||||
return this.addListener(this._api, 'parity_getBlockHeaderByNumber', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outBlock(data));
|
|
||||||
}, [inBlockNumber(blockNumber)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
cidV0 (callback, data) {
|
|
||||||
return this.addListener(this._api, 'parity_cidV0', callback, [inData(data)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// parity accounts API (only secure API or configured to be exposed)
|
|
||||||
allAccountsInfo (callback) {
|
|
||||||
return this._addListener(this._api, 'parity_allAccountsInfo', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outAccountInfo(data));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getDappAddresses (callback, dappId) {
|
|
||||||
return this._addListener(this._api, 'parity_getDappAddresses', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outAddresses(data));
|
|
||||||
}, [dappId]);
|
|
||||||
}
|
|
||||||
|
|
||||||
getDappDefaultAddress (callback, dappId) {
|
|
||||||
return this._addListener(this._api, 'parity_getDappDefaultAddress', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outAddress(data));
|
|
||||||
}, [dappId]);
|
|
||||||
}
|
|
||||||
|
|
||||||
getNewDappsAddresses (callback) {
|
|
||||||
return this._addListener(this._api, 'parity_getDappDefaultAddress', (error, addresses) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, addresses ? addresses.map(outAddress) : null);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getNewDappsDefaultAddress (callback) {
|
|
||||||
return this._addListener(this._api, 'parity_getNewDappsDefaultAddress', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outAddress(data));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
listRecentDapps (callback) {
|
|
||||||
return this._addListener(this._api, 'parity_listRecentDapps', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outRecentDapps(data));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
listGethAccounts (callback) {
|
|
||||||
return this._addListener(this._api, 'parity_listGethAccounts', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outAddresses(data));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
listVaults (callback) {
|
|
||||||
return this._addListener(this._api, 'parity_listVaults', callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
listOpenedVaults (callback) {
|
|
||||||
return this._addListener(this._api, 'parity_listOpenedVaults', callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
getVaultMeta (callback, vaultName) {
|
|
||||||
return this._addListener(this._api, 'parity_getVaultMeta', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outVaultMeta(data));
|
|
||||||
}, [vaultName]);
|
|
||||||
}
|
|
||||||
|
|
||||||
deriveAddressHash (callback, address, password, hash, shouldSave) {
|
|
||||||
return this._addListener(this._api, 'parity_deriveAddressHash', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outAddress(data));
|
|
||||||
}, [inAddress(address), password, inDeriveHash(hash), !!shouldSave]);
|
|
||||||
}
|
|
||||||
|
|
||||||
deriveAddressIndex (callback, address, password, index, shouldSave) {
|
|
||||||
return this._addListener(this._api, 'parity_deriveAddressIndex', (error, data) => {
|
|
||||||
error
|
|
||||||
? callback(error)
|
|
||||||
: callback(null, outAddress(data));
|
|
||||||
}, [inAddress(address), password, inDeriveIndex(index), !!shouldSave]);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,50 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import Eth from './eth';
|
|
||||||
import Parity from './parity';
|
|
||||||
import Net from './net';
|
|
||||||
|
|
||||||
import { isFunction } from '../util/types';
|
|
||||||
|
|
||||||
export default class Pubsub {
|
|
||||||
constructor (provider) {
|
|
||||||
if (!provider || !isFunction(provider.subscribe)) {
|
|
||||||
throw new Error('Pubsub API needs transport with subscribe() function defined. (WebSocket)');
|
|
||||||
}
|
|
||||||
|
|
||||||
this._eth = new Eth(provider);
|
|
||||||
this._net = new Net(provider);
|
|
||||||
this._parity = new Parity(provider);
|
|
||||||
}
|
|
||||||
|
|
||||||
get net () {
|
|
||||||
return this._net;
|
|
||||||
}
|
|
||||||
|
|
||||||
get eth () {
|
|
||||||
return this._eth;
|
|
||||||
}
|
|
||||||
|
|
||||||
get parity () {
|
|
||||||
return this._parity;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsubscribe (subscriptionIds) {
|
|
||||||
// subscriptions are namespace independent. Thus we can simply removeListener from any.
|
|
||||||
return this._parity.removeListener(subscriptionIds);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,613 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import BigNumber from 'bignumber.js';
|
|
||||||
import { TEST_WS_URL, mockWs } from '../../../test/mockRpc';
|
|
||||||
import { isBigNumber } from '../../../test/types';
|
|
||||||
|
|
||||||
import { WsSecure } from '../provider';
|
|
||||||
import Pubsub from './pubsub';
|
|
||||||
|
|
||||||
describe('api/pubsub/Pubsub', () => {
|
|
||||||
let scope;
|
|
||||||
let instance;
|
|
||||||
const address = '0x63Cf90D3f0410092FC0fca41846f596223979195';
|
|
||||||
|
|
||||||
describe('accountsInfo', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
scope = mockWs([{ method: 'parity_subscribe', reply: 2, subscription: {
|
|
||||||
method: 'parity_subscription',
|
|
||||||
params: {
|
|
||||||
result: {
|
|
||||||
'0x63cf90d3f0410092fc0fca41846f596223979195': {
|
|
||||||
name: 'name', uuid: 'uuid', meta: '{"data":"data"}'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
subscription: 2
|
|
||||||
}
|
|
||||||
} }]);
|
|
||||||
instance = new Pubsub(new WsSecure(TEST_WS_URL));
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
scope.stop();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('retrieves the available account info', (done) => {
|
|
||||||
instance.parity.accountsInfo((error, result) => {
|
|
||||||
expect(error).to.be.null;
|
|
||||||
expect(result).to.deep.equal({
|
|
||||||
'0x63Cf90D3f0410092FC0fca41846f596223979195': {
|
|
||||||
name: 'name', uuid: 'uuid', meta: {
|
|
||||||
data: 'data'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Unsubscribe', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
scope = mockWs([{ method: 'parity_subscribe', reply: 2 },
|
|
||||||
{ method: 'parity_unsubscribe', reply: true }]);
|
|
||||||
instance = new Pubsub(new WsSecure(TEST_WS_URL));
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
scope.stop();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Promise gets resolved on success.', (done) => {
|
|
||||||
instance.parity.accountsInfo().then(s => {
|
|
||||||
instance.parity.unsubscribe(s).then(b => {
|
|
||||||
expect(b).to.be.true;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('chainStatus', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
scope = mockWs([{ method: 'parity_subscribe', reply: 2, subscription: {
|
|
||||||
method: 'parity_subscription',
|
|
||||||
params: {
|
|
||||||
result: {
|
|
||||||
'blockGap': [0x123, 0x456]
|
|
||||||
},
|
|
||||||
subscription: 2
|
|
||||||
}
|
|
||||||
} }]);
|
|
||||||
instance = new Pubsub(new WsSecure(TEST_WS_URL));
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
scope.stop();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('retrieves the chain status', (done) => {
|
|
||||||
instance.parity.chainStatus((error, result) => {
|
|
||||||
expect(error).to.be.null;
|
|
||||||
expect(result).to.deep.equal({
|
|
||||||
'blockGap': [new BigNumber(0x123), new BigNumber(0x456)]
|
|
||||||
});
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('gasFloorTarget', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
scope = mockWs([{ method: 'parity_subscribe', reply: 2, subscription: {
|
|
||||||
method: 'parity_subscription',
|
|
||||||
params: {
|
|
||||||
result: '0x123456',
|
|
||||||
subscription: 2
|
|
||||||
}
|
|
||||||
} }]);
|
|
||||||
instance = new Pubsub(new WsSecure(TEST_WS_URL));
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
scope.stop();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns the gasfloor, formatted', (done) => {
|
|
||||||
instance.parity.gasFloorTarget((error, result) => {
|
|
||||||
expect(error).to.be.null;
|
|
||||||
expect(isBigNumber(result)).to.be.true;
|
|
||||||
expect(result.eq(0x123456)).to.be.true;
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('transactionsLimit', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
scope = mockWs([{ method: 'parity_subscribe', reply: 2, subscription: {
|
|
||||||
method: 'parity_subscription',
|
|
||||||
params: {
|
|
||||||
result: 1024,
|
|
||||||
subscription: 2
|
|
||||||
}
|
|
||||||
} }]);
|
|
||||||
instance = new Pubsub(new WsSecure(TEST_WS_URL));
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
scope.stop();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns the tx limit, formatted', (done) => {
|
|
||||||
instance.parity.transactionsLimit((error, result) => {
|
|
||||||
expect(error).to.be.null;
|
|
||||||
expect(isBigNumber(result)).to.be.true;
|
|
||||||
expect(result.eq(1024)).to.be.true;
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('minGasPrice', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
scope = mockWs([{ method: 'parity_subscribe', reply: 2, subscription: {
|
|
||||||
method: 'parity_subscription',
|
|
||||||
params: {
|
|
||||||
result: '0x123456',
|
|
||||||
subscription: 2
|
|
||||||
}
|
|
||||||
} }]);
|
|
||||||
instance = new Pubsub(new WsSecure(TEST_WS_URL));
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
scope.stop();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns the min gasprice, formatted', (done) => {
|
|
||||||
instance.parity.minGasPrice((error, result) => {
|
|
||||||
expect(error).to.be.null;
|
|
||||||
expect(isBigNumber(result)).to.be.true;
|
|
||||||
expect(result.eq(0x123456)).to.be.true;
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('netPeers', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
scope = mockWs([{ method: 'parity_subscribe', reply: 2, subscription: {
|
|
||||||
method: 'parity_subscription',
|
|
||||||
params: {
|
|
||||||
result: { active: 123, connected: 456, max: 789, peers: [] },
|
|
||||||
subscription: 2
|
|
||||||
}
|
|
||||||
} }]);
|
|
||||||
instance = new Pubsub(new WsSecure(TEST_WS_URL));
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
scope.stop();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns the peer structure, formatted', (done) => {
|
|
||||||
instance.parity.netPeers((error, peers) => {
|
|
||||||
expect(error).to.be.null;
|
|
||||||
expect(peers.active.eq(123)).to.be.true;
|
|
||||||
expect(peers.connected.eq(456)).to.be.true;
|
|
||||||
expect(peers.max.eq(789)).to.be.true;
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('netPort', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
scope = mockWs([{ method: 'parity_subscribe', reply: 2, subscription: {
|
|
||||||
method: 'parity_subscription',
|
|
||||||
params: {
|
|
||||||
result: 33030,
|
|
||||||
subscription: 2
|
|
||||||
}
|
|
||||||
} }]);
|
|
||||||
instance = new Pubsub(new WsSecure(TEST_WS_URL));
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
scope.stop();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns the connected port, formatted', (done) => {
|
|
||||||
instance.parity.netPort((error, count) => {
|
|
||||||
expect(error).to.be.null;
|
|
||||||
expect(isBigNumber(count)).to.be.true;
|
|
||||||
expect(count.eq(33030)).to.be.true;
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Eth API
|
|
||||||
describe('accounts', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
scope = mockWs([{ method: 'parity_subscribe', reply: 2, subscription: {
|
|
||||||
method: 'parity_subscription',
|
|
||||||
params: {
|
|
||||||
result: [address.toLowerCase()],
|
|
||||||
subscription: 2
|
|
||||||
}
|
|
||||||
} }]);
|
|
||||||
instance = new Pubsub(new WsSecure(TEST_WS_URL));
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
scope.stop();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns a list of accounts, formatted', (done) => {
|
|
||||||
instance.eth.accounts((error, accounts) => {
|
|
||||||
expect(error).to.be.null;
|
|
||||||
expect(accounts).to.deep.equal([address]);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('newHeads', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
scope = mockWs([{ method: 'eth_subscribe', reply: 2, subscription: {
|
|
||||||
method: 'eth_subscription',
|
|
||||||
params: {
|
|
||||||
result: '0x123456',
|
|
||||||
subscription: 2
|
|
||||||
}
|
|
||||||
} }]);
|
|
||||||
instance = new Pubsub(new WsSecure(TEST_WS_URL));
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
scope.stop();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns newHeads for eth_subscribe', (done) => {
|
|
||||||
instance.eth.newHeads((error, blockNumber) => {
|
|
||||||
expect(error).to.be.null;
|
|
||||||
expect(blockNumber).to.equal('0x123456');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('blockNumber', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
scope = mockWs([{ method: 'parity_subscribe', reply: 2, subscription: {
|
|
||||||
method: 'parity_subscription',
|
|
||||||
params: {
|
|
||||||
result: '0x123456',
|
|
||||||
subscription: 2
|
|
||||||
}
|
|
||||||
} }]);
|
|
||||||
instance = new Pubsub(new WsSecure(TEST_WS_URL));
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
scope.stop();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns the current blockNumber, formatted', (done) => {
|
|
||||||
instance.eth.blockNumber((error, blockNumber) => {
|
|
||||||
expect(error).to.be.null;
|
|
||||||
expect(isBigNumber(blockNumber)).to.be.true;
|
|
||||||
expect(blockNumber.toString(16)).to.equal('123456');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('call', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
scope = mockWs([{ method: 'parity_subscribe', reply: 2, subscription: {
|
|
||||||
method: 'parity_subscription',
|
|
||||||
params: {
|
|
||||||
result: [],
|
|
||||||
subscription: 2
|
|
||||||
}
|
|
||||||
} }]);
|
|
||||||
instance = new Pubsub(new WsSecure(TEST_WS_URL));
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
scope.stop();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('formats the input options & blockNumber', (done) => {
|
|
||||||
instance.eth.call((error) => {
|
|
||||||
expect(error).to.be.null;
|
|
||||||
expect(scope.body.parity_subscribe.params).to.deep.equal(['eth_call', [{ data: '0x12345678' }, 'earliest']]);
|
|
||||||
done();
|
|
||||||
}, { data: '12345678' }, 'earliest');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('provides a latest blockNumber when not specified', (done) => {
|
|
||||||
instance.eth.call((error) => {
|
|
||||||
expect(error).to.be.null;
|
|
||||||
expect(scope.body.parity_subscribe.params).to.deep.equal(['eth_call', [{ data: '0x12345678' }, 'latest']]);
|
|
||||||
done();
|
|
||||||
}, { data: '12345678' });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('coinbase', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
scope = mockWs([{ method: 'parity_subscribe', reply: 2, subscription: {
|
|
||||||
method: 'parity_subscription',
|
|
||||||
params: {
|
|
||||||
result: address.toLowerCase(),
|
|
||||||
subscription: 2
|
|
||||||
}
|
|
||||||
} }]);
|
|
||||||
instance = new Pubsub(new WsSecure(TEST_WS_URL));
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
scope.stop();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns the coinbase, formatted', (done) => {
|
|
||||||
instance.eth.coinbase((error, account) => {
|
|
||||||
expect(error).to.be.null;
|
|
||||||
expect(account).to.deep.equal(address);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('estimateGas', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
scope = mockWs([{ method: 'parity_subscribe', reply: 2, subscription: {
|
|
||||||
method: 'parity_subscription',
|
|
||||||
params: {
|
|
||||||
result: '0x123',
|
|
||||||
subscription: 2
|
|
||||||
}
|
|
||||||
} }]);
|
|
||||||
instance = new Pubsub(new WsSecure(TEST_WS_URL));
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
scope.stop();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('converts the options correctly', (done) => {
|
|
||||||
instance.eth.estimateGas((error) => {
|
|
||||||
expect(error).to.be.null;
|
|
||||||
expect(scope.body.parity_subscribe.params).to.deep.equal(['eth_estimateGas', [{ gas: '0x5208' }]]);
|
|
||||||
done();
|
|
||||||
}, { gas: 21000 });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns the gas used, formatted', (done) => {
|
|
||||||
instance.eth.estimateGas((error, gas) => {
|
|
||||||
expect(error).to.be.null;
|
|
||||||
expect(isBigNumber(gas)).to.be.true;
|
|
||||||
expect(gas.toString(16)).to.deep.equal('123');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('gasPrice', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
scope = mockWs([{ method: 'parity_subscribe', reply: 2, subscription: {
|
|
||||||
method: 'parity_subscription',
|
|
||||||
params: {
|
|
||||||
result: '0x123',
|
|
||||||
subscription: 2
|
|
||||||
}
|
|
||||||
} }]);
|
|
||||||
instance = new Pubsub(new WsSecure(TEST_WS_URL));
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
scope.stop();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns the gas price, formatted', (done) => {
|
|
||||||
instance.eth.gasPrice((error, price) => {
|
|
||||||
expect(error).to.be.null;
|
|
||||||
expect(isBigNumber(price)).to.be.true;
|
|
||||||
expect(price.toString(16)).to.deep.equal('123');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getBalance', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
scope = mockWs([{ method: 'parity_subscribe', reply: 2, subscription: {
|
|
||||||
method: 'parity_subscription',
|
|
||||||
params: {
|
|
||||||
result: '0x123',
|
|
||||||
subscription: 2
|
|
||||||
}
|
|
||||||
} }]);
|
|
||||||
instance = new Pubsub(new WsSecure(TEST_WS_URL));
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
scope.stop();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('passes in the address (default blockNumber)', (done) => {
|
|
||||||
instance.eth.getBalance((error) => {
|
|
||||||
expect(error).to.be.null;
|
|
||||||
expect(scope.body.parity_subscribe.params).to.deep.equal(['eth_getBalance', [address.toLowerCase(), 'latest']]);
|
|
||||||
done();
|
|
||||||
}, address);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('passes in the address & blockNumber', (done) => {
|
|
||||||
instance.eth.getBalance((error) => {
|
|
||||||
expect(error).to.be.null;
|
|
||||||
expect(scope.body.parity_subscribe.params).to.deep.equal(['eth_getBalance', [address.toLowerCase(), '0x456']]);
|
|
||||||
done();
|
|
||||||
}, address, 0x456);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns the balance', (done) => {
|
|
||||||
instance.eth.getBalance((error, balance) => {
|
|
||||||
expect(error).to.be.null;
|
|
||||||
expect(isBigNumber(balance)).to.be.true;
|
|
||||||
expect(balance.toString(16)).to.deep.equal('123');
|
|
||||||
done();
|
|
||||||
}, address);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getBlockByHash', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
scope = mockWs([{ method: 'parity_subscribe', reply: 2, subscription: {
|
|
||||||
method: 'parity_subscription',
|
|
||||||
params: {
|
|
||||||
result: { miner: address.toLowerCase() },
|
|
||||||
subscription: 2
|
|
||||||
}
|
|
||||||
} }]);
|
|
||||||
instance = new Pubsub(new WsSecure(TEST_WS_URL));
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
scope.stop();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('formats the input hash as a hash, default full', (done) => {
|
|
||||||
instance.eth.getBlockByHash((error) => {
|
|
||||||
expect(error).to.be.null;
|
|
||||||
expect(scope.body.parity_subscribe.params).to.deep.equal(['eth_getBlockByHash', ['0x1234', false]]);
|
|
||||||
done();
|
|
||||||
}, '1234');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('formats the input hash as a hash, full true', (done) => {
|
|
||||||
instance.eth.getBlockByHash((error) => {
|
|
||||||
expect(error).to.be.null;
|
|
||||||
expect(scope.body.parity_subscribe.params).to.deep.equal(['eth_getBlockByHash', ['0x1234', true]]);
|
|
||||||
done();
|
|
||||||
}, '1234', true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('formats the output into block', (done) => {
|
|
||||||
instance.eth.getBlockByHash((error, block) => {
|
|
||||||
expect(error).to.be.null;
|
|
||||||
expect(block.miner).to.equal(address);
|
|
||||||
done();
|
|
||||||
}, '1234');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getBlockByNumber', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
scope = mockWs([{ method: 'parity_subscribe', reply: 2, subscription: {
|
|
||||||
method: 'parity_subscription',
|
|
||||||
params: {
|
|
||||||
result: { miner: address.toLowerCase() },
|
|
||||||
subscription: 2
|
|
||||||
}
|
|
||||||
} }]);
|
|
||||||
instance = new Pubsub(new WsSecure(TEST_WS_URL));
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
scope.stop();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('assumes blockNumber latest & full false', (done) => {
|
|
||||||
instance.eth.getBlockByNumber((error) => {
|
|
||||||
expect(error).to.be.null;
|
|
||||||
expect(scope.body.parity_subscribe.params).to.deep.equal(['eth_getBlockByNumber', ['latest', false]]);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('uses input blockNumber & full false', (done) => {
|
|
||||||
instance.eth.getBlockByNumber((error) => {
|
|
||||||
expect(error).to.be.null;
|
|
||||||
expect(scope.body.parity_subscribe.params).to.deep.equal(['eth_getBlockByNumber', ['0x1234', false]]);
|
|
||||||
done();
|
|
||||||
}, '0x1234');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('formats the input blockNumber, full true', (done) => {
|
|
||||||
instance.eth.getBlockByNumber((error) => {
|
|
||||||
expect(error).to.be.null;
|
|
||||||
expect(scope.body.parity_subscribe.params).to.deep.equal(['eth_getBlockByNumber', ['0x1234', true]]);
|
|
||||||
done();
|
|
||||||
}, 0x1234, true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('formats the output into block', (done) => {
|
|
||||||
instance.eth.getBlockByNumber((error, block) => {
|
|
||||||
expect(error).to.be.null;
|
|
||||||
expect(block.miner).to.equal(address);
|
|
||||||
done();
|
|
||||||
}, 0x1234);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getTransactionCount', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
scope = mockWs([{ method: 'parity_subscribe', reply: 2, subscription: {
|
|
||||||
method: 'parity_subscription',
|
|
||||||
params: {
|
|
||||||
result: '0x123',
|
|
||||||
subscription: 2
|
|
||||||
}
|
|
||||||
} }]);
|
|
||||||
instance = new Pubsub(new WsSecure(TEST_WS_URL));
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
scope.stop();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('passes in the address (default blockNumber)', (done) => {
|
|
||||||
instance.eth.getTransactionCount((error) => {
|
|
||||||
expect(error).to.be.null;
|
|
||||||
expect(scope.body.parity_subscribe.params).to.deep.equal(['eth_getTransactionCount', [address.toLowerCase(), 'latest']]);
|
|
||||||
done();
|
|
||||||
}, address);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('passes in the address & blockNumber', (done) => {
|
|
||||||
instance.eth.getTransactionCount((error) => {
|
|
||||||
expect(error).to.be.null;
|
|
||||||
expect(scope.body.parity_subscribe.params).to.deep.equal(['eth_getTransactionCount', [address.toLowerCase(), '0x456']]);
|
|
||||||
done();
|
|
||||||
}, address, 0x456);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns the count, formatted', (done) => {
|
|
||||||
instance.eth.getTransactionCount((error, count) => {
|
|
||||||
expect(error).to.be.null;
|
|
||||||
expect(isBigNumber(count)).to.be.true;
|
|
||||||
expect(count.toString(16)).to.equal('123');
|
|
||||||
done();
|
|
||||||
}, address, 0x456);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,37 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
export default class PubsubBase {
|
|
||||||
// Provider for websocket pubsub transport
|
|
||||||
constructor (provider) {
|
|
||||||
this._provider = provider;
|
|
||||||
}
|
|
||||||
|
|
||||||
addListener (module, eventName, handler, eventParams) {
|
|
||||||
return eventParams
|
|
||||||
? this._provider.subscribe(module, handler, [eventName, eventParams])
|
|
||||||
: this._provider.subscribe(module, handler, [eventName, []]);
|
|
||||||
// this._transport.subscribe(module, handler, eventName); After Patch from tomac is merged to master! => eth_subscribe does not support empty array as params
|
|
||||||
}
|
|
||||||
|
|
||||||
removeListener (subscriptionIds) {
|
|
||||||
return this._provider.unsubscribe(subscriptionIds);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsubscribe (subscriptionIds) {
|
|
||||||
return this.removeListener(subscriptionIds);
|
|
||||||
}
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user