diff --git a/.gitignore b/.gitignore
index 12bd2818..1a91b1c5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -29,3 +29,4 @@ eth_common/.ethereum
src/temp
**/*.lcov
coverage.lcov
+test-result
diff --git a/Makefile b/Makefile
index e350065b..872720e6 100644
--- a/Makefile
+++ b/Makefile
@@ -46,12 +46,14 @@ watch:
${TSC} --project tsconfig.json --watch
lint:
- ${TSLINT}
+ ${TSLINT} --project tsconfig.json
test:
node --experimental-modules --es-module-specifier-resolution=node node_modules/.bin/nyc node_modules/mocha/bin/_mocha
test-fast:
node --inspect --experimental-modules node_modules/.bin/_mocha
+test-fast-bail:
+ node --inspect --experimental-modules node_modules/.bin/_mocha --bail
test-coveralls:
${NYC} report --reporter=text-lcov | ${COVERALLS} --verbose
diff --git a/README.md b/README.md
index c6a44952..919a973a 100644
--- a/README.md
+++ b/README.md
@@ -141,3 +141,4 @@ make test-local
You can find full documentation [here](docs/index.md).
You may find issues while using this library, as it's still under development. Please report any issues you come accross.
+
diff --git a/docs/eth-connect.abiinput.components.md b/docs/eth-connect.abiinput.components.md
deleted file mode 100644
index 708dd718..00000000
--- a/docs/eth-connect.abiinput.components.md
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-[Home](./index.md) > [eth-connect](./eth-connect.md) > [AbiInput](./eth-connect.abiinput.md) > [components](./eth-connect.abiinput.components.md)
-
-## AbiInput.components property
-
-Signature:
-
-```typescript
-components?: AbiInput[];
-```
diff --git a/docs/eth-connect.abiinput.internaltype.md b/docs/eth-connect.abiinput.internaltype.md
deleted file mode 100644
index d67c5849..00000000
--- a/docs/eth-connect.abiinput.internaltype.md
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-[Home](./index.md) > [eth-connect](./eth-connect.md) > [AbiInput](./eth-connect.abiinput.md) > [internalType](./eth-connect.abiinput.internaltype.md)
-
-## AbiInput.internalType property
-
-Signature:
-
-```typescript
-internalType?: string;
-```
diff --git a/docs/eth-connect.abiinput.md b/docs/eth-connect.abiinput.md
index 0032ed22..6b614d7a 100644
--- a/docs/eth-connect.abiinput.md
+++ b/docs/eth-connect.abiinput.md
@@ -8,16 +8,13 @@
Signature:
```typescript
-export interface AbiInput
+export interface AbiInput extends AbiOutput
```
+Extends: [AbiOutput](./eth-connect.abioutput.md)
## Properties
| Property | Type | Description |
| --- | --- | --- |
-| [components?](./eth-connect.abiinput.components.md) | [AbiInput](./eth-connect.abiinput.md)\[\] | (Optional) |
| [indexed?](./eth-connect.abiinput.indexed.md) | boolean | (Optional) |
-| [internalType?](./eth-connect.abiinput.internaltype.md) | string | (Optional) |
-| [name](./eth-connect.abiinput.name.md) | string | |
-| [type](./eth-connect.abiinput.type.md) | string | |
diff --git a/docs/eth-connect.abiinput.name.md b/docs/eth-connect.abiinput.name.md
deleted file mode 100644
index 116e5579..00000000
--- a/docs/eth-connect.abiinput.name.md
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-[Home](./index.md) > [eth-connect](./eth-connect.md) > [AbiInput](./eth-connect.abiinput.md) > [name](./eth-connect.abiinput.name.md)
-
-## AbiInput.name property
-
-Signature:
-
-```typescript
-name: string;
-```
diff --git a/docs/eth-connect.abiinput.type.md b/docs/eth-connect.abiinput.type.md
deleted file mode 100644
index 64fe435c..00000000
--- a/docs/eth-connect.abiinput.type.md
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-[Home](./index.md) > [eth-connect](./eth-connect.md) > [AbiInput](./eth-connect.abiinput.md) > [type](./eth-connect.abiinput.type.md)
-
-## AbiInput.type property
-
-Signature:
-
-```typescript
-type: string;
-```
diff --git a/docs/eth-connect.bytestohex.md b/docs/eth-connect.bytestohex.md
new file mode 100644
index 00000000..7751a2bd
--- /dev/null
+++ b/docs/eth-connect.bytestohex.md
@@ -0,0 +1,23 @@
+
+
+[Home](./index.md) > [eth-connect](./eth-connect.md) > [bytesToHex](./eth-connect.bytestohex.md)
+
+## bytesToHex() function
+
+
+Signature:
+
+```typescript
+export declare function bytesToHex(bytes: Uint8Array): string;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| bytes | Uint8Array | |
+
+Returns:
+
+string
+
diff --git a/docs/eth-connect.bytestoutf8string.md b/docs/eth-connect.bytestoutf8string.md
new file mode 100644
index 00000000..59b340b3
--- /dev/null
+++ b/docs/eth-connect.bytestoutf8string.md
@@ -0,0 +1,24 @@
+
+
+[Home](./index.md) > [eth-connect](./eth-connect.md) > [bytesToUtf8String](./eth-connect.bytestoutf8string.md)
+
+## bytesToUtf8String() function
+
+Decodes an Uint8Array or hex string into a UTF-8 string
+
+Signature:
+
+```typescript
+export declare function bytesToUtf8String(bytesOrHexString: Uint8Array | string): string;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| bytesOrHexString | Uint8Array \| string | |
+
+Returns:
+
+string
+
diff --git a/docs/eth-connect.concatbytes.md b/docs/eth-connect.concatbytes.md
new file mode 100644
index 00000000..2d1ba4d8
--- /dev/null
+++ b/docs/eth-connect.concatbytes.md
@@ -0,0 +1,22 @@
+
+
+[Home](./index.md) > [eth-connect](./eth-connect.md) > [concatBytes](./eth-connect.concatbytes.md)
+
+## concatBytes() function
+
+Signature:
+
+```typescript
+export declare function concatBytes(...buffers: Uint8Array[]): Uint8Array;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| buffers | Uint8Array\[\] | |
+
+Returns:
+
+Uint8Array
+
diff --git a/docs/eth-connect.fromtwoscomplement.md b/docs/eth-connect.fromtwoscomplement.md
new file mode 100644
index 00000000..65944308
--- /dev/null
+++ b/docs/eth-connect.fromtwoscomplement.md
@@ -0,0 +1,25 @@
+
+
+[Home](./index.md) > [eth-connect](./eth-connect.md) > [fromTwosComplement](./eth-connect.fromtwoscomplement.md)
+
+## fromTwosComplement() function
+
+If the bit N is 1
+
+Signature:
+
+```typescript
+export declare function fromTwosComplement(num: BigNumber, bits?: number): BigNumber;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| num | [BigNumber](./eth-connect.bignumber.md) | |
+| bits | number | |
+
+Returns:
+
+[BigNumber](./eth-connect.bignumber.md)
+
diff --git a/docs/eth-connect.fromutf8.md b/docs/eth-connect.fromutf8.md
deleted file mode 100644
index d962738f..00000000
--- a/docs/eth-connect.fromutf8.md
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-[Home](./index.md) > [eth-connect](./eth-connect.md) > [fromUtf8](./eth-connect.fromutf8.md)
-
-## fromUtf8() function
-
-Should be called to get hex representation (prefixed by 0x) of utf8 string
-
-Signature:
-
-```typescript
-export declare function fromUtf8(_str: string, allowZero?: boolean): string;
-```
-
-## Parameters
-
-| Parameter | Type | Description |
-| --- | --- | --- |
-| \_str | string | |
-| allowZero | boolean | |
-
-Returns:
-
-string
-
diff --git a/docs/eth-connect.getaddress.md b/docs/eth-connect.getaddress.md
new file mode 100644
index 00000000..6aac622d
--- /dev/null
+++ b/docs/eth-connect.getaddress.md
@@ -0,0 +1,23 @@
+
+
+[Home](./index.md) > [eth-connect](./eth-connect.md) > [getAddress](./eth-connect.getaddress.md)
+
+## getAddress() function
+
+
+Signature:
+
+```typescript
+export declare function getAddress(address: string): string;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| address | string | |
+
+Returns:
+
+string
+
diff --git a/docs/eth-connect.signedisnegative.md b/docs/eth-connect.signedisnegative.md
new file mode 100644
index 00000000..b32b3b99
--- /dev/null
+++ b/docs/eth-connect.signedisnegative.md
@@ -0,0 +1,25 @@
+
+
+[Home](./index.md) > [eth-connect](./eth-connect.md) > [signedIsNegative](./eth-connect.signedisnegative.md)
+
+## signedIsNegative() function
+
+Check if input value is negative in twos complement
+
+Signature:
+
+```typescript
+export declare function signedIsNegative(value: BigNumber, bits: number): boolean;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| value | [BigNumber](./eth-connect.bignumber.md) | |
+| bits | number | |
+
+Returns:
+
+boolean
+
diff --git a/docs/eth-connect.solidityevent.types.md b/docs/eth-connect.solidityevent.types.md
index 392b6e2d..11c41de2 100644
--- a/docs/eth-connect.solidityevent.types.md
+++ b/docs/eth-connect.solidityevent.types.md
@@ -9,7 +9,7 @@ Should be used to get filtered param types
Signature:
```typescript
-types(indexed: boolean): string[];
+types(indexed: boolean): AbiInput[];
```
## Parameters
@@ -20,5 +20,5 @@ types(indexed: boolean): string[];
Returns:
-string\[\]
+[AbiInput](./eth-connect.abiinput.md)\[\]
diff --git a/docs/eth-connect.solidityfunction._inputtypes.md b/docs/eth-connect.solidityfunction._inputtypes.md
index 30ec3e8a..367e2087 100644
--- a/docs/eth-connect.solidityfunction._inputtypes.md
+++ b/docs/eth-connect.solidityfunction._inputtypes.md
@@ -7,5 +7,5 @@
Signature:
```typescript
-_inputTypes: string[];
+_inputTypes: AbiInput[];
```
diff --git a/docs/eth-connect.solidityfunction._outputtypes.md b/docs/eth-connect.solidityfunction._outputtypes.md
index 755c06bb..c7cfee02 100644
--- a/docs/eth-connect.solidityfunction._outputtypes.md
+++ b/docs/eth-connect.solidityfunction._outputtypes.md
@@ -7,5 +7,5 @@
Signature:
```typescript
-_outputTypes: string[];
+_outputTypes: AbiOutput[];
```
diff --git a/docs/eth-connect.solidityfunction.md b/docs/eth-connect.solidityfunction.md
index 6a386810..b0fbc571 100644
--- a/docs/eth-connect.solidityfunction.md
+++ b/docs/eth-connect.solidityfunction.md
@@ -23,9 +23,9 @@ export declare class SolidityFunction
| Property | Modifiers | Type | Description |
| --- | --- | --- | --- |
| [\_constant](./eth-connect.solidityfunction._constant.md) | | boolean | |
-| [\_inputTypes](./eth-connect.solidityfunction._inputtypes.md) | | string\[\] | |
+| [\_inputTypes](./eth-connect.solidityfunction._inputtypes.md) | | [AbiInput](./eth-connect.abiinput.md)\[\] | |
| [\_name](./eth-connect.solidityfunction._name.md) | | string | |
-| [\_outputTypes](./eth-connect.solidityfunction._outputtypes.md) | | string\[\] | |
+| [\_outputTypes](./eth-connect.solidityfunction._outputtypes.md) | | [AbiOutput](./eth-connect.abioutput.md)\[\] | |
| [\_payable](./eth-connect.solidityfunction._payable.md) | | boolean | |
| [json](./eth-connect.solidityfunction.json.md) | | [AbiFunction](./eth-connect.abifunction.md) | |
| [needsToBeTransaction](./eth-connect.solidityfunction.needstobetransaction.md) | | boolean | |
diff --git a/docs/eth-connect.stringtoutf8bytes.md b/docs/eth-connect.stringtoutf8bytes.md
new file mode 100644
index 00000000..0f757855
--- /dev/null
+++ b/docs/eth-connect.stringtoutf8bytes.md
@@ -0,0 +1,24 @@
+
+
+[Home](./index.md) > [eth-connect](./eth-connect.md) > [stringToUtf8Bytes](./eth-connect.stringtoutf8bytes.md)
+
+## stringToUtf8Bytes() function
+
+Converts a string into a Uint8Array encoded with UTF-8
+
+Signature:
+
+```typescript
+export declare function stringToUtf8Bytes(str: string): Uint8Array;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| str | string | |
+
+Returns:
+
+Uint8Array
+
diff --git a/docs/eth-connect.tohex.md b/docs/eth-connect.tohex.md
index 32348558..3f23e9f4 100644
--- a/docs/eth-connect.tohex.md
+++ b/docs/eth-connect.tohex.md
@@ -11,14 +11,14 @@ And even stringifys objects before.
Signature:
```typescript
-export declare function toHex(val: BigNumber.Value | boolean): string;
+export declare function toHex(val: BigNumber.Value | boolean | Uint8Array): string;
```
## Parameters
| Parameter | Type | Description |
| --- | --- | --- |
-| val | [BigNumber.Value](./eth-connect.bignumber.value.md) \| boolean | |
+| val | [BigNumber.Value](./eth-connect.bignumber.value.md) \| boolean \| Uint8Array | |
Returns:
diff --git a/docs/eth-connect.totwoscomplement.md b/docs/eth-connect.totwoscomplement.md
index 97c8541b..6812259f 100644
--- a/docs/eth-connect.totwoscomplement.md
+++ b/docs/eth-connect.totwoscomplement.md
@@ -9,7 +9,7 @@ Takes and input transforms it into bignumber and if it is negative value, into t
Signature:
```typescript
-export declare function toTwosComplement(num: BigNumber.Value): BigNumber;
+export declare function toTwosComplement(num: BigNumber.Value, bits?: number): BigNumber;
```
## Parameters
@@ -17,6 +17,7 @@ export declare function toTwosComplement(num: BigNumber.Value): BigNumber;
| Parameter | Type | Description |
| --- | --- | --- |
| num | [BigNumber.Value](./eth-connect.bignumber.value.md) | |
+| bits | number | |
Returns:
diff --git a/docs/eth-connect.toutf8.md b/docs/eth-connect.toutf8.md
deleted file mode 100644
index 8e2550fc..00000000
--- a/docs/eth-connect.toutf8.md
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-[Home](./index.md) > [eth-connect](./eth-connect.md) > [toUtf8](./eth-connect.toutf8.md)
-
-## toUtf8() function
-
-Should be called to get utf8 from it's hex representation
-
-Signature:
-
-```typescript
-export declare function toUtf8(hex: string): string;
-```
-
-## Parameters
-
-| Parameter | Type | Description |
-| --- | --- | --- |
-| hex | string | |
-
-Returns:
-
-string
-
diff --git a/docs/index.md b/docs/index.md
index fd3a05f9..197c1654 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -35,13 +35,17 @@
| Function | Description |
| --- | --- |
+| [bytesToHex(bytes)](./eth-connect.bytestohex.md) | |
+| [bytesToUtf8String(bytesOrHexString)](./eth-connect.bytestoutf8string.md) | Decodes an Uint8Array or hex string into a UTF-8 string |
+| [concatBytes(buffers)](./eth-connect.concatbytes.md) | |
| [extractDisplayName(name)](./eth-connect.extractdisplayname.md) | Should be called to get display name of contract function |
| [extractTypeName(name)](./eth-connect.extracttypename.md) | Should be called to get type name of contract function |
| [fromAscii(str, num)](./eth-connect.fromascii.md) | Should be called to get hex representation (prefixed by 0x) of ascii string |
| [fromDecimal(value)](./eth-connect.fromdecimal.md) | Converts value to it's hex representation |
-| [fromUtf8(\_str, allowZero)](./eth-connect.fromutf8.md) | Should be called to get hex representation (prefixed by 0x) of utf8 string |
+| [fromTwosComplement(num, bits)](./eth-connect.fromtwoscomplement.md) | If the bit N is 1 |
| [fromWei(num, unit)](./eth-connect.fromwei.md) | Takes a number of wei and converts it to any other ether unit.Possible units are: SI Short SI Full Effigy Other - kwei femtoether babbage - mwei picoether lovelace - gwei nanoether shannon nano - -- microether szabo micro - -- milliether finney milli - ether -- -- - kether -- grand - mether - gether - tether |
| [fromWei(num, unit)](./eth-connect.fromwei_1.md) | |
+| [getAddress(address)](./eth-connect.getaddress.md) | |
| [getValueOfUnit(\_unit)](./eth-connect.getvalueofunit.md) | Returns value of unit in Wei |
| [hexToBytes(hex)](./eth-connect.hextobytes.md) | |
| [isAddress(address)](./eth-connect.isaddress.md) | Checks if the given string is an address |
@@ -61,6 +65,8 @@
| [padLeft(str, chars, sign)](./eth-connect.padleft.md) | Should be called to pad string to expected length |
| [padRight(str, chars, sign)](./eth-connect.padright.md) | Should be called to pad string to expected length |
| [sha3(value, options)](./eth-connect.sha3.md) | |
+| [signedIsNegative(value, bits)](./eth-connect.signedisnegative.md) | Check if input value is negative in twos complement |
+| [stringToUtf8Bytes(str)](./eth-connect.stringtoutf8bytes.md) | Converts a string into a Uint8Array encoded with UTF-8 |
| [toAddress(address)](./eth-connect.toaddress.md) | Transforms given string to valid 20 bytes-length addres with 0x prefix |
| [toArray(value)](./eth-connect.toarray.md) | Ensures the result will be an array |
| [toAscii(hex)](./eth-connect.toascii.md) | Should be called to get ascii from it's hex representation |
@@ -74,8 +80,7 @@
| [toJsonRpcRequest(method, params)](./eth-connect.tojsonrpcrequest.md) | Should be called to valid json create payload object |
| [toNullDecimal(value)](./eth-connect.tonulldecimal.md) | Converts value to it's decimal representation in string |
| [toString\_2(value)](./eth-connect.tostring_2.md) | Converts value to string |
-| [toTwosComplement(num)](./eth-connect.totwoscomplement.md) | Takes and input transforms it into bignumber and if it is negative value, into two's complement |
-| [toUtf8(hex)](./eth-connect.toutf8.md) | Should be called to get utf8 from it's hex representation |
+| [toTwosComplement(num, bits)](./eth-connect.totwoscomplement.md) | Takes and input transforms it into bignumber and if it is negative value, into two's complement |
| [toWei(num, unit)](./eth-connect.towei.md) | Takes a number of a unit and converts it to wei.Possible units are: SI Short SI Full Effigy Other - kwei femtoether babbage - mwei picoether lovelace - gwei nanoether shannon nano - -- microether szabo micro - -- milliether finney milli - ether -- -- - kether -- grand - mether - gether - tether |
| [transformToFullName(json)](./eth-connect.transformtofullname.md) | Should be used to create full function/event name from json abi |
diff --git a/package-lock.json b/package-lock.json
index 5c576c44..b9acaf27 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -794,12 +794,6 @@
"integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==",
"dev": true
},
- "@types/utf8": {
- "version": "2.1.6",
- "resolved": "https://registry.npmjs.org/@types/utf8/-/utf8-2.1.6.tgz",
- "integrity": "sha512-pRs2gYF5yoKYrgSaira0DJqVg2tFuF+Qjp838xS7K+mJyY2jJzjsrl6y17GbIa4uMRogMbxs+ghNCvKg6XyNrA==",
- "dev": true
- },
"@types/yargs": {
"version": "15.0.13",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.13.tgz",
@@ -4421,12 +4415,6 @@
"node-gyp-build": "^4.2.0"
}
},
- "utf8": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz",
- "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==",
- "dev": true
- },
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
diff --git a/package.json b/package.json
index 590419a2..1ecb41c5 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "eth-connect",
- "version": "5.0.0",
+ "version": "6.0.0",
"private": true,
"description": "Ethereum TypeScript API, middleware to talk to a ethereum node using an async provider",
"decentralandLibrary": {},
@@ -41,13 +41,11 @@
],
"all": true
},
- "dependencies": {},
"devDependencies": {
"@istanbuljs/nyc-config-typescript": "^1.0.1",
"@microsoft/api-documenter": "^7.12.7",
"@microsoft/api-extractor": "^7.13.2",
"@types/mocha": "^8.2.1",
- "@types/utf8": "^2.1.6",
"bignumber.js": "^9.0.1",
"coveralls": "^3.1.0",
"dcl-tslint-config-standard": "^3.0.0",
@@ -69,7 +67,6 @@
"tslint": "^6.1.3",
"tslint-language-service": "^0.9.9",
"typescript": "^4.2.3",
- "utf8": "^3.0.0",
"websocket": "^1.0.33"
}
}
diff --git a/report/eth-connect.api.md b/report/eth-connect.api.md
index 8bdad7f0..e1aa0ae6 100644
--- a/report/eth-connect.api.md
+++ b/report/eth-connect.api.md
@@ -93,17 +93,9 @@ export interface AbiFunction {
}
// @public (undocumented)
-export interface AbiInput {
- // (undocumented)
- components?: AbiInput[];
+export interface AbiInput extends AbiOutput {
// (undocumented)
indexed?: boolean;
- // (undocumented)
- internalType?: string;
- // (undocumented)
- name: string;
- // (undocumented)
- type: string;
}
// @public (undocumented)
@@ -599,11 +591,22 @@ export type BlockObject = {
uncles: Array;
};
+// @public (undocumented)
+export function bytesToHex(bytes: Uint8Array): string;
+
+// @public
+export function bytesToUtf8String(bytesOrHexString: Uint8Array | string): string;
+
// Warning: (ae-missing-release-tag) "Callback" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export type Callback = (err: Error | null, message?: any) => void;
+// Warning: (ae-missing-release-tag) "concatBytes" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
+//
+// @public (undocumented)
+export function concatBytes(...buffers: Uint8Array[]): Uint8Array;
+
// @public (undocumented)
export type ConfirmedTransaction = TransactionObject & {
type: TransactionType.confirmed;
@@ -868,7 +871,7 @@ export function fromAscii(str: string, num?: number): string;
export function fromDecimal(value: BigNumber.Value): string;
// @public
-export function fromUtf8(_str: string, allowZero?: boolean): string;
+export function fromTwosComplement(num: BigNumber, bits?: number): BigNumber;
// Warning: (ae-missing-release-tag) "fromWei" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
@@ -878,6 +881,9 @@ export function fromWei(num: BigNumber, unit: Unit): BigNumber;
// @public (undocumented)
export function fromWei(num: string | number, unit: Unit): string;
+// @public (undocumented)
+export function getAddress(address: string): string;
+
// @public
export function getValueOfUnit(_unit: Unit): BigNumber;
@@ -1241,6 +1247,11 @@ export type SHHPost = {
ttl: Quantity;
};
+// Warning: (ae-missing-release-tag) "signedIsNegative" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
+//
+// @public
+export function signedIsNegative(value: BigNumber, bits: number): boolean;
+
// Warning: (ae-missing-release-tag) "SolidityEvent" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public
@@ -1281,7 +1292,7 @@ export class SolidityEvent {
requestManager: RequestManager;
signature(): string;
typeName(): string;
- types(indexed: boolean): string[];
+ types(indexed: boolean): AbiInput[];
}
// Warning: (ae-missing-release-tag) "SolidityFunction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
@@ -1298,7 +1309,7 @@ export class SolidityFunction {
// (undocumented)
extractDefaultBlock(args: any[]): string;
// (undocumented)
- _inputTypes: string[];
+ _inputTypes: AbiInput[];
// (undocumented)
json: AbiFunction;
// (undocumented)
@@ -1306,7 +1317,7 @@ export class SolidityFunction {
// (undocumented)
needsToBeTransaction: boolean;
// (undocumented)
- _outputTypes: string[];
+ _outputTypes: AbiOutput[];
// (undocumented)
_payable: boolean;
signature(): string;
@@ -1320,6 +1331,9 @@ export class SolidityFunction {
// @public (undocumented)
export type StateMutabilityType = 'pure' | 'view' | 'nonpayable' | 'payable';
+// @public
+export function stringToUtf8Bytes(str: string): Uint8Array;
+
// @public (undocumented)
export type Syncing = {
startingBlock: Quantity;
@@ -1365,7 +1379,7 @@ export function toData(val: BigNumber.Value): string;
export function toDecimal(value: BigNumber.Value): number;
// @public
-export function toHex(val: BigNumber.Value | boolean): string;
+export function toHex(val: BigNumber.Value | boolean | Uint8Array): string;
// Warning: (ae-missing-release-tag) "toJsonRpcRequest" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
@@ -1391,10 +1405,7 @@ function toString_2(value: BigNumber.Value): string;
export { toString_2 as toString }
// @public
-export function toTwosComplement(num: BigNumber.Value): BigNumber;
-
-// @public
-export function toUtf8(hex: string): string;
+export function toTwosComplement(num: BigNumber.Value, bits?: number): BigNumber;
// @public
export function toWei(num: number | string, unit: Unit): string | BigNumber;
diff --git a/src/ContractFactory.ts b/src/ContractFactory.ts
index cb416c34..261f0600 100644
--- a/src/ContractFactory.ts
+++ b/src/ContractFactory.ts
@@ -87,9 +87,7 @@ function encodeConstructorParams(abi: AbiItem[], params: any[]) {
return json.type === 'constructor' && json.inputs && json.inputs.length === params.length
})
.map(function (json) {
- return json.inputs!.map(function (input) {
- return input.type
- })
+ return json.inputs || []
})
.map(function (types) {
return coder.encodeParams(types, params)
diff --git a/src/Filter.ts b/src/Filter.ts
index 5148cb65..09707c77 100644
--- a/src/Filter.ts
+++ b/src/Filter.ts
@@ -21,6 +21,7 @@ import { RequestManager } from './RequestManager'
import * as config from './utils/config'
import { FilterOptions, LogObject, TxHash, SHHFilterOptions, Data, SHHFilterMessage } from './Schema'
import { future, IFuture } from 'fp-future'
+import { stringToUtf8Bytes } from './utils/utf8'
function safeAsync(fn: () => Promise) {
return function () {
@@ -42,7 +43,7 @@ function toTopic(value: any): string | null {
if (strValue.indexOf('0x') === 0) {
return strValue
} else {
- return utils.fromUtf8(strValue)
+ return utils.bytesToHex(stringToUtf8Bytes(strValue))
}
}
diff --git a/src/Schema.ts b/src/Schema.ts
index 8c7332b6..4be9abbb 100644
--- a/src/Schema.ts
+++ b/src/Schema.ts
@@ -524,23 +524,20 @@ export interface AbiConstructor {
gas?: number
}
+
/**
* @public
*/
-export interface AbiInput {
+ export interface AbiOutput {
name: string
type: string
- indexed?: boolean
- components?: AbiInput[]
+ components?: AbiOutput[]
internalType?: string
}
/**
* @public
*/
-export interface AbiOutput {
- name: string
- type: string
- components?: AbiOutput[]
- internalType?: string
+export interface AbiInput extends AbiOutput {
+ indexed?: boolean
}
diff --git a/src/SolidityEvent.ts b/src/SolidityEvent.ts
index dbb0a546..ffd935b3 100644
--- a/src/SolidityEvent.ts
+++ b/src/SolidityEvent.ts
@@ -48,14 +48,10 @@ export class SolidityEvent {
*
* @param decide - True if returned typed should be indexed
*/
- types(indexed: boolean): string[] {
- return this._params
- .filter(function (i) {
- return i.indexed === indexed
- })
- .map(function (i) {
- return i.type
- })
+ types(indexed: boolean): AbiInput[] {
+ return this._params.filter(function (i) {
+ return i.indexed === indexed
+ })
}
/**
@@ -114,10 +110,10 @@ export class SolidityEvent {
if (utils.isArray(value)) {
return value.map(function (v) {
- return '0x' + coder.encodeParam(i.type, v)
+ return '0x' + coder.encodeParams([i], [v])
})
}
- return '0x' + coder.encodeParam(i.type, value)
+ return '0x' + coder.encodeParams([i], [value])
})
result.topics = result.topics.concat(indexedTopics)
diff --git a/src/SolidityFunction.ts b/src/SolidityFunction.ts
index b4ca729e..44471fc8 100644
--- a/src/SolidityFunction.ts
+++ b/src/SolidityFunction.ts
@@ -22,14 +22,14 @@ import * as errors from './utils/errors'
import { coder } from './solidity/coder'
import { RequestManager } from './RequestManager'
import { Contract } from './Contract'
-import { AbiFunction, Quantity } from './Schema'
+import { AbiFunction, AbiInput, AbiOutput, Quantity } from './Schema'
/**
* This prototype should be used to call/sendTransaction to solidity functions
*/
export class SolidityFunction {
- _inputTypes: string[]
- _outputTypes: string[]
+ _inputTypes: AbiInput[]
+ _outputTypes: AbiOutput[]
_constant: boolean
_name: string
_payable: boolean
@@ -37,12 +37,8 @@ export class SolidityFunction {
needsToBeTransaction: boolean
constructor(public json: AbiFunction) {
- this._inputTypes = (json.inputs || []).map(function (i) {
- return i.type
- })
- this._outputTypes = (json.outputs || []).map(function (i) {
- return i.type
- })
+ this._inputTypes = json.inputs || []
+ this._outputTypes = json.outputs || []
this._constant = !!json.constant
this._payable = !!json.payable || json.stateMutability === 'payable'
@@ -94,7 +90,7 @@ export class SolidityFunction {
}
if (args.length > this._inputTypes.length && utils.isObject(args[args.length - 1])) {
- options = args[args.length - 1]
+ options = args.pop()
}
this.validateArgs(args)
diff --git a/src/abi/bytes.ts b/src/abi/bytes.ts
new file mode 100644
index 00000000..3755b09b
--- /dev/null
+++ b/src/abi/bytes.ts
@@ -0,0 +1,79 @@
+import { INVALID_ARGUMENT, error } from '../utils/errors'
+
+///////////////////////////////
+// Exported Types
+
+export type Arrayish = string | ArrayLike
+
+///////////////////////////////
+
+function addSlice(array: Uint8Array): Uint8Array {
+ if ('slice' in array && array.slice) {
+ return array
+ }
+
+ array.slice = function () {
+ var args: any = Array.prototype.slice.call(arguments)
+ return new Uint8Array(Array.prototype.slice.apply(array, args))
+ }
+
+ return array
+}
+
+export function isArrayish(value: any): value is Arrayish {
+ if (!value || parseInt(String(value.length)) != value.length || typeof value === 'string') {
+ return false
+ }
+
+ for (var i = 0; i < value.length; i++) {
+ var v = value[i]
+ if (v < 0 || v >= 256 || parseInt(String(v)) != v) {
+ return false
+ }
+ }
+
+ return true
+}
+
+export function arrayify(value: Arrayish): Uint8Array {
+ if (value == null) {
+ throw error('cannot convert null value to array', INVALID_ARGUMENT, { arg: 'value', value: value })
+ }
+
+ if (value instanceof Uint8Array) {
+ return addSlice(new Uint8Array(value))
+ }
+
+ if (typeof value === 'string') {
+ let match = value.match(/^(0x)?[0-9a-fA-F]*$/)
+
+ if (!match) {
+ throw error('invalid hexidecimal string', INVALID_ARGUMENT, { arg: 'value', value: value })
+ }
+
+ if (match[1] !== '0x') {
+ throw error('hex string must have 0x prefix', INVALID_ARGUMENT, {
+ arg: 'value',
+ value: value
+ })
+ }
+
+ value = value.substring(2)
+ if (value.length % 2) {
+ value = '0' + value
+ }
+
+ var result: any = []
+ for (var i = 0; i < value.length; i += 2) {
+ result.push(parseInt(value.substr(i, 2), 16))
+ }
+
+ return addSlice(new Uint8Array(result))
+ }
+
+ if (isArrayish(value)) {
+ return addSlice(new Uint8Array(value))
+ }
+
+ throw error('invalid arrayify value', undefined, { arg: 'value', value: value, type: typeof value })
+}
diff --git a/src/abi/coder.ts b/src/abi/coder.ts
new file mode 100644
index 00000000..33d3bc15
--- /dev/null
+++ b/src/abi/coder.ts
@@ -0,0 +1,805 @@
+'use strict'
+
+// See: https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI
+
+import { checkArgumentCount, checkNew, INVALID_ARGUMENT, error } from '../utils/errors'
+import { BigNumber } from '../utils/BigNumber'
+import { arrayify } from './bytes'
+import { stringToUtf8Bytes, bytesToUtf8String } from '../utils/utf8'
+import { defineReadOnly } from './properties'
+
+///////////////////////////////
+// Imported Types
+
+import { Arrayish } from './bytes'
+import {
+ bytesToHex,
+ fromTwosComplement,
+ hexToBytes,
+ isAddress,
+ padLeft,
+ toBigNumber,
+ toTwosComplement,
+ concatBytes,
+ toHex,
+ getAddress
+} from '../utils/utils'
+import { inputAddressFormatter } from '../utils/formatters'
+import { AbiEvent, AbiFunction, AbiInput, AbiOutput } from '../Schema'
+import { MaxUint256, NegativeOne, One, Zero } from './constants'
+import { parseParamType } from './parser'
+
+///////////////////////////////
+// Exported Types
+
+export type CoerceFunc = (type: string, value: any) => any
+
+///////////////////////////////
+
+const paramTypeBytes = new RegExp(/^bytes([0-9]*)$/)
+const paramTypeNumber = new RegExp(/^(u?int)([0-9]*)$/)
+const paramTypeArray = new RegExp(/^(.*)\[([0-9]*)\]$/)
+
+export const defaultCoerceFunc: CoerceFunc = function (type: string, value: any): any {
+ var match = type.match(paramTypeNumber)
+ if (match && parseInt(match[2]) <= 48) {
+ return value.toNumber()
+ }
+ return value
+}
+
+export function formatParamType(paramType: Readonly): string {
+ return getParamCoder(defaultCoerceFunc, paramType).type
+}
+
+// @TODO: Allow a second boolean to expose names and modifiers
+export function formatSignature(fragment: AbiEvent | AbiFunction): string {
+ return fragment.name + '(' + (fragment.inputs || []).map((i) => formatParamType(i)).join(',') + ')'
+}
+
+///////////////////////////////////
+// Coders
+
+type DecodedResult = { consumed: number; value: T }
+abstract class Coder {
+ readonly coerceFunc: CoerceFunc
+ readonly name: string
+ readonly type: string
+ readonly localName: string
+ readonly dynamic: boolean
+ constructor(coerceFunc: CoerceFunc, name: string, type: string, localName: string = '', dynamic: boolean) {
+ this.coerceFunc = coerceFunc
+ this.name = name
+ this.type = type
+ this.localName = localName
+ this.dynamic = dynamic
+ }
+
+ abstract encode(value: any): Uint8Array
+ abstract decode(data: Uint8Array, offset: number): DecodedResult
+}
+
+// Clones the functionality of an existing Coder, but without a localName
+class CoderAnonymous extends Coder {
+ private coder!: Coder
+ constructor(coder: Coder) {
+ super(coder.coerceFunc, coder.name, coder.type, undefined, coder.dynamic)
+ defineReadOnly(this, 'coder', coder)
+ }
+ encode(value: any): Uint8Array {
+ return this.coder.encode(value)
+ }
+ decode(data: Uint8Array, offset: number): DecodedResult {
+ return this.coder.decode(data, offset)
+ }
+}
+
+class CoderNull extends Coder {
+ constructor(coerceFunc: CoerceFunc, localName: string) {
+ super(coerceFunc, 'null', '', localName, false)
+ }
+
+ encode(_value: any): Uint8Array {
+ return arrayify([])
+ }
+
+ decode(data: Uint8Array, offset: number): DecodedResult {
+ if (offset > data.length) {
+ throw new Error('invalid null')
+ }
+ return {
+ consumed: 0,
+ value: this.coerceFunc('null', undefined)
+ }
+ }
+}
+
+function maskn(v: BigNumber, bits: number): BigNumber {
+ return new BigNumber(v.toString(2).substr(-bits), 2)
+}
+
+class CoderNumber extends Coder {
+ readonly size: number
+ readonly signed: boolean
+ constructor(coerceFunc: CoerceFunc, size: number, signed: boolean, localName: string) {
+ const name = (signed ? 'int' : 'uint') + size * 8
+ super(coerceFunc, name, name, localName, false)
+
+ this.size = size
+ this.signed = signed
+ }
+
+ encode(value: BigNumber.Value): Uint8Array {
+ try {
+ let v = toBigNumber(value)
+
+ if (this.signed) {
+ let bounds = maskn(MaxUint256, this.size * 8 - 1)
+ if (v.gt(bounds)) {
+ throw new Error('out-of-bounds')
+ }
+ bounds = bounds.plus(One).multipliedBy(NegativeOne)
+ if (v.lt(bounds)) {
+ throw new Error('out-of-bounds')
+ }
+ } else if (v.lt(Zero) || v.gt(maskn(MaxUint256, this.size * 8))) {
+ throw new Error('out-of-bounds')
+ }
+
+ v = maskn(toTwosComplement(v, this.size * 8), this.size * 8)
+
+ if (this.signed) {
+ v = toTwosComplement(fromTwosComplement(v, this.size * 8), 256)
+ }
+
+ let result = padLeft(toTwosComplement(v).toString(16), 64)
+
+ if (result.indexOf('NaN') != -1) {
+ throw error('invalid number value, NaN', INVALID_ARGUMENT, {
+ arg: this.localName,
+ coderType: this.name,
+ value: value,
+ v,
+ twosComplement: toTwosComplement(v),
+ twosComplement16: toTwosComplement(v).toString(16),
+ pad: padLeft(toTwosComplement(v).toString(16), 64),
+ size: this.size
+ })
+ }
+
+ return hexToBytes(result)
+ } catch (error) {
+ throw error('invalid number value', INVALID_ARGUMENT, {
+ arg: this.localName,
+ coderType: this.name,
+ value: value,
+ message: error.toString()
+ })
+ }
+ }
+
+ decode(data: Uint8Array, offset: number): DecodedResult {
+ if (data.length < offset + 32) {
+ throw error('insufficient data for ' + this.name + ' type', INVALID_ARGUMENT, {
+ arg: this.localName,
+ coderType: this.name,
+ value: toHex(data.slice(offset, offset + 32))
+ })
+ }
+ var junkLength = 32 - this.size
+ var value = new BigNumber(bytesToHex(data.slice(offset + junkLength, offset + 32)), 16)
+
+ if (this.signed) {
+ value = fromTwosComplement(value, this.size * 8)
+ } else {
+ value = maskn(value, this.size * 8)
+ }
+
+ return {
+ consumed: 32,
+ value: this.coerceFunc(this.name, value)
+ }
+ }
+}
+var uint256Coder = new CoderNumber(
+ function (_type: string, value: any) {
+ return value
+ },
+ 32,
+ false,
+ 'none'
+)
+
+class CoderBoolean extends Coder {
+ constructor(coerceFunc: CoerceFunc, localName: string) {
+ super(coerceFunc, 'bool', 'bool', localName, false)
+ }
+
+ encode(value: boolean): Uint8Array {
+ return uint256Coder.encode(!!value ? 1 : 0)
+ }
+
+ decode(data: Uint8Array, offset: number): DecodedResult {
+ try {
+ var result = uint256Coder.decode(data, offset)
+ } catch (error) {
+ if (error.reason === 'insufficient data for uint256 type') {
+ throw error('insufficient data for boolean type', INVALID_ARGUMENT, {
+ arg: this.localName,
+ coderType: 'boolean',
+ value: error.value
+ })
+ }
+ throw error
+ }
+ return {
+ consumed: result.consumed,
+ value: this.coerceFunc('bool', !result.value.isZero())
+ }
+ }
+}
+
+class CoderFixedBytes extends Coder {
+ readonly length: number
+ constructor(coerceFunc: CoerceFunc, length: number, localName: string) {
+ const name = 'bytes' + length
+ super(coerceFunc, name, name, localName, false)
+ this.length = length
+ }
+
+ encode(value: Arrayish): Uint8Array {
+ var result = new Uint8Array(32)
+
+ try {
+ if (typeof value == 'string') {
+ if (value.length % 2 !== 0) {
+ throw new Error(`hex string cannot be odd-length`)
+ }
+ }
+
+ let data = arrayify(value)
+
+ if (data.length > this.length) {
+ throw new Error(`incorrect data length`)
+ }
+
+ result.set(data)
+ } catch (error) {
+ throw error('invalid ' + this.name + ' value. Use hex strings or Uint8Array', INVALID_ARGUMENT, {
+ arg: this.localName,
+ coderType: this.name,
+ value: error.value || value,
+ details: error.message
+ })
+ }
+
+ return result
+ }
+
+ decode(data: Uint8Array, offset: number): DecodedResult {
+ if (data.length < offset + 32) {
+ throw error('insufficient data for ' + this.name + ' type', INVALID_ARGUMENT, {
+ arg: this.localName,
+ coderType: this.name,
+ value: toHex(data.slice(offset, offset + 32))
+ })
+ }
+
+ return {
+ consumed: 32,
+ value: this.coerceFunc(this.name, data.slice(offset, offset + this.length))
+ }
+ }
+}
+
+class CoderFunction extends CoderFixedBytes {
+ constructor(coerceFunc: CoerceFunc, localName: string) {
+ super(coerceFunc, 24, localName)
+ }
+}
+
+class CoderAddress extends Coder {
+ constructor(coerceFunc: CoerceFunc, localName: string) {
+ super(coerceFunc, 'address', 'address', localName, false)
+ }
+ encode(inputAddress: string): Uint8Array {
+ let result = new Uint8Array(32)
+ const address = inputAddress.trim()
+ if (!isAddress(address)) {
+ throw error(`invalid address format`, INVALID_ARGUMENT, {
+ arg: this.localName,
+ coderType: 'address',
+ value: inputAddress
+ })
+ }
+ try {
+ result.set(hexToBytes(inputAddressFormatter(address)), 12)
+ } catch (error) {
+ throw error(`invalid address (${error.message})`, INVALID_ARGUMENT, {
+ arg: this.localName,
+ coderType: 'address',
+ value: inputAddress
+ })
+ }
+ return result
+ }
+ decode(data: Uint8Array, offset: number): DecodedResult {
+ if (data.length < offset + 32) {
+ throw error('insufficuent data for address type', INVALID_ARGUMENT, {
+ arg: this.localName,
+ coderType: 'address',
+ value: toHex(data.slice(offset, offset + 32)),
+ missingBytes: offset + 32 - data.length
+ })
+ }
+ return {
+ consumed: 32,
+ value: this.coerceFunc('address', getAddress(toHex(data.slice(offset + 12, offset + 32))))
+ }
+ }
+}
+
+function _encodeDynamicBytes(value: Uint8Array): Uint8Array {
+ var dataLength = 32 * Math.ceil(value.length / 32)
+ var padding = new Uint8Array(dataLength - value.length)
+
+ return concatBytes(uint256Coder.encode(value.length), value, padding)
+}
+
+function _decodeDynamicBytes(data: Uint8Array, offset: number, localName: string): DecodedResult {
+ if (data.length < offset + 32) {
+ throw error('insufficient data for dynamicBytes length', INVALID_ARGUMENT, {
+ arg: localName,
+ coderType: 'dynamicBytes',
+ value: toHex(data.slice(offset, offset + 32))
+ })
+ }
+
+ var length = uint256Coder.decode(data, offset).value
+ try {
+ length = length.toNumber()
+ } catch (error) {
+ throw error('dynamic bytes count too large', INVALID_ARGUMENT, {
+ arg: localName,
+ coderType: 'dynamicBytes',
+ value: length.toString()
+ })
+ }
+
+ if (data.length < offset + 32 + length) {
+ throw error('insufficient data for dynamicBytes type', INVALID_ARGUMENT, {
+ arg: localName,
+ coderType: 'dynamicBytes',
+ value: toHex(data.slice(offset, offset + 32 + length))
+ })
+ }
+
+ return {
+ consumed: 32 + 32 * Math.ceil(length / 32),
+ value: data.slice(offset + 32, offset + 32 + length)
+ }
+}
+
+class CoderDynamicBytes extends Coder {
+ constructor(coerceFunc: CoerceFunc, localName: string) {
+ super(coerceFunc, 'bytes', 'bytes', localName, true)
+ }
+ encode(value: Arrayish): Uint8Array {
+ try {
+ return _encodeDynamicBytes(arrayify(value))
+ } catch (error) {
+ throw error('invalid bytes value', INVALID_ARGUMENT, {
+ arg: this.localName,
+ coderType: 'bytes',
+ value: error.value
+ })
+ }
+ }
+
+ decode(data: Uint8Array, offset: number): DecodedResult {
+ var result = _decodeDynamicBytes(data, offset, this.localName)
+ result.value = this.coerceFunc('bytes', result.value)
+ return result
+ }
+}
+
+class CoderString extends Coder {
+ constructor(coerceFunc: CoerceFunc, localName: string) {
+ super(coerceFunc, 'string', 'string', localName, true)
+ }
+
+ encode(value: string): Uint8Array {
+ if (typeof value !== 'string') {
+ throw error('invalid string value', INVALID_ARGUMENT, {
+ arg: this.localName,
+ coderType: 'string',
+ value: value
+ })
+ }
+ return _encodeDynamicBytes(stringToUtf8Bytes(value))
+ }
+
+ decode(data: Uint8Array, offset: number): DecodedResult {
+ var result = _decodeDynamicBytes(data, offset, this.localName)
+ result.value = this.coerceFunc('string', bytesToUtf8String(result.value))
+ return result
+ }
+}
+
+function alignSize(size: number): number {
+ return 32 * Math.ceil(size / 32)
+}
+
+function pack(coders: Array, values: Array): Uint8Array {
+ if (Array.isArray(values)) {
+ // do nothing
+ } else if (values && typeof values === 'object') {
+ var arrayValues: Array = []
+ coders.forEach(function (coder) {
+ arrayValues.push((values)[coder.localName])
+ })
+ values = arrayValues
+ } else {
+ throw error('invalid tuple value', INVALID_ARGUMENT, {
+ coderType: 'tuple',
+ value: values
+ })
+ }
+
+ if (coders.length !== values.length) {
+ throw error('types/value length mismatch', INVALID_ARGUMENT, {
+ coderType: 'tuple',
+ value: values
+ })
+ }
+
+ var parts: Array<{ dynamic: boolean; value: any }> = []
+
+ coders.forEach(function (coder, index) {
+ parts.push({ dynamic: coder.dynamic, value: coder.encode(values[index]) })
+ })
+
+ var staticSize = 0,
+ dynamicSize = 0
+ parts.forEach(function (part) {
+ if (part.dynamic) {
+ staticSize += 32
+ dynamicSize += alignSize(part.value.length)
+ } else {
+ staticSize += alignSize(part.value.length)
+ }
+ })
+
+ var offset = 0,
+ dynamicOffset = staticSize
+ var data = new Uint8Array(staticSize + dynamicSize)
+
+ parts.forEach(function (part) {
+ if (part.dynamic) {
+ //uint256Coder.encode(dynamicOffset).copy(data, offset);
+ data.set(uint256Coder.encode(dynamicOffset), offset)
+ offset += 32
+
+ //part.value.copy(data, dynamicOffset); @TODO
+ data.set(part.value, dynamicOffset)
+ dynamicOffset += alignSize(part.value.length)
+ } else {
+ //part.value.copy(data, offset); @TODO
+ data.set(part.value, offset)
+ offset += alignSize(part.value.length)
+ }
+ })
+
+ return data
+}
+
+export class Tuple extends Array {
+ [key: string]: any
+}
+
+function unpack(coders: Array, data: Uint8Array, offset: number): DecodedResult {
+ var baseOffset = offset
+ var consumed = 0
+
+ var value: any[] = []
+ coders.forEach(function (coder) {
+ if (coder.dynamic) {
+ var dynamicOffset = uint256Coder.decode(data, offset)
+ var result = coder.decode(data, baseOffset + dynamicOffset.value.toNumber())
+ // The dynamic part is leap-frogged somewhere else; doesn't count towards size
+ result.consumed = dynamicOffset.consumed
+ } else {
+ var result = coder.decode(data, offset)
+ }
+
+ if (result.value != undefined) {
+ value.push(result.value)
+ }
+
+ offset += result.consumed
+ consumed += result.consumed
+ })
+
+ return {
+ value: value,
+ consumed: consumed
+ }
+}
+
+function unpackWithNames(coders: Array, data: Uint8Array, offset: number): DecodedResult {
+ var baseOffset = offset
+ var consumed = 0
+ var value = new Tuple()
+ coders.forEach(function (coder) {
+ if (coder.dynamic) {
+ var dynamicOffset = uint256Coder.decode(data, offset)
+ var result = coder.decode(data, baseOffset + dynamicOffset.value.toNumber())
+ // The dynamic part is leap-frogged somewhere else; doesn't count towards size
+ result.consumed = dynamicOffset.consumed
+ } else {
+ var result = coder.decode(data, offset)
+ }
+
+ if (result.value != undefined) {
+ value.push(result.value)
+ }
+
+ offset += result.consumed
+ consumed += result.consumed
+ })
+
+ coders.forEach(function (coder: Coder, index: number) {
+ let name: string = coder.localName
+ if (!name) {
+ return
+ }
+
+ if (name === 'length') {
+ name = '_length'
+ }
+
+ if (value[name] != null) {
+ return
+ }
+
+ value[name] = value[index]
+ })
+
+ return {
+ value: value,
+ consumed: consumed
+ }
+}
+
+class CoderArray extends Coder {
+ readonly coder: Coder
+ readonly length: number
+ constructor(coerceFunc: CoerceFunc, coder: Coder, length: number, localName: string) {
+ const type = coder.type + '[' + (length >= 0 ? length : '') + ']'
+ const dynamic = length === -1 || coder.dynamic
+ super(coerceFunc, 'array', type, localName, dynamic)
+
+ this.coder = coder
+ this.length = length
+ }
+
+ encode(value: Array): Uint8Array {
+ if (!Array.isArray(value)) {
+ throw error('expected array value', INVALID_ARGUMENT, {
+ arg: this.localName,
+ coderType: 'array',
+ value: value
+ })
+ }
+
+ var count = this.length
+
+ var result = new Uint8Array(0)
+ if (count === -1) {
+ count = value.length
+ result = uint256Coder.encode(count)
+ }
+
+ checkArgumentCount(count, value.length, 'in coder array' + (this.localName ? ' ' + this.localName : ''))
+
+ var coders: Coder[] = []
+ for (var i = 0; i < value.length; i++) {
+ coders.push(this.coder)
+ }
+
+ return concatBytes(result, pack(coders, value))
+ }
+
+ decode(data: Uint8Array, offset: number) {
+ // @TODO:
+ //if (data.length < offset + length * 32) { throw new Error('invalid array'); }
+
+ var consumed = 0
+
+ var count = this.length
+
+ if (count === -1) {
+ try {
+ var decodedLength = uint256Coder.decode(data, offset)
+ } catch (error) {
+ throw error('insufficient data for dynamic array length', INVALID_ARGUMENT, {
+ arg: this.localName,
+ coderType: 'array',
+ value: error.value
+ })
+ }
+ try {
+ count = decodedLength.value.toNumber()
+ } catch (error) {
+ throw error('array count too large', INVALID_ARGUMENT, {
+ arg: this.localName,
+ coderType: 'array',
+ value: decodedLength.value.toString()
+ })
+ }
+ consumed += decodedLength.consumed
+ offset += decodedLength.consumed
+ }
+
+ var coders: Coder[] = []
+ for (var i = 0; i < count; i++) {
+ coders.push(new CoderAnonymous(this.coder))
+ }
+
+ var result = unpack(coders, data, offset)
+ result.consumed += consumed
+ result.value = this.coerceFunc(this.type, result.value)
+ return result
+ }
+}
+
+class CoderTuple extends Coder {
+ readonly coders: Array
+ constructor(coerceFunc: CoerceFunc, coders: Array, localName: string) {
+ var dynamic = false
+ var types: Array = []
+ coders.forEach(function (coder) {
+ if (coder.dynamic) {
+ dynamic = true
+ }
+ types.push(coder.type)
+ })
+ var type = 'tuple(' + types.join(',') + ')'
+
+ super(coerceFunc, 'tuple', type, localName, dynamic)
+ this.coders = coders
+ }
+
+ encode(value: Array): Uint8Array {
+ return pack(this.coders, value)
+ }
+
+ decode(data: Uint8Array, offset: number): DecodedResult {
+ var result = unpackWithNames(this.coders, data, offset)
+ result.value = this.coerceFunc(this.type, result.value)
+ return result
+ }
+}
+
+// @TODO: Is there a way to return "class"?
+const paramTypeSimple: { [key: string]: any } = {
+ address: CoderAddress,
+ bool: CoderBoolean,
+ string: CoderString,
+ bytes: CoderDynamicBytes,
+ function: CoderFunction
+}
+
+function getTupleParamCoder(
+ coerceFunc: CoerceFunc,
+ components: ReadonlyArray>,
+ localName: string
+): CoderTuple {
+ if (!components) {
+ components = []
+ }
+ var coders = components.map((component) => getParamCoder(coerceFunc, component))
+
+ return new CoderTuple(coerceFunc, coders, localName)
+}
+
+function getParamCoder(coerceFunc: CoerceFunc, param: Readonly): Coder {
+ var coder = paramTypeSimple[param.type]
+ if (coder) {
+ return new coder(coerceFunc, param.name)
+ }
+ var match = param.type.match(paramTypeNumber)
+ if (match) {
+ let size = parseInt(match[2] || '256')
+ if (size === 0 || size > 256 || size % 8 !== 0) {
+ throw error('invalid ' + match[1] + ' bit length', INVALID_ARGUMENT, {
+ arg: 'param',
+ value: param
+ })
+ }
+ return new CoderNumber(coerceFunc, size / 8, match[1] === 'int', param.name!)
+ }
+
+ var match = param.type.match(paramTypeBytes)
+ if (match) {
+ let size = parseInt(match[1])
+ if (size === 0 || size > 32) {
+ throw error('invalid bytes length', INVALID_ARGUMENT, {
+ arg: 'param',
+ value: param
+ })
+ }
+ return new CoderFixedBytes(coerceFunc, size, param.name!)
+ }
+
+ var match = param.type.match(paramTypeArray)
+
+ if (match) {
+ const newParam = { ...param }
+ let size = parseInt(match[2] || '-1')
+ newParam.type = match[1]
+ return new CoderArray(coerceFunc, getParamCoder(coerceFunc, newParam), size, param.name!)
+ }
+
+ if (param.type.substring(0, 5) === 'tuple') {
+ return getTupleParamCoder(coerceFunc, param.components!, param.name!)
+ }
+
+ if (param.type === '') {
+ return new CoderNull(coerceFunc, param.name!)
+ }
+
+ throw error('invalid type', INVALID_ARGUMENT, {
+ arg: 'type',
+ value: param.type,
+ fullType: param
+ })
+}
+
+export class AbiCoder {
+ readonly coerceFunc!: CoerceFunc
+ constructor(coerceFunc?: CoerceFunc) {
+ checkNew(this, AbiCoder)
+
+ if (!coerceFunc) {
+ coerceFunc = defaultCoerceFunc
+ }
+
+ defineReadOnly(this, 'coerceFunc', coerceFunc)
+ }
+
+ encode(types: ReadonlyArray>, values: Array): Uint8Array {
+ if (types.length !== values.length) {
+ throw error('types/values length mismatch', INVALID_ARGUMENT, {
+ count: { types: types.length, values: values.length },
+ value: { types: types, values: values }
+ })
+ }
+
+ const coders = types
+ .map(($) => {
+ if (typeof $ === 'string') {
+ return parseParamType($)
+ } else {
+ return $
+ }
+ })
+ .map(($) => getParamCoder(this.coerceFunc, $))
+
+ return new CoderTuple(this.coerceFunc, coders, '_').encode(values)
+ }
+
+ decode(types: ReadonlyArray>, data: Uint8Array): any {
+ const coders = types
+ .map(($) => {
+ if (typeof $ === 'string') {
+ return parseParamType($)
+ } else {
+ return $
+ }
+ })
+ .map(($) => getParamCoder(this.coerceFunc, $))
+
+ return new CoderTuple(this.coerceFunc, coders, '_').decode(data, 0).value
+ }
+}
diff --git a/src/abi/constants.ts b/src/abi/constants.ts
new file mode 100644
index 00000000..e6875377
--- /dev/null
+++ b/src/abi/constants.ts
@@ -0,0 +1,14 @@
+import { BigNumber } from '../utils/BigNumber'
+
+// NFKD (decomposed)
+//const EtherSymbol = '\uD835\uDF63';
+
+// NFKC (composed)
+const EtherSymbol = '\u039e'
+
+const NegativeOne: BigNumber = new BigNumber(-1)
+const Zero: BigNumber = new BigNumber(0)
+const One: BigNumber = new BigNumber(1)
+const MaxUint256: BigNumber = new BigNumber('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff')
+
+export { EtherSymbol, NegativeOne, Zero, One, MaxUint256 }
diff --git a/src/abi/parser.ts b/src/abi/parser.ts
new file mode 100644
index 00000000..be814479
--- /dev/null
+++ b/src/abi/parser.ts
@@ -0,0 +1,362 @@
+///////////////////////////////////
+// Parsing for Solidity Signatures
+
+import { AbiEvent, AbiFunction, AbiInput } from '../Schema'
+import { formatSignature } from './coder'
+
+export function parseParamType(type: string): AbiInput {
+ return parseParam(type, true)
+}
+
+export function parseSignatureFunction(fragment: string): AbiFunction {
+ var abi: AbiFunction = {
+ constant: false,
+ inputs: [],
+ name: '',
+ outputs: [],
+ payable: false,
+ type: 'function'
+ }
+
+ let comps = fragment.split('@')
+ if (comps.length !== 1) {
+ if (comps.length > 2) {
+ throw new Error('invalid signature')
+ }
+ if (!comps[1].match(/^[0-9]+$/)) {
+ throw new Error('invalid signature gas')
+ }
+ abi.gas = parseFloat(comps[1])
+ fragment = comps[0]
+ }
+
+ comps = fragment.split(' returns ')
+ var left = comps[0].match(regexParen)
+ if (!left) {
+ throw new Error('invalid signature')
+ }
+
+ abi.name = left[1].trim()
+ if (!abi.name.match(regexIdentifier)) {
+ throw new Error('invalid identifier: "' + left[1] + '"')
+ }
+
+ splitNesting(left[2]).forEach(function (param) {
+ abi.inputs!.push(parseParam(param))
+ })
+
+ left[3].split(' ').forEach(function (modifier) {
+ switch (modifier) {
+ case 'constant':
+ abi.constant = true
+ break
+ case 'payable':
+ abi.payable = true
+ abi.stateMutability = 'payable'
+ break
+ case 'pure':
+ abi.constant = true
+ abi.stateMutability = 'pure'
+ break
+ case 'view':
+ abi.constant = true
+ abi.stateMutability = 'view'
+ break
+ case 'external':
+ case 'public':
+ case '':
+ break
+ }
+ })
+
+ // We have outputs
+ if (comps.length > 1) {
+ var right = comps[1].match(regexParen)
+ if (!right || right[1].trim() != '' || right[3].trim() != '') {
+ throw new Error('unexpected tokens')
+ }
+
+ splitNesting(right[2]).forEach(function (param) {
+ abi.outputs!.push(parseParam(param))
+ })
+ }
+
+ if (abi.name === 'constructor') {
+ ;(abi as any).type = 'constructor'
+
+ if (abi.outputs!.length) {
+ throw new Error('constructor may not have outputs')
+ }
+
+ // delete abi.name
+ // delete abi.outputs
+ }
+
+ return abi
+}
+
+const regexParen = new RegExp('^([^)(]*)\\((.*)\\)([^)(]*)$')
+const regexIdentifier = new RegExp('^[A-Za-z_][A-Za-z0-9_]*$')
+
+function verifyType(type: string): string {
+ // These need to be transformed to their full description
+ if (type.match(/^uint($|[^1-9])/)) {
+ type = 'uint256' + type.substring(4)
+ } else if (type.match(/^int($|[^1-9])/)) {
+ type = 'int256' + type.substring(3)
+ }
+
+ return type
+}
+
+type ParseState = {
+ allowArray?: boolean
+ allowName?: boolean
+ allowParams?: boolean
+ allowType?: boolean
+ readArray?: boolean
+}
+
+type ParseNode = {
+ parent?: any
+ type?: string
+ name?: string
+ state?: ParseState
+ indexed?: boolean
+ components?: Array
+}
+
+function parseParam(param: string, allowIndexed?: boolean): AbiInput {
+ function throwError(i: number) {
+ return new Error('unexpected character "' + param[i] + '" at position ' + i + ' in "' + param + '"')
+ }
+
+ var parent: ParseNode = { type: '', name: '', state: { allowType: true } }
+ var node: any = parent
+
+ for (var i = 0; i < param.length; i++) {
+ var c = param[i]
+ switch (c) {
+ case '(':
+ if (!node.state.allowParams) {
+ throw throwError(i)
+ }
+ node.state.allowType = false
+ node.type = verifyType(node.type)
+ node.components = [{ type: '', name: '', parent: node, state: { allowType: true } }]
+ node = node.components[0]
+ break
+
+ case ')':
+ delete node.state
+ if (allowIndexed && node.name === 'indexed') {
+ node.indexed = true
+ node.name = ''
+ }
+ node.type = verifyType(node.type)
+
+ var child = node
+ node = node.parent
+ if (!node) {
+ throw throwError(i)
+ }
+ delete child.parent
+ node.state.allowParams = false
+ node.state.allowName = true
+ node.state.allowArray = true
+ break
+
+ case ',':
+ delete node.state
+ if (allowIndexed && node.name === 'indexed') {
+ node.indexed = true
+ node.name = ''
+ }
+ node.type = verifyType(node.type)
+
+ var sibling: ParseNode = { type: '', name: '', parent: node.parent, state: { allowType: true } }
+ node.parent.components.push(sibling)
+ delete node.parent
+ node = sibling
+ break
+
+ // Hit a space...
+ case ' ':
+ // If reading type, the type is done and may read a param or name
+ if (node.state.allowType) {
+ if (node.type !== '') {
+ node.type = verifyType(node.type)
+ delete node.state.allowType
+ node.state.allowName = true
+ node.state.allowParams = true
+ }
+ }
+
+ // If reading name, the name is done
+ if (node.state.allowName) {
+ if (node.name !== '') {
+ if (allowIndexed && node.name === 'indexed') {
+ node.indexed = true
+ node.name = ''
+ } else {
+ node.state.allowName = false
+ }
+ }
+ }
+
+ break
+
+ case '[':
+ if (!node.state.allowArray) {
+ throw throwError(i)
+ }
+
+ node.type += c
+
+ node.state.allowArray = false
+ node.state.allowName = false
+ node.state.readArray = true
+ break
+
+ case ']':
+ if (!node.state.readArray) {
+ throw throwError(i)
+ }
+
+ node.type += c
+
+ node.state.readArray = false
+ node.state.allowArray = true
+ node.state.allowName = true
+ break
+
+ default:
+ if (node.state.allowType) {
+ node.type += c
+ node.state.allowParams = true
+ node.state.allowArray = true
+ } else if (node.state.allowName) {
+ node.name += c
+ delete node.state.allowArray
+ } else if (node.state.readArray) {
+ node.type += c
+ } else {
+ throw throwError(i)
+ }
+ }
+ }
+
+ if (node.parent) {
+ throw new Error('unexpected eof')
+ }
+
+ delete parent.state
+
+ if (allowIndexed && node.name === 'indexed') {
+ node.indexed = true
+ node.name = ''
+ }
+
+ parent.type = verifyType(parent.type!)
+
+ return parent as AbiInput
+}
+
+// @TODO: Better return type
+export function parseSignatureEvent(fragment: string): AbiEvent {
+ var abi: AbiEvent = {
+ anonymous: false,
+ inputs: [],
+ name: '',
+ type: 'event'
+ }
+
+ var match = fragment.match(regexParen)
+ if (!match) {
+ throw new Error('invalid event: ' + fragment)
+ }
+
+ abi.name = match[1].trim()
+
+ splitNesting(match[2]).forEach(function (param) {
+ param = parseParam(param, true)
+ param.indexed = !!param.indexed
+ abi.inputs!.push(param)
+ })
+
+ match[3].split(' ').forEach(function (modifier) {
+ switch (modifier) {
+ case 'anonymous':
+ abi.anonymous = true
+ break
+ case '':
+ break
+ }
+ })
+
+ if (abi.name && !abi.name.match(regexIdentifier)) {
+ throw new Error('invalid identifier: "' + abi.name + '"')
+ }
+
+ return abi
+}
+
+function splitNesting(value: string): Array {
+ value = value.trim()
+
+ var result: string[] = []
+ var accum = ''
+ var depth = 0
+ for (var offset = 0; offset < value.length; offset++) {
+ var c = value[offset]
+ if (c === ',' && depth === 0) {
+ result.push(accum)
+ accum = ''
+ } else {
+ accum += c
+ if (c === '(') {
+ depth++
+ } else if (c === ')') {
+ depth--
+ if (depth === -1) {
+ throw new Error('unbalanced parenthsis')
+ }
+ }
+ }
+ }
+ if (accum) {
+ result.push(accum)
+ }
+
+ return result
+}
+
+export function parseSignature(fragment: string): AbiEvent | AbiFunction {
+ if (typeof fragment === 'string') {
+ // Make sure the "returns" is surrounded by a space and all whitespace is exactly one space
+ fragment = fragment.replace(/\(/g, ' (').replace(/\)/g, ') ').replace(/\s+/g, ' ')
+ fragment = fragment.trim()
+
+ if (fragment.substring(0, 6) === 'event ') {
+ const ret = parseSignatureEvent(fragment.substring(6).trim())
+
+ // check if it throws
+ formatSignature(ret)
+
+ return ret
+ } else {
+ if (fragment.substring(0, 9) === 'function ') {
+ fragment = fragment.substring(9)
+ }
+
+ const ret = parseSignatureFunction(fragment.trim())
+
+ // check if it throws
+ formatSignature(ret)
+
+ return ret
+ }
+ }
+
+ throw new Error('unknown signature')
+}
diff --git a/src/abi/properties.ts b/src/abi/properties.ts
new file mode 100644
index 00000000..df06decc
--- /dev/null
+++ b/src/abi/properties.ts
@@ -0,0 +1,7 @@
+export function defineReadOnly(object: any, name: string, value: any): void {
+ Object.defineProperty(object, name, {
+ enumerable: true,
+ value: value,
+ writable: false
+ })
+}
diff --git a/src/index.ts b/src/index.ts
index 4bf154ef..30c6708d 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -19,6 +19,7 @@ export * from './providers/HTTPProvider'
export * from './providers/WebSocketProvider'
export * from './utils/utils'
export * from './Schema'
+export * from './utils/utf8'
export * from './utils/jsonrpc'
export { IFuture } from 'fp-future'
@@ -36,4 +37,5 @@ export { SolidityFunction } from './SolidityFunction'
export { SolidityEvent } from './SolidityEvent'
import { RequestManager } from './RequestManager'
+
export default RequestManager
diff --git a/src/solidity/address.ts b/src/solidity/address.ts
deleted file mode 100644
index 64d473f1..00000000
--- a/src/solidity/address.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import * as f from './formatters'
-import { SolidityType } from './type'
-
-export class SolidityTypeAddress extends SolidityType {
- constructor() {
- super({
- inputFormatter: f.formatInputAddress,
- outputFormatter: f.formatOutputAddress
- })
- }
-
- // tslint:disable-next-line:prefer-function-over-method
- isType(name: string) {
- return !!name.match(/address(\[([0-9]*)\])?/)
- }
-}
diff --git a/src/solidity/bool.ts b/src/solidity/bool.ts
deleted file mode 100644
index 7423726b..00000000
--- a/src/solidity/bool.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import * as f from './formatters'
-import { SolidityType } from './type'
-
-/**
- * SolidityTypeBool is a prootype that represents bool type
- * It matches:
- * bool
- * bool[]
- * bool[4]
- * bool[][]
- * bool[3][]
- * bool[][6][], ...
- */
-export class SolidityTypeBool extends SolidityType {
- constructor() {
- super({
- inputFormatter: f.formatInputBool,
- outputFormatter: f.formatOutputBool
- })
- }
- isType(name: string) {
- return !!name.match(/^bool(\[([0-9]*)\])*$/)
- }
-}
diff --git a/src/solidity/bytes.ts b/src/solidity/bytes.ts
deleted file mode 100644
index e4728ca5..00000000
--- a/src/solidity/bytes.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import * as f from './formatters'
-import { SolidityType } from './type'
-
-/**
- * SolidityTypeBytes is a prototype that represents the bytes type.
- * It matches:
- * bytes
- * bytes[]
- * bytes[4]
- * bytes[][]
- * bytes[3][]
- * bytes[][6][], ...
- * bytes32
- * bytes8[4]
- * bytes[3][]
- */
-export class SolidityTypeBytes extends SolidityType {
- constructor() {
- super({
- inputFormatter: f.formatInputBytes,
- outputFormatter: f.formatOutputBytes
- })
- }
- // tslint:disable-next-line:prefer-function-over-method
- isType(name: string) {
- return !!name.match(/^bytes([0-9]{1,})(\[([0-9]*)\])*$/)
- }
-}
diff --git a/src/solidity/coder.ts b/src/solidity/coder.ts
index 1ff62d44..069c4d48 100644
--- a/src/solidity/coder.ts
+++ b/src/solidity/coder.ts
@@ -15,64 +15,17 @@
along with web3.js. If not, see .
*/
-import * as formatter from './formatters'
+import { AbiCoder } from '../abi/coder'
+import { AbiOutput } from '../Schema'
+import * as utils from '../utils/utils'
+import { bytesToHex } from '../utils/utils'
-import { SolidityTypeAddress } from './address'
-import { SolidityTypeBool } from './bool'
-import { SolidityTypeInt } from './int'
-import { SolidityTypeUInt } from './uint'
-import { SolidityTypeDynamicBytes } from './dynamicbytes'
-import { SolidityTypeString } from './string'
-import { SolidityTypeReal } from './real'
-import { SolidityTypeUReal } from './ureal'
-import { SolidityTypeBytes } from './bytes'
-import { SolidityType } from './type'
-
-function isDynamic(solidityType: SolidityType, type: string) {
- return solidityType.isDynamicType(type) || solidityType.isDynamicArray(type)
-}
+const ethersAbiCoder = new AbiCoder()
/**
* SolidityCoder prototype should be used to encode/decode solidity params of any type
*/
-export class SolidityCoder {
- _types: SolidityType[]
-
- constructor(types: SolidityType[]) {
- this._types = types
- }
-
- /**
- * This method should be used to transform type to SolidityType
- *
- * @param {string} type
- * @returns {SolidityType}
- * @throws {Error} throws if no matching type is found
- */
- _requireType(type: string): SolidityType {
- let solidityType = this._types.filter(function (t) {
- return t.isType(type)
- })[0]
-
- if (!solidityType) {
- throw Error('invalid solidity type!: ' + type)
- }
-
- return solidityType
- }
-
- /**
- * Should be used to encode plain param
- *
- * @method encodeParam
- * @param {string} type
- * @param {object} plain param
- * @return {string} encoded plain param
- */
- encodeParam(type: string, param: any): string {
- return this.encodeParams([type], [param])
- }
-
+export namespace coder {
/**
* Should be used to encode list of params
*
@@ -81,123 +34,8 @@ export class SolidityCoder {
* @param {Array} params
* @return {string} encoded list of params
*/
- encodeParams(types: string[], params: any[]): string {
- let solidityTypes = this.getSolidityTypes(types)
-
- let encodeds = solidityTypes.map(function (solidityType, index) {
- return solidityType.encode(params[index], types[index])
- })
-
- let dynamicOffset = solidityTypes.reduce(function (acc, solidityType, index) {
- let staticPartLength = solidityType.staticPartLength(types[index])
- let roundedStaticPartLength = Math.floor((staticPartLength + 31) / 32) * 32
-
- return acc + (isDynamic(solidityTypes[index], types[index]) ? 32 : roundedStaticPartLength)
- }, 0)
-
- let result = this.encodeMultiWithOffset(types, solidityTypes, encodeds, dynamicOffset)
-
- return result
- }
-
- encodeMultiWithOffset(
- types: string[],
- solidityTypes: SolidityType[],
- encodeds: (string | string[])[],
- _dynamicOffset: number
- ): string {
- let dynamicOffset = _dynamicOffset
- let results: string[] = []
-
- types.forEach((_, i) => {
- if (isDynamic(solidityTypes[i], types[i])) {
- results.push(formatter.formatInputInt(dynamicOffset).encode())
- let e = this.encodeWithOffset(types[i], solidityTypes[i], encodeds[i], dynamicOffset)
- dynamicOffset += e.length / 2
- } else {
- // don't add length to dynamicOffset. it's already counted
- results.push(this.encodeWithOffset(types[i], solidityTypes[i], encodeds[i], dynamicOffset))
- }
-
- // TODO: figure out nested arrays
- })
-
- types.forEach((_, i) => {
- if (isDynamic(solidityTypes[i], types[i])) {
- let e = this.encodeWithOffset(types[i], solidityTypes[i], encodeds[i], dynamicOffset)
- dynamicOffset += e.length / 2
- results.push(e)
- }
- })
- return results.join('')
- }
-
- // tslint:disable-next-line:prefer-function-over-method
- encodeWithOffset(type: string, solidityType: SolidityType, encoded: string | string[], offset: number): string {
- /* jshint maxcomplexity: 17 */
- /* jshint maxdepth: 5 */
-
- let encodingMode = { dynamic: 1, static: 2, other: 3 }
-
- let mode = solidityType.isDynamicArray(type)
- ? encodingMode.dynamic
- : solidityType.isStaticArray(type)
- ? encodingMode.static
- : encodingMode.other
-
- if (mode !== encodingMode.other) {
- let nestedName = solidityType.nestedName(type)
- let nestedStaticPartLength = solidityType.staticPartLength(nestedName)
- let results: string[] = []
-
- if (mode === encodingMode.dynamic) {
- results.push(encoded[0] as string)
- }
-
- if (solidityType.isDynamicArray(nestedName)) {
- let previousLength = mode === encodingMode.dynamic ? 2 : 0
-
- for (let i = 0; i < encoded.length; i++) {
- // calculate length of previous item
- if (mode === encodingMode.dynamic) {
- previousLength += +encoded[i - 1][0] || 0
- } else if (mode === encodingMode.static) {
- previousLength += +(encoded[i - 1] || [])[0] || 0
- }
- results.push(formatter.formatInputInt(offset + i * nestedStaticPartLength + previousLength * 32).encode())
- }
- }
-
- let len = mode === encodingMode.dynamic ? encoded.length - 1 : encoded.length
- for (let c = 0; c < len; c++) {
- let additionalOffset = results.join('').length / 2
- if (mode === encodingMode.dynamic) {
- results.push(this.encodeWithOffset(nestedName, solidityType, encoded[c + 1], offset + additionalOffset))
- } else if (mode === encodingMode.static) {
- results.push(this.encodeWithOffset(nestedName, solidityType, encoded[c], offset + additionalOffset))
- }
- }
-
- return results.join('')
- }
-
- if (typeof encoded != 'string') {
- throw new Error('Encoded is not string')
- }
-
- return encoded as any
- }
-
- /**
- * Should be used to decode bytes to plain param
- *
- * @method decodeParam
- * @param {string} type
- * @param {string} bytes
- * @return {object} plain param
- */
- decodeParam(type: string, bytes: string) {
- return this.decodeParams([type], bytes)[0]
+ export function encodeParams(types: ReadonlyArray>, params: any[]): string {
+ return bytesToHex(ethersAbiCoder.encode(types, params))
}
/**
@@ -208,46 +46,17 @@ export class SolidityCoder {
* @param {string} bytes
* @return {Array} array of plain params
*/
- decodeParams(types: string[], bytes: string): any[] {
- let solidityTypes = this.getSolidityTypes(types)
- let offsets = this.getOffsets(types, solidityTypes)
-
- return solidityTypes.map(function (solidityType, index) {
- return solidityType.decode(bytes, offsets[index], types[index])
- })
- }
-
- // tslint:disable-next-line:prefer-function-over-method
- getOffsets(types: string[], solidityTypes: SolidityType[]): number[] {
- let lengths = solidityTypes.map(function (solidityType, index) {
- return solidityType.staticPartLength(types[index])
- })
-
- for (let i = 1; i < lengths.length; i++) {
- // sum with length of previous element
- lengths[i] += lengths[i - 1]
+ export function decodeParams(outputs: ReadonlyArray>, bytes: string): any {
+ if (outputs.length > 0 && (!bytes || bytes === '0x' || bytes === '0X')) {
+ throw new Error(
+ "Returned values aren't valid, did it run Out of Gas? " +
+ 'You might also see this error if you are not using the ' +
+ 'correct ABI for the contract you are retrieving data from, ' +
+ 'requesting data from a block number that does not exist, ' +
+ 'or querying a node which is not fully synced.'
+ )
}
- return lengths.map(function (length, index) {
- // remove the current length, so the length is sum of previous elements
- let staticPartLength = solidityTypes[index].staticPartLength(types[index])
- return length - staticPartLength
- })
- }
-
- getSolidityTypes(types: string[]): SolidityType[] {
- return types.map((type) => this._requireType(type))
+ return ethersAbiCoder.decode(outputs, utils.hexToBytes('0x' + bytes.replace(/0x/i, '')))
}
}
-
-export const coder = new SolidityCoder([
- new SolidityTypeAddress(),
- new SolidityTypeBool(),
- new SolidityTypeInt(),
- new SolidityTypeUInt(),
- new SolidityTypeDynamicBytes(),
- new SolidityTypeBytes(),
- new SolidityTypeString(),
- new SolidityTypeReal(),
- new SolidityTypeUReal()
-])
diff --git a/src/solidity/dynamicbytes.ts b/src/solidity/dynamicbytes.ts
deleted file mode 100644
index 826aa31b..00000000
--- a/src/solidity/dynamicbytes.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import * as f from './formatters'
-import { SolidityType } from './type'
-
-export class SolidityTypeDynamicBytes extends SolidityType {
- constructor() {
- super({
- inputFormatter: f.formatInputDynamicBytes,
- outputFormatter: f.formatOutputDynamicBytes
- })
- }
-
- // tslint:disable-next-line:prefer-function-over-method
- isType(name: string) {
- return !!name.match(/^bytes(\[([0-9]*)\])*$/)
- }
-
- // tslint:disable-next-line:prefer-function-over-method
- isDynamicType() {
- return true
- }
-}
diff --git a/src/solidity/formatters.ts b/src/solidity/formatters.ts
deleted file mode 100644
index 2ba03330..00000000
--- a/src/solidity/formatters.ts
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- This file is part of web3.js.
-
- web3.js is free software: you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- web3.js 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 Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with web3.js. If not, see .
-*/
-
-import * as utils from '../utils/utils'
-import * as config from '../utils/config'
-import { SolidityParam } from './param'
-import { BigNumber } from '../utils/BigNumber'
-import { inputAddressFormatter } from '../utils/formatters'
-
-/**
- * Formats input value to byte representation of int
- * If value is negative, return it's two's complement
- * If the value is floating point, round it down
- */
-export function formatInputInt(value: BigNumber.Value) {
- BigNumber.config(config.ETH_BIGNUMBER_ROUNDING_MODE)
-
- let result = utils.padLeft(utils.toTwosComplement(value).toString(16), 64)
-
- const ret = new SolidityParam(result)
-
- if (ret.value.indexOf('NaN') != -1) {
- throw new Error(`The number ${JSON.stringify(value)} can't be parsed.`)
- }
-
- return ret
-}
-
-export function formatInputAddress(value: string) {
- if (typeof value != 'string') throw new Error('The input must be a valid address, got: ' + JSON.stringify(value))
- return formatInputInt(inputAddressFormatter(value.trim()))
-}
-
-/**
- * Formats input bytes
- */
-export function formatInputBytes(value: string) {
- let result = utils.toHex(value).substr(2)
- let l = Math.floor((result.length + 63) / 64)
- result = utils.padRight(result, l * 64)
- return new SolidityParam(result)
-}
-
-/**
- * Formats input bytes
- */
-export function formatInputDynamicBytes(value: string) {
- let result = utils.toHex(value).substr(2)
- let length = result.length / 2
- let l = Math.floor((result.length + 63) / 64)
- result = utils.padRight(result, l * 64)
- return new SolidityParam(formatInputInt(length).value + result)
-}
-
-/**
- * Formats input value to byte representation of string
- */
-export function formatInputString(value: string) {
- let result = utils.fromUtf8(value).substr(2)
- let length = result.length / 2
- let l = Math.floor((result.length + 63) / 64)
- result = utils.padRight(result, l * 64)
- return new SolidityParam(formatInputInt(length).value + result)
-}
-
-/**
- * Formats input value to byte representation of bool
- */
-export function formatInputBool(value: boolean) {
- let result = '000000000000000000000000000000000000000000000000000000000000000' + (value ? '1' : '0')
- return new SolidityParam(result)
-}
-
-/**
- * Formats input value to byte representation of real
- * Values are multiplied by 2^m and encoded as integers
- */
-export function formatInputReal(value: BigNumber.Value) {
- return formatInputInt(new BigNumber(value).times(new BigNumber(2).pow(128)))
-}
-
-/**
- * Check if input value is negative
- *
- * @param value - The value is hex format
- */
-export function signedIsNegative(value: string) {
- return new BigNumber(value.substr(0, 1), 16).toString(2).substr(0, 1) === '1'
-}
-
-/**
- * Formats right-aligned output bytes to int
- */
-export function formatOutputInt(param: SolidityParam): BigNumber {
- let value = param.staticPart() || '0'
-
- // check if it's negative number
- // it it is, return two's complement
- if (signedIsNegative(value)) {
- return new BigNumber(value, 16)
- .minus(new BigNumber('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 16))
- .minus(1)
- }
- return new BigNumber(value, 16)
-}
-
-/**
- * Formats right-aligned output bytes to uint
- */
-export function formatOutputUInt(param: SolidityParam) {
- let value = param.staticPart()
- return new BigNumber(value, 16)
-}
-
-/**
- * Formats right-aligned output bytes to real
- */
-export function formatOutputReal(param: SolidityParam) {
- return formatOutputInt(param).dividedBy(new BigNumber(2).pow(128))
-}
-
-/**
- * Formats right-aligned output bytes to ureal
- */
-export function formatOutputUReal(param: SolidityParam) {
- return formatOutputUInt(param).dividedBy(new BigNumber(2).pow(128))
-}
-
-/**
- * Should be used to format output bool
- */
-export function formatOutputBool(param: SolidityParam) {
- return param.staticPart() === '0000000000000000000000000000000000000000000000000000000000000001' ? true : false
-}
-
-/**
- * Should be used to format output bytes
- *
- * @param param - The left-aligned hex representation of string
- * @param name - The type name
- */
-export function formatOutputBytes(param: SolidityParam, name: string) {
- let matches = name.match(/^bytes([0-9]*)/)
- if (!matches) throw new Error('Type is not bytes')
- let size = parseInt(matches[1], 10)
- return '0x' + param.staticPart().slice(0, 2 * size)
-}
-
-/**
- * Should be used to format output bytes
- *
- * @param param - The left-aligned hex representation of string
- */
-export function formatOutputDynamicBytes(param: SolidityParam) {
- let length = new BigNumber(param.dynamicPart().slice(0, 64), 16).toNumber() * 2
- return '0x' + param.dynamicPart().substr(64, length)
-}
-
-/**
- * Should be used to format output string
- *
- * @param param - The left-aligned hex representation of string
- */
-export function formatOutputString(param: SolidityParam) {
- let length = new BigNumber(param.dynamicPart().slice(0, 64), 16).toNumber() * 2
- return utils.toUtf8(param.dynamicPart().substr(64, length))
-}
-
-/**
- * Should be used to format output address
- *
- * @param param - The right-aligned input bytes
- */
-export function formatOutputAddress(param: SolidityParam) {
- let value = param.staticPart()
- return '0x' + value.slice(value.length - 40, value.length)
-}
diff --git a/src/solidity/int.ts b/src/solidity/int.ts
deleted file mode 100644
index bd9bd094..00000000
--- a/src/solidity/int.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import BigNumber from 'bignumber.js'
-import * as f from './formatters'
-import { SolidityType } from './type'
-
-/**
- * SolidityTypeInt is a prootype that represents int type
- * It matches:
- * int
- * int[]
- * int[4]
- * int[][]
- * int[3][]
- * int[][6][], ...
- * int32
- * int64[]
- * int8[4]
- * int256[][]
- * int[3][]
- * int64[][6][], ...
- */
-export class SolidityTypeInt extends SolidityType {
- constructor() {
- super({
- inputFormatter: f.formatInputInt,
- outputFormatter: f.formatOutputInt
- })
- }
-
- // tslint:disable-next-line:prefer-function-over-method
- isType(name: string) {
- return !!name.match(/^int([0-9]*)?(\[([0-9]*)\])*$/)
- }
-}
diff --git a/src/solidity/param.ts b/src/solidity/param.ts
deleted file mode 100644
index 05de9b3d..00000000
--- a/src/solidity/param.ts
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- This file is part of web3.js.
-
- web3.js is free software: you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- web3.js 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 Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with web3.js. If not, see .
-*/
-
-import * as utils from '../utils/utils'
-
-/**
- * SolidityParam object prototype.
- * Should be used when encoding, decoding solidity bytes
- */
-export class SolidityParam {
- constructor(public value: string = '', public offset?: number) {}
-
- /**
- * This method should be called to check if param has dynamic size.
- * If it has, it returns true, otherwise false
- *
- * @method isDynamic
- * @returns {Boolean}
- */
- isDynamic(): boolean {
- return this.offset !== undefined
- }
-
- /**
- * This method should be called to transform offset to bytes
- *
- * @method offsetAsBytes
- * @returns {string} bytes representation of offset
- */
- offsetAsBytes(): string {
- return !this.isDynamic() ? '' : utils.padLeft(utils.toTwosComplement(this.offset || '').toString(16), 64)
- }
-
- /**
- * This method should be called to get static part of param
- *
- * @method staticPart
- * @returns {string} offset if it is a dynamic param, otherwise value
- */
- staticPart(): string {
- if (!this.isDynamic()) {
- return this.value
- }
- return this.offsetAsBytes()
- }
-
- /**
- * This method should be called to get dynamic part of param
- *
- * @method dynamicPart
- * @returns {string} returns a value if it is a dynamic param, otherwise empty string
- */
- dynamicPart(): string {
- return this.isDynamic() ? this.value : ''
- }
-
- /**
- * This method should be called to encode param
- *
- * @method encode
- * @returns {string}
- */
- encode(): string {
- return this.staticPart() + this.dynamicPart()
- }
-}
diff --git a/src/solidity/real.ts b/src/solidity/real.ts
deleted file mode 100644
index a895d3e5..00000000
--- a/src/solidity/real.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import * as f from './formatters'
-import { SolidityType } from './type'
-import { BigNumber } from '../utils/BigNumber'
-
-/**
- * SolidityTypeReal is a prootype that represents real type
- * It matches:
- * real
- * real[]
- * real[4]
- * real[][]
- * real[3][]
- * real[][6][], ...
- * real32
- * real64[]
- * real8[4]
- * real256[][]
- * real[3][]
- * real64[][6][], ...
- */
-export class SolidityTypeReal extends SolidityType {
- constructor() {
- super({
- inputFormatter: f.formatInputReal,
- outputFormatter: f.formatOutputReal
- })
- }
-
- // tslint:disable-next-line:prefer-function-over-method
- isType(name: string) {
- return !!name.match(/real([0-9]*)?(\[([0-9]*)\])?/)
- }
-}
diff --git a/src/solidity/string.ts b/src/solidity/string.ts
deleted file mode 100644
index c4533951..00000000
--- a/src/solidity/string.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import * as f from './formatters'
-import { SolidityType } from './type'
-
-export class SolidityTypeString extends SolidityType {
- constructor() {
- super({
- inputFormatter: f.formatInputString,
- outputFormatter: f.formatOutputString
- })
- }
-
- // tslint:disable-next-line:prefer-function-over-method
- isType(name: string) {
- return !!name.match(/^string(\[([0-9]*)\])*$/)
- }
-
- // tslint:disable-next-line:prefer-function-over-method
- isDynamicType() {
- return true
- }
-}
diff --git a/src/solidity/type.ts b/src/solidity/type.ts
deleted file mode 100644
index 87ad12f7..00000000
--- a/src/solidity/type.ts
+++ /dev/null
@@ -1,242 +0,0 @@
-import * as f from './formatters'
-import { SolidityParam } from './param'
-
-/**
- * SolidityType prototype is used to encode/decode solidity params of certain type
- */
-export abstract class SolidityType {
- _inputFormatter: (value: ValueType, name: string) => SolidityParam
- _outputFormatter: (param: SolidityParam, name: string) => ValueType
-
- constructor(config: {
- inputFormatter: (value: ValueType, name: string) => SolidityParam
- outputFormatter: (param: SolidityParam, name: string) => ValueType
- }) {
- this._inputFormatter = config.inputFormatter
- this._outputFormatter = config.outputFormatter
- }
-
- /**
- * Should be used to determine if this SolidityType do match given name
- *
- * @method isType
- * @param {string} name
- * @return {Bool} true if type match this SolidityType, otherwise false
- */
- abstract isType(name: string): boolean
-
- /**
- * Should be used to determine what is the length of static part in given type
- *
- * @method staticPartLength
- * @param {string} name
- * @return {number} length of static part in bytes
- */
- staticPartLength(name: string): number {
- // If name isn't an array then treat it like a single element array.
- return (this.nestedTypes(name) || ['[1]'])
- .map(function (type) {
- // the length of the nested array
- return parseInt(type.slice(1, -1), 10) || 1
- })
- .reduce(function (previous, current) {
- return previous * current
- // all basic types are 32 bytes long
- }, 32)
- }
-
- /**
- * Should be used to determine if type is dynamic array
- * eg:
- * "type[]" => true
- * "type[4]" => false
- *
- * @method isDynamicArray
- * @param {string} name
- * @return {bool} true if the type is dynamic array
- */
- isDynamicArray(name: string): boolean {
- let nestedTypes = this.nestedTypes(name)
- return !!nestedTypes && !nestedTypes[nestedTypes.length - 1].match(/[0-9]{1,}/g)
- }
-
- /**
- * Should be used to determine if type is static array
- * eg:
- * "type[]" => false
- * "type[4]" => true
- *
- * @method isStaticArray
- * @param {string} name
- * @return {Bool} true if the type is static array
- */
- isStaticArray(name: string): boolean {
- let nestedTypes = this.nestedTypes(name)
- return !!nestedTypes && !!nestedTypes[nestedTypes.length - 1].match(/[0-9]{1,}/g)
- }
-
- /**
- * Should return length of static array
- * eg.
- * "int[32]" => 32
- * "int256[14]" => 14
- * "int[2][3]" => 3
- * "int" => 1
- * "int[1]" => 1
- * "int[]" => 1
- *
- * @method staticArrayLength
- * @param {string} name
- * @return {number} static array length
- */
- staticArrayLength(name: string): number {
- let nestedTypes = this.nestedTypes(name)
- if (nestedTypes) {
- const match = nestedTypes[nestedTypes.length - 1].match(/[0-9]{1,}/g)
- if (!match) throw new Error('untested path')
- return parseInt(match[match.length - 1] || '1', 10)
- }
- return 1
- }
-
- /**
- * Should return nested type
- * eg.
- * "int[32]" => "int"
- * "int256[14]" => "int256"
- * "int[2][3]" => "int[2]"
- * "int" => "int"
- * "int[]" => "int"
- *
- * @method nestedName
- * @param {string} name
- * @return {string} nested name
- */
- nestedName(name: string): string {
- // remove last [] in name
- let nestedTypes = this.nestedTypes(name)
- if (!nestedTypes) {
- return name
- }
-
- return name.substr(0, name.length - nestedTypes[nestedTypes.length - 1].length)
- }
-
- /**
- * Should return true if type has dynamic size by default
- * such types are "string", "bytes"
- *
- * @method isDynamicType
- * @param {string} name
- * @return {Bool} true if is dynamic, otherwise false
- */
- // tslint:disable-next-line:prefer-function-over-method
- isDynamicType(_?: string): boolean {
- return false
- }
-
- /**
- * Should return array of nested types
- * eg.
- * "int[2][3][]" => ["[2]", "[3]", "[]"]
- * "int[] => ["[]"]
- * "int" => null
- *
- * @method nestedTypes
- * @param {string} name
- * @return {Array} array of nested types
- */
- // tslint:disable-next-line:prefer-function-over-method
- nestedTypes(name: string): string[] | null {
- // return list of strings eg. "[]", "[3]", "[]", "[2]"
- return name.match(/(\[[0-9]*\])/g)
- }
-
- /**
- * Should be used to encode the value
- *
- * @method encode
- * @param {object} value
- * @param {string} name
- * @return {string} encoded value
- */
- encode(value: any, name: string): string | string[] {
- if (this.isDynamicArray(name)) {
- let length = value.length // in int
- let nestedName = this.nestedName(name)
-
- let result = []
- result.push(f.formatInputInt(length).encode())
-
- value.forEach((v: any) => {
- result.push(this.encode(v, nestedName))
- })
-
- return result
- } else if (this.isStaticArray(name)) {
- let length = this.staticArrayLength(name) // in int
- let nestedName = this.nestedName(name)
-
- let result: string[] = []
- for (let i = 0; i < length; i++) {
- result.push(this.encode(value[i], nestedName) as string)
- }
-
- return result
- }
-
- return this._inputFormatter(value, name).encode()
- }
-
- /**
- * Should be used to decode value from bytes
- *
- * @method decode
- * @param {string} bytes
- * @param {number} offset in bytes
- * @param {string} name type name
- * @returns {object} decoded value
- */
- decode(bytes: string, offset: number, name: string): any {
- if (this.isDynamicArray(name)) {
- let arrayOffset = parseInt('0x' + bytes.substr(offset * 2, 64), 16) // in bytes
- let length = parseInt('0x' + bytes.substr(arrayOffset * 2, 64), 16) // in int
- let arrayStart = arrayOffset + 32 // array starts after length; // in bytes
-
- let nestedName = this.nestedName(name)
- let nestedStaticPartLength = this.staticPartLength(nestedName) // in bytes
- let roundedNestedStaticPartLength = Math.floor((nestedStaticPartLength + 31) / 32) * 32
- let result = []
-
- for (let i = 0; i < length * roundedNestedStaticPartLength; i += roundedNestedStaticPartLength) {
- result.push(this.decode(bytes, arrayStart + i, nestedName))
- }
-
- return result
- } else if (this.isStaticArray(name)) {
- let length = this.staticArrayLength(name) // in int
- let arrayStart = offset // in bytes
-
- let nestedName = this.nestedName(name)
- let nestedStaticPartLength = this.staticPartLength(nestedName) // in bytes
- let roundedNestedStaticPartLength = Math.floor((nestedStaticPartLength + 31) / 32) * 32
- let result = []
-
- for (let i = 0; i < length * roundedNestedStaticPartLength; i += roundedNestedStaticPartLength) {
- result.push(this.decode(bytes, arrayStart + i, nestedName))
- }
-
- return result
- } else if (this.isDynamicType(name)) {
- let dynamicOffset = parseInt('0x' + bytes.substr(offset * 2, 64), 16) // in bytes
- let length = parseInt('0x' + bytes.substr(dynamicOffset * 2, 64), 16) // in bytes
- let roundedLength = Math.floor((length + 31) / 32) // in int
- let param = new SolidityParam(bytes.substr(dynamicOffset * 2, (1 + roundedLength) * 64), 0)
- return this._outputFormatter(param, name)
- }
-
- let length = this.staticPartLength(name)
- let param = new SolidityParam(bytes.substr(offset * 2, length * 2))
- return this._outputFormatter(param, name)
- }
-}
diff --git a/src/solidity/uint.ts b/src/solidity/uint.ts
deleted file mode 100644
index a75c4ef9..00000000
--- a/src/solidity/uint.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import BigNumber from 'bignumber.js'
-import * as f from './formatters'
-import { SolidityType } from './type'
-
-/**
- * SolidityTypeUInt is a prootype that represents uint type
- * It matches:
- * uint
- * uint[]
- * uint[4]
- * uint[][]
- * uint[3][]
- * uint[][6][], ...
- * uint32
- * uint64[]
- * uint8[4]
- * uint256[][]
- * uint[3][]
- * uint64[][6][], ...
- */
-export class SolidityTypeUInt extends SolidityType {
- constructor() {
- super({
- inputFormatter: f.formatInputInt,
- outputFormatter: f.formatOutputUInt
- })
- }
-
- // tslint:disable-next-line:prefer-function-over-method
- isType(name: string) {
- return !!name.match(/^uint([0-9]*)?(\[([0-9]*)\])*$/)
- }
-}
diff --git a/src/solidity/ureal.ts b/src/solidity/ureal.ts
deleted file mode 100644
index 8fe83099..00000000
--- a/src/solidity/ureal.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import * as f from './formatters'
-import { SolidityType } from './type'
-import { BigNumber } from '../utils/BigNumber'
-
-/**
- * SolidityTypeUReal is a prootype that represents ureal type
- * It matches:
- * ureal
- * ureal[]
- * ureal[4]
- * ureal[][]
- * ureal[3][]
- * ureal[][6][], ...
- * ureal32
- * ureal64[]
- * ureal8[4]
- * ureal256[][]
- * ureal[3][]
- * ureal64[][6][], ...
- */
-export class SolidityTypeUReal extends SolidityType {
- constructor() {
- super({
- inputFormatter: f.formatInputReal,
- outputFormatter: f.formatOutputUReal
- })
- }
-
- // tslint:disable-next-line:prefer-function-over-method
- isType(name: string) {
- return !!name.match(/^ureal([0-9]*)?(\[([0-9]*)\])*$/)
- }
-}
diff --git a/src/utils/BigNumber.ts b/src/utils/BigNumber.ts
index e1259015..d60dbcde 100644
--- a/src/utils/BigNumber.ts
+++ b/src/utils/BigNumber.ts
@@ -1 +1,8 @@
-export { BigNumber } from 'bignumber.js'
+import { BigNumber } from 'bignumber.js'
+export { BigNumber }
+
+const ETH_BIGNUMBER_ROUNDING_MODE = {
+ ROUNDING_MODE: BigNumber.ROUND_DOWN as BigNumber.RoundingMode
+}
+
+BigNumber.config(ETH_BIGNUMBER_ROUNDING_MODE)
diff --git a/src/utils/config.ts b/src/utils/config.ts
index 47c51bb3..c554ce9a 100644
--- a/src/utils/config.ts
+++ b/src/utils/config.ts
@@ -15,8 +15,6 @@
along with web3.js. If not, see .
*/
-import { BigNumber } from '../utils/BigNumber'
-
export const ETH_UNITS = [
'wei',
'kwei',
@@ -47,10 +45,5 @@ export const ETH_UNITS = [
'Uether'
]
-export const ETH_PADDING = 32
-export const ETH_SIGNATURE_LENGTH = 4
-export const ETH_BIGNUMBER_ROUNDING_MODE = {
- ROUNDING_MODE: BigNumber.ROUND_DOWN as BigNumber.RoundingMode
-}
export const ETH_POLLING_TIMEOUT = 1000 / 2
export let defaultBlock: 'latest' = 'latest'
diff --git a/src/utils/errors.ts b/src/utils/errors.ts
index a2e58ac6..10b514e3 100644
--- a/src/utils/errors.ts
+++ b/src/utils/errors.ts
@@ -15,6 +15,62 @@
along with web3.js. If not, see .
*/
+// Unknown Error
+export const UNKNOWN_ERROR = 'UNKNOWN_ERROR'
+
+// Not implemented
+export const NOT_IMPLEMENTED = 'NOT_IMPLEMENTED'
+
+// Missing new operator to an object
+// - name: The name of the class
+export const MISSING_NEW = 'MISSING_NEW'
+
+// Call exception
+// - transaction: the transaction
+// - address?: the contract address
+// - args?: The arguments passed into the function
+// - method?: The Solidity method signature
+// - errorSignature?: The EIP848 error signature
+// - errorArgs?: The EIP848 error parameters
+// - reason: The reason (only for EIP848 "Error(string)")
+export const CALL_EXCEPTION = 'CALL_EXCEPTION'
+
+// Invalid argument (e.g. value is incompatible with type) to a function:
+// - arg: The argument name that was invalid
+// - value: The value of the argument
+export const INVALID_ARGUMENT = 'INVALID_ARGUMENT'
+
+// Missing argument to a function:
+// - count: The number of arguments received
+// - expectedCount: The number of arguments expected
+export const MISSING_ARGUMENT = 'MISSING_ARGUMENT'
+
+// Too many arguments
+// - count: The number of arguments received
+// - expectedCount: The number of arguments expected
+export const UNEXPECTED_ARGUMENT = 'UNEXPECTED_ARGUMENT'
+
+// Numeric Fault
+// - operation: the operation being executed
+// - fault: the reason this faulted
+export const NUMERIC_FAULT = 'NUMERIC_FAULT'
+
+// Insufficien funds (< value + gasLimit * gasPrice)
+// - transaction: the transaction attempted
+export const INSUFFICIENT_FUNDS = 'INSUFFICIENT_FUNDS'
+
+// Nonce has already been used
+// - transaction: the transaction attempted
+export const NONCE_EXPIRED = 'NONCE_EXPIRED'
+
+// The replacement fee for the transaction is too low
+// - transaction: the transaction attempted
+export const REPLACEMENT_UNDERPRICED = 'REPLACEMENT_UNDERPRICED'
+
+// Unsupported operation
+// - operation
+export const UNSUPPORTED_OPERATION = 'UNSUPPORTED_OPERATION'
+
export function InvalidNumberOfSolidityArgs(given: number, expected: number) {
return new Error(`Invalid number of arguments to Solidity function. given: ${given}, expected: ${expected}`)
}
@@ -44,3 +100,64 @@ export function InvalidResponse(result: any) {
export function ConnectionTimeout(ms: number) {
return new Error('CONNECTION TIMEOUT: timeout of ' + ms + ' ms achived')
}
+
+let _permanentCensorErrors = false
+let _censorErrors = false
+
+export function error(message: string, code: string = UNKNOWN_ERROR, params: any = {}): Error {
+ if (_censorErrors) {
+ return new Error('unknown error')
+ }
+
+ let messageDetails: Array = []
+ Object.keys(params).forEach((key) => {
+ try {
+ messageDetails.push(key + '=' + JSON.stringify(params[key]))
+ } catch (error) {
+ messageDetails.push(key + '=' + JSON.stringify(params[key].toString()))
+ }
+ })
+
+ let reason = message
+ if (messageDetails.length) {
+ message += ' (' + messageDetails.join(', ') + ')'
+ }
+
+ // @TODO: Any??
+ let error: any = new Error(message)
+ error.reason = reason
+ error.code = code
+
+ Object.keys(params).forEach(function (key) {
+ error[key] = params[key]
+ })
+
+ return error
+}
+
+export function checkNew(self: any, kind: any): void {
+ if (!(self instanceof kind)) {
+ throw error('missing new', MISSING_NEW, { name: kind.name })
+ }
+}
+
+export function checkArgumentCount(count: number, expectedCount: number, suffix?: string): void {
+ if (!suffix) {
+ suffix = ''
+ }
+ if (count < expectedCount) {
+ throw error('missing argument' + suffix, MISSING_ARGUMENT, { count: count, expectedCount: expectedCount })
+ }
+ if (count > expectedCount) {
+ throw error('too many arguments' + suffix, UNEXPECTED_ARGUMENT, { count: count, expectedCount: expectedCount })
+ }
+}
+
+export function setCensorship(censorship: boolean, permanent?: boolean): void {
+ if (_permanentCensorErrors) {
+ throw error('error censorship permanent', UNSUPPORTED_OPERATION, { operation: 'setCersorship' })
+ }
+
+ _censorErrors = !!censorship
+ _permanentCensorErrors = !!permanent
+}
diff --git a/src/utils/formatters.ts b/src/utils/formatters.ts
index 699b09ea..98388a44 100644
--- a/src/utils/formatters.ts
+++ b/src/utils/formatters.ts
@@ -30,6 +30,7 @@ import {
TransactionReceipt
} from '../Schema'
import { BigNumber } from './BigNumber'
+import { stringToUtf8Bytes } from './utf8'
/**
* Should format the output to a big number
@@ -255,7 +256,7 @@ export function inputPostFormatter(post: any) {
// format the following options
post.topics = post.topics.map(function (topic: string) {
// convert only if not hex
- return topic.indexOf('0x') === 0 ? topic : utils.fromUtf8(topic)
+ return topic.indexOf('0x') === 0 ? topic : '0x' + utils.bytesToHex(stringToUtf8Bytes(topic))
})
return post
diff --git a/src/utils/utf8.ts b/src/utils/utf8.ts
new file mode 100644
index 00000000..48728412
--- /dev/null
+++ b/src/utils/utf8.ts
@@ -0,0 +1,20 @@
+import { hexToBytes } from './utils'
+
+/**
+ * Converts a string into a Uint8Array encoded with UTF-8
+ * @public
+ */
+export function stringToUtf8Bytes(str: string): Uint8Array {
+ return new TextEncoder().encode(str)
+}
+
+/**
+ * Decodes an Uint8Array or hex string into a UTF-8 string
+ * @public
+ */
+export function bytesToUtf8String(bytesOrHexString: Uint8Array | string): string {
+ if (typeof bytesOrHexString == 'string') {
+ return bytesToUtf8String(hexToBytes(bytesOrHexString))
+ }
+ return new TextDecoder().decode(bytesOrHexString)
+}
diff --git a/src/utils/utils.ts b/src/utils/utils.ts
index 2f89369d..ff1bbd08 100644
--- a/src/utils/utils.ts
+++ b/src/utils/utils.ts
@@ -15,10 +15,11 @@
along with web3.js. If not, see .
*/
-import * as utf8 from 'utf8'
import { keccak256 } from 'js-sha3'
import { BigNumber } from './BigNumber'
-import { AbiItem } from '../Schema'
+import { AbiInput, AbiItem } from '../Schema'
+import { stringToUtf8Bytes } from './utf8'
+import * as errors from './errors'
/**
* @public
@@ -36,13 +37,22 @@ export function hexToBytes(hex: string): Uint8Array {
for (let char = 0; char < hex.length; char += 2) {
const n = parseInt(hex.substr(char, 2), 16)
if (isNaN(n)) throw new Error('Cannot read hex string:' + JSON.stringify(hex))
- result[i] = parseInt(hex.substr(char, 2), 16)
+ result[i] = n
i++
}
return result
}
+/**
+ * @public
+ */
+export function bytesToHex(bytes: Uint8Array): string {
+ const hashArray = Array.from(bytes) // convert buffer to byte array
+ const hashHex = hashArray.map((b) => b.toString(16).padStart(2, '0')).join('') // convert bytes to hex string
+ return hashHex
+}
+
/**
* @public
*/
@@ -56,7 +66,7 @@ export function sha3(value: string | number[] | ArrayBuffer | Uint8Array, option
const t = hexToBytes(mutValue)
return keccak256(t)
} else {
- return keccak256(utf8.encode(value))
+ return keccak256(stringToUtf8Bytes(value))
}
}
@@ -111,27 +121,6 @@ export function padRight(str: string, chars: number, sign?: string) {
return str + new Array(chars - str.length + 1).join(sign ? sign : '0')
}
-/**
- * @public
- * Should be called to get utf8 from it's hex representation
- */
-export function toUtf8(hex: string): string {
- // Find termination
- let str = ''
- let i = 0
- let l = hex.length
- if (hex.substring(0, 2) === '0x') {
- i = 2
- }
- for (; i < l; i += 2) {
- let code = parseInt(hex.substr(i, 2), 16)
- if (code === 0) break
- str += String.fromCharCode(code)
- }
-
- return utf8.decode(str)
-}
-
/**
* @public
* Should be called to get ascii from it's hex representation
@@ -152,31 +141,6 @@ export function toAscii(hex: string) {
return str
}
-/**
- * @public
- * Should be called to get hex representation (prefixed by 0x) of utf8 string
- */
-export function fromUtf8(_str: string, allowZero = false) {
- let str = utf8.encode(_str)
- let hex = ''
-
- for (let i = 0; i < str.length; i++) {
- let code = str.charCodeAt(i)
- if (code === 0) {
- if (allowZero) {
- hex += '00'
- } else {
- break
- }
- } else {
- let n = code.toString(16)
- hex += n.length < 2 ? '0' + n : n
- }
- }
-
- return '0x' + hex
-}
-
/**
* @public
* Should be called to get hex representation (prefixed by 0x) of ascii string
@@ -197,20 +161,59 @@ export function fromAscii(str: string, num: number = 0) {
* Should be used to create full function/event name from json abi
*/
export function transformToFullName(json: AbiItem) {
- if (json.name && json.name.indexOf('(') !== -1) {
+ if (isObject(json) && json.name && json.name.indexOf('(') !== -1) {
return json.name
}
- let typeName: string = ''
- if (json.inputs) {
- typeName = json.inputs
- .map(function (i) {
- return i.type
- })
- .join()
+ return json.name + '(' + _flattenTypes(false, json.inputs || []).join(',') + ')'
+}
+
+export function concatBytes(...buffers: Uint8Array[]) {
+ const length = buffers.reduce(($, buf) => $ + buf.length, 0)
+ var mergedArray = new Uint8Array(length)
+ let cursor = 0
+ for (let buf of buffers) {
+ mergedArray.set(buf, cursor)
+ cursor += buf.length
}
+ return mergedArray
+}
+
+/**
+ * Should be used to flatten json abi inputs/outputs into an array of type-representing-strings
+ *
+ * @method _flattenTypes
+ * @param {bool} includeTuple
+ * @param {Object} puts
+ * @return {Array} parameters as strings
+ */
+function _flattenTypes(includeTuple: boolean, puts: AbiInput[]) {
+ const types: string[] = []
+
+ puts.forEach(function (param) {
+ if (typeof param.components === 'object') {
+ if (param.type.substring(0, 5) !== 'tuple') {
+ throw new Error('components found but type is not tuple; report on GitHub')
+ }
+ var suffix = ''
+ var arrayBracket = param.type.indexOf('[')
+ if (arrayBracket >= 0) {
+ suffix = param.type.substring(arrayBracket)
+ }
+ var result = _flattenTypes(includeTuple, param.components)
+ if (isArray(result) && includeTuple) {
+ types.push('tuple(' + result.join(',') + ')' + suffix)
+ } else if (!includeTuple) {
+ types.push('(' + result.join(',') + ')' + suffix)
+ } else {
+ types.push('(' + result + ')')
+ }
+ } else {
+ types.push(param.type)
+ }
+ })
- return json.name + '(' + typeName + ')'
+ return types
}
/**
@@ -310,19 +313,23 @@ export function fromDecimal(value: BigNumber.Value) {
*
* And even stringifys objects before.
*/
-export function toHex(val: BigNumber.Value | boolean) {
+export function toHex(val: BigNumber.Value | boolean | Uint8Array) {
if (isBoolean(val)) return fromDecimal(+val)
if (isBigNumber(val)) return fromDecimal(val)
- if (typeof val === 'object') return fromUtf8(JSON.stringify(val))
-
// if its a negative number, pass it through fromDecimal
if (isString(val)) {
const valStr = val as string
if (valStr.indexOf('-0x') === 0) return fromDecimal(valStr)
else if (valStr.indexOf('0x') === 0) return valStr
- else if (!isFinite(valStr as any)) return fromUtf8(valStr, true)
+ else if (!isFinite(valStr as any)) return bytesToHex(stringToUtf8Bytes(valStr))
+ }
+
+ if (val instanceof Uint8Array) return '0x' + bytesToHex(val)
+
+ if (isArray(val) || isObject(val)) {
+ throw new Error('toHex can only be called with scalar values, not objects or arrays')
}
return fromDecimal(val)
@@ -411,23 +418,74 @@ export function toBigNumber(_num: BigNumber.Value): BigNumber {
return new BigNumber(num.replace('0x', '').toLowerCase(), 16)
}
+ if (num instanceof Uint8Array) {
+ return new BigNumber(bytesToHex(num), 16)
+ }
+
return new BigNumber(num, 10)
}
+function bitMask(bits: number) {
+ return new BigNumber(new Array(bits).fill('1').join(''), 2)
+}
+
/**
* @public
* Takes and input transforms it into bignumber and if it is negative value, into two's complement
*/
-export function toTwosComplement(num: BigNumber.Value): BigNumber {
+export function toTwosComplement(num: BigNumber.Value, bits = 256): BigNumber {
let bigNumber = toBigNumber(num).integerValue() as BigNumber
if (bigNumber.isLessThan(0)) {
- return new BigNumber('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 16).plus(bigNumber).plus(1)
+ const mask = bitMask(bits)
+ return mask.plus(bigNumber).plus(1)
}
return bigNumber
}
+/**
+ * Check if input value is negative in twos complement
+ */
+export function signedIsNegative(value: BigNumber, bits: number) {
+ const binary = padLeft(value.toString(2), bits, '0')
+ return binary[0] == '1'
+}
+
+/**
+ * @public
+ */
+export function getAddress(address: string): string {
+ if (typeof address !== 'string') {
+ throw errors.error('invalid address', errors.INVALID_ARGUMENT, { arg: 'address', value: address })
+ }
+
+ if (address.trim().match(/^(0x)?[0-9a-fA-F]{40}$/)) {
+ // Missing the 0x prefix
+ if (address.trim().substring(0, 2) !== '0x') {
+ address = '0x' + address
+ }
+
+ return toChecksumAddress(address)
+ } else {
+ throw errors.error('invalid address', errors.INVALID_ARGUMENT, { arg: 'address', value: address })
+ }
+}
+
+/**
+ * @public
+ * If the bit N is 1
+ */
+export function fromTwosComplement(num: BigNumber, bits = 256): BigNumber {
+ // check if it's negative number
+ // it it is, return two's complement
+ if (signedIsNegative(num, bits)) {
+ const mask = bitMask(bits)
+ return num.minus(mask).minus(1)
+ }
+ return num
+}
+
/**
* @public
* Checks if the given string is strictly an address
diff --git a/test/allevents.decode.ts b/test/allevents.decode.ts
index 033c52f2..f3c9efc5 100644
--- a/test/allevents.decode.ts
+++ b/test/allevents.decode.ts
@@ -140,7 +140,8 @@ let tests = [
'0000000000000000000000000000000000000000000000000000000000000004',
topics: [
'0x0e99121e9409665e680573fa7da0cb6651dbdcf10c95f585b92b2c9b9702cff9',
- '0x0000000000000000000000000000000000000000000000000000000000000010'
+ '0x0000000000000000000000000000000000000000000000000000000000000010',
+ '0x0000000000000000000000000000000000000000000000000000000000000002'
]
},
expected: {
@@ -149,7 +150,7 @@ let tests = [
a: new BigNumber(1),
b: new BigNumber(16),
c: new BigNumber(4),
- d: new BigNumber(0)
+ d: new BigNumber(2)
},
logIndex: 1,
removed: false,
@@ -158,7 +159,8 @@ let tests = [
'0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000004',
topics: [
'0x0e99121e9409665e680573fa7da0cb6651dbdcf10c95f585b92b2c9b9702cff9',
- '0x0000000000000000000000000000000000000000000000000000000000000010'
+ '0x0000000000000000000000000000000000000000000000000000000000000010',
+ '0x0000000000000000000000000000000000000000000000000000000000000002'
],
transactionHash: '0x1234567890',
address: address,
diff --git a/test/coder.decodeParam.ts b/test/coder.decodeParam.ts
index dd0f8172..9c02b907 100644
--- a/test/coder.decodeParam.ts
+++ b/test/coder.decodeParam.ts
@@ -1,35 +1,38 @@
import * as expect from 'expect'
import * as coder from '../src/solidity/coder'
+import { Tuple } from '../src/abi/coder'
import { BigNumber as bn } from '../dist/eth-connect'
+import { hexToBytes } from '../src'
+import { parseParamType } from '../src/abi/parser'
-describe('lib/solidity/coder', function() {
- describe('decodeParam', function() {
- let test = function(t) {
- it('should turn ' + t.value + ' to ' + t.expected, function() {
- expect(coder.coder.decodeParam(t.type, t.value)).toEqual(t.expected)
+describe('lib/solidity/coder', function () {
+ describe('decodeParam', function () {
+ let test = function (t) {
+ it('should turn ' + t.value + ' to ' + t.type + '=' + t.expected, function () {
+ expect(coder.coder.decodeParams([parseParamType(t.type)], t.value)).toEqual([t.expected])
+ expect(coder.coder.decodeParams([t.type], t.value)).toEqual([t.expected])
})
}
-
test({
type: 'address',
- expected: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
+ expected: '0x407D73d8a49eeb85D32Cf465507dd71d507100c1',
value: '000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1'
})
test({
type: 'address',
- expected: '0xbf79ce2fbd819e5abc2327563d02a200255b7cb3',
+ expected: '0xBF79cE2fbd819e5aBC2327563D02a200255B7Cb3',
value: '000000000000000000000000bf79ce2fbd819e5abc2327563d02a200255b7cb3'
})
test({
type: 'address[2]',
- expected: ['0x407d73d8a49eeb85d32cf465507dd71d507100c1', '0x407d73d8a49eeb85d32cf465507dd71d507100c3'],
+ expected: ['0x407D73d8a49eeb85D32Cf465507dd71d507100c1', '0x407D73d8A49eEB85D32Cf465507Dd71d507100c3'],
value:
'000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1' +
'000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c3'
})
test({
type: 'address[]',
- expected: ['0x407d73d8a49eeb85d32cf465507dd71d507100c1', '0x407d73d8a49eeb85d32cf465507dd71d507100c3'],
+ expected: ['0x407D73d8a49eeb85D32Cf465507dd71d507100c1', '0x407D73d8A49eEB85D32Cf465507Dd71d507100c3'],
value:
'0000000000000000000000000000000000000000000000000000000000000020' +
'0000000000000000000000000000000000000000000000000000000000000002' +
@@ -39,10 +42,11 @@ describe('lib/solidity/coder', function() {
test({
type: 'address[][2]',
expected: [
- ['0x407d73d8a49eeb85d32cf465507dd71d507100c1', '0x407d73d8a49eeb85d32cf465507dd71d507100c2'],
- ['0x407d73d8a49eeb85d32cf465507dd71d507100c3', '0x407d73d8a49eeb85d32cf465507dd71d507100c4']
+ ['0x407D73d8a49eeb85D32Cf465507dd71d507100c1', '0x407d73d8a49EEB85d32Cf465507dD71D507100c2'],
+ ['0x407D73d8A49eEB85D32Cf465507Dd71d507100c3', '0x407D73d8a49eeb85D32CF465507dd71d507100C4']
],
value:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
'0000000000000000000000000000000000000000000000000000000000000040' +
'00000000000000000000000000000000000000000000000000000000000000a0' +
'0000000000000000000000000000000000000000000000000000000000000002' /* 40 */ +
@@ -55,29 +59,29 @@ describe('lib/solidity/coder', function() {
test({
type: 'address[2][]',
expected: [
- ['0x407d73d8a49eeb85d32cf465507dd71d507100c1', '0x407d73d8a49eeb85d32cf465507dd71d507100c2'],
- ['0x407d73d8a49eeb85d32cf465507dd71d507100c3', '0x407d73d8a49eeb85d32cf465507dd71d507100c4']
+ ['0x507D73d8a49EEb85d32cf465507Dd71D507100c1', '0x507D73D8A49EEb85d32cF465507Dd71D507100C2'],
+ ['0x507d73D8a49EEB85D32cF465507DD71d507100c3', '0x507D73d8a49Eeb85D32CF465507dd71d507100C4']
],
value:
'0000000000000000000000000000000000000000000000000000000000000020' +
'0000000000000000000000000000000000000000000000000000000000000002' /* 20 */ +
- '000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1' +
- '000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c2' +
- '000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c3' +
- '000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c4'
+ '000000000000000000000000507d73d8a49eeb85d32cf465507dd71d507100c1' +
+ '000000000000000000000000507d73d8a49eeb85d32cf465507dd71d507100c2' +
+ '000000000000000000000000507d73d8a49eeb85d32cf465507dd71d507100c3' +
+ '000000000000000000000000507d73d8a49eeb85d32cf465507dd71d507100c4'
})
test({
type: 'address[][]',
expected: [
- ['0x407d73d8a49eeb85d32cf465507dd71d507100c1', '0x407d73d8a49eeb85d32cf465507dd71d507100c2'],
- ['0x407d73d8a49eeb85d32cf465507dd71d507100c3', '0x407d73d8a49eeb85d32cf465507dd71d507100c4']
+ ['0x407D73d8a49eeb85D32Cf465507dd71d507100c1', '0x407d73d8a49EEB85d32Cf465507dD71D507100c2'],
+ ['0x407D73d8A49eEB85D32Cf465507Dd71d507100c3', '0x407D73d8a49eeb85D32CF465507dd71d507100C4']
],
value:
'0000000000000000000000000000000000000000000000000000000000000020' +
'0000000000000000000000000000000000000000000000000000000000000002' /* 20 */ +
- '0000000000000000000000000000000000000000000000000000000000000080' +
- '00000000000000000000000000000000000000000000000000000000000000e0' +
- '0000000000000000000000000000000000000000000000000000000000000002' /* 80 */ +
+ '0000000000000000000000000000000000000000000000000000000000000040' +
+ '00000000000000000000000000000000000000000000000000000000000000a0' +
+ '0000000000000000000000000000000000000000000000000000000000000002' /* 40 */ +
'000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1' /* a0 */ +
'000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c2' +
'0000000000000000000000000000000000000000000000000000000000000002' /* e0 */ +
@@ -141,19 +145,19 @@ describe('lib/solidity/coder', function() {
})
test({
type: 'int8',
- expected: new bn(16),
+ expected: 16,
value: '0000000000000000000000000000000000000000000000000000000000000010'
})
test({
type: 'int8[2]',
- expected: [new bn(16), new bn(2)],
+ expected: [16, 2],
value:
'0000000000000000000000000000000000000000000000000000000000000010' +
'0000000000000000000000000000000000000000000000000000000000000002'
})
test({
type: 'int32',
- expected: new bn(16),
+ expected: 16,
value: '0000000000000000000000000000000000000000000000000000000000000010'
})
test({
@@ -201,7 +205,10 @@ describe('lib/solidity/coder', function() {
})
test({
type: 'int[3][]',
- expected: [[new bn(1), new bn(2), new bn(3)], [new bn(4), new bn(5), new bn(6)]],
+ expected: [
+ [new bn(1), new bn(2), new bn(3)],
+ [new bn(4), new bn(5), new bn(6)]
+ ],
value:
'0000000000000000000000000000000000000000000000000000000000000020' +
'0000000000000000000000000000000000000000000000000000000000000002' +
@@ -245,12 +252,12 @@ describe('lib/solidity/coder', function() {
})
test({
type: 'uint8',
- expected: new bn(16),
+ expected: 16,
value: '0000000000000000000000000000000000000000000000000000000000000010'
})
test({
type: 'uint32',
- expected: new bn(16),
+ expected: 16,
value: '0000000000000000000000000000000000000000000000000000000000000010'
})
test({
@@ -298,7 +305,10 @@ describe('lib/solidity/coder', function() {
})
test({
type: 'uint[3][]',
- expected: [[new bn(1), new bn(2), new bn(3)], [new bn(4), new bn(5), new bn(6)]],
+ expected: [
+ [new bn(1), new bn(2), new bn(3)],
+ [new bn(4), new bn(5), new bn(6)]
+ ],
value:
'0000000000000000000000000000000000000000000000000000000000000020' +
'0000000000000000000000000000000000000000000000000000000000000002' +
@@ -311,7 +321,7 @@ describe('lib/solidity/coder', function() {
})
test({
type: 'bytes',
- expected: '0x6761766f66796f726b',
+ expected: hexToBytes('0x6761766f66796f726b'),
value:
'0000000000000000000000000000000000000000000000000000000000000020' +
'0000000000000000000000000000000000000000000000000000000000000009' +
@@ -319,7 +329,7 @@ describe('lib/solidity/coder', function() {
})
test({
type: 'bytes',
- expected: '0x731a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b',
+ expected: hexToBytes('0x731a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b'),
value:
'0000000000000000000000000000000000000000000000000000000000000020' +
'0000000000000000000000000000000000000000000000000000000000000020' +
@@ -327,10 +337,11 @@ describe('lib/solidity/coder', function() {
})
test({
type: 'bytes',
- expected:
+ expected: hexToBytes(
'0x131a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b' +
- '231a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b' +
- '331a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b',
+ '231a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b' +
+ '331a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b'
+ ),
value:
'0000000000000000000000000000000000000000000000000000000000000020' +
'0000000000000000000000000000000000000000000000000000000000000060' +
@@ -340,9 +351,10 @@ describe('lib/solidity/coder', function() {
})
test({
type: 'bytes',
- expected:
+ expected: hexToBytes(
'0x731a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b' +
- '731a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b',
+ '731a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b'
+ ),
value:
'0000000000000000000000000000000000000000000000000000000000000020' +
'0000000000000000000000000000000000000000000000000000000000000040' +
@@ -352,10 +364,11 @@ describe('lib/solidity/coder', function() {
test({
type: 'bytes[2]',
expected: [
- '0x731a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134a',
- '0x731a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b'
+ hexToBytes('0x731a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134a'),
+ hexToBytes('0x731a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b')
],
value:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
'0000000000000000000000000000000000000000000000000000000000000040' +
'0000000000000000000000000000000000000000000000000000000000000080' +
'0000000000000000000000000000000000000000000000000000000000000020' +
@@ -366,38 +379,45 @@ describe('lib/solidity/coder', function() {
test({
type: 'bytes[][2]',
expected: [
- ['0x731a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134a'],
[
- '0x731a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b' +
- '731a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134c',
- '0x731a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134d'
+ hexToBytes('0x00000c8c18f9252830fb3c56471c51335a8262f16a6d70e276417a7c7d897f617fff'),
+ hexToBytes('0x21f9252830fb3c56471c51335a8262f16a6d70e276417a7c7d897f617fff')
+ ],
+ [
+ hexToBytes('0x00000c8c18f9252830fb3c56471c51335a8262f16a6d70e276417a7c7d897f617fff'),
+ hexToBytes('0x21f9252830fb3c56471c51335a8262f16a6d70e276417a7c7d897f617fff')
]
],
value:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
'0000000000000000000000000000000000000000000000000000000000000040' +
- '0000000000000000000000000000000000000000000000000000000000000080' +
- '0000000000000000000000000000000000000000000000000000000000000001' + // 40
- '00000000000000000000000000000000000000000000000000000000000000e0' +
- '0000000000000000000000000000000000000000000000000000000000000002' + // 80
- '0000000000000000000000000000000000000000000000000000000000000120' +
- '0000000000000000000000000000000000000000000000000000000000000180' +
- '0000000000000000000000000000000000000000000000000000000000000020' + // e0
- '731a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134a' +
- '0000000000000000000000000000000000000000000000000000000000000040' + // 120
- '731a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b' +
- '731a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134c' +
- '0000000000000000000000000000000000000000000000000000000000000020' + // 180
- '731a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134d'
+ '0000000000000000000000000000000000000000000000000000000000000140' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000040' +
+ '00000000000000000000000000000000000000000000000000000000000000a0' +
+ '0000000000000000000000000000000000000000000000000000000000000022' +
+ '00000c8c18f9252830fb3c56471c51335a8262f16a6d70e276417a7c7d897f61' +
+ '7fff000000000000000000000000000000000000000000000000000000000000' +
+ '000000000000000000000000000000000000000000000000000000000000001e' +
+ '21f9252830fb3c56471c51335a8262f16a6d70e276417a7c7d897f617fff0000' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000040' +
+ '00000000000000000000000000000000000000000000000000000000000000a0' +
+ '0000000000000000000000000000000000000000000000000000000000000022' +
+ '00000c8c18f9252830fb3c56471c51335a8262f16a6d70e276417a7c7d897f61' +
+ '7fff000000000000000000000000000000000000000000000000000000000000' +
+ '000000000000000000000000000000000000000000000000000000000000001e' +
+ '21f9252830fb3c56471c51335a8262f16a6d70e276417a7c7d897f617fff0000'
})
test({
type: 'bytes1',
- expected: '0xcf',
+ expected: hexToBytes('0xcf'),
value: 'cf00000000000000000000000000000000000000000000000000000000000000'
})
test({
type: 'bytes1[4]',
- expected: ['0xcf', '0x68', '0x4d', '0xfb'],
+ expected: [hexToBytes('0xcf'), hexToBytes('0x68'), hexToBytes('0x4d'), hexToBytes('0xfb')],
value:
'cf00000000000000000000000000000000000000000000000000000000000000' +
'6800000000000000000000000000000000000000000000000000000000000000' +
@@ -406,7 +426,7 @@ describe('lib/solidity/coder', function() {
})
test({
type: 'bytes32',
- expected: '0x6761766f66796f726b0000000000000000000000000000000000000000000000',
+ expected: hexToBytes('0x6761766f66796f726b0000000000000000000000000000000000000000000000'),
value: '6761766f66796f726b0000000000000000000000000000000000000000000000'
})
@@ -444,7 +464,7 @@ describe('lib/solidity/coder', function() {
})
test({
type: 'bytes',
- expected: '0xc3a40000c3a4',
+ expected: hexToBytes('0xc3a40000c3a4'),
value:
'0000000000000000000000000000000000000000000000000000000000000020' +
'0000000000000000000000000000000000000000000000000000000000000006' +
@@ -452,47 +472,12 @@ describe('lib/solidity/coder', function() {
})
test({
type: 'bytes32',
- expected: '0xc3a40000c3a40000000000000000000000000000000000000000000000000000',
+ expected: hexToBytes('0xc3a40000c3a40000000000000000000000000000000000000000000000000000'),
value: 'c3a40000c3a40000000000000000000000000000000000000000000000000000'
})
- test({
- type: 'real',
- expected: new bn(1),
- value: '0000000000000000000000000000000100000000000000000000000000000000'
- })
- test({
- type: 'real',
- expected: new bn(2.125),
- value: '0000000000000000000000000000000220000000000000000000000000000000'
- })
- test({
- type: 'real',
- expected: new bn(8.5),
- value: '0000000000000000000000000000000880000000000000000000000000000000'
- })
- test({
- type: 'real',
- expected: new bn(-1),
- value: 'ffffffffffffffffffffffffffffffff00000000000000000000000000000000'
- })
- test({
- type: 'ureal',
- expected: new bn(1),
- value: '0000000000000000000000000000000100000000000000000000000000000000'
- })
- test({
- type: 'ureal',
- expected: new bn(2.125),
- value: '0000000000000000000000000000000220000000000000000000000000000000'
- })
- test({
- type: 'ureal',
- expected: new bn(8.5),
- value: '0000000000000000000000000000000880000000000000000000000000000000'
- })
test({
type: 'address',
- expected: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
+ expected: '0x407D73d8a49eeb85D32Cf465507dd71d507100c1',
value: '000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1'
})
test({
@@ -506,12 +491,13 @@ describe('lib/solidity/coder', function() {
})
test({
type: 'bytes',
- expected:
+ expected: hexToBytes(
'0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' +
- 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' +
- 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' +
- 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' +
- 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1',
+ 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' +
+ 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' +
+ 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' +
+ 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1'
+ ),
value:
'0000000000000000000000000000000000000000000000000000000000000020' +
'000000000000000000000000000000000000000000000000000000000000009f' +
@@ -521,39 +507,190 @@ describe('lib/solidity/coder', function() {
'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' +
'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff100'
})
+
+ test({
+ type: 'tuple(address)',
+ expected: new Tuple('0xbBF289D846208c16EDc8474705C748aff07732dB'),
+ value: '000000000000000000000000bbf289d846208c16edc8474705c748aff07732db'
+ })
+ test({
+ type: 'tuple(address,address)',
+ expected: new Tuple('0xbBF289D846208c16EDc8474705C748aff07732dB', '0xbBF289D846208c16EDc8474705C748aff07732dB'),
+ value:
+ '000000000000000000000000bbf289d846208c16edc8474705c748aff07732db' +
+ '000000000000000000000000bbf289d846208c16edc8474705c748aff07732db'
+ })
+ test({
+ type: 'tuple(uint256,uint256)',
+ expected: new Tuple(new bn(5), new bn(5)),
+ value:
+ '0000000000000000000000000000000000000000000000000000000000000005' +
+ '0000000000000000000000000000000000000000000000000000000000000005'
+ })
+ test({
+ type: 'tuple(string,string)',
+ expected: new Tuple('hello', 'world'),
+ value:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000040' +
+ '0000000000000000000000000000000000000000000000000000000000000080' +
+ '0000000000000000000000000000000000000000000000000000000000000005' +
+ '68656c6c6f000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000005' +
+ '776f726c64000000000000000000000000000000000000000000000000000000'
+ })
+ test({
+ type: 'tuple(bytes,bytes)',
+ expected: new Tuple(hexToBytes('0x01fe517acd15ff'), hexToBytes('0xabcdef12345678')),
+ value:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000040' +
+ '0000000000000000000000000000000000000000000000000000000000000080' +
+ '0000000000000000000000000000000000000000000000000000000000000007' +
+ '01fe517acd15ff00000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000007' +
+ 'abcdef1234567800000000000000000000000000000000000000000000000000'
+ })
+ test({
+ type: 'tuple(bool,bool)',
+ expected: new Tuple(false, true),
+ value:
+ '0000000000000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000001'
+ })
+ test({
+ type: 'tuple(uint256,string,bytes)',
+ expected: new Tuple(new bn(4), 'what what', hexToBytes('0xabcdef12345678')),
+ value:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000004' +
+ '0000000000000000000000000000000000000000000000000000000000000060' +
+ '00000000000000000000000000000000000000000000000000000000000000a0' +
+ '0000000000000000000000000000000000000000000000000000000000000009' +
+ '7768617420776861740000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000007' +
+ 'abcdef1234567800000000000000000000000000000000000000000000000000'
+ })
+ test({
+ type: 'tuple(uint128,string,bytes)',
+ expected: new Tuple(new bn(666), 'encode your kids', hexToBytes('0x656e636f646520796f75722077696665')),
+ value:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '000000000000000000000000000000000000000000000000000000000000029a' +
+ '0000000000000000000000000000000000000000000000000000000000000060' +
+ '00000000000000000000000000000000000000000000000000000000000000a0' +
+ '0000000000000000000000000000000000000000000000000000000000000010' +
+ '656e636f646520796f7572206b69647300000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000010' +
+ '656e636f646520796f7572207769666500000000000000000000000000000000'
+ })
+ test({
+ type: 'tuple(string,bytes32,uint256,bool)',
+ expected: new Tuple(
+ 'foo bar',
+ hexToBytes('0xaabbccddeeff0000000000000000000000000000000000000000000000000000'),
+ new bn(321),
+ true
+ ),
+ value:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000080' +
+ 'aabbccddeeff0000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000141' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000007' +
+ '666f6f2062617200000000000000000000000000000000000000000000000000'
+ })
+ test({
+ type: 'tuple(uint8,uint8,uint8,uint8,string,address,bool)',
+ expected: new Tuple(1, 2, 3, 4, 'five', '0x0000000000000000000000000000000000000006', true),
+ value:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000003' +
+ '0000000000000000000000000000000000000000000000000000000000000004' +
+ '00000000000000000000000000000000000000000000000000000000000000e0' +
+ '0000000000000000000000000000000000000000000000000000000000000006' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000004' +
+ '6669766500000000000000000000000000000000000000000000000000000000'
+ })
+ test({
+ type: 'tuple(tuple(address,address),tuple(uint256,uint256))',
+ expected: [
+ ['0x1234567890123456789012345678901234567890', '0x1234567890123456789012345678901234567890'],
+ [new bn(5), new bn(6)]
+ ],
+ value:
+ '0000000000000000000000001234567890123456789012345678901234567890' +
+ '0000000000000000000000001234567890123456789012345678901234567890' +
+ '0000000000000000000000000000000000000000000000000000000000000005' +
+ '0000000000000000000000000000000000000000000000000000000000000006'
+ })
+ test({
+ type: 'tuple(tuple(address,address),tuple(uint256,uint256),tuple(string,string))',
+ expected: [
+ ['0x1234567890123456789012345678901234567890', '0x1234567890123456789012345678901234567890'],
+ [new bn(5), new bn(6)],
+ ['a string', 'another string']
+ ],
+ value:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000001234567890123456789012345678901234567890' +
+ '0000000000000000000000001234567890123456789012345678901234567890' +
+ '0000000000000000000000000000000000000000000000000000000000000005' +
+ '0000000000000000000000000000000000000000000000000000000000000006' +
+ '00000000000000000000000000000000000000000000000000000000000000a0' +
+ '0000000000000000000000000000000000000000000000000000000000000040' +
+ '0000000000000000000000000000000000000000000000000000000000000080' +
+ '0000000000000000000000000000000000000000000000000000000000000008' +
+ '6120737472696e67000000000000000000000000000000000000000000000000' +
+ '000000000000000000000000000000000000000000000000000000000000000e' +
+ '616e6f7468657220737472696e67000000000000000000000000000000000000'
+ })
})
})
-describe('lib/solidity/coder', function() {
- describe('decodeParams', function() {
- let test = function(t) {
- it('should turn ' + t.values + ' to ' + t.expected, function() {
+describe('lib/solidity/coder', function () {
+ describe('decodeParams', function () {
+ let test = function (t) {
+ it('should turn ' + t.values + ' to ' + t.expected, function () {
+ expect(
+ coder.coder.decodeParams(
+ t.types.map((type) => parseParamType(type)),
+ t.values
+ )
+ ).toEqual(t.expected)
expect(coder.coder.decodeParams(t.types, t.values)).toEqual(t.expected)
})
}
test({
types: ['address'],
- expected: ['0x407d73d8a49eeb85d32cf465507dd71d507100c1'],
+ expected: ['0x407D73d8a49eeb85D32Cf465507dd71d507100c1'],
values: '000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1'
})
test({
types: ['address', 'address'],
- expected: ['0x407d73d8a49eeb85d32cf465507dd71d507100c1', '0x407d73d8a49eeb85d32cf465507dd71d507100c3'],
+ expected: ['0x407D73d8a49eeb85D32Cf465507dd71d507100c1', '0x407D73d8A49eEB85D32Cf465507Dd71d507100c3'],
values:
'000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1' +
'000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c3'
})
test({
types: ['address', 'address'],
- expected: ['0x6224fe0bea79701d338cf65ebc0da0caa566c544', '0xBF79cE2fbd819e5aBC2327563D02a200255B7Cb3'],
+ expected: ['0x6224fe0bEA79701d338Cf65ebc0DA0CaA566C544', '0xBF79cE2fbd819e5aBC2327563D02a200255B7Cb3'],
values:
'0000000000000000000000006224fe0bea79701d338cf65ebc0da0caa566c544' +
'000000000000000000000000BF79cE2fbd819e5aBC2327563D02a200255B7Cb3'
})
test({
types: ['bool[2]', 'bool[3]'],
- expected: [[true, false], [false, false, true]],
+ expected: [
+ [true, false],
+ [false, false, true]
+ ],
values:
'0000000000000000000000000000000000000000000000000000000000000001' +
'0000000000000000000000000000000000000000000000000000000000000000' +
@@ -563,7 +700,10 @@ describe('lib/solidity/coder', function() {
})
test({
types: ['int[2]', 'int256[3]'],
- expected: [[new bn(1), new bn(2)], [new bn(3), new bn(4), new bn(5)]],
+ expected: [
+ [new bn(1), new bn(2)],
+ [new bn(3), new bn(4), new bn(5)]
+ ],
values:
'0000000000000000000000000000000000000000000000000000000000000001' +
'0000000000000000000000000000000000000000000000000000000000000002' +
@@ -578,7 +718,10 @@ describe('lib/solidity/coder', function() {
})
test({
types: ['uint[2]', 'uint256[3]'],
- expected: [[new bn(1), new bn(2)], [new bn(3), new bn(4), new bn(5)]],
+ expected: [
+ [new bn(1), new bn(2)],
+ [new bn(3), new bn(4), new bn(5)]
+ ],
values:
'0000000000000000000000000000000000000000000000000000000000000001' +
'0000000000000000000000000000000000000000000000000000000000000002' +
@@ -593,14 +736,14 @@ describe('lib/solidity/coder', function() {
})
test({
types: ['bytes1', 'bytes1'],
- expected: ['0xaa', '0xbb'],
+ expected: [new Uint8Array([0xaa]), new Uint8Array([0xbb])],
values:
'aa00000000000000000000000000000000000000000000000000000000000000' +
'bb00000000000000000000000000000000000000000000000000000000000000'
})
test({
types: ['bytes1[2]', 'bytes1'],
- expected: [['0xaa', '0xbb'], '0xcc'],
+ expected: [[new Uint8Array([0xaa]), new Uint8Array([0xbb])], new Uint8Array([0xcc])],
values:
'aa00000000000000000000000000000000000000000000000000000000000000' +
'bb00000000000000000000000000000000000000000000000000000000000000' +
@@ -609,8 +752,8 @@ describe('lib/solidity/coder', function() {
test({
types: ['bytes', 'bytes'],
expected: [
- '0x731a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b',
- '0x731a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134c'
+ hexToBytes('0x731a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b'),
+ hexToBytes('0x731a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134c')
],
values:
'0000000000000000000000000000000000000000000000000000000000000040' +
@@ -632,14 +775,14 @@ describe('lib/solidity/coder', function() {
})
test({
types: ['bytes32', 'int'],
- expected: ['0x6761766f66796f726b0000000000000000000000000000000000000000000000', new bn(5)],
+ expected: [hexToBytes('0x6761766f66796f726b0000000000000000000000000000000000000000000000'), new bn(5)],
values:
'6761766f66796f726b0000000000000000000000000000000000000000000000' +
'0000000000000000000000000000000000000000000000000000000000000005'
})
test({
types: ['int', 'bytes32'],
- expected: [new bn(5), '0x6761766f66796f726b0000000000000000000000000000000000000000000000'],
+ expected: [new bn(5), hexToBytes('0x6761766f66796f726b0000000000000000000000000000000000000000000000')],
values:
'0000000000000000000000000000000000000000000000000000000000000005' +
'6761766f66796f726b0000000000000000000000000000000000000000000000'
@@ -665,11 +808,15 @@ describe('lib/solidity/coder', function() {
types: ['int', 'bytes', 'int', 'bytes'],
expected: [
new bn(5),
- '0x131a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b' +
- '231a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b',
+ hexToBytes(
+ '0x131a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b' +
+ '231a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b'
+ ),
new bn(3),
- '0x331a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b' +
- '431a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b'
+ hexToBytes(
+ '0x331a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b' +
+ '431a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b'
+ )
],
values:
'0000000000000000000000000000000000000000000000000000000000000005' +
@@ -685,7 +832,7 @@ describe('lib/solidity/coder', function() {
})
test({
types: ['address[2][1]', 'bool'],
- expected: [[['0x407d73d8a49eeb85d32cf465507dd71d507100c1', '0x407d73d8a49eeb85d32cf465507dd71d507100c3']], false],
+ expected: [[['0x407D73d8a49eeb85D32Cf465507dd71d507100c1', '0x407D73d8A49eEB85D32Cf465507Dd71d507100c3']], false],
values:
'000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1' +
'000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c3' +
@@ -701,7 +848,7 @@ describe('lib/solidity/coder', function() {
})
test({
types: ['bytes1[2][1]', 'bool'],
- expected: [[['0xaa', '0xbb']], true],
+ expected: [[[hexToBytes('0xaa'), hexToBytes('0xbb')]], true],
values:
'aa00000000000000000000000000000000000000000000000000000000000000' +
'bb00000000000000000000000000000000000000000000000000000000000000' +
@@ -716,28 +863,304 @@ describe('lib/solidity/coder', function() {
'0000000000000000000000000000000000000000000000000000000000000001'
})
test({
- types: ['real[2][1]', 'bool'],
- expected: [[[new bn(1), new bn(2.125)]], true],
+ types: ['uint[2][1]', 'bool'],
+ expected: [[[new bn(1), new bn(2)]], true],
values:
- '0000000000000000000000000000000100000000000000000000000000000000' +
- '0000000000000000000000000000000220000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
'0000000000000000000000000000000000000000000000000000000000000001'
})
test({
- types: ['uint[2][1]', 'bool'],
- expected: [[[new bn(1), new bn(2)]], true],
+ types: ['tuple(address,address)', 'tuple(string,string)', 'bool'],
+ expected: [
+ ['0x1234567890123456789012345678901234567890', '0x1234567890123456789012345678901234567890'],
+ ['hello', 'world'],
+ false
+ ],
+ values:
+ '0000000000000000000000001234567890123456789012345678901234567890' +
+ '0000000000000000000000001234567890123456789012345678901234567890' +
+ '0000000000000000000000000000000000000000000000000000000000000080' +
+ '0000000000000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000040' +
+ '0000000000000000000000000000000000000000000000000000000000000080' +
+ '0000000000000000000000000000000000000000000000000000000000000005' +
+ '68656c6c6f000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000005' +
+ '776f726c64000000000000000000000000000000000000000000000000000000'
+ })
+
+ test({
+ types: ['string', 'tuple(uint256,string)', 'bool', 'tuple(bytes32,bytes)'],
+ expected: [
+ 'the string',
+ new Tuple(new bn(56), 'some string'),
+ true,
+ new Tuple(
+ hexToBytes('0x1234567890123456789012345678901234567890123456789012345678901234'),
+ hexToBytes('0x129581')
+ )
+ ],
+ values:
+ '0000000000000000000000000000000000000000000000000000000000000080' +
+ '00000000000000000000000000000000000000000000000000000000000000c0' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000140' +
+ '000000000000000000000000000000000000000000000000000000000000000a' +
+ '74686520737472696e6700000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000038' +
+ '0000000000000000000000000000000000000000000000000000000000000040' +
+ '000000000000000000000000000000000000000000000000000000000000000b' +
+ '736f6d6520737472696e67000000000000000000000000000000000000000000' +
+ '1234567890123456789012345678901234567890123456789012345678901234' +
+ '0000000000000000000000000000000000000000000000000000000000000040' +
+ '0000000000000000000000000000000000000000000000000000000000000003' +
+ '1295810000000000000000000000000000000000000000000000000000000000'
+ })
+ test({
+ types: [
+ 'bool',
+ 'tuple(bool,tuple(bool,tuple(bool,bool)))',
+ 'tuple(uint256,tuple(uint256,uint256,tuple(uint256,string)))',
+ 'string'
+ ],
+ expected: [
+ true,
+ [false, [true, [false, true]]],
+ [new bn(256), [new bn(76), new bn(67), [new bn(1337), 'hello']]],
+ 'last param'
+ ],
values:
'0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '00000000000000000000000000000000000000000000000000000000000000e0' +
+ '0000000000000000000000000000000000000000000000000000000000000200' +
+ '0000000000000000000000000000000000000000000000000000000000000100' +
+ '0000000000000000000000000000000000000000000000000000000000000040' +
+ '000000000000000000000000000000000000000000000000000000000000004c' +
+ '0000000000000000000000000000000000000000000000000000000000000043' +
+ '0000000000000000000000000000000000000000000000000000000000000060' +
+ '0000000000000000000000000000000000000000000000000000000000000539' +
+ '0000000000000000000000000000000000000000000000000000000000000040' +
+ '0000000000000000000000000000000000000000000000000000000000000005' +
+ '68656c6c6f000000000000000000000000000000000000000000000000000000' +
+ '000000000000000000000000000000000000000000000000000000000000000a' +
+ '6c61737420706172616d00000000000000000000000000000000000000000000'
+ })
+
+ test({
+ types: ['string', 'tuple(string,string,tuple(string,string))', 'bytes', 'tuple(bytes,tuple(bytes,string))'],
+ expected: [
+ 'hello world',
+ new Tuple('what', 'is', new Tuple('even', 'happening')),
+ hexToBytes('0x696e'),
+ new Tuple(hexToBytes('0x74686973'), new Tuple(hexToBytes('0x676f64666f7273616b656e'), 'test'))
+ ],
+ values:
+ '0000000000000000000000000000000000000000000000000000000000000080' +
+ '00000000000000000000000000000000000000000000000000000000000000c0' +
+ '0000000000000000000000000000000000000000000000000000000000000260' +
+ '00000000000000000000000000000000000000000000000000000000000002a0' +
+ '000000000000000000000000000000000000000000000000000000000000000b' +
+ '68656c6c6f20776f726c64000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000060' +
+ '00000000000000000000000000000000000000000000000000000000000000a0' +
+ '00000000000000000000000000000000000000000000000000000000000000e0' +
+ '0000000000000000000000000000000000000000000000000000000000000004' +
+ '7768617400000000000000000000000000000000000000000000000000000000' +
'0000000000000000000000000000000000000000000000000000000000000002' +
- '0000000000000000000000000000000000000000000000000000000000000001'
+ '6973000000000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000040' +
+ '0000000000000000000000000000000000000000000000000000000000000080' +
+ '0000000000000000000000000000000000000000000000000000000000000004' +
+ '6576656e00000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000009' +
+ '68617070656e696e670000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '696e000000000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000040' +
+ '0000000000000000000000000000000000000000000000000000000000000080' +
+ '0000000000000000000000000000000000000000000000000000000000000004' +
+ '7468697300000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000040' +
+ '0000000000000000000000000000000000000000000000000000000000000080' +
+ '000000000000000000000000000000000000000000000000000000000000000b' +
+ '676f64666f7273616b656e000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000004' +
+ '7465737400000000000000000000000000000000000000000000000000000000'
})
test({
- types: ['ureal[2][1]', 'bool'],
- expected: [[[new bn(1), new bn(2.125)]], true],
+ types: [
+ 'string',
+ 'bool',
+ 'tuple(string,tuple(tuple(bool,string,bool),tuple(string,bytes32,bytes)))',
+ 'bytes',
+ 'tuple(bool,tuple(bytes32,address),bytes)'
+ ],
+ expected: new Tuple(
+ 'this',
+ true,
+ new Tuple(
+ 'is',
+ new Tuple(
+ new Tuple(true, 'utter', true),
+ new Tuple(
+ 'madness',
+ hexToBytes('0x1234567890123456789012345678901234567890123456789012345678901234'),
+ hexToBytes('0x6275742049206c6f7665206974')
+ )
+ )
+ ),
+ hexToBytes('0x6265636175736520697420776f726b73'),
+ new Tuple(
+ true,
+ new Tuple(
+ hexToBytes('0x1234567890123456789012345678901234567890123456789012345678901234'),
+ '0x1337133713371337133713371337133713371337'
+ ),
+ hexToBytes('0x6265636175736520697420776f726b736265636175736520697420776f726b73')
+ )
+ ),
values:
- '0000000000000000000000000000000100000000000000000000000000000000' +
- '0000000000000000000000000000000220000000000000000000000000000000' +
- '0000000000000000000000000000000000000000000000000000000000000001'
+ '00000000000000000000000000000000000000000000000000000000000000a0' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '00000000000000000000000000000000000000000000000000000000000000e0' +
+ '0000000000000000000000000000000000000000000000000000000000000320' +
+ '0000000000000000000000000000000000000000000000000000000000000360' +
+ '0000000000000000000000000000000000000000000000000000000000000004' +
+ '7468697300000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000040' +
+ '0000000000000000000000000000000000000000000000000000000000000080' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '6973000000000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000040' +
+ '00000000000000000000000000000000000000000000000000000000000000e0' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000060' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000005' +
+ '7574746572000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000060' +
+ '1234567890123456789012345678901234567890123456789012345678901234' +
+ '00000000000000000000000000000000000000000000000000000000000000a0' +
+ '0000000000000000000000000000000000000000000000000000000000000007' +
+ '6d61646e65737300000000000000000000000000000000000000000000000000' +
+ '000000000000000000000000000000000000000000000000000000000000000d' +
+ '6275742049206c6f766520697400000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000010' +
+ '6265636175736520697420776f726b7300000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '1234567890123456789012345678901234567890123456789012345678901234' +
+ '0000000000000000000000001337133713371337133713371337133713371337' +
+ '0000000000000000000000000000000000000000000000000000000000000080' +
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '6265636175736520697420776f726b736265636175736520697420776f726b73'
+ })
+ test({
+ types: [
+ 'tuple(string,tuple(bool,bool))',
+ 'address',
+ 'bytes',
+ 'tuple(bytes,bytes,string,bool,address)',
+ 'int256',
+ 'tuple(int256,uint256,tuple(string,int256,address))'
+ ],
+ expected: [
+ new Tuple('this is more reasonable', new Tuple(true, false)),
+ '0x1b3F5FE0Fd513E6cbdEE459F0b0e19095FE91958',
+ hexToBytes('0x6c6f6c6f6c6f6c6f6c'),
+ new Tuple(
+ hexToBytes('0xabcdef12345678'),
+ hexToBytes('0x87654321fedcba'),
+ 'bazbar',
+ false,
+ '0xd13b6e9058E58B8677233CEc2315e1D9e77C79C4'
+ ),
+ new bn(-6),
+ new Tuple(new bn(-7), new bn(5), new Tuple('foobar', new bn(-8), '0xB1eeF147028E9f480DbC5ccaA3277D417D1b85F0'))
+ ],
+ values:
+ '00000000000000000000000000000000000000000000000000000000000000c0' +
+ '0000000000000000000000001b3f5fe0fd513e6cbdee459f0b0e19095fe91958' +
+ '0000000000000000000000000000000000000000000000000000000000000160' +
+ '00000000000000000000000000000000000000000000000000000000000001a0' +
+ 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa' +
+ '0000000000000000000000000000000000000000000000000000000000000300' +
+ '0000000000000000000000000000000000000000000000000000000000000060' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000017' +
+ '74686973206973206d6f726520726561736f6e61626c65000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000009' +
+ '6c6f6c6f6c6f6c6f6c0000000000000000000000000000000000000000000000' +
+ '00000000000000000000000000000000000000000000000000000000000000a0' +
+ '00000000000000000000000000000000000000000000000000000000000000e0' +
+ '0000000000000000000000000000000000000000000000000000000000000120' +
+ '0000000000000000000000000000000000000000000000000000000000000000' +
+ '000000000000000000000000d13b6e9058e58b8677233cec2315e1d9e77c79c4' +
+ '0000000000000000000000000000000000000000000000000000000000000007' +
+ 'abcdef1234567800000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000007' +
+ '87654321fedcba00000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000006' +
+ '62617a6261720000000000000000000000000000000000000000000000000000' +
+ 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9' +
+ '0000000000000000000000000000000000000000000000000000000000000005' +
+ '0000000000000000000000000000000000000000000000000000000000000060' +
+ '0000000000000000000000000000000000000000000000000000000000000060' +
+ 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8' +
+ '000000000000000000000000b1eef147028e9f480dbc5ccaa3277d417d1b85f0' +
+ '0000000000000000000000000000000000000000000000000000000000000006' +
+ '666f6f6261720000000000000000000000000000000000000000000000000000'
+ })
+ test({
+ types: [
+ 'tuple(bytes32,bool,bytes32)',
+ 'address',
+ 'tuple(bytes32,bytes32,string)',
+ 'tuple(tuple(address,bool),tuple(address,bytes32),tuple(int256,uint256))'
+ ],
+ expected: [
+ new Tuple(
+ hexToBytes('0xffffffffffffffffffffffffffffffffabdef123849181759adebfadecaefbae'),
+ true,
+ hexToBytes('0xffffffffffffffffffffffffffffffffabdef123849181759adebfadecaefbae')
+ ),
+ '0x1234567890123456789012345678901234567890',
+ new Tuple(
+ hexToBytes('0x0ab3e6dfa1594c15af0000000000000000000000000000000000000000000000'),
+ hexToBytes('0xffffffffffffffffffffffffffffffffabdef123849181759adebfadecaefbae'),
+ 'string'
+ ),
+ [
+ new Tuple('0x1234567890123456789012345678901234567890', true),
+ new Tuple(
+ '0x1234567890123456789012345678901234567890',
+ hexToBytes('0xffffffffffffffffffffffffffffffffabdef123849181759adebfadecaefbae')
+ ),
+ new Tuple(new bn(-6124612), new bn(89000))
+ ]
+ ],
+ values:
+ 'ffffffffffffffffffffffffffffffffabdef123849181759adebfadecaefbae' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ 'ffffffffffffffffffffffffffffffffabdef123849181759adebfadecaefbae' +
+ '0000000000000000000000001234567890123456789012345678901234567890' +
+ '0000000000000000000000000000000000000000000000000000000000000160' +
+ '0000000000000000000000001234567890123456789012345678901234567890' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000001234567890123456789012345678901234567890' +
+ 'ffffffffffffffffffffffffffffffffabdef123849181759adebfadecaefbae' +
+ 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa28bbc' +
+ '0000000000000000000000000000000000000000000000000000000000015ba8' +
+ '0ab3e6dfa1594c15af0000000000000000000000000000000000000000000000' +
+ 'ffffffffffffffffffffffffffffffffabdef123849181759adebfadecaefbae' +
+ '0000000000000000000000000000000000000000000000000000000000000060' +
+ '0000000000000000000000000000000000000000000000000000000000000006' +
+ '737472696e670000000000000000000000000000000000000000000000000000'
})
})
})
diff --git a/test/coder.encodeParam.ts b/test/coder.encodeParam.ts
index d6368742..12864980 100644
--- a/test/coder.encodeParam.ts
+++ b/test/coder.encodeParam.ts
@@ -1,17 +1,20 @@
import * as expect from 'expect'
import * as coder from '../src/solidity/coder'
+import { hexToBytes } from '../src'
+import { parseParamType } from '../src/abi/parser'
describe('lib/solidity/coder', function () {
describe('encodeParam', function () {
let test = function (t) {
- it('should turn ' + t.value + ' to ' + t.expected, function () {
- expect(coder.coder.encodeParam(t.type, t.value)).toEqual(t.expected)
+ it('should turn ' + t.type + ' ' + t.value + ' to ' + t.expected, function () {
+ expect(coder.coder.encodeParams([parseParamType(t.type)], [t.value])).toEqual(t.expected)
+ expect(coder.coder.encodeParams([t.type], [t.value])).toEqual(t.expected)
})
}
test({
type: 'address',
- value: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
+ value: '0x407D73d8a49eeb85D32Cf465507dd71d507100c1',
expected: '000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1'
})
test({
@@ -21,21 +24,21 @@ describe('lib/solidity/coder', function () {
})
test({
type: 'address[2]',
- value: ['0xBF79cE2fbd819e5aBC2327563D02a200255B7Cb3', '0x407d73d8a49eeb85d32cf465507dd71d507100c3'],
+ value: ['0xBF79cE2fbd819e5aBC2327563D02a200255B7Cb3', '0x407D73d8A49eEB85D32Cf465507Dd71d507100c3'],
expected:
'000000000000000000000000bf79ce2fbd819e5abc2327563d02a200255b7cb3' +
'000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c3'
})
test({
type: 'address[2]',
- value: ['0x407d73d8a49eeb85d32cf465507dd71d507100c1', '0x407d73d8a49eeb85d32cf465507dd71d507100c3'],
+ value: ['0x407D73d8a49eeb85D32Cf465507dd71d507100c1', '0x407D73d8A49eEB85D32Cf465507Dd71d507100c3'],
expected:
'000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1' +
'000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c3'
})
test({
type: 'address[]',
- value: ['0x407d73d8a49eeb85d32cf465507dd71d507100c1', '0x407d73d8a49eeb85d32cf465507dd71d507100c3'],
+ value: ['0x407D73d8a49eeb85D32Cf465507dd71d507100c1', '0x407D73d8A49eEB85D32Cf465507Dd71d507100c3'],
expected:
'0000000000000000000000000000000000000000000000000000000000000020' +
'0000000000000000000000000000000000000000000000000000000000000002' +
@@ -45,10 +48,11 @@ describe('lib/solidity/coder', function () {
test({
type: 'address[][2]',
value: [
- ['0x407d73d8a49eeb85d32cf465507dd71d507100c1', '0x407d73d8a49eeb85d32cf465507dd71d507100c2'],
- ['0x407d73d8a49eeb85d32cf465507dd71d507100c3', '0x407d73d8a49eeb85d32cf465507dd71d507100c4']
+ ['0x407D73d8a49eeb85D32Cf465507dd71d507100c1', '0x407d73d8a49EEB85d32Cf465507dD71D507100c2'],
+ ['0x407D73d8A49eEB85D32Cf465507Dd71d507100c3', '0x407D73d8a49eeb85D32CF465507dd71d507100C4']
],
expected:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
'0000000000000000000000000000000000000000000000000000000000000040' +
'00000000000000000000000000000000000000000000000000000000000000a0' +
'0000000000000000000000000000000000000000000000000000000000000002' +
@@ -61,8 +65,8 @@ describe('lib/solidity/coder', function () {
test({
type: 'address[2][]',
value: [
- ['0x407d73d8a49eeb85d32cf465507dd71d507100c1', '0x407d73d8a49eeb85d32cf465507dd71d507100c2'],
- ['0x407d73d8a49eeb85d32cf465507dd71d507100c3', '0x407d73d8a49eeb85d32cf465507dd71d507100c4']
+ ['0x407D73d8a49eeb85D32Cf465507dd71d507100c1', '0x407d73d8a49EEB85d32Cf465507dD71D507100c2'],
+ ['0x407D73d8A49eEB85D32Cf465507Dd71d507100c3', '0x407D73d8a49eeb85D32CF465507dd71d507100C4']
],
expected:
'0000000000000000000000000000000000000000000000000000000000000020' +
@@ -188,15 +192,6 @@ describe('lib/solidity/coder', function () {
value: '0xc3a40000c3a4',
expected: 'c3a40000c3a40000000000000000000000000000000000000000000000000000'
})
- test({
- type: 'bytes64',
- value:
- '0xc3a40000c3a40000000000000000000000000000000000000000000000000000' +
- 'c3a40000c3a40000000000000000000000000000000000000000000000000000',
- expected:
- 'c3a40000c3a40000000000000000000000000000000000000000000000000000' +
- 'c3a40000c3a40000000000000000000000000000000000000000000000000000'
- })
test({
type: 'string',
value: 'ää',
@@ -264,13 +259,6 @@ describe('lib/solidity/coder', function () {
'fb00000000000000000000000000000000000000000000000000000000000000'
})
- test({ type: 'real', value: 1, expected: '0000000000000000000000000000000100000000000000000000000000000000' })
- test({ type: 'real', value: 2.125, expected: '0000000000000000000000000000000220000000000000000000000000000000' })
- test({ type: 'real', value: 8.5, expected: '0000000000000000000000000000000880000000000000000000000000000000' })
- test({ type: 'real', value: -1, expected: 'ffffffffffffffffffffffffffffffff00000000000000000000000000000000' })
- test({ type: 'ureal', value: 1, expected: '0000000000000000000000000000000100000000000000000000000000000000' })
- test({ type: 'ureal', value: 2.125, expected: '0000000000000000000000000000000220000000000000000000000000000000' })
- test({ type: 'ureal', value: 8.5, expected: '0000000000000000000000000000000880000000000000000000000000000000' })
test({
type: 'bytes',
value:
@@ -304,6 +292,192 @@ describe('lib/solidity/coder', function () {
'77656c636f6d6520746f20657468657265756d2e2077656c636f6d6520746f20' +
'657468657265756d2e2077656c636f6d6520746f20657468657265756d2e0000'
})
+
+ test({
+ type: 'tuple(string,string)',
+ value: ['welcome to ethereum.', 'welcome to ethereum.'],
+ expected:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000040' +
+ '0000000000000000000000000000000000000000000000000000000000000080' +
+ '0000000000000000000000000000000000000000000000000000000000000014' +
+ '77656c636f6d6520746f20657468657265756d2e000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000014' +
+ '77656c636f6d6520746f20657468657265756d2e000000000000000000000000'
+ })
+ test({
+ type: 'tuple(bytes,bytes)',
+ value: ['0x77656c636f6d6520746f20657468657265756d2e', '0x77656c636f6d6520746f20657468657265756d2e'],
+ expected:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000040' +
+ '0000000000000000000000000000000000000000000000000000000000000080' +
+ '0000000000000000000000000000000000000000000000000000000000000014' +
+ '77656c636f6d6520746f20657468657265756d2e000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000014' +
+ '77656c636f6d6520746f20657468657265756d2e000000000000000000000000'
+ })
+ test({
+ type: 'tuple(bytes,bool,uint256)',
+ value: ['0x77656c636f6d6520746f20657468657265756d2e', true, 124515],
+ expected:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000060' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '000000000000000000000000000000000000000000000000000000000001e663' +
+ '0000000000000000000000000000000000000000000000000000000000000014' +
+ '77656c636f6d6520746f20657468657265756d2e000000000000000000000000'
+ })
+ test({
+ type: 'tuple(string,tuple(bool,int256),address)',
+ value: ['hello', [true, -151], '0x0175010374017501037401750103740175010374'],
+ expected:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000080' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff69' +
+ '0000000000000000000000000175010374017501037401750103740175010374' +
+ '0000000000000000000000000000000000000000000000000000000000000005' +
+ '68656c6c6f000000000000000000000000000000000000000000000000000000'
+ })
+ test({
+ type: 'tuple(tuple(bool,bool),tuple(address,address),tuple(string,string))',
+ value: [
+ [true, false],
+ ['0x81017589ab81017589ab81017589ab81017589ab', '0x81017589ab81017589ab81017589ab81017589ab'],
+ ['string One', 'string Two']
+ ],
+ expected:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000000' +
+ '00000000000000000000000081017589ab81017589ab81017589ab81017589ab' +
+ '00000000000000000000000081017589ab81017589ab81017589ab81017589ab' +
+ '00000000000000000000000000000000000000000000000000000000000000a0' +
+ '0000000000000000000000000000000000000000000000000000000000000040' +
+ '0000000000000000000000000000000000000000000000000000000000000080' +
+ '000000000000000000000000000000000000000000000000000000000000000a' +
+ '737472696e67204f6e6500000000000000000000000000000000000000000000' +
+ '000000000000000000000000000000000000000000000000000000000000000a' +
+ '737472696e672054776f00000000000000000000000000000000000000000000'
+ })
+ test({
+ type: 'tuple(tuple(tuple(bool,bool),tuple(bytes,bytes),tuple(address,bool)),address)',
+ value: [
+ [
+ [false, false],
+ ['0xab1394581edfa2ef9ca71', '0x15abe391df19aef19a4561'],
+ ['0xec2270c849236333c86834728e783cd2f789088e', true]
+ ],
+ '0x81017589ab81017589ab81017589ab81017589ab'
+ ],
+ expected:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000040' +
+ '00000000000000000000000081017589ab81017589ab81017589ab81017589ab' +
+ '0000000000000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000000' +
+ '00000000000000000000000000000000000000000000000000000000000000a0' +
+ '000000000000000000000000ec2270c849236333c86834728e783cd2f789088e' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000040' +
+ '0000000000000000000000000000000000000000000000000000000000000080' +
+ '000000000000000000000000000000000000000000000000000000000000000b' +
+ '0ab1394581edfa2ef9ca71000000000000000000000000000000000000000000' +
+ '000000000000000000000000000000000000000000000000000000000000000b' +
+ '15abe391df19aef19a4561000000000000000000000000000000000000000000'
+ })
+ test({
+ type: 'tuple(bool,string,bool,tuple(address,address))',
+ value: [
+ true,
+ 'testing',
+ false,
+ ['0x1981710abe1981710abe1981710abe1981710abe', '0x1981710abe1981710abe1981710abe1981710abe']
+ ],
+ expected:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '00000000000000000000000000000000000000000000000000000000000000a0' +
+ '0000000000000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000001981710abe1981710abe1981710abe1981710abe' +
+ '0000000000000000000000001981710abe1981710abe1981710abe1981710abe' +
+ '0000000000000000000000000000000000000000000000000000000000000007' +
+ '74657374696e6700000000000000000000000000000000000000000000000000'
+ })
+ test({
+ type: 'tuple(address,address,tuple(string,tuple(int256,int256),string))',
+ value: [
+ '0x1981710abe1981710abe1981710abe1981710abe',
+ '0x1981710abe1981710abe1981710abe1981710abe',
+ ['structs are great', [-1951, 194018], 'so many possibilities']
+ ],
+ expected:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000001981710abe1981710abe1981710abe1981710abe' +
+ '0000000000000000000000001981710abe1981710abe1981710abe1981710abe' +
+ '0000000000000000000000000000000000000000000000000000000000000060' +
+ '0000000000000000000000000000000000000000000000000000000000000080' +
+ 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff861' +
+ '000000000000000000000000000000000000000000000000000000000002f5e2' +
+ '00000000000000000000000000000000000000000000000000000000000000c0' +
+ '0000000000000000000000000000000000000000000000000000000000000011' +
+ '7374727563747320617265206772656174000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000015' +
+ '736f206d616e7920706f73736962696c69746965730000000000000000000000'
+ })
+ test({
+ type: 'tuple(bool,tuple(bytes32,int256,tuple(bytes24,bytes8)),tuple(bool,bool,bool),string)',
+ value: [
+ true,
+ [
+ '0xabdef18710a18a18abdef18710a18a18abdef18710a18a18abdef18710a18a18',
+ -18291849,
+ ['0xabdef18710a18a18abdef18710a18a18abdef18710a18a18', '0xabdef18710a18a18']
+ ],
+ [false, true, false],
+ 'testing testing'
+ ],
+ expected:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ 'abdef18710a18a18abdef18710a18a18abdef18710a18a18abdef18710a18a18' +
+ 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffee8e377' +
+ 'abdef18710a18a18abdef18710a18a18abdef18710a18a180000000000000000' +
+ 'abdef18710a18a18000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000120' +
+ '000000000000000000000000000000000000000000000000000000000000000f' +
+ '74657374696e672074657374696e670000000000000000000000000000000000'
+ })
+ test({
+ type: 'tuple(bool,tuple(bytes32,int256,tuple(bytes24,bytes8)),tuple(bool,bool,bool),string)',
+ value: [
+ true,
+ [
+ hexToBytes('0xdeadbeef01'),
+ -18291849,
+ ['0xabdef18710a18a18abdef18710a18a18abdef18710a18a18', '0xabdef18710a18a18']
+ ],
+ [false, true, false],
+ 'testing testing'
+ ],
+ expected:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ 'deadbeef01000000000000000000000000000000000000000000000000000000' +
+ 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffee8e377' +
+ 'abdef18710a18a18abdef18710a18a18abdef18710a18a180000000000000000' +
+ 'abdef18710a18a18000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000120' +
+ '000000000000000000000000000000000000000000000000000000000000000f' +
+ '74657374696e672074657374696e670000000000000000000000000000000000'
+ })
})
})
@@ -311,13 +485,19 @@ describe('lib/solidity/coder', function () {
describe('encodeParams', function () {
let test = function (t) {
it('should turn ' + t.values + ' to ' + t.expected, function () {
+ expect(
+ coder.coder.encodeParams(
+ t.types.map((type) => parseParamType(type)),
+ t.values
+ )
+ ).toEqual(t.expected)
expect(coder.coder.encodeParams(t.types, t.values)).toEqual(t.expected)
})
}
test({
types: ['address', 'address'],
- values: ['0x407d73d8a49eeb85d32cf465507dd71d507100c1', '0x407d73d8a49eeb85d32cf465507dd71d507100c3'],
+ values: ['0x407D73d8a49eeb85D32Cf465507dd71d507100c1', '0x407D73d8A49eEB85D32Cf465507Dd71d507100c3'],
expected:
'000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1' +
'000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c3'
@@ -559,9 +739,313 @@ describe('lib/solidity/coder', function () {
'0000000000000000000000000000000000000000000000000000000000000020' +
'4d00000000000000000000000000000000000000000000000000000000000012'
})
- })
+ test({
+ types: ['string', 'tuple(string,string)'],
+ values: ['what', ['what what', 'what what']],
+ expected:
+ '0000000000000000000000000000000000000000000000000000000000000040' +
+ '0000000000000000000000000000000000000000000000000000000000000080' +
+ '0000000000000000000000000000000000000000000000000000000000000004' +
+ '7768617400000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000040' +
+ '0000000000000000000000000000000000000000000000000000000000000080' +
+ '0000000000000000000000000000000000000000000000000000000000000009' +
+ '7768617420776861740000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000009' +
+ '7768617420776861740000000000000000000000000000000000000000000000'
+ })
+ test({
+ types: ['tuple(bytes32,bool)', 'tuple(bool,address)'],
+ values: [
+ ['0xabdef18710a18a18abdef18710a18a18abdef18710a18a18abdef18710a18a18', true],
+ [true, '0x77656c636f6d6520746f20657468657265756d2e']
+ ],
+ expected:
+ 'abdef18710a18a18abdef18710a18a18abdef18710a18a18abdef18710a18a18' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '00000000000000000000000077656c636f6d6520746f20657468657265756d2e'
+ })
+ test({
+ types: ['tuple(bytes32,bool)', 'tuple(bool,address)'],
+ values: [
+ ['0xabdef18710a18a18abdef18710a18a18abdef18710a18a18abdef18710a18a18', true],
+ [true, '0x77656c636f6d6520746f20657468657265756d2e']
+ ],
+ expected:
+ 'abdef18710a18a18abdef18710a18a18abdef18710a18a18abdef18710a18a18' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '00000000000000000000000077656c636f6d6520746f20657468657265756d2e'
+ })
+ test({
+ types: ['tuple(address,uint256)', 'tuple(uint256,bool)', 'tuple(bytes32,bytes32)'],
+ values: [
+ ['0x77656c636f6d6520746f20657468657265756d2e', '148'],
+ ['5910', true],
+ [
+ '0xabdef18710a18a18abdef18710a18a18abdef18710a18a18abdef18710a18a18',
+ '0xabdef18710a18a18abdef18710a18a18abdef18710a18a18abdef18710a18a18'
+ ]
+ ],
+ expected:
+ '00000000000000000000000077656c636f6d6520746f20657468657265756d2e' +
+ '0000000000000000000000000000000000000000000000000000000000000094' +
+ '0000000000000000000000000000000000000000000000000000000000001716' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ 'abdef18710a18a18abdef18710a18a18abdef18710a18a18abdef18710a18a18' +
+ 'abdef18710a18a18abdef18710a18a18abdef18710a18a18abdef18710a18a18'
+ })
+
+ test({
+ types: [
+ 'tuple(tuple(address,address),tuple(bool,bool))',
+ 'tuple(tuple(bool,bool),tuple(bytes,bytes),tuple(uint256,uint256))',
+ 'address'
+ ],
+ values: [
+ [
+ ['0x77656c636f6d6520746f20657468657265756d2e', '0x77656c636f6d6520746f20657468657265756d2e'],
+ [true, false]
+ ],
+ [
+ [false, true],
+ ['0xab1394581edfa2ef9ca71', '0x15abe391df19aef19a4561'],
+ ['182', '1937']
+ ],
+ '0x77656c636f6d6520746f20657468657265756d2e'
+ ],
+ expected:
+ '00000000000000000000000077656c636f6d6520746f20657468657265756d2e' +
+ '00000000000000000000000077656c636f6d6520746f20657468657265756d2e' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000000' +
+ '00000000000000000000000000000000000000000000000000000000000000c0' +
+ '00000000000000000000000077656c636f6d6520746f20657468657265756d2e' +
+ '0000000000000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '00000000000000000000000000000000000000000000000000000000000000a0' +
+ '00000000000000000000000000000000000000000000000000000000000000b6' +
+ '0000000000000000000000000000000000000000000000000000000000000791' +
+ '0000000000000000000000000000000000000000000000000000000000000040' +
+ '0000000000000000000000000000000000000000000000000000000000000080' +
+ '000000000000000000000000000000000000000000000000000000000000000b' +
+ '0ab1394581edfa2ef9ca71000000000000000000000000000000000000000000' +
+ '000000000000000000000000000000000000000000000000000000000000000b' +
+ '15abe391df19aef19a4561000000000000000000000000000000000000000000'
+ })
+ test({
+ types: [
+ 'tuple(tuple(uint256,bool),tuple(uint256,tuple(bytes,bytes)))',
+ 'bytes',
+ 'tuple(bool,tuple(bytes,address),bytes)'
+ ],
+ values: [
+ [
+ ['18320', true],
+ ['691', ['0xab1394581edfa2ef9ca71', '0x15abe391df19aef19a4561']]
+ ],
+ '0xab1394581edfa2ef9ca71',
+ [
+ false,
+ ['0xfe', '0x77656c636f6d6520746f20657468657265756d2e'],
+ '0xabdef18710a18a18abdef18710a18a18abdef18710a18a18abdef18710a18a18'
+ ]
+ ],
+ expected:
+ '0000000000000000000000000000000000000000000000000000000000000060' +
+ '00000000000000000000000000000000000000000000000000000000000001c0' +
+ '0000000000000000000000000000000000000000000000000000000000000200' +
+ '0000000000000000000000000000000000000000000000000000000000004790' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000060' +
+ '00000000000000000000000000000000000000000000000000000000000002b3' +
+ '0000000000000000000000000000000000000000000000000000000000000040' +
+ '0000000000000000000000000000000000000000000000000000000000000040' +
+ '0000000000000000000000000000000000000000000000000000000000000080' +
+ '000000000000000000000000000000000000000000000000000000000000000b' +
+ '0ab1394581edfa2ef9ca71000000000000000000000000000000000000000000' +
+ '000000000000000000000000000000000000000000000000000000000000000b' +
+ '15abe391df19aef19a4561000000000000000000000000000000000000000000' +
+ '000000000000000000000000000000000000000000000000000000000000000b' +
+ '0ab1394581edfa2ef9ca71000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000060' +
+ '00000000000000000000000000000000000000000000000000000000000000e0' +
+ '0000000000000000000000000000000000000000000000000000000000000040' +
+ '00000000000000000000000077656c636f6d6520746f20657468657265756d2e' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ 'fe00000000000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ 'abdef18710a18a18abdef18710a18a18abdef18710a18a18abdef18710a18a18'
+ })
+
+ test({
+ types: ['address', 'tuple(bool,tuple(address,address))', 'tuple(tuple(address,tuple(int256,int256)),bool)'],
+ values: [
+ '0x77656c636f6d6520746f20657468657265756d2e',
+ [true, ['0x77656c636f6d6520746f20657468657265756d2e', '0x77656c636f6d6520746f20657468657265756d2e']],
+ [['0x77656c636f6d6520746f20657468657265756d2e', ['-12451', '-12451018']], false]
+ ],
+ expected:
+ '00000000000000000000000077656c636f6d6520746f20657468657265756d2e' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '00000000000000000000000077656c636f6d6520746f20657468657265756d2e' +
+ '00000000000000000000000077656c636f6d6520746f20657468657265756d2e' +
+ '00000000000000000000000077656c636f6d6520746f20657468657265756d2e' +
+ 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcf5d' +
+ 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff420336' +
+ '0000000000000000000000000000000000000000000000000000000000000000'
+ })
+
+ test({
+ types: [
+ 'bytes',
+ 'tuple(tuple(bool,bool,bool),tuple(bytes,bytes,bytes),tuple(bytes,bool,address),tuple(uint256,int256,address))',
+ 'tuple(bytes,tuple(tuple(int256,bool),tuple(uint256,bytes)))'
+ ],
+ values: [
+ '0xabef15',
+ [
+ [true, false, true],
+ ['0xabef15', '0xcdef151', '0xabfe151'],
+ ['0x15abe391df19aef19a4561', true, '0x77656c636f6d6520746f20657468657265756d2e'],
+ ['1840181', '-819184919', '0x77656c636f6d6520746f20657468657265756d2e']
+ ],
+ [
+ '0x77656c636f6d6520746f20657468657265756d2e',
+ [
+ ['-18491', false],
+ ['1918491', '0xabdcf151dae']
+ ]
+ ]
+ ],
+ expected:
+ '0000000000000000000000000000000000000000000000000000000000000060' +
+ '00000000000000000000000000000000000000000000000000000000000000a0' +
+ '0000000000000000000000000000000000000000000000000000000000000360' +
+ '0000000000000000000000000000000000000000000000000000000000000003' +
+ 'abef150000000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000100' +
+ '0000000000000000000000000000000000000000000000000000000000000220' +
+ '00000000000000000000000000000000000000000000000000000000001c1435' +
+ 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffcf2c3ae9' +
+ '00000000000000000000000077656c636f6d6520746f20657468657265756d2e' +
+ '0000000000000000000000000000000000000000000000000000000000000060' +
+ '00000000000000000000000000000000000000000000000000000000000000a0' +
+ '00000000000000000000000000000000000000000000000000000000000000e0' +
+ '0000000000000000000000000000000000000000000000000000000000000003' +
+ 'abef150000000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000004' +
+ '0cdef15100000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000004' +
+ '0abfe15100000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000060' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '00000000000000000000000077656c636f6d6520746f20657468657265756d2e' +
+ '000000000000000000000000000000000000000000000000000000000000000b' +
+ '15abe391df19aef19a4561000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000040' +
+ '0000000000000000000000000000000000000000000000000000000000000080' +
+ '0000000000000000000000000000000000000000000000000000000000000014' +
+ '77656c636f6d6520746f20657468657265756d2e000000000000000000000000' +
+ 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb7c5' +
+ '0000000000000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000060' +
+ '00000000000000000000000000000000000000000000000000000000001d461b' +
+ '0000000000000000000000000000000000000000000000000000000000000040' +
+ '0000000000000000000000000000000000000000000000000000000000000006' +
+ '0abdcf151dae0000000000000000000000000000000000000000000000000000'
+ })
+
+ test({
+ types: [
+ 'tuple(bytes,tuple(address,address))',
+ 'tuple(address,address,address,bytes,address)',
+ 'tuple(address,tuple(address,tuple(address,bool)))'
+ ],
+ values: [
+ ['0xabef15', ['0x77656c636f6d6520746f20657468657265756d2e', '0x77656c636f6d6520746f20657468657265756d2e']],
+ [
+ '0x77656c636f6d6520746f20657468657265756d2e',
+ '0x77656c636f6d6520746f20657468657265756d2e',
+ '0x77656c636f6d6520746f20657468657265756d2e',
+ '0xabef15',
+ '0x77656c636f6d6520746f20657468657265756d2e'
+ ],
+ [
+ '0x81017589ab81017589ab81017589ab81017589ab',
+ ['0x77656c636f6d6520746f20657468657265756d2e', ['0x81017589ab81017589ab81017589ab81017589ab', false]]
+ ]
+ ],
+ expected:
+ '00000000000000000000000000000000000000000000000000000000000000c0' +
+ '0000000000000000000000000000000000000000000000000000000000000160' +
+ '00000000000000000000000081017589ab81017589ab81017589ab81017589ab' +
+ '00000000000000000000000077656c636f6d6520746f20657468657265756d2e' +
+ '00000000000000000000000081017589ab81017589ab81017589ab81017589ab' +
+ '0000000000000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000060' +
+ '00000000000000000000000077656c636f6d6520746f20657468657265756d2e' +
+ '00000000000000000000000077656c636f6d6520746f20657468657265756d2e' +
+ '0000000000000000000000000000000000000000000000000000000000000003' +
+ 'abef150000000000000000000000000000000000000000000000000000000000' +
+ '00000000000000000000000077656c636f6d6520746f20657468657265756d2e' +
+ '00000000000000000000000077656c636f6d6520746f20657468657265756d2e' +
+ '00000000000000000000000077656c636f6d6520746f20657468657265756d2e' +
+ '00000000000000000000000000000000000000000000000000000000000000a0' +
+ '00000000000000000000000077656c636f6d6520746f20657468657265756d2e' +
+ '0000000000000000000000000000000000000000000000000000000000000003' +
+ 'abef150000000000000000000000000000000000000000000000000000000000'
+ })
+
+ test({
+ types: ['tuple(bytes,bytes)', 'bytes', 'tuple(tuple(bytes),tuple(bytes,bytes),tuple(bytes,bytes,bytes))'],
+ values: [
+ ['0xabef15', '0xa'],
+ '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
+ [['0xaf'], ['0xaf', '0xbc'], ['0xaf', '0xbc', '0xde']]
+ ],
+ expected:
+ '0000000000000000000000000000000000000000000000000000000000000060' +
+ '0000000000000000000000000000000000000000000000000000000000000120' +
+ '0000000000000000000000000000000000000000000000000000000000000160' +
+ '0000000000000000000000000000000000000000000000000000000000000040' +
+ '0000000000000000000000000000000000000000000000000000000000000080' +
+ '0000000000000000000000000000000000000000000000000000000000000003' +
+ 'abef150000000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0a00000000000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' +
+ '0000000000000000000000000000000000000000000000000000000000000060' +
+ '00000000000000000000000000000000000000000000000000000000000000c0' +
+ '0000000000000000000000000000000000000000000000000000000000000180' +
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ 'af00000000000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000040' +
+ '0000000000000000000000000000000000000000000000000000000000000080' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ 'af00000000000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ 'bc00000000000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000060' +
+ '00000000000000000000000000000000000000000000000000000000000000a0' +
+ '00000000000000000000000000000000000000000000000000000000000000e0' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ 'af00000000000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ 'bc00000000000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ 'de00000000000000000000000000000000000000000000000000000000000000'
+ })
+ })
var tests = [
{
@@ -584,10 +1068,23 @@ describe('lib/solidity/coder', function () {
}
]
-
it('encodeParams', function () {
tests.forEach(function (test) {
+ expect(
+ coder.coder.encodeParams(
+ test.types.map((type) => parseParamType(type)),
+ test.params
+ )
+ ).toEqual(test.result)
expect(coder.coder.encodeParams(test.types, test.params)).toEqual(test.result)
})
})
+
+ it('sanity hexToBytes', () => {
+ expect(hexToBytes('0xf')).toEqual(new Uint8Array([0xf]))
+ expect(hexToBytes('0x0f')).toEqual(new Uint8Array([0xf]))
+ expect(hexToBytes('0x81')).toEqual(new Uint8Array([0x81]))
+ expect(hexToBytes('0x0f1')).toEqual(new Uint8Array([0xf, 0x1]))
+ expect(hexToBytes('0xf1')).toEqual(new Uint8Array([0xf1]))
+ })
})
diff --git a/test/contract.ts b/test/contract.ts
index 0bd8bc87..e676aba9 100644
--- a/test/contract.ts
+++ b/test/contract.ts
@@ -58,6 +58,41 @@ let desc = [
},
],
},
+ {
+ "inputs": [
+ {
+ "components": [
+ {
+ "internalType": "contract IERC721CollectionV2",
+ "name": "collection",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256[]",
+ "name": "ids",
+ "type": "uint256[]"
+ },
+ {
+ "internalType": "uint256[]",
+ "name": "prices",
+ "type": "uint256[]"
+ },
+ {
+ "internalType": "address[]",
+ "name": "beneficiaries",
+ "type": "address[]"
+ }
+ ],
+ "internalType": "struct CollectionStore.ItemToBuy[]",
+ "name": "_itemsToBuy",
+ "type": "tuple[]"
+ }
+ ],
+ "name": "buy",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
{
name: 'Changed',
type: 'event',
@@ -379,6 +414,33 @@ describe('contract', function () {
await didCall
})
+ it('should sendTransaction with tuples to contract function', async function () {
+ const provider = new FakeHttpProvider()
+ const rm = new RequestManager(provider)
+ let address = '0x1234567890123456789012345678901234567891'
+
+ const didCall = provider.injectHandler('eth_sendTransaction', async (payload) => {
+ expect(payload.params).toEqual([
+ {
+ data:
+ '0xa4fdc78a0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000006b80863d347a7bde24ee9317f04baaa9259a5d6a000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000008ac7230489e80000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000014dc79964da2c08b23698b3d3cc7ca32193d9955',
+ from: address,
+ to: address,
+ },
+ ])
+ provider.injectResult('0xb')
+ })
+
+ let contract: any = await new ContractFactory(rm, desc).at(address)
+
+ await contract.buy(
+ [
+ ['0x6b80863d347a7bde24ee9317f04baaa9259a5d6a', [0], ['10000000000000000000'], ['0x14dC79964da2C08b23698B3D3cc7Ca32193d9955']]
+ ], { from: address })
+
+ await didCall
+ })
+
it('should make a call with optional params', async function () {
const provider = new FakeHttpProvider()
const rm = new RequestManager(provider)
diff --git a/test/errors.ts b/test/errors.ts
index 53621ab0..0e5c6661 100644
--- a/test/errors.ts
+++ b/test/errors.ts
@@ -1,12 +1,10 @@
import * as expect from 'expect'
-import * as errors from '../src/utils/errors'
+import { error } from '../src/utils/errors'
-describe('lib/web3/method', function() {
- describe('getCall', function() {
- for (let key in errors) {
- it('should return and error', function() {
- expect(errors[key]()).toBeInstanceOf(Error)
- })
- }
+describe('lib/web3/method', function () {
+ describe('getCall', function () {
+ it('should return and error', function () {
+ expect(error('something')).toBeInstanceOf(Error)
+ })
})
})
diff --git a/test/formatters.inputAddressFormatter.ts b/test/formatters.inputAddressFormatter.ts
deleted file mode 100644
index f23cc1ba..00000000
--- a/test/formatters.inputAddressFormatter.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-import * as expect from 'expect'
-import { coder } from '../src/solidity/coder'
-import { formatInputAddress } from '../src/solidity/formatters'
-import * as formatters from '../src/utils/formatters'
-
-let tests = [
- // { input: 'XE7338O073KYGTWWZN0F2WZ0R8PX5ZPPZS', result: '0x00c5496aee77c1ba1f0854206a26dda82a81d6d8' },
- { input: '0x00c5496aee77c1ba1f0854206a26dda82a81d6d8', result: '0x00c5496aee77c1ba1f0854206a26dda82a81d6d8' },
- { input: '00c5496aee77c1ba1f0854206a26dda82a81d6d8', result: '0x00c5496aee77c1ba1f0854206a26dda82a81d6d8' },
- { input: '0x11f4d0a3c12e86b4b5f39b213f7e19d048276dae', result: '0x11f4d0a3c12e86b4b5f39b213f7e19d048276dae' },
- { input: '0xBF79cE2fbd819e5aBC2327563D02a200255B7Cb3', result: '0xBF79cE2fbd819e5aBC2327563D02a200255B7Cb3' }
-]
-
-let errorTests = [
- '0x0c5496aee77c1ba1f0854206a26dda82a81d6d8',
- '0x0c5496aee77c1ba1f0854206a26dda82a81d6d8',
- '00c5496aee77c1ba1f0854206a26dda82a81d6d',
- '0x0',
- 'XE7338O073KYGTWWZN0F2WZ0R8PX5ZPPZE',
- '0x'
-]
-
-describe('formatters', function () {
- describe('inputAddressFormatter', function () {
- tests.forEach(function (test, i) {
- it('should return the correct value: ' + i, function () {
- expect(formatters.inputAddressFormatter(test.input)).toEqual(test.result)
- })
- })
- })
-})
-
-describe('formatters', function () {
- describe('inputAddressFormatter', function () {
- errorTests.forEach(function (test, i) {
- it('should throw an exception: ' + i, function () {
- expect(function () {
- formatters.inputAddressFormatter(test)
- }).toThrow()
- })
- })
- })
- describe('formatInputAddress', () => {
- tests.forEach(function (test) {
- it('formatInputAddress: ' + test.input, () => {
- const t = formatInputAddress(test.input)
- expect(coder.decodeParam('address', t.encode())).toEqual(test.result.toLowerCase())
- })
- })
- })
-})
diff --git a/test/geth.packing.ts b/test/geth.packing.ts
new file mode 100644
index 00000000..2437ce25
--- /dev/null
+++ b/test/geth.packing.ts
@@ -0,0 +1,1159 @@
+import { AbiInput, AbiOutput, BigNumber as bn } from '../dist/eth-connect'
+import * as expect from 'expect'
+import { coder } from '../src/solidity/coder'
+import { hexToBytes, isArray, isBigNumber } from '../src'
+import { formatParamType, Tuple } from '../src/abi/coder'
+
+var packUnpackTests: Array<{ def: Partial[]; packed: string; unpacked: any }> = [
+ // Booleans
+ {
+ def: [{ type: 'bool' }],
+ packed: '0000000000000000000000000000000000000000000000000000000000000001',
+ unpacked: [true]
+ },
+ {
+ def: [{ type: 'bool' }],
+ packed: '0000000000000000000000000000000000000000000000000000000000000000',
+ unpacked: [false]
+ },
+ // Integers
+ {
+ def: [{ type: 'uint8' }],
+ unpacked: [2],
+ packed: '0000000000000000000000000000000000000000000000000000000000000002'
+ },
+ {
+ def: [{ type: 'uint256' }],
+ unpacked: [new bn(10)],
+ packed: '000000000000000000000000000000000000000000000000000000000000000a'
+ },
+ {
+ def: [{ type: 'uint8[]' }],
+ unpacked: [[1, 2]],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002'
+ },
+ {
+ def: [{ type: 'uint16' }],
+ unpacked: [5],
+ packed: '0000000000000000000000000000000000000000000000000000000000000005'
+ },
+ {
+ def: [{ type: 'uint16[]' }],
+ unpacked: [[1, 2]],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002'
+ },
+ {
+ def: [{ type: 'uint16' }],
+ packed: '0000000000000000000000000000000000000000000000000000000000000001',
+ unpacked: [1]
+ },
+ {
+ def: [{ type: 'uint32' }],
+ packed: '0000000000000000000000000000000000000000000000000000000000000001',
+ unpacked: [1]
+ },
+ {
+ def: [{ type: 'uint32[]' }],
+ unpacked: [[1, 2]],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002'
+ },
+ {
+ def: [{ type: 'uint64' }],
+ unpacked: [new bn(6)],
+ packed: '0000000000000000000000000000000000000000000000000000000000000006'
+ },
+ {
+ def: [{ type: 'uint64[]' }],
+ unpacked: [[new bn(1), new bn(2)]],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002'
+ },
+ {
+ def: [{ type: 'uint256' }],
+ unpacked: [new bn(11)],
+ packed: '000000000000000000000000000000000000000000000000000000000000000b'
+ },
+ {
+ def: [{ type: 'uint256[]' }],
+ unpacked: [[new bn(1), new bn(2)]],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002'
+ },
+ {
+ def: [{ type: 'int8' }],
+ unpacked: [2],
+ packed: '0000000000000000000000000000000000000000000000000000000000000002'
+ },
+ {
+ def: [{ type: 'int8[]' }],
+ unpacked: [[1, 2]],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002'
+ },
+ {
+ def: [{ type: 'int16' }],
+ unpacked: [2],
+ packed: '0000000000000000000000000000000000000000000000000000000000000002'
+ },
+ {
+ def: [{ type: 'int16[]' }],
+ unpacked: [[1, 2]],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002'
+ },
+ {
+ def: [{ type: 'int32' }],
+ unpacked: [2],
+ packed: '0000000000000000000000000000000000000000000000000000000000000002'
+ },
+ {
+ def: [{ type: 'int32' }],
+ packed: '0000000000000000000000000000000000000000000000000000000000000001',
+ unpacked: [1]
+ },
+ {
+ def: [{ type: 'int32[]' }],
+ unpacked: [[1, 2]],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002'
+ },
+ {
+ def: [{ type: 'int64' }],
+ unpacked: [new bn(2)],
+ packed: '0000000000000000000000000000000000000000000000000000000000000002'
+ },
+ {
+ def: [{ type: 'int64[]' }],
+ unpacked: [[new bn(1), new bn(2)]],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002'
+ },
+ {
+ def: [{ type: 'int256' }],
+ unpacked: [new bn(2)],
+ packed: '0000000000000000000000000000000000000000000000000000000000000002'
+ },
+ {
+ def: [{ type: 'int256' }],
+ packed: 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
+ unpacked: [new bn(-1)]
+ },
+ {
+ def: [{ type: 'int256[]' }],
+ unpacked: [[new bn(1), new bn(2)]],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002'
+ },
+ // Address
+ {
+ def: [{ type: 'address' }],
+ packed: '0000000000000000000000000100000000000000000000000000000000000000',
+ unpacked: ['0x0100000000000000000000000000000000000000']
+ },
+ {
+ def: [{ type: 'address[]' }],
+ unpacked: [['0x0100000000000000000000000000000000000000', '0x0200000000000000000000000000000000000000']],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000100000000000000000000000000000000000000' +
+ '0000000000000000000000000200000000000000000000000000000000000000'
+ },
+ // Bytes
+ {
+ def: [{ type: 'bytes1' }],
+ unpacked: [hexToBytes('0x01')],
+ packed: '0100000000000000000000000000000000000000000000000000000000000000'
+ },
+ {
+ def: [{ type: 'bytes2' }],
+ unpacked: [hexToBytes('0100')],
+ packed: '0100000000000000000000000000000000000000000000000000000000000000'
+ },
+ {
+ def: [{ type: 'bytes3' }],
+ unpacked: [hexToBytes('010000')],
+ packed: '0100000000000000000000000000000000000000000000000000000000000000'
+ },
+ {
+ def: [{ type: 'bytes32' }],
+ packed: '0100000000000000000000000000000000000000000000000000000000000000',
+ unpacked: [hexToBytes('0100000000000000000000000000000000000000000000000000000000000000')]
+ },
+ {
+ def: [{ type: 'bytes' }],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0100000000000000000000000000000000000000000000000000000000000000',
+ unpacked: [hexToBytes('0100000000000000000000000000000000000000000000000000000000000000')]
+ },
+ // TODO:
+ // Functions
+ {
+ def: [{ type: 'function' }],
+ packed: '0100000000000000000000000000000000000000000000000000000000000000',
+ unpacked: [hexToBytes('0x010000000000000000000000000000000000000000000000')]
+ },
+
+ // Slice and Array
+ {
+ def: [{ type: 'uint8[]' }],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002',
+ unpacked: [[1, 2]]
+ },
+ {
+ def: [{ type: 'uint8[]' }],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000000',
+ unpacked: [[]]
+ },
+ {
+ def: [{ type: 'uint256[]' }],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000000',
+ unpacked: [[]]
+ },
+ {
+ def: [{ type: 'uint8[2]' }],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002',
+ unpacked: [[1, 2]]
+ },
+ {
+ def: [{ type: 'int8[2]' }],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002',
+ unpacked: [[1, 2]]
+ },
+ {
+ def: [{ type: 'int16[]' }],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002',
+ unpacked: [[1, 2]]
+ },
+ {
+ def: [{ type: 'int16[2]' }],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002',
+ unpacked: [[1, 2]]
+ },
+ {
+ def: [{ type: 'int32[]' }],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002',
+ unpacked: [[1, 2]]
+ },
+ {
+ def: [{ type: 'int32[2]' }],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002',
+ unpacked: [[1, 2]]
+ },
+ {
+ def: [{ type: 'int64[]' }],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002',
+ unpacked: [[new bn(1), new bn(2)]]
+ },
+ {
+ def: [{ type: 'int64[2]' }],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002',
+ unpacked: [[new bn(1), new bn(2)]]
+ },
+ {
+ def: [{ type: 'int256[]' }],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002',
+ unpacked: [[new bn(1), new bn(2)]]
+ },
+ {
+ def: [{ type: 'int256[3]' }],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000003',
+ unpacked: [[new bn(1), new bn(2), new bn(3)]]
+ },
+ // multi dimensional, if these pass, all types that don't require length prefix should pass
+ {
+ def: [{ type: 'uint8[][]' }],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000000',
+ unpacked: [[]]
+ },
+ {
+ def: [{ type: 'uint8[][]' }],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000040' +
+ '00000000000000000000000000000000000000000000000000000000000000a0' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002',
+ unpacked: [
+ [
+ [1, 2],
+ [1, 2]
+ ]
+ ]
+ },
+ {
+ def: [{ type: 'uint8[][]' }],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000040' +
+ '00000000000000000000000000000000000000000000000000000000000000a0' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000003' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000003',
+ unpacked: [
+ [
+ [1, 2],
+ [1, 2, 3]
+ ]
+ ]
+ },
+ {
+ def: [{ type: 'uint8[][2]' }],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000040' +
+ '0000000000000000000000000000000000000000000000000000000000000060' +
+ '0000000000000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000000',
+ unpacked: [[[], []]]
+ },
+ {
+ def: [{ type: 'uint8[2][2]' }],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002',
+ unpacked: [
+ [
+ [1, 2],
+ [1, 2]
+ ]
+ ]
+ },
+ {
+ def: [{ type: 'uint8[][2]' }],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000040' +
+ '0000000000000000000000000000000000000000000000000000000000000080' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000001',
+ unpacked: [[[1], [1]]]
+ },
+ {
+ def: [{ type: 'uint8[2][]' }],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000000',
+ unpacked: [[]]
+ },
+ {
+ def: [{ type: 'uint8[2][]' }],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002',
+ unpacked: [[[1, 2]]]
+ },
+ {
+ def: [{ type: 'uint8[2][]' }],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002',
+ unpacked: [
+ [
+ [1, 2],
+ [1, 2]
+ ]
+ ]
+ },
+ {
+ def: [{ type: 'uint16[]' }],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002',
+ unpacked: [[1, 2]]
+ },
+ {
+ def: [{ type: 'uint16[2]' }],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002',
+ unpacked: [[1, 2]]
+ },
+ {
+ def: [{ type: 'uint32[]' }],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002',
+ unpacked: [[1, 2]]
+ },
+ {
+ def: [{ type: 'uint32[2][3][4]' }],
+ unpacked: [
+ [
+ [
+ [1, 2],
+ [3, 4],
+ [5, 6]
+ ],
+ [
+ [7, 8],
+ [9, 10],
+ [11, 12]
+ ],
+ [
+ [13, 14],
+ [15, 16],
+ [17, 18]
+ ],
+ [
+ [19, 20],
+ [21, 22],
+ [23, 24]
+ ]
+ ]
+ ],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000003' +
+ '0000000000000000000000000000000000000000000000000000000000000004' +
+ '0000000000000000000000000000000000000000000000000000000000000005' +
+ '0000000000000000000000000000000000000000000000000000000000000006' +
+ '0000000000000000000000000000000000000000000000000000000000000007' +
+ '0000000000000000000000000000000000000000000000000000000000000008' +
+ '0000000000000000000000000000000000000000000000000000000000000009' +
+ '000000000000000000000000000000000000000000000000000000000000000a' +
+ '000000000000000000000000000000000000000000000000000000000000000b' +
+ '000000000000000000000000000000000000000000000000000000000000000c' +
+ '000000000000000000000000000000000000000000000000000000000000000d' +
+ '000000000000000000000000000000000000000000000000000000000000000e' +
+ '000000000000000000000000000000000000000000000000000000000000000f' +
+ '0000000000000000000000000000000000000000000000000000000000000010' +
+ '0000000000000000000000000000000000000000000000000000000000000011' +
+ '0000000000000000000000000000000000000000000000000000000000000012' +
+ '0000000000000000000000000000000000000000000000000000000000000013' +
+ '0000000000000000000000000000000000000000000000000000000000000014' +
+ '0000000000000000000000000000000000000000000000000000000000000015' +
+ '0000000000000000000000000000000000000000000000000000000000000016' +
+ '0000000000000000000000000000000000000000000000000000000000000017' +
+ '0000000000000000000000000000000000000000000000000000000000000018'
+ },
+
+ {
+ def: [{ type: 'bytes32[]' }],
+ unpacked: [
+ [
+ hexToBytes('0100000000000000000000000000000000000000000000000000000000000000'),
+ hexToBytes('0200000000000000000000000000000000000000000000000000000000000000')
+ ]
+ ],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0100000000000000000000000000000000000000000000000000000000000000' +
+ '0200000000000000000000000000000000000000000000000000000000000000'
+ },
+ {
+ def: [{ type: 'uint32[2]' }],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002',
+ unpacked: [[1, 2]]
+ },
+ {
+ def: [{ type: 'uint128[2]' }],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002',
+ unpacked: [[new bn(1), new bn(2)]]
+ },
+ {
+ def: [{ type: 'uint64[]' }],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002',
+ unpacked: [[new bn(1), new bn(2)]]
+ },
+ {
+ def: [{ type: 'uint64[2]' }],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002',
+ unpacked: [[new bn(1), new bn(2)]]
+ },
+ {
+ def: [{ type: 'uint256[]' }],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002',
+ unpacked: [[new bn(1), new bn(2)]]
+ },
+ {
+ def: [{ type: 'uint256[3]' }],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000003',
+ unpacked: [[new bn(1), new bn(2), new bn(3)]]
+ },
+ {
+ def: [{ type: 'string[4]' }],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000080' +
+ '00000000000000000000000000000000000000000000000000000000000000c0' +
+ '0000000000000000000000000000000000000000000000000000000000000100' +
+ '0000000000000000000000000000000000000000000000000000000000000140' +
+ '0000000000000000000000000000000000000000000000000000000000000005' +
+ '48656c6c6f000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000005' +
+ '576f726c64000000000000000000000000000000000000000000000000000000' +
+ '000000000000000000000000000000000000000000000000000000000000000b' +
+ '476f2d657468657265756d000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000008' +
+ '457468657265756d000000000000000000000000000000000000000000000000',
+ unpacked: [['Hello', 'World', 'Go-ethereum', 'Ethereum']]
+ },
+ {
+ def: [{ type: 'string[]' }],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000040' +
+ '0000000000000000000000000000000000000000000000000000000000000080' +
+ '0000000000000000000000000000000000000000000000000000000000000008' +
+ '457468657265756d000000000000000000000000000000000000000000000000' +
+ '000000000000000000000000000000000000000000000000000000000000000b' +
+ '676f2d657468657265756d000000000000000000000000000000000000000000',
+ unpacked: [['Ethereum', 'go-ethereum']]
+ },
+ {
+ def: [{ type: 'bytes[]' }],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000040' +
+ '0000000000000000000000000000000000000000000000000000000000000080' +
+ '0000000000000000000000000000000000000000000000000000000000000003' +
+ 'f0f0f00000000000000000000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000000000000000000000000003' +
+ 'f0f0f00000000000000000000000000000000000000000000000000000000000',
+ unpacked: [[hexToBytes('f0f0f0'), hexToBytes('f0f0f0')]]
+ },
+ {
+ def: [{ type: 'uint256[2][][]' }],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000040' +
+ '00000000000000000000000000000000000000000000000000000000000000e0' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '00000000000000000000000000000000000000000000000000000000000000c8' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '00000000000000000000000000000000000000000000000000000000000003e8' +
+ '0000000000000000000000000000000000000000000000000000000000000002' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '00000000000000000000000000000000000000000000000000000000000000c8' +
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '00000000000000000000000000000000000000000000000000000000000003e8',
+ unpacked: [
+ [
+ [
+ [new bn(1), new bn(200)],
+ [new bn(1), new bn(1000)]
+ ],
+ [
+ [new bn(1), new bn(200)],
+ [new bn(1), new bn(1000)]
+ ]
+ ]
+ ]
+ },
+ // struct outputs
+ {
+ def: [
+ {
+ components: [
+ { name: 'int1', type: 'int256' },
+ { name: 'int2', type: 'int256' }
+ ],
+ type: 'tuple'
+ }
+ ],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002',
+ unpacked: [
+ {
+ int1: new bn(1),
+ int2: new bn(2)
+ }
+ ]
+ },
+ {
+ def: [{ components: [{ name: 'int_one', type: 'int256' }], type: 'tuple' }],
+ packed: '0000000000000000000000000000000000000000000000000000000000000001',
+ unpacked: [
+ {
+ int_one: new bn(1)
+ }
+ ]
+ },
+ {
+ def: [{ components: [{ name: 'int__one', type: 'int256' }], type: 'tuple' }],
+ packed: '0000000000000000000000000000000000000000000000000000000000000001',
+ unpacked: [
+ {
+ int__one: new bn(1)
+ }
+ ]
+ },
+ {
+ def: [{ components: [{ name: 'int_one_', type: 'int256' }], type: 'tuple' }],
+ packed: '0000000000000000000000000000000000000000000000000000000000000001',
+ unpacked: [
+ {
+ int_one_: new bn(1)
+ }
+ ]
+ },
+ {
+ def: [
+ {
+ components: [
+ { name: 'int_one', type: 'int256' },
+ { name: 'intone', type: 'int256' }
+ ],
+ type: 'tuple'
+ }
+ ],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000001' +
+ '0000000000000000000000000000000000000000000000000000000000000002',
+ unpacked: [
+ {
+ int_one: new bn(1),
+ intone: new bn(2)
+ }
+ ]
+ },
+ {
+ def: [{ type: 'string' }],
+ unpacked: ['foobar'],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000006' +
+ '666f6f6261720000000000000000000000000000000000000000000000000000'
+ },
+ {
+ def: [{ type: 'string[]' }],
+ unpacked: [['hello', 'foobar']],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000002' + // len(array) = 2
+ '0000000000000000000000000000000000000000000000000000000000000040' + // offset 64 to i = 0
+ '0000000000000000000000000000000000000000000000000000000000000080' + // offset 128 to i = 1
+ '0000000000000000000000000000000000000000000000000000000000000005' + // len(str[0]) = 5
+ '68656c6c6f000000000000000000000000000000000000000000000000000000' + // str[0]
+ '0000000000000000000000000000000000000000000000000000000000000006' + // len(str[1]) = 6
+ '666f6f6261720000000000000000000000000000000000000000000000000000' // str[1]
+ },
+ {
+ def: [{ type: 'string[2]' }],
+ unpacked: [['hello', 'foobar']],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000040' + // offset to i = 0
+ '0000000000000000000000000000000000000000000000000000000000000080' + // offset to i = 1
+ '0000000000000000000000000000000000000000000000000000000000000005' + // len(str[0]) = 5
+ '68656c6c6f000000000000000000000000000000000000000000000000000000' + // str[0]
+ '0000000000000000000000000000000000000000000000000000000000000006' + // len(str[1]) = 6
+ '666f6f6261720000000000000000000000000000000000000000000000000000' // str[1]
+ },
+ {
+ def: [{ type: 'bytes32[][]' }],
+ unpacked: [
+ [
+ [
+ hexToBytes('0100000000000000000000000000000000000000000000000000000000000000'),
+ hexToBytes('0200000000000000000000000000000000000000000000000000000000000000')
+ ],
+ [
+ hexToBytes('0300000000000000000000000000000000000000000000000000000000000000'),
+ hexToBytes('0400000000000000000000000000000000000000000000000000000000000000'),
+ hexToBytes('0500000000000000000000000000000000000000000000000000000000000000')
+ ]
+ ]
+ ],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000002' + // len(array) = 2
+ '0000000000000000000000000000000000000000000000000000000000000040' + // offset 64 to i = 0
+ '00000000000000000000000000000000000000000000000000000000000000a0' + // offset 160 to i = 1
+ '0000000000000000000000000000000000000000000000000000000000000002' + // len(array[0]) = 2
+ '0100000000000000000000000000000000000000000000000000000000000000' + // array[0][0]
+ '0200000000000000000000000000000000000000000000000000000000000000' + // array[0][1]
+ '0000000000000000000000000000000000000000000000000000000000000003' + // len(array[1]) = 3
+ '0300000000000000000000000000000000000000000000000000000000000000' + // array[1][0]
+ '0400000000000000000000000000000000000000000000000000000000000000' + // array[1][1]
+ '0500000000000000000000000000000000000000000000000000000000000000' // array[1][2]
+ },
+ {
+ def: [{ type: 'bytes32[][2]' }],
+ unpacked: [
+ [
+ [
+ hexToBytes('0100000000000000000000000000000000000000000000000000000000000000'),
+ hexToBytes('0200000000000000000000000000000000000000000000000000000000000000')
+ ],
+ [
+ hexToBytes('0300000000000000000000000000000000000000000000000000000000000000'),
+ hexToBytes('0400000000000000000000000000000000000000000000000000000000000000'),
+ hexToBytes('0500000000000000000000000000000000000000000000000000000000000000')
+ ]
+ ]
+ ],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000040' + // offset 64 to i = 0
+ '00000000000000000000000000000000000000000000000000000000000000a0' + // offset 160 to i = 1
+ '0000000000000000000000000000000000000000000000000000000000000002' + // len(array[0]) = 2
+ '0100000000000000000000000000000000000000000000000000000000000000' + // array[0][0]
+ '0200000000000000000000000000000000000000000000000000000000000000' + // array[0][1]
+ '0000000000000000000000000000000000000000000000000000000000000003' + // len(array[1]) = 3
+ '0300000000000000000000000000000000000000000000000000000000000000' + // array[1][0]
+ '0400000000000000000000000000000000000000000000000000000000000000' + // array[1][1]
+ '0500000000000000000000000000000000000000000000000000000000000000' // array[1][2]
+ },
+ {
+ def: [{ type: 'bytes32[3][2]' }],
+ unpacked: [
+ [
+ [
+ hexToBytes('0100000000000000000000000000000000000000000000000000000000000000'),
+ hexToBytes('0200000000000000000000000000000000000000000000000000000000000000'),
+ hexToBytes('0300000000000000000000000000000000000000000000000000000000000000')
+ ],
+ [
+ hexToBytes('0300000000000000000000000000000000000000000000000000000000000000'),
+ hexToBytes('0400000000000000000000000000000000000000000000000000000000000000'),
+ hexToBytes('0500000000000000000000000000000000000000000000000000000000000000')
+ ]
+ ]
+ ],
+ packed:
+ '0100000000000000000000000000000000000000000000000000000000000000' + // array[0][0]
+ '0200000000000000000000000000000000000000000000000000000000000000' + // array[0][1]
+ '0300000000000000000000000000000000000000000000000000000000000000' + // array[0][2]
+ '0300000000000000000000000000000000000000000000000000000000000000' + // array[1][0]
+ '0400000000000000000000000000000000000000000000000000000000000000' + // array[1][1]
+ '0500000000000000000000000000000000000000000000000000000000000000' // array[1][2]
+ },
+ // // tuples
+ {
+ // static tuple
+ def: [
+ {
+ components: [
+ { name: 'a', type: 'int64' },
+ { name: 'b', type: 'int256' },
+ { name: 'c', type: 'int256' },
+ { name: 'd', type: 'bool' },
+ { name: 'e', type: 'bytes32[3][2]' }
+ ],
+ type: 'tuple'
+ }
+ ],
+ unpacked: [
+ {
+ a: new bn(1),
+ b: new bn(1),
+ c: new bn(-1),
+ d: true,
+ e: [
+ [
+ hexToBytes('0100000000000000000000000000000000000000000000000000000000000000'),
+ hexToBytes('0200000000000000000000000000000000000000000000000000000000000000'),
+ hexToBytes('0300000000000000000000000000000000000000000000000000000000000000')
+ ],
+ [
+ hexToBytes('0300000000000000000000000000000000000000000000000000000000000000'),
+ hexToBytes('0400000000000000000000000000000000000000000000000000000000000000'),
+ hexToBytes('0500000000000000000000000000000000000000000000000000000000000000')
+ ]
+ ]
+ }
+ ],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000001' + // struct[a]
+ '0000000000000000000000000000000000000000000000000000000000000001' + // struct[b]
+ 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + // struct[c]
+ '0000000000000000000000000000000000000000000000000000000000000001' + // struct[d]
+ '0100000000000000000000000000000000000000000000000000000000000000' + // struct[e] array[0][0]
+ '0200000000000000000000000000000000000000000000000000000000000000' + // struct[e] array[0][1]
+ '0300000000000000000000000000000000000000000000000000000000000000' + // struct[e] array[0][2]
+ '0300000000000000000000000000000000000000000000000000000000000000' + // struct[e] array[1][0]
+ '0400000000000000000000000000000000000000000000000000000000000000' + // struct[e] array[1][1]
+ '0500000000000000000000000000000000000000000000000000000000000000' // struct[e] array[1][2]
+ },
+ {
+ def: [
+ {
+ components: [
+ { name: 'a', type: 'string' },
+ { name: 'b', type: 'int64' },
+ { name: 'c', type: 'bytes' },
+ { name: 'd', type: 'string[]' },
+ { name: 'e', type: 'int256[]' },
+ { name: 'f', type: 'address[]' }
+ ],
+ type: 'tuple'
+ }
+ ],
+ unpacked: [
+ {
+ a: 'foobar',
+ b: new bn(1),
+ c: new Uint8Array([1]),
+ d: ['foo', 'bar'],
+ e: [new bn(1), new bn(-1)],
+ f: ['0x407D73d8a49eeb85D32Cf465507dd71d507100c1', '0x407d73d8a49EEB85d32Cf465507dD71D507100c2']
+ }
+ ],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' + // struct a
+ '00000000000000000000000000000000000000000000000000000000000000c0' + // struct[a] offset
+ '0000000000000000000000000000000000000000000000000000000000000001' + // struct[b]
+ '0000000000000000000000000000000000000000000000000000000000000100' + // struct[c] offset
+ '0000000000000000000000000000000000000000000000000000000000000140' + // struct[d] offset
+ '0000000000000000000000000000000000000000000000000000000000000220' + // struct[e] offset
+ '0000000000000000000000000000000000000000000000000000000000000280' + // struct[f] offset
+ '0000000000000000000000000000000000000000000000000000000000000006' + // struct[a] length
+ '666f6f6261720000000000000000000000000000000000000000000000000000' + // struct[a] "foobar"
+ '0000000000000000000000000000000000000000000000000000000000000001' + // struct[c] length
+ '0100000000000000000000000000000000000000000000000000000000000000' + // []byte{1}
+ '0000000000000000000000000000000000000000000000000000000000000002' + // struct[d] length
+ '0000000000000000000000000000000000000000000000000000000000000040' + // foo offset
+ '0000000000000000000000000000000000000000000000000000000000000080' + // bar offset
+ '0000000000000000000000000000000000000000000000000000000000000003' + // foo length
+ '666f6f0000000000000000000000000000000000000000000000000000000000' + // foo
+ '0000000000000000000000000000000000000000000000000000000000000003' + // bar offset
+ '6261720000000000000000000000000000000000000000000000000000000000' + // bar
+ '0000000000000000000000000000000000000000000000000000000000000002' + // struct[e] length
+ '0000000000000000000000000000000000000000000000000000000000000001' + // 1
+ 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + // -1
+ '0000000000000000000000000000000000000000000000000000000000000002' + // struct[f] length
+ '000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1' + // common.Address{1}
+ '000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c2' // common.Address{2}
+ },
+ {
+ def: [
+ {
+ components: [
+ {
+ type: 'tuple',
+ components: [
+ { name: 'c', type: 'uint256' },
+ { name: 'd', type: 'uint256[]' }
+ ],
+ name: 'a'
+ },
+ { name: 'b', type: 'uint256[]' }
+ ],
+ type: 'tuple'
+ }
+ ],
+ unpacked: [
+ {
+ a: {
+ c: new bn(1),
+ d: [new bn(1), new bn(2)]
+ },
+ b: [new bn(1), new bn(2)]
+ }
+ ],
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' + // struct a
+ '0000000000000000000000000000000000000000000000000000000000000040' + // a offset
+ '00000000000000000000000000000000000000000000000000000000000000e0' + // b offset
+ '0000000000000000000000000000000000000000000000000000000000000001' + // a.c value
+ '0000000000000000000000000000000000000000000000000000000000000040' + // a.d offset
+ '0000000000000000000000000000000000000000000000000000000000000002' + // a.d length
+ '0000000000000000000000000000000000000000000000000000000000000001' + // a.d[0] value
+ '0000000000000000000000000000000000000000000000000000000000000002' + // a.d[1] value
+ '0000000000000000000000000000000000000000000000000000000000000002' + // b length
+ '0000000000000000000000000000000000000000000000000000000000000001' + // b[0] value
+ '0000000000000000000000000000000000000000000000000000000000000002' // b[1] value
+ },
+
+ {
+ def: [
+ {
+ components: [
+ { name: 'a', type: 'int256' },
+ { name: 'b', type: 'int256[]' }
+ ],
+ name: 'envelope',
+ type: 'tuple[]'
+ }
+ ],
+ unpacked: {
+ envelope: [
+ { a: new bn(-1), b: [new bn(1), new bn(3)] },
+ { a: new bn(1), b: [new bn(2), new bn(-1)] }
+ ]
+ },
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000002' + // tuple length
+ '0000000000000000000000000000000000000000000000000000000000000040' + // tuple[0] offset
+ '00000000000000000000000000000000000000000000000000000000000000e0' + // tuple[1] offset
+ 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + // tuple[0].A
+ '0000000000000000000000000000000000000000000000000000000000000040' + // tuple[0].B offset
+ '0000000000000000000000000000000000000000000000000000000000000002' + // tuple[0].B length
+ '0000000000000000000000000000000000000000000000000000000000000001' + // tuple[0].B[0] value
+ '0000000000000000000000000000000000000000000000000000000000000003' + // tuple[0].B[1] value
+ '0000000000000000000000000000000000000000000000000000000000000001' + // tuple[1].A
+ '0000000000000000000000000000000000000000000000000000000000000040' + // tuple[1].B offset
+ '0000000000000000000000000000000000000000000000000000000000000002' + // tuple[1].B length
+ '0000000000000000000000000000000000000000000000000000000000000002' + // tuple[1].B[0] value
+ 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' // tuple[1].B[1] value
+ },
+ {
+ def: [
+ {
+ components: [
+ { name: 'a', type: 'int256' },
+ { name: 'b', type: 'int256' }
+ ],
+ name: 'a',
+ type: 'tuple[2]'
+ }
+ ],
+ unpacked: {
+ a: [
+ {
+ a: new bn(-1),
+ b: new bn(1)
+ },
+ {
+ a: new bn(1),
+ b: new bn(-1)
+ }
+ ]
+ },
+ packed:
+ 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + // tuple[0].a
+ '0000000000000000000000000000000000000000000000000000000000000001' + // tuple[0].b
+ '0000000000000000000000000000000000000000000000000000000000000001' + // tuple[1].a
+ 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' // tuple[1].b
+ },
+ {
+ def: [
+ {
+ name: 'envelope',
+ components: [{ name: 'a', type: 'int256[]' }],
+ type: 'tuple[2]'
+ }
+ ],
+ unpacked: { envelope: [{ a: [new bn(-1), new bn(1)] }, { a: [new bn(1), new bn(-1)] }] },
+ packed:
+ '0000000000000000000000000000000000000000000000000000000000000020' +
+ '0000000000000000000000000000000000000000000000000000000000000040' + // tuple[0] offset
+ '00000000000000000000000000000000000000000000000000000000000000c0' + // tuple[1] offset
+ '0000000000000000000000000000000000000000000000000000000000000020' + // tuple[0].A offset
+ '0000000000000000000000000000000000000000000000000000000000000002' + // tuple[0].A length
+ 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + // tuple[0].A[0]
+ '0000000000000000000000000000000000000000000000000000000000000001' + // tuple[0].A[1]
+ '0000000000000000000000000000000000000000000000000000000000000020' + // tuple[1].A offset
+ '0000000000000000000000000000000000000000000000000000000000000002' + // tuple[1].A length
+ '0000000000000000000000000000000000000000000000000000000000000001' + // tuple[1].A[0]
+ 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' // tuple[1].A[1]
+ }
+]
+
+function coerceTuple(value: any) {
+ if (
+ value instanceof Uint8Array ||
+ typeof value == 'string' ||
+ typeof value == 'boolean' ||
+ typeof value == 'number' ||
+ isBigNumber(value)
+ ) {
+ return value
+ }
+ if (Array.isArray(value)) {
+ return value.map(coerceTuple)
+ }
+ if (typeof value == 'object' && value && value.__proto__ == ({} as any).__proto__) {
+ const ret = new Tuple()
+ Object.entries(value).forEach(([key, v], index) => {
+ ret[key] = coerceTuple(v) // this vlaue NEEDS to be duplicated in order to make the comparator work
+ ret[index] = coerceTuple(v) // this vlaue NEEDS to be duplicated in order to make the comparator work
+ })
+ return ret
+ }
+
+ return value
+}
+
+function coerce(t: any) {
+ if (isArray(t)) {
+ return t.map(coerceTuple)
+ } else {
+ return coerceTuple(t)
+ }
+}
+
+function coerceTupleNoName(value: any) {
+ if (
+ value instanceof Uint8Array ||
+ typeof value == 'string' ||
+ typeof value == 'boolean' ||
+ typeof value == 'number' ||
+ isBigNumber(value)
+ ) {
+ return value
+ }
+ if (Array.isArray(value)) {
+ return value.map(coerceTupleNoName)
+ }
+ if (typeof value == 'object' && value && value.__proto__ == ({} as any).__proto__) {
+ const ret = new Tuple()
+ Object.entries(value).forEach(([_, v], index) => {
+ ret[index] = coerceTupleNoName(v) // this vlaue NEEDS to be duplicated in order to make the comparator work
+ })
+ return ret
+ }
+
+ return value
+}
+
+function coerceNoName(t: any) {
+ if (isArray(t)) {
+ return t.map(coerceTupleNoName)
+ } else {
+ return coerceTupleNoName(t)
+ }
+}
+
+describe('geth/packing', function () {
+ packUnpackTests.forEach((test) => {
+ describe(JSON.stringify(test.def), () => {
+ it('pack: should turn ' + JSON.stringify(test.unpacked) + ' to ' + test.packed, function () {
+ expect(coder.encodeParams(test.def as AbiInput[], coerce(test.unpacked))).toEqual(test.packed)
+ })
+ it('unpack: should turn ' + test.packed + ' to ' + JSON.stringify(test.unpacked), function () {
+ expect(coder.decodeParams(test.def as AbiInput[], test.packed)).toEqual(coerce(test.unpacked))
+ })
+ const fmt = test.def.map(formatParamType)
+ describe('toStr: ' + fmt, () => {
+ it('pack: should turn ' + JSON.stringify(test.unpacked) + ' to ' + test.packed, function () {
+ expect(coder.encodeParams(fmt, coerceNoName(test.unpacked))).toEqual(test.packed)
+ })
+ const unpacked = coerceNoName(test.unpacked)
+ it('unpack: should turn ' + test.packed + ' to ' + JSON.stringify(unpacked), function () {
+ expect(coder.decodeParams(fmt, test.packed)).toEqual(unpacked)
+ })
+ it('integration: unpacked (str) > packed (str) > unpacked (obj)', function () {
+ expect(
+ coder.decodeParams(test.def as AbiInput[], coder.encodeParams(fmt, coerceNoName(test.unpacked)))
+ ).toEqual(coerce(test.unpacked))
+ })
+ })
+ })
+ })
+})
diff --git a/test/integration.erc20.ts b/test/integration.erc20.ts
index 58366111..6bfaa6c9 100644
--- a/test/integration.erc20.ts
+++ b/test/integration.erc20.ts
@@ -202,7 +202,7 @@ function doTest(requestManager: RequestManager) {
it('test allowance, invalid address', async function () {
this.timeout(30000)
const accounts = await requestManager.eth_accounts()
- await expect(ERC20Contract.allowance(accounts[0], '0x1')).rejects.toThrow('Invalid address')
+ await expect(ERC20Contract.allowance(accounts[0], '0x1')).rejects.toThrow(/invalid address/)
})
it('test allowance', async function () {
diff --git a/test/integration.events.ts b/test/integration.events.ts
index e54b2624..798e609b 100644
--- a/test/integration.events.ts
+++ b/test/integration.events.ts
@@ -79,11 +79,11 @@ const contract = {
name: 'getInstructor',
outputs: [
{
- name: '',
+ name: 'name',
type: 'string'
},
{
- name: '',
+ name: 'age',
type: 'uint256'
}
],
@@ -211,12 +211,18 @@ function doTest(rm: RequestManager) {
await rm.waitForCompletion(tx)
})
- it('getInstructor()', async () => {
+ it('getInstructor() - index', async () => {
const [name, age] = await TestContract.getInstructor()
expect(name).toEqual('agustin')
expect(age.toNumber()).toEqual(99)
})
+ it('getInstructor() - assoc', async () => {
+ const { name, age } = await TestContract.getInstructor()
+ expect(name).toEqual('agustin')
+ expect(age.toNumber()).toEqual(99)
+ })
+
it('did receive a filter message', async () => {
await didReceiveAnyMessage
})
diff --git a/test/parser.spec.ts b/test/parser.spec.ts
new file mode 100644
index 00000000..c2932e98
--- /dev/null
+++ b/test/parser.spec.ts
@@ -0,0 +1,276 @@
+import * as expect from 'expect'
+import { AbiEvent, AbiFunction } from '../src'
+import { parseSignature } from '../src/abi/parser'
+
+const suite: Record = {
+ 'event BaseURI(string _oldBaseURI, string _newBaseURI)': {
+ anonymous: false,
+ inputs: [
+ { type: 'string', name: '_oldBaseURI', indexed: false },
+ { type: 'string', name: '_newBaseURI', indexed: false }
+ ],
+ name: 'BaseURI',
+ type: 'event'
+ },
+ 'event SetGlobalMinter(address indexed _minter, bool _value)': {
+ anonymous: false,
+ inputs: [
+ { type: 'address', name: '_minter', indexed: true },
+ { type: 'bool', name: '_value', indexed: false }
+ ],
+ name: 'SetGlobalMinter',
+ type: 'event'
+ },
+ 'event SetGlobalManager(address indexed _manager, bool _value)': {
+ anonymous: false,
+ inputs: [
+ { type: 'address', name: '_manager', indexed: true },
+ { type: 'bool', name: '_value', indexed: false }
+ ],
+ name: 'SetGlobalManager',
+ type: 'event'
+ },
+ 'event SetItemMinter(uint256 indexed _itemId, address indexed _minter, bool _value)': {
+ anonymous: false,
+ inputs: [
+ { type: 'uint256', name: '_itemId', indexed: true },
+ { type: 'address', name: '_minter', indexed: true },
+ { type: 'bool', name: '_value', indexed: false }
+ ],
+ name: 'SetItemMinter',
+ type: 'event'
+ },
+ 'event SetItemManager(uint256 indexed _itemId, address indexed _manager, bool _value)': {
+ anonymous: false,
+ inputs: [
+ { type: 'uint256', name: '_itemId', indexed: true },
+ { type: 'address', name: '_manager', indexed: true },
+ { type: 'bool', name: '_value', indexed: false }
+ ],
+ name: 'SetItemManager',
+ type: 'event'
+ },
+ 'event AddItem(uint256 indexed _itemId, tuple(uint256) _item)': {
+ anonymous: false,
+ inputs: [
+ { type: 'uint256', name: '_itemId', indexed: true },
+ {
+ type: 'tuple',
+ name: '_item',
+ indexed: false,
+ components: [
+ {
+ name: '',
+ type: 'uint256'
+ }
+ ]
+ }
+ ],
+ name: 'AddItem',
+ type: 'event'
+ },
+ 'event RescueItem(uint256 indexed _itemId, bytes32 _contentHash, string _metadata)': {
+ anonymous: false,
+ inputs: [
+ { type: 'uint256', name: '_itemId', indexed: true },
+ { type: 'bytes32', name: '_contentHash', indexed: false },
+ { type: 'string', name: '_metadata', indexed: false }
+ ],
+ name: 'RescueItem',
+ type: 'event'
+ },
+ 'event Issue(address indexed _beneficiary, uint256 indexed _tokenId, uint256 indexed _itemId, uint256 _issuedId)': {
+ anonymous: false,
+ inputs: [
+ { type: 'address', name: '_beneficiary', indexed: true },
+ { type: 'uint256', name: '_tokenId', indexed: true },
+ { type: 'uint256', name: '_itemId', indexed: true },
+ { type: 'uint256', name: '_issuedId', indexed: false }
+ ],
+ name: 'Issue',
+ type: 'event'
+ },
+ 'event UpdateItemSalesData(uint256 indexed _itemId, uint256 _price, address _beneficiary)': {
+ anonymous: false,
+ inputs: [
+ { type: 'uint256', name: '_itemId', indexed: true },
+ { type: 'uint256', name: '_price', indexed: false },
+ { type: 'address', name: '_beneficiary', indexed: false }
+ ],
+ name: 'UpdateItemSalesData',
+ type: 'event'
+ },
+ 'event UpdateItemMetadata(uint256 indexed _itemId, string _metadata)': {
+ anonymous: false,
+ inputs: [
+ { type: 'uint256', name: '_itemId', indexed: true },
+ { type: 'string', name: '_metadata', indexed: false }
+ ],
+ name: 'UpdateItemMetadata',
+ type: 'event'
+ },
+ 'event CreatorshipTransferred(address indexed _previousCreator, address indexed _newCreator)': {
+ anonymous: false,
+ inputs: [
+ { type: 'address', name: '_previousCreator', indexed: true },
+ { type: 'address', name: '_newCreator', indexed: true }
+ ],
+ name: 'CreatorshipTransferred',
+ type: 'event'
+ },
+ 'event SetApproved(bool _previousValue, bool _newValue)': {
+ anonymous: false,
+ inputs: [
+ { type: 'bool', name: '_previousValue', indexed: false },
+ { type: 'bool', name: '_newValue', indexed: false }
+ ],
+ name: 'SetApproved',
+ type: 'event'
+ },
+ 'event SetEditable(bool _previousValue, bool _newValue)': {
+ anonymous: false,
+ inputs: [
+ { type: 'bool', name: '_previousValue', indexed: false },
+ { type: 'bool', name: '_newValue', indexed: false }
+ ],
+ name: 'SetEditable',
+ type: 'event'
+ },
+ 'event Complete()': { anonymous: false, inputs: [], name: 'Complete', type: 'event' },
+ 'function issueTokens(address[] _beneficiaries, uint256[] _itemIds) external virtual': {
+ constant: false,
+ inputs: [
+ {
+ name: '_beneficiaries',
+ type: 'address[]'
+ },
+ {
+ name: '_itemIds',
+ type: 'uint256[]'
+ }
+ ],
+ name: 'issueTokens',
+ outputs: [],
+ payable: false,
+ type: 'function'
+ },
+ 'function getRarityName(tuple(uint256) _rarity) public pure returns (string memory)': {
+ constant: true,
+ inputs: [
+ {
+ type: 'tuple',
+ name: '_rarity',
+ components: [
+ {
+ name: '',
+ type: 'uint256'
+ }
+ ]
+ }
+ ],
+ name: 'getRarityName',
+ outputs: [{ type: 'string', name: 'memory' }],
+ payable: false,
+ type: 'function',
+ stateMutability: 'pure'
+ },
+ 'function isMintingAllowed() public view returns (bool)': {
+ constant: true,
+ inputs: [],
+ name: 'isMintingAllowed',
+ outputs: [{ type: 'bool', name: '' }],
+ payable: false,
+ type: 'function',
+ stateMutability: 'view'
+ },
+ 'function tokenURI(uint256 _tokenId) public view virtual override returns (string memory)': {
+ constant: true,
+ inputs: [{ type: 'uint256', name: '_tokenId' }],
+ name: 'tokenURI',
+ outputs: [{ type: 'string', name: 'memory' }],
+ payable: false,
+ type: 'function',
+ stateMutability: 'view'
+ },
+ 'function batchTransferFrom(address _from, address _to, uint256[] _tokenIds) public': {
+ constant: false,
+ inputs: [
+ {
+ name: '_from',
+ type: 'address'
+ },
+ {
+ name: '_to',
+ type: 'address'
+ },
+ {
+ name: '_tokenIds',
+ type: 'uint256[]'
+ }
+ ],
+ name: 'batchTransferFrom',
+ outputs: [],
+ payable: false,
+ type: 'function'
+ },
+ // TODO: test this with real ABI and integration tests
+ 'function decodeTokenId(uint256 _id) public pure returns (uint256 itemId, uint256 issuedId)': {
+ constant: true,
+ inputs: [{ type: 'uint256', name: '_id' }],
+ name: 'decodeTokenId',
+ outputs: [
+ { type: 'uint256', name: 'itemId' },
+ { type: 'uint256', name: 'issuedId' }
+ ],
+ payable: false,
+ type: 'function',
+ stateMutability: 'pure'
+ },
+ // TODO: test this with real ABI and integration tests
+ 'function bar(tuple(uint256,uint256)) returns (tuple(bool a,bool b))': {
+ constant: false,
+ inputs: [
+ {
+ components: [
+ {
+ name: '',
+ type: 'uint256'
+ },
+ {
+ name: '',
+ type: 'uint256'
+ }
+ ],
+ name: '',
+ type: 'tuple'
+ }
+ ],
+ name: 'bar',
+ outputs: [
+ {
+ components: [
+ {
+ name: 'a',
+ type: 'bool'
+ },
+ {
+ name: 'b',
+ type: 'bool'
+ }
+ ],
+ name: '',
+ type: 'tuple'
+ }
+ ],
+ payable: false,
+ type: 'function'
+ }
+}
+
+describe('parser', function () {
+ for (let test in suite) {
+ it(`converts "${test}" to an object`, () => {
+ expect(parseSignature(test)).toEqual(suite[test])
+ })
+ }
+})
diff --git a/test/setup.js b/test/setup.js
index fd501b03..def66d29 100644
--- a/test/setup.js
+++ b/test/setup.js
@@ -1,11 +1,23 @@
-const { resolve } = require("path")
-process.env.TS_NODE_PROJECT = resolve(__dirname, "tsconfig.json")
+const { resolve } = require('path')
+process.env.TS_NODE_PROJECT = resolve(__dirname, 'tsconfig.json')
process.stdout.write('creating test environment...\n')
require('ts-node/register')
require('source-map-support/register')
+const { Tuple } = require('../src/abi/coder')
+const util = require('util')
+
+Tuple.prototype[util.inspect.custom] = function () {
+ return `
+Tuple {
+ array ${JSON.stringify(this.slice())}
+ struct {}
+}
+`.trim()
+}
+
process.on('unhandledRejection', (reason, promise) => {
promise.catch((e) => {
console.error('unhandledRejection:', reason.toString())
diff --git a/test/soldity.formatters.formatInputInt.ts b/test/soldity.formatters.formatInputInt.ts
deleted file mode 100644
index da174755..00000000
--- a/test/soldity.formatters.formatInputInt.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import * as expect from 'expect'
-import * as formatters from '../src/solidity/formatters'
-import { SolidityParam } from '../src/solidity/param'
-
-let tests = [
- { input: 1, result: new SolidityParam('0000000000000000000000000000000000000000000000000000000000000001') },
- { input: 1.1, result: new SolidityParam('0000000000000000000000000000000000000000000000000000000000000001') },
- { input: -1.1, result: new SolidityParam('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff') },
- { input: -1, result: new SolidityParam('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff') }
-]
-
-describe('formatters', function () {
- describe('formatInputInt', function () {
- tests.forEach(function (test, i) {
- it('should return the correct value: ' + i, function () {
- expect(formatters.formatInputInt(test.input)).toEqual(test.result)
- })
- })
- })
-})
diff --git a/test/utils.fromUtf8.ts b/test/utils.fromUtf8.ts
index 241b7e35..2a5a643b 100644
--- a/test/utils.fromUtf8.ts
+++ b/test/utils.fromUtf8.ts
@@ -1,26 +1,27 @@
import * as expect from 'expect'
+import { stringToUtf8Bytes } from '../src/utils/utf8'
import * as utils from '../src/utils/utils'
let tests = [
- { value: 'myString', expected: '0x6d79537472696e67' },
- { value: 'myString\x00', expected: '0x6d79537472696e67' },
+ { value: 'myString', expected: '6d79537472696e67' },
+ { value: 'myString\x00', expected: '6d79537472696e6700' },
{
value: '我能吞下玻璃而不伤身体。',
- expected: '0xe68891e883bde5909ee4b88be78ebbe79283e8808ce4b88de4bca4e8baabe4bd93e38082'
+ expected: 'e68891e883bde5909ee4b88be78ebbe79283e8808ce4b88de4bca4e8baabe4bd93e38082'
},
{
value: '나는 유리를 먹을 수 있어요. 그래도 아프지 않아요',
expected:
- '0xeb8298eb8a9420ec9ca0eba6aceba5bc20eba8b9ec9d8420ec889820ec9e88ec96b4ec9a942e20eab7b8eb9e98eb8f8420ec9584ed9484eca78020ec958aec9584ec9a94'
+ 'eb8298eb8a9420ec9ca0eba6aceba5bc20eba8b9ec9d8420ec889820ec9e88ec96b4ec9a942e20eab7b8eb9e98eb8f8420ec9584ed9484eca78020ec958aec9584ec9a94'
},
- { value: 'expected value\u0000\u0000\u0000', expected: '0x65787065637465642076616c7565' }
+ { value: 'expected value\u0000\u0000\u0000', expected: '65787065637465642076616c7565000000' }
]
describe('lib/utils/utils', function () {
describe('fromUtf8', function () {
tests.forEach(function (test) {
it('should turn ' + test.value + ' to ' + test.expected, function () {
- expect(utils.fromUtf8(test.value)).toEqual(test.expected)
+ expect(utils.bytesToHex(stringToUtf8Bytes(test.value))).toEqual(test.expected)
})
})
})
diff --git a/test/utils.toHex.ts b/test/utils.toHex.ts
index 287c275c..1e4e4b18 100644
--- a/test/utils.toHex.ts
+++ b/test/utils.toHex.ts
@@ -26,17 +26,16 @@ let tests = [
value: '-0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd',
expected: '-0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd'
},
+ { value: new Uint8Array([0, 1, 2, 3, 4, 0, 0]), expected: '0x00010203040000' },
{ value: 0, expected: '0x0' },
{ value: '0', expected: '0x0' },
{ value: '0x0', expected: '0x0' },
{ value: -0, expected: '0x0' },
{ value: '-0', expected: '0x0' },
{ value: '-0x0', expected: '0x0' },
- { value: [1, 2, 3, { test: 'data' }], expected: '0x5b312c322c332c7b2274657374223a2264617461227d5d' },
- { value: { test: 'test' }, expected: '0x7b2274657374223a2274657374227d' },
- { value: '{"test": "test"}', expected: '0x7b2274657374223a202274657374227d' },
- { value: 'myString', expected: '0x6d79537472696e67' },
- { value: '내가 제일 잘 나가', expected: '0xeb82b4eab08020eca09cec9dbc20ec9e9820eb8298eab080' },
+ { value: '{"test": "test"}', expected: '7b2274657374223a202274657374227d' },
+ { value: 'myString', expected: '6d79537472696e67' },
+ { value: '내가 제일 잘 나가', expected: 'eb82b4eab08020eca09cec9dbc20ec9e9820eb8298eab080' },
{ value: new BigNumber(15), expected: '0xf' },
{ value: true, expected: '0x1' },
{ value: false, expected: '0x0' },
@@ -44,16 +43,22 @@ let tests = [
value:
'\u0003\u0000\u0000\u00005èÆÕL]\u0012|ξ\u001a7«\u00052\u0011(ÐY\n<\u0010\u0000\u0000\u0000\u0000\u0000\u0000e!ßd/ñõì\f:z¦Î¦±ç·÷Í¢Ëß\u00076*
\bñùC1ÉUÀé2\u001aÓB',
expected:
- '0x0300000035c3a8c386c3954c5d127cc29dc38ec2bec29e1a37c2abc29b05321128c390c297590a3c100000000000006521c39f642fc3b1c3b5c3ac0c3a7ac2a6c38ec2a6c2b1c3a7c2b7c3b7c38dc2a2c38bc39f07362ac28508c28ec297c3b1c29ec3b94331c38955c380c3a9321ac393c28642c28c'
+ '0300000035c3a8c386c3954c5d127cc29dc38ec2bec29e1a37c2abc29b05321128c390c297590a3c100000000000006521c39f642fc3b1c3b5c3ac0c3a7ac2a6c38ec2a6c2b1c3a7c2b7c3b7c38dc2a2c38bc39f07362ac28508c28ec297c3b1c29ec3b94331c38955c380c3a9321ac393c28642c28c'
}
]
-describe('lib/utils/utils', function() {
- describe('toHex', function() {
- tests.forEach(function(test) {
- it('should turn ' + test.value + ' to ' + test.expected, function() {
+describe('lib/utils/utils', function () {
+ describe('toHex', function () {
+ tests.forEach(function (test) {
+ it('should turn ' + test.value + ' to ' + test.expected, function () {
expect(utils.toHex(test.value as any)).toEqual(test.expected)
})
})
+ it('should throw in arrays', function () {
+ expect(() => utils.toHex([1, 2, 3, { test: 'data' }] as any)).toThrow()
+ })
+ it('should throw in objects', function () {
+ expect(() => utils.toHex({ test: 'data' } as any)).toThrow()
+ })
})
})
diff --git a/test/utils.toUtf8.ts b/test/utils.toUtf8.ts
index 4171b0b8..21a00f88 100644
--- a/test/utils.toUtf8.ts
+++ b/test/utils.toUtf8.ts
@@ -1,17 +1,20 @@
import * as expect from 'expect'
-import * as utils from '../src/utils/utils'
+import { hexToBytes } from '../src'
+import * as utils from '../src/utils/utf8'
let tests = [
{ value: '0x6d79537472696e67', expected: 'myString' },
- { value: '0x6d79537472696e6700', expected: 'myString' },
- { value: '0x65787065637465642076616c7565000000000000000000000000000000000000', expected: 'expected value' }
-]
+ { value: '0x6d79537472696e6700', expected: 'myString\x00' },
+ { value: hexToBytes('0x6d79537472696e6700'), expected: 'myString\x00' },
+ { value: hexToBytes('6d79537472696e6700'), expected: 'myString\x00' },
+ { value: '0x65787065637465642076616c75650000', expected: 'expected value\x00\x00' }
+] as const
describe('lib/utils/utils', function () {
describe('toUtf8', function () {
tests.forEach(function (test) {
it('should turn ' + test.value + ' to ' + test.expected, function () {
- expect(utils.toUtf8(test.value)).toEqual(test.expected)
+ expect(utils.bytesToUtf8String(test.value)).toEqual(test.expected)
})
})
})