From 034f8cc9cbc93f03421d68450b927f7e25f072e9 Mon Sep 17 00:00:00 2001 From: naz_dou <41945483+nduchak@users.noreply.github.com> Date: Thu, 11 Apr 2019 17:58:38 +0300 Subject: [PATCH 01/16] Realign 2.4.1 (#327) * chore(package): Bump version to 2.4.1 * chore(Adjust CHANGELOG): * chore(CAHNGELOG): Fix typo * docs(USAGE): Fix networkId in Wallet example * fix(Http): Remove userAgent from axios * chore(CHANGELOG): Fix typo * docs(*): Regenrate docs --- CHANGELOG.md | 33 ++++++++++++++++++++- docs/api/channel/index.md | 60 ++++++++++++++++++++++++++++++++++----- docs/usage.md | 2 +- es/utils/http.js | 9 +----- package.json | 2 +- 5 files changed, 88 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d2b759024e..daa98f540c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,36 @@ All notable changes to this project will be documented in this file. This change log follows the conventions of [keepachangelog.com](http://keepachangelog.com/). +## [2.4.1] +### Added +- feat(ACI): Add transform decoded data for 'address' type +- feat(Aepp): Add Compiler to Aepp rpc methods. Update example app +- feat(Channel): Add call contract static support +- feat(Channel): Add get contract state support +- feat(Channel): Get full channel state support +- docs(*): Adjust ACI, Contract and Usage +### Changed +- refactor(Http): Handle no response in http stamp error handler +- fix(Crypto): Fix crypto `formatAddress` +- fix(Crypto): Move ADDRESS_FORMAT to crypto + + ### Removed +- none + + ### Breaking Changes +- State Channel: + - `channel.state()` now returns offchain state instead of last co-signed offchain transaction + - `channel.update(...).state` has been renamed to `signedTx` + - `channel.withdraw(...).state` has been renamed to `signedTx` + - `channel.deposit(...).state` has been renamed to `signedTx` + - `channel.leave().state` has been renamed to `signedTx` + - `channel.createContract(...).state` has been renamed to `signedTx` + - `channel.callContract(...).state` has been renamed to `signedTx` + + ### Notes and known Issues +- none + + ## [2.4.0] ### Added - Install and configure `commitizen` @@ -628,4 +658,5 @@ await account.address(format: ADDRESS_FORMAT) // default ADDRESS_FORMAT.api [2.3.0]: https://github.com/aeternity/aepp-sdk-js/compare/2.3.0-next...2.3.0 [2.3.1]: https://github.com/aeternity/aepp-sdk-js/compare/2.3.0...2.3.1 [2.3.2]: https://github.com/aeternity/aepp-sdk-js/compare/2.3.1...2.3.2 -[2.4.0.]: https://github.com/aeternity/aepp-sdk-js/compare/2.3.2...2.4.0 +[2.4.0]: https://github.com/aeternity/aepp-sdk-js/compare/2.3.2...2.4.0 +[2.4.1]: https://github.com/aeternity/aepp-sdk-js/compare/2.4.0...2.4.1 diff --git a/docs/api/channel/index.md b/docs/api/channel/index.md index 246d6f384a..7219ee5d6f 100644 --- a/docs/api/channel/index.md +++ b/docs/api/channel/index.md @@ -23,7 +23,9 @@ import Channel from '@aeternity/aepp-sdk/es/channel/index' * [~deposit(amount, sign, [callbacks])](#module_@aeternity/aepp-sdk/es/channel/index--Channel..deposit) ⇒ `Promise.<object>` * [~createContract(options, sign)](#module_@aeternity/aepp-sdk/es/channel/index--Channel..createContract) ⇒ `Promise.<object>` * [~callContract(options, sign)](#module_@aeternity/aepp-sdk/es/channel/index--Channel..callContract) ⇒ `Promise.<object>` + * [~callContractStatic(options)](#module_@aeternity/aepp-sdk/es/channel/index--Channel..callContractStatic) ⇒ `Promise.<object>` * [~getContractCall(options)](#module_@aeternity/aepp-sdk/es/channel/index--Channel..getContractCall) ⇒ `Promise.<object>` + * [~getContractState(contract)](#module_@aeternity/aepp-sdk/es/channel/index--Channel..getContractState) ⇒ `Promise.<object>` * [~sendMessage(message, recipient)](#module_@aeternity/aepp-sdk/es/channel/index--Channel..sendMessage) @@ -117,7 +119,7 @@ channel.update( 'ak$Gi42jcRm9DcZjk72UWQQBSxi43BG3285C9n4QSvP5JdzDyH2o', 10, async (tx) => await account.signTransaction(tx) -).then({ accepted, state } => +).then({ accepted, signedTx } => if (accepted) { console.log('Update has been accepted') } @@ -175,7 +177,7 @@ Leave channel **Kind**: inner method of [`Channel`](#exp_module_@aeternity/aepp-sdk/es/channel/index--Channel) **Example** ```js -channel.leave().then(({channelId, state}) => +channel.leave().then(({ channelId, signedTx }) => console.log(channelId) console.log(state) ) @@ -219,10 +221,9 @@ channel.withdraw( 100, async (tx) => await account.signTransaction(tx), { onOnChainTx: (tx) => console.log('on_chain_tx', tx) } -).then(({ accepted, state }) => { +).then(({ accepted, signedTx }) => { if (accepted) { console.log('Withdrawal has been accepted') - console.log('The new state is:', state) } else { console.log('Withdrawal has been rejected') } @@ -284,7 +285,7 @@ channel.createContract({ deposit: 10, vmVersion: 3, abiVersion: 1 -}).then(({ accepted, state, address }) => { +}).then(({ accepted, signedTx, address }) => { if (accepted) { console.log('New contract has been created') console.log('Contract address:', address) @@ -316,15 +317,41 @@ channel.callContract({ callData: 'cb_1111111111111111...', amount: 0, abiVersion: 1 -}).then(({ accepted, state }) => { +}).then(({ accepted, signedTx }) => { if (accepted) { console.log('Contract called succesfully') - console.log('The new state is:', state) } else { console.log('Contract call has been rejected') } }) ``` + + +#### Channel~callContractStatic(options) ⇒ `Promise.<object>` +Call contract using dry-run + +**Kind**: inner method of [`Channel`](#exp_module_@aeternity/aepp-sdk/es/channel/index--Channel) + +| Param | Type | Description | +| --- | --- | --- | +| options | `object` | | +| [options.amount] | `string` | Amount the caller of the contract commits to it | +| [options.callData] | `string` | ABI encoded compiled AEVM call data for the code | +| [options.contract] | `number` | Address of the contract to call | +| [options.abiVersion] | `number` | Version of the ABI | + +**Example** +```js +channel.callContractStatic({ + contract: 'ct_9sRA9AVE4BYTAkh5RNfJYmwQe1NZ4MErasQLXZkFWG43TPBqa', + callData: 'cb_1111111111111111...', + amount: 0, + abiVersion: 1 +}).then(({ returnValue, gasUsed }) => { + console.log('Returned value:', returnValue) + console.log('Gas used:', gasUsed) +}) +``` #### Channel~getContractCall(options) ⇒ `Promise.<object>` @@ -349,6 +376,25 @@ channel.getContractCall({ if (returnType === 'ok') console.log(returnValue) }) ``` + + +#### Channel~getContractState(contract) ⇒ `Promise.<object>` +Get contract latest state + +**Kind**: inner method of [`Channel`](#exp_module_@aeternity/aepp-sdk/es/channel/index--Channel) + +| Param | Type | Description | +| --- | --- | --- | +| contract | `string` | Address of the contract | + +**Example** +```js +channel.getContractState( + 'ct_9sRA9AVE4BYTAkh5RNfJYmwQe1NZ4MErasQLXZkFWG43TPBqa', +).then(({ contract }) => { + console.log('deposit:', contract.deposit) +}) +``` #### Channel~sendMessage(message, recipient) diff --git a/docs/usage.md b/docs/usage.md index f16a196ac2..cdd0561741 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -235,7 +235,7 @@ Example spend function, using aeternity's SDK abstraction onChain: confirm, // guard returning boolean onAccount: confirm, // guard returning boolean onContract: confirm, // guard returning boolean - networkId: 'aet_ua' // or any other networkId your client should connect to + networkId: 'ae_uat' // or any other networkId your client should connect to }).then(ae => ae.spend(parseInt(amount), receiver_pub_key)) ``` diff --git a/es/utils/http.js b/es/utils/http.js index 812bbf6c0c..b3e75dbab7 100644 --- a/es/utils/http.js +++ b/es/utils/http.js @@ -1,15 +1,8 @@ -import ax from 'axios' -import https from 'https' +import axios from 'axios' import JSONbig from 'json-bigint' import * as R from 'ramda' import stampit from '@stamp/it' -const axios = ax.create({ - httpsAgent: new https.Agent({ - rejectUnauthorized: true // For develop - }) -}) - async function get (url, options) { return processResponse( axios.get(`${this.baseUrl}${url}`, R.merge(this.httpConfig, options)) diff --git a/package.json b/package.json index d1866c089a..5e4356d9ef 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@aeternity/aepp-sdk", - "version": "2.4.0", + "version": "2.4.1", "description": "SDK for the æternity blockchain", "main": "dist/aepp-sdk.js", "browser": "dist/aepp-sdk.browser.js", From e37cdfc53b4920ba4d655ecfb138ce68333322ef Mon Sep 17 00:00:00 2001 From: naz_dou <41945483+nduchak@users.noreply.github.com> Date: Tue, 16 Apr 2019 13:18:07 +0300 Subject: [PATCH 02/16] fix(ACI): Fix address type transformation when decoding data (#335) --- es/contract/aci.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/es/contract/aci.js b/es/contract/aci.js index 482c25f968..e489f6793f 100644 --- a/es/contract/aci.js +++ b/es/contract/aci.js @@ -23,7 +23,9 @@ * @example import ContractACI from '@aeternity/aepp-sdk/es/contract/aci' */ import AsyncInit from '../utils/async-init' -import { decode, encode } from '../tx/builder/helpers' +import { decode } from '../tx/builder/helpers' +import { aeEncodeKey } from '../utils/crypto' +import { toBytes } from '../utils/bytes' const SOPHIA_TYPES = [ 'int', @@ -116,7 +118,7 @@ function transformDecodedData (aci, result, { skipTransformDecoded = false } = { case SOPHIA_TYPES.bool: return !!result.value case SOPHIA_TYPES.address: - return encode(Buffer.from(result.value, 'hex'), 'ak') + return aeEncodeKey(toBytes(result.value, true)) case SOPHIA_TYPES.map: const [keyT, ...valueT] = generic.split(',') return result.value From e047f3baaab67df91a8d3812c459e56237261327 Mon Sep 17 00:00:00 2001 From: naz_dou <41945483+nduchak@users.noreply.github.com> Date: Tue, 16 Apr 2019 16:18:30 +0300 Subject: [PATCH 03/16] feat(ACI): Update due to compiler API changes (#331) * feat(ACI): Update due to compiler API changes * feat(ACI): Update ACI to compiler API breaking changes Add 'tuple' type arguments transformation, add tuple to transformEncodeData * test Jenkins * build(Compiler): Add compiler to docker-compose * test Jenkins * build(Compiler): Add compiler env to docker --- .env | 1 + docker-compose.yml | 8 +++++- docker/sdk.env | 1 + es/contract/aci.js | 58 +++++++++++++++++++++++---------------- test/integration/index.js | 2 +- 5 files changed, 45 insertions(+), 25 deletions(-) diff --git a/.env b/.env index ad47323d1e..81096ddd67 100644 --- a/.env +++ b/.env @@ -1 +1,2 @@ TAG=v2.2.0 +COMPILER_TAG=v2.1.0 diff --git a/docker-compose.yml b/docker-compose.yml index 0c8bbd544b..153c6c96b1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,7 +4,7 @@ services: build: context: . dockerfile: Dockerfile.ci - depends_on: [node] + depends_on: [node, compiler] entrypoint: docker/wait-for-it.sh node:3013 -- env_file: [./docker/sdk.env] environment: @@ -28,6 +28,12 @@ services: - node_db:/home/aeternity/node/data/mnesia - node_keys:/home/aeternity/node/keys + + compiler: + image: aeternity/aesophia_http:${COMPILER_TAG} + hostname: compiler + expose: [3080] + volumes: node_db: node_keys: diff --git a/docker/sdk.env b/docker/sdk.env index 21b96f3803..630de59694 100644 --- a/docker/sdk.env +++ b/docker/sdk.env @@ -2,4 +2,5 @@ TEST_NODE=node:3013 TEST_URL=http://node:3013 TEST_INTERNAL_URL=http://node:3113 TEST_NETWORK_ID=ae_devnet +COMPILER_URL=http://compiler:3080 diff --git a/es/contract/aci.js b/es/contract/aci.js index e489f6793f..00e616cc7e 100644 --- a/es/contract/aci.js +++ b/es/contract/aci.js @@ -48,12 +48,13 @@ const SOPHIA_TYPES = [ */ function transform (type, value) { const { t, generic } = readType(type) - switch (t) { case SOPHIA_TYPES.string: return `"${value}"` case SOPHIA_TYPES.list: return `[${value.map(el => transform(generic, el))}]` + case SOPHIA_TYPES.tuple: + return `(${value.map((el, i) => transform(generic[i], el))})` case SOPHIA_TYPES.address: return `#${decode(value, 'ak').toString('hex')}` } @@ -63,22 +64,19 @@ function transform (type, value) { /** * Parse sophia type * @param type + * @param returnType * @return {*} */ -function readType (type) { - const i = type.indexOf('(') - - if (i === -1) return { t: type } +function readType (type, returnType = false) { + const [t] = Array.isArray(type) ? type : [type] + // Base types + if (typeof t === 'string') return { t } - // Tuple - if (type[0] === '(') { - return { t: SOPHIA_TYPES.tuple, generic: type.slice(1).slice(0, -1).split(',').map(e => e.trim()) } + // Map, Tuple, List + if (typeof t === 'object') { + const [[baseType, generic]] = Object.entries(t) + return { t: baseType, generic } } - - const baseType = type.split('(')[0] - const generic = type.slice(i + 1, type.length - 1) - - return { t: baseType, generic } } /** @@ -112,29 +110,28 @@ function validate (type, value) { */ function transformDecodedData (aci, result, { skipTransformDecoded = false } = {}) { if (skipTransformDecoded) return result - const { t, generic } = readType(aci.type) - + const { t, generic } = readType(aci, true) switch (t) { case SOPHIA_TYPES.bool: return !!result.value case SOPHIA_TYPES.address: return aeEncodeKey(toBytes(result.value, true)) case SOPHIA_TYPES.map: - const [keyT, ...valueT] = generic.split(',') + const [keyT, valueT] = generic return result.value .reduce( (acc, { key, val }, i) => { - key = transformDecodedData({ type: keyT.toString() }, { value: key.value }) - val = transformDecodedData({ type: valueT.toString() }, { value: val.value }) + key = transformDecodedData(keyT, { value: key.value }) + val = transformDecodedData(valueT, { value: val.value }) acc[i] = { key, val } return acc }, {} ) case SOPHIA_TYPES.list: - return result.value.map(({ value }) => transformDecodedData({ type: generic }, { value })) + return result.value.map(({ value }) => transformDecodedData(generic, { value })) case SOPHIA_TYPES.tuple: - return result.value.map(({ value }, i) => { return transformDecodedData({ type: generic[i] }, { value }) }) + return result.value.map(({ value }, i) => { return transformDecodedData(generic[i], { value }) }) } return result.value } @@ -232,6 +229,22 @@ async function getContractInstance (source, { aci, contractAddress } = {}) { return instance } +function transformReturnType (returns) { + if (typeof returns === 'string') return returns + if (typeof returns === 'object') { + const [[key, value]] = Object.entries(returns) + return `${key !== 'tuple' ? key : ''}(${value + .reduce( + (acc, el, i) => { + if (i !== 0) acc += ',' + acc += transformReturnType(el) + return acc + }, + '') + })` + } +} + function call (self) { return async function (fn, params = [], options = { skipArgsConvert: false, skipTransformDecoded: false, callStatic: false }) { const fnACI = getFunctionACI(this.aci, fn) @@ -245,10 +258,10 @@ function call (self) { options }) : await self.contractCall(this.source, this.deployInfo.address, fn, params, options) - + const returnType = await transformReturnType(fnACI.returns) return { ...result, - decode: async () => transformDecodedData(fnACI, await self.contractDecodeData(fnACI.type, result.result.returnValue), options) + decode: async () => transformDecodedData(fnACI.returns, await self.contractDecodeData(returnType, result.result.returnValue), options) } } } @@ -257,7 +270,6 @@ function deploy (self) { return async function (init = [], options = { skipArgsConvert: false }) { const fnACI = getFunctionACI(this.aci, 'init') if (!this.compiled) await this.compile() - init = !options.skipArgsConvert ? prepareArgsForEncode(fnACI, init) : init const { owner, transaction, address, createdAt, result } = await self.contractDeploy(this.compiled, this.source, init, options) diff --git a/test/integration/index.js b/test/integration/index.js index 1d84426463..efaf651096 100644 --- a/test/integration/index.js +++ b/test/integration/index.js @@ -21,7 +21,7 @@ import { BigNumber } from 'bignumber.js' const url = process.env.TEST_URL || 'http://localhost:3013' const internalUrl = process.env.TEST_INTERNAL_URL || 'http://localhost:3113' -const compilerUrl = 'https://compiler.aepps.com' +const compilerUrl = process.env.COMPILER_URL || 'http://localhost:3080' const networkId = process.env.TEST_NETWORK_ID || 'ae_devnet' const account = Crypto.generateKeyPair() From 028ad7172d30fd8a9de252476353621ca2dfe259 Mon Sep 17 00:00:00 2001 From: naz_dou <41945483+nduchak@users.noreply.github.com> Date: Tue, 16 Apr 2019 16:27:55 +0300 Subject: [PATCH 04/16] Feature/add contract to tx validator (#333) * fix(ACI): Fix rtype or options for contract instance methods * feat(TxValidator): Add minGasPrice validation to contract transactions * feat(TxValidator): Add check for invalid gasPrice * fix(VALIDATOR): Fix min gas price validation for contract transactions * test(Verification): Fix tx verification test --- docs/api/contract/aci.md | 4 ++-- es/contract/aci.js | 4 ++-- es/tx/builder/schema.js | 13 +++++++++++-- es/tx/tx.js | 3 +-- es/tx/validator.js | 5 ++++- test/integration/txVerification.js | 2 +- 6 files changed, 21 insertions(+), 10 deletions(-) diff --git a/docs/api/contract/aci.md b/docs/api/contract/aci.md index eafb666711..21bcdd42f0 100644 --- a/docs/api/contract/aci.md +++ b/docs/api/contract/aci.md @@ -31,7 +31,7 @@ Deploy contract **Kind**: Exported member **Returns**: `ContractInstance` - Contract ACI object with predefined js methods for contract usage -**rtype**: `(init: Array, options: Object = { fromJsType: true }) => ContractInstance: Object` +**rtype**: `(init: Array, options: Object = { skipArgsConvert: false }) => ContractInstance: Object` | Param | Type | Default | Description | | --- | --- | --- | --- | @@ -46,7 +46,7 @@ Call contract function **Kind**: Exported member **Returns**: `Object` - CallResult -**rtype**: `(init: Array, options: Object = { fromJsType: true, transformDecoded: true }) => CallResult: Object` +**rtype**: `(init: Array, options: Object = { skipArgsConvert: false, skipTransformDecoded: false, callStatic: false }) => CallResult: Object` | Param | Type | Default | Description | | --- | --- | --- | --- | diff --git a/es/contract/aci.js b/es/contract/aci.js index 00e616cc7e..324dee6879 100644 --- a/es/contract/aci.js +++ b/es/contract/aci.js @@ -205,7 +205,7 @@ async function getContractInstance (source, { aci, contractAddress } = {}) { /** * Deploy contract * @alias module:@aeternity/aepp-sdk/es/contract/aci - * @rtype (init: Array, options: Object = { fromJsType: true }) => ContractInstance: Object + * @rtype (init: Array, options: Object = { skipArgsConvert: false }) => ContractInstance: Object * @param {Array} init Contract init function arguments array * @param {Object} [options={}] options Options object * @param {Boolean} [options.skipArgsConvert=false] Skip Validation and Transforming arguments before prepare call-data @@ -215,7 +215,7 @@ async function getContractInstance (source, { aci, contractAddress } = {}) { /** * Call contract function * @alias module:@aeternity/aepp-sdk/es/contract/aci - * @rtype (init: Array, options: Object = { fromJsType: true, transformDecoded: true }) => CallResult: Object + * @rtype (init: Array, options: Object = { skipArgsConvert: false, skipTransformDecoded: false, callStatic: false }) => CallResult: Object * @param {String} fn Function name * @param {Array} params Array of function arguments * @param {Object} [options={}] Array of function arguments diff --git a/es/tx/builder/schema.js b/es/tx/builder/schema.js index 4e8fa52766..cdb26e9a47 100644 --- a/es/tx/builder/schema.js +++ b/es/tx/builder/schema.js @@ -50,6 +50,8 @@ const OBJECT_TAG_CHANNEL_OFFCHAIN_CALL_CONTRACT_TX = 574 const TX_FIELD = (name, type, prefix) => [name, type, prefix] const TX_SCHEMA_FIELD = (schema, objectId) => [schema, objectId] +export const MIN_GAS_PRICE = 1000000000 // min gasPrice 1e9 + // # see https://github.com/aeternity/protocol/blob/minerva/contracts/contract_vms.md#virtual-machines-on-the-%C3%A6ternity-blockchain const VM_VERSIONS = { NO_VM: 0, @@ -515,7 +517,8 @@ const VALIDATORS = { insufficientBalanceForAmountFee: 'insufficientBalanceForAmountFee', insufficientBalanceForAmount: 'insufficientBalanceForAmount', nonceUsed: 'nonceUsed', - nonceHigh: 'nonceHigh' + nonceHigh: 'nonceHigh', + minGasPrice: 'minGasPrice' } const ERRORS = { @@ -525,7 +528,8 @@ const ERRORS = { insufficientBalanceForAmountFee: { key: 'InsufficientBalanceForAmountFee', type: ERROR_TYPE.WARNING, txKey: 'fee' }, insufficientBalanceForAmount: { key: 'InsufficientBalanceForAmount', type: ERROR_TYPE.WARNING, txKey: 'amount' }, nonceUsed: { key: 'NonceUsed', type: ERROR_TYPE.ERROR, txKey: 'nonce' }, - nonceHigh: { key: 'NonceHigh', type: ERROR_TYPE.WARNING, txKey: 'nonce' } + nonceHigh: { key: 'NonceHigh', type: ERROR_TYPE.WARNING, txKey: 'nonce' }, + minGasPrice: { key: 'minGasPrice', type: ERROR_TYPE.ERROR, txKey: 'gasPrice' } } export const SIGNATURE_VERIFICATION_SCHEMA = [ @@ -565,5 +569,10 @@ export const BASE_VERIFICATION_SCHEMA = [ ({ accountNonce }) => `The nonce is technically valid but will not be processed immediately by the node (next valid nonce is ${accountNonce + 1})`, VALIDATORS.nonceHigh, ERRORS.nonceHigh + ), + VERIFICATION_FIELD( + () => `The gasPrice must be bigger then ${MIN_GAS_PRICE}`, + VALIDATORS.minGasPrice, + ERRORS.minGasPrice ) ] diff --git a/es/tx/tx.js b/es/tx/tx.js index 21e03b6c38..db998838e8 100644 --- a/es/tx/tx.js +++ b/es/tx/tx.js @@ -29,12 +29,11 @@ import Tx from './' import Node from '../node' import { buildTx, calculateFee } from './builder' -import { TX_TYPE } from './builder/schema' +import { MIN_GAS_PRICE, TX_TYPE } from './builder/schema' import { buildContractId, oracleQueryId } from './builder/helpers' const ORACLE_VM_VERSION = 0 const CONTRACT_VM_VERSION = 1 -const MIN_GAS_PRICE = 1000000000 // min gasPrice 1e9 // TODO This values using as default for minerva node const CONTRACT_MINERVA_VM_ABI = 196609 const CONTRACT_MINERVA_VM = 3 diff --git a/es/tx/validator.js b/es/tx/validator.js index edf362fc03..a9aa5d7f37 100644 --- a/es/tx/validator.js +++ b/es/tx/validator.js @@ -7,7 +7,7 @@ import { encode } from '../tx/builder/helpers' import { BigNumber } from 'bignumber.js' import { - BASE_VERIFICATION_SCHEMA, OBJECT_ID_TX_TYPE, + BASE_VERIFICATION_SCHEMA, MIN_GAS_PRICE, OBJECT_ID_TX_TYPE, OBJECT_TAG_SIGNED_TRANSACTION, SIGNATURE_VERIFICATION_SCHEMA } from './builder/schema' @@ -50,6 +50,9 @@ const VALIDATORS = { // IF NONCE TO HIGH nonceHigh ({ accountNonce, nonce }) { return !(BigNumber(nonce).gt(BigNumber(accountNonce).plus(1))) + }, + minGasPrice ({ gasPrice }) { + return isNaN(gasPrice) || BigNumber(gasPrice).gte(BigNumber(MIN_GAS_PRICE)) } } diff --git a/test/integration/txVerification.js b/test/integration/txVerification.js index f5821fd390..17f5b85c3c 100644 --- a/test/integration/txVerification.js +++ b/test/integration/txVerification.js @@ -59,7 +59,7 @@ describe('Verify Transaction', function () { .filter(({type}) => type === 'error') .map(({ txKey }) => txKey) - JSON.stringify(ERRORS).should.be.equals(JSON.stringify(error)) + JSON.stringify(ERRORS.filter(e => e !== 'gasPrice')).should.be.equals(JSON.stringify(error)) }) it('verify transaction before broadcast', async () => { client = await ready(this) From 9f35bc8a8e9ba892e982684b9bb1cd5ae4527891 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Powaga?= Date: Tue, 16 Apr 2019 14:54:44 +0100 Subject: [PATCH 05/16] Channel tx serializations (#284) * Improve channel rpc usage * Fix lint error * Remove unreachable code * Make sure that sign function is correctly called * Improve error handling for update method * Add missing channel tx serializations * Add channel close solo and settle tx serialization * Add channel slash tx serialization * Add proof of inclusion tx serialization * Add basic merkle patricia tree implementation * Add merkle patricia tree serialization and verify function * fix(schema.js): Fix linter error * Improve channel tests and error handling (#276) * Make sure that sign function is correctly called * Improve error handling for update method * Improve state channel params handling. Fixes #299 (#300) * Compiler improvements (#303) * refactor(Chain and Contract): Fix Chain.getAccount. Omprove Compiler Add ability to get account/balance on specific block hash/height. Add test. Add changeCompilerUrl to Compiler stamp #302 * fix(Crypto): Fix name hash function arguments parsing * refactor(Compiler): Remove async for changeCompilerUrl function * Channel contracts (#279) * Add support for contracts in state channels * Remove console.log * Remove console.log * Improve channel rpc usage (#275) * Improve channel rpc usage * Fix lint error * Remove unreachable code * Improve channel tests and error handling (#276) * Make sure that sign function is correctly called * Improve error handling for update method * Improve state channel params handling. Fixes #299 (#300) * Fix channel tests * Add contract call tx serialization * Add channel tx serialization * Add missing tree tx serializations * Add channel snapshot solo tx serialization --- es/channel/handlers.js | 4 +- es/channel/index.js | 11 ++ es/channel/internal.js | 2 + es/tx/builder/helpers.js | 2 +- es/tx/builder/index.js | 40 ++++- es/tx/builder/schema.js | 279 ++++++++++++++++++++++++++++++++- es/tx/tx.js | 114 ++++++++++++++ es/utils/mptree.js | 146 +++++++++++++++++ test/integration/channel.js | 303 ++++++++++++++++++++++++++++++++---- test/unit/mptree.js | 55 +++++++ 10 files changed, 917 insertions(+), 39 deletions(-) create mode 100644 es/utils/mptree.js create mode 100644 test/unit/mptree.js diff --git a/es/channel/handlers.js b/es/channel/handlers.js index 498c1b030b..1d43dcd699 100644 --- a/es/channel/handlers.js +++ b/es/channel/handlers.js @@ -21,7 +21,8 @@ import { changeStatus, changeState, send, - emit + emit, + channelId } from './internal' import { unpackTx } from '../tx/builder' @@ -86,6 +87,7 @@ export function awaitingBlockInclusion (channel, message, state) { export function awaitingOpenConfirmation (channel, message, state) { if (message.method === 'channels.info' && message.params.data.event === 'open') { + channelId.set(channel, message.params.channel_id) return { handler: awaitingInitialState } } } diff --git a/es/channel/index.js b/es/channel/index.js index e3229ee6fa..ba1e9cb989 100644 --- a/es/channel/index.js +++ b/es/channel/index.js @@ -31,6 +31,7 @@ import { initialize, enqueueAction, send, + channelId, call } from './internal' import * as R from 'ramda' @@ -70,6 +71,15 @@ async function state () { return snakeToPascalObjKeys(await call(this, 'channels.get.offchain_state', {})) } +/** + * Get channel id + * + * @return {string} + */ +function id () { + return channelId.get(this) +} + /** * Trigger an update * @@ -546,6 +556,7 @@ const Channel = AsyncInit.compose({ on, status, state, + id, update, poi, balances, diff --git a/es/channel/internal.js b/es/channel/internal.js index 0d6d1bf2aa..aaa710b755 100644 --- a/es/channel/internal.js +++ b/es/channel/internal.js @@ -32,6 +32,7 @@ const messageQueueLocked = new WeakMap() const actionQueue = new WeakMap() const actionQueueLocked = new WeakMap() const sequence = new WeakMap() +const channelId = new WeakMap() const rpcCallbacks = new WeakMap() function channelURL (url, params, endpoint = 'channel') { @@ -196,5 +197,6 @@ export { changeState, send, enqueueAction, + channelId, call } diff --git a/es/tx/builder/helpers.js b/es/tx/builder/helpers.js index 9c25d188cd..0830705700 100644 --- a/es/tx/builder/helpers.js +++ b/es/tx/builder/helpers.js @@ -20,7 +20,7 @@ import { BigNumber } from 'bignumber.js' export const createSalt = salt -const base64Types = ['tx', 'st', 'ss', 'pi', 'ov', 'or', 'cb'] +const base64Types = ['tx', 'st', 'ss', 'pi', 'ov', 'or', 'cb', 'cs'] /** * Build a contract public key diff --git a/es/tx/builder/index.js b/es/tx/builder/index.js index 93764c5fc8..d4bf9826cd 100644 --- a/es/tx/builder/index.js +++ b/es/tx/builder/index.js @@ -16,6 +16,7 @@ import { } from './schema' import { readInt, readId, readPointers, writeId, writeInt, buildPointers, encode, decode } from './helpers' import { toBytes } from '../../utils/bytes' +import * as mpt from '../../utils/mptree' /** * JavaScript-based Transaction builder @@ -37,6 +38,10 @@ function deserializeField (value, type, prefix) { return readInt(value) case FIELD_TYPES.id: return readId(value) + case FIELD_TYPES.ids: + return value.map(readId) + case FIELD_TYPES.bool: + return value[0] === 1 case FIELD_TYPES.binary: return encode(value, prefix) case FIELD_TYPES.string: @@ -45,11 +50,26 @@ function deserializeField (value, type, prefix) { return readPointers(value) case FIELD_TYPES.rlpBinary: return unpackTx(value, true) + case FIELD_TYPES.rlpBinaries: + return value.map(v => unpackTx(v, true)) + case FIELD_TYPES.rawBinary: + return value + case FIELD_TYPES.hex: + return value.toString('hex') case FIELD_TYPES.offChainUpdates: return value.map(v => unpackTx(v, true)) case FIELD_TYPES.callStack: // TODO: fix this return [readInt(value)] + case FIELD_TYPES.mptree: + return value.map(mpt.deserialize) + case FIELD_TYPES.callReturnType: + switch (readInt(value)) { + case '0': return 'ok' + case '1': return 'error' + case '2': return 'revert' + default: return value + } default: return value } @@ -61,14 +81,29 @@ function serializeField (value, type, prefix) { return writeInt(value) case FIELD_TYPES.id: return writeId(value) + case FIELD_TYPES.ids: + return value.map(writeId) + case FIELD_TYPES.bool: + return Buffer.from([value ? 1 : 0]) case FIELD_TYPES.binary: return decode(value, prefix) + case FIELD_TYPES.hex: + return Buffer.from(value, 'hex') case FIELD_TYPES.signatures: return value.map(Buffer.from) case FIELD_TYPES.string: return toBytes(value) case FIELD_TYPES.pointers: return buildPointers(value) + case FIELD_TYPES.mptree: + return value.map(mpt.serialize) + case FIELD_TYPES.callReturnType: + switch (value) { + case 'ok': return writeInt(0) + case 'error': return writeInt(1) + case 'revert': return writeInt(2) + default: return value + } default: return value } @@ -250,10 +285,11 @@ export function unpackRawTx (binary, schema) { * @param {String} type Transaction type * @param {Object} [options={}] options * @param {Object} [options.excludeKeys] excludeKeys Array of keys to exclude for validation and build + * @param {String} [options.prefix] Prefix of transaction * @throws {Error} Validation error * @return {Object} { tx, rlpEncoded, binary } Object with tx -> Base64Check transaction hash with 'tx_' prefix, rlp encoded transaction and binary transaction */ -export function buildTx (params, type, { excludeKeys = [] } = {}) { +export function buildTx (params, type, { excludeKeys = [], prefix = 'tx' } = {}) { if (!TX_SERIALIZATION_SCHEMA[type]) { throw new Error('Transaction serialization not implemented for ' + type) } @@ -261,7 +297,7 @@ export function buildTx (params, type, { excludeKeys = [] } = {}) { const binary = buildRawTx({ ...params, VSN, tag }, schema, { excludeKeys }).filter(e => e !== undefined) const rlpEncoded = rlp.encode(binary) - const tx = encode(rlpEncoded, 'tx') + const tx = encode(rlpEncoded, prefix) return { tx, rlpEncoded, binary, txObject: unpackRawTx(binary, schema) } } diff --git a/es/tx/builder/schema.js b/es/tx/builder/schema.js index cdb26e9a47..a62797a76f 100644 --- a/es/tx/builder/schema.js +++ b/es/tx/builder/schema.js @@ -24,6 +24,7 @@ const ID_TAG_CHANNEL = 6 // # OBJECT tags // # see https://github.com/aeternity/protocol/blob/master/serializations.md#binary-serialization +const OBJECT_TAG_ACCOUNT = 10 export const OBJECT_TAG_SIGNED_TRANSACTION = 11 const OBJECT_TAG_SPEND_TRANSACTION = 12 const OBJECT_TAG_ORACLE_REGISTER_TRANSACTION = 22 @@ -35,17 +36,35 @@ const OBJECT_TAG_NAME_SERVICE_PRECLAIM_TRANSACTION = 33 const OBJECT_TAG_NAME_SERVICE_UPDATE_TRANSACTION = 34 const OBJECT_TAG_NAME_SERVICE_REVOKE_TRANSACTION = 35 const OBJECT_TAG_NAME_SERVICE_TRANSFER_TRANSACTION = 36 +const OBJECT_TAG_CONTRACT = 40 +const OBJECT_TAG_CONTRACT_CALL = 41 const OBJECT_TAG_CONTRACT_CREATE_TRANSACTION = 42 const OBJECT_TAG_CONTRACT_CALL_TRANSACTION = 43 - const OBJECT_TAG_CHANNEL_CREATE_TX = 50 const OBJECT_TAG_CHANNEL_DEPOSIT_TX = 51 const OBJECT_TAG_CHANNEL_WITHRAW_TX = 52 const OBJECT_TAG_CHANNEL_CLOSE_MUTUAL_TX = 53 +const OBJECT_TAG_CHANNEL_CLOSE_SOLO_TX = 54 +const OBJECT_TAG_CHANNEL_SLASH_TX = 55 const OBJECT_TAG_CHANNEL_SETTLE_TX = 56 const OBJECT_TAG_CHANNEL_OFFCHAIN_TX = 57 +const OBJECT_TAG_CHANNEL = 58 +const OBJECT_TAG_CHANNEL_SNAPSHOT_SOLO_TX = 59 +const OBJECT_TAG_CHANNEL_OFFCHAIN_UPDATE_TRANSFER_TX = 570 +const OBJECT_TAG_CHANNEL_OFFCHAIN_UPDATE_DEPOSIT_TX = 571 +const OBJECT_TAG_CHANNEL_OFFCHAIN_UPDATE_WITHDRAWAL_TX = 572 const OBJECT_TAG_CHANNEL_OFFCHAIN_CREATE_CONTRACT_TX = 573 const OBJECT_TAG_CHANNEL_OFFCHAIN_CALL_CONTRACT_TX = 574 +const OBJECT_TAG_PROOF_OF_INCLUSION = 60 +const OBJECT_TAG_STATE_TREES = 62 +const OBJECT_TAG_MERKLE_PATRICIA_TREE = 63 +const OBJECT_TAG_MERKLE_PATRICIA_TREE_VALUE = 64 +const OBJECT_TAG_CONTRACTS_TREE = 621 +const OBJECT_TAG_CONTRACT_CALLS_TREE = 622 +const OBJECT_TAG_CHANNELS_TREE = 623 +const OBJECT_TAG_NAMESERVICE_TREE = 624 +const OBJECT_TAG_ORACLES_TREE = 625 +const OBJECT_TAG_ACCOUNTS_TREE = 626 const TX_FIELD = (name, type, prefix) => [name, type, prefix] const TX_SCHEMA_FIELD = (schema, objectId) => [schema, objectId] @@ -88,6 +107,7 @@ const revertObject = (obj) => Object.entries(obj).reduce((acc, [key, v]) => (acc * @property {String} oracleResponse */ export const TX_TYPE = { + account: 'account', signed: 'signedTx', spend: 'spendTx', // AENS @@ -97,8 +117,10 @@ export const TX_TYPE = { nameRevoke: 'nameRevokeTx', nameTransfer: 'nameTransfer', // CONTRACT + contract: 'contract', contractCreate: 'contractCreateTx', contractCall: 'contractCallTx', + contractCallResult: 'contractCallResult', // ORACLE oracleRegister: 'oracleRegister', oracleExtend: 'oracleExtend', @@ -107,15 +129,34 @@ export const TX_TYPE = { // STATE CHANNEL channelCreate: 'channelCreate', channelCloseMutual: 'channelCloseMutual', + channelCloseSolo: 'channelCloseSolo', + channelSlash: 'channelSlash', channelDeposit: 'channelDeposit', channelWithdraw: 'channelWithdraw', channelSettle: 'channelSettle', channelOffChain: 'channelOffChain', + channel: 'channel', + channelSnapshotSolo: 'channelSnapshotSolo', + channelOffChainUpdateTransfer: 'channelOffChainUpdateTransfer', + channelOffChainUpdateDeposit: 'channelOffChainUpdateDeposit', + channelOffChainUpdateWithdrawal: 'channelOffChainUpdateWithdrawal', channelOffChainCreateContract: 'channelOffChainCreateContract', - channelOffChainCallContract: 'channelOffChainCallContract' + channelOffChainCallContract: 'channelOffChainCallContract', + proofOfInclusion: 'proofOfInclusion', + stateTrees: 'stateTrees', + merklePatriciaTree: 'merklePatriciaTree', + merklePatriciaTreeValue: 'merklePatriciaTreeValue', + contractsTree: 'contractsTree', + contractCallsTree: 'contractCallsTree', + channelsTree: 'channelsTree', + nameserviceTree: 'nameserviceTree', + oraclesTree: 'oraclesTree', + accountsTree: 'accountsTree' } export const OBJECT_ID_TX_TYPE = { + [OBJECT_TAG_ACCOUNT]: TX_TYPE.account, + [OBJECT_TAG_SIGNED_TRANSACTION]: TX_TYPE.signed, [OBJECT_TAG_SPEND_TRANSACTION]: TX_TYPE.spend, // AENS [OBJECT_TAG_NAME_SERVICE_CLAIM_TRANSACTION]: TX_TYPE.nameClaim, @@ -124,8 +165,10 @@ export const OBJECT_ID_TX_TYPE = { [OBJECT_TAG_NAME_SERVICE_REVOKE_TRANSACTION]: TX_TYPE.nameRevoke, [OBJECT_TAG_NAME_SERVICE_TRANSFER_TRANSACTION]: TX_TYPE.nameTransfer, // CONTRACT + [OBJECT_TAG_CONTRACT]: TX_TYPE.contract, [OBJECT_TAG_CONTRACT_CREATE_TRANSACTION]: TX_TYPE.contractCreate, [OBJECT_TAG_CONTRACT_CALL_TRANSACTION]: TX_TYPE.contractCall, + [OBJECT_TAG_CONTRACT_CALL]: TX_TYPE.contractCallResult, // ORACLE [OBJECT_TAG_ORACLE_REGISTER_TRANSACTION]: TX_TYPE.oracleRegister, [OBJECT_TAG_ORACLE_EXTEND_TRANSACTION]: TX_TYPE.oracleExtend, @@ -134,24 +177,49 @@ export const OBJECT_ID_TX_TYPE = { // STATE CHANNEL [OBJECT_TAG_CHANNEL_CREATE_TX]: TX_TYPE.channelCreate, [OBJECT_TAG_CHANNEL_CLOSE_MUTUAL_TX]: TX_TYPE.channelCloseMutual, + [OBJECT_TAG_CHANNEL_CLOSE_SOLO_TX]: TX_TYPE.channelCloseSolo, + [OBJECT_TAG_CHANNEL_SLASH_TX]: TX_TYPE.channelSlash, [OBJECT_TAG_CHANNEL_DEPOSIT_TX]: TX_TYPE.channelDeposit, [OBJECT_TAG_CHANNEL_WITHRAW_TX]: TX_TYPE.channelWithdraw, [OBJECT_TAG_CHANNEL_SETTLE_TX]: TX_TYPE.channelSettle, [OBJECT_TAG_CHANNEL_OFFCHAIN_TX]: TX_TYPE.channelOffChain, + [OBJECT_TAG_CHANNEL]: TX_TYPE.channel, + [OBJECT_TAG_CHANNEL_SNAPSHOT_SOLO_TX]: TX_TYPE.channelSnapshotSolo, + [OBJECT_TAG_CHANNEL_OFFCHAIN_UPDATE_TRANSFER_TX]: TX_TYPE.channelOffChainUpdateTransfer, + [OBJECT_TAG_CHANNEL_OFFCHAIN_UPDATE_DEPOSIT_TX]: TX_TYPE.channelOffChainUpdateDeposit, + [OBJECT_TAG_CHANNEL_OFFCHAIN_UPDATE_WITHDRAWAL_TX]: TX_TYPE.channelOffChainUpdateWithdrawal, [OBJECT_TAG_CHANNEL_OFFCHAIN_CREATE_CONTRACT_TX]: TX_TYPE.channelOffChainCreateContract, - [OBJECT_TAG_CHANNEL_OFFCHAIN_CALL_CONTRACT_TX]: TX_TYPE.channelOffChainCallContract + [OBJECT_TAG_CHANNEL_OFFCHAIN_CALL_CONTRACT_TX]: TX_TYPE.channelOffChainCallContract, + [OBJECT_TAG_PROOF_OF_INCLUSION]: TX_TYPE.proofOfInclusion, + [OBJECT_TAG_STATE_TREES]: TX_TYPE.stateTrees, + [OBJECT_TAG_MERKLE_PATRICIA_TREE]: TX_TYPE.merklePatriciaTree, + [OBJECT_TAG_MERKLE_PATRICIA_TREE_VALUE]: TX_TYPE.merklePatriciaTreeValue, + [OBJECT_TAG_CONTRACTS_TREE]: TX_TYPE.contractsTree, + [OBJECT_TAG_CONTRACT_CALLS_TREE]: TX_TYPE.contractCallsTree, + [OBJECT_TAG_CHANNELS_TREE]: TX_TYPE.channelsTree, + [OBJECT_TAG_NAMESERVICE_TREE]: TX_TYPE.nameserviceTree, + [OBJECT_TAG_ORACLES_TREE]: TX_TYPE.oraclesTree, + [OBJECT_TAG_ACCOUNTS_TREE]: TX_TYPE.accountsTree } export const FIELD_TYPES = { int: 'int', id: 'id', + ids: 'ids', string: 'string', binary: 'binary', rlpBinary: 'rlpBinary', + rlpBinaries: 'rlpBinaries', + rawBinary: 'rawBinary', + bool: 'bool', + hex: 'hex', signatures: 'signatures', pointers: 'pointers', offChainUpdates: 'offChainUpdates', - callStack: 'callStack' + callStack: 'callStack', + proofOfInclusion: 'proofOfInclusion', + mptree: 'mptree', + callReturnType: 'callReturnType' } // FEE CALCULATION @@ -221,6 +289,12 @@ const BASE_TX = [ TX_FIELD('VSN', FIELD_TYPES.int) ] +const ACCOUNT_TX = [ + ...BASE_TX, + TX_FIELD('nonce', FIELD_TYPES.int), + TX_FIELD('balance', FIELD_TYPES.int) +] + const SPEND_TX = [ ...BASE_TX, TX_FIELD('senderId', FIELD_TYPES.id, 'ak'), @@ -288,6 +362,17 @@ const NAME_REVOKE_TX = [ TX_FIELD('ttl', FIELD_TYPES.int) ] +const CONTRACT_TX = [ + ...BASE_TX, + TX_FIELD('owner', FIELD_TYPES.id, 'ak'), + TX_FIELD('ctVersion', FIELD_TYPES.int), + TX_FIELD('code', FIELD_TYPES.binary, 'cb'), + TX_FIELD('log', FIELD_TYPES.binary, 'cb'), + TX_FIELD('active', FIELD_TYPES.bool), + TX_FIELD('referers', FIELD_TYPES.ids, 'ak'), + TX_FIELD('deposit', FIELD_TYPES.int) +] + const CONTRACT_CREATE_TX = [ ...BASE_TX, TX_FIELD('ownerId', FIELD_TYPES.id, 'ak'), @@ -317,6 +402,20 @@ const CONTRACT_CALL_TX = [ TX_FIELD('callData', FIELD_TYPES.binary, 'cb') ] +const CONTRACT_CALL_RESULT_TX = [ + ...BASE_TX, + TX_FIELD('callerId', FIELD_TYPES.id, 'ak'), + TX_FIELD('callerNonce', FIELD_TYPES.int), + TX_FIELD('height', FIELD_TYPES.int), + TX_FIELD('contractId', FIELD_TYPES.id, 'ct'), + TX_FIELD('gasPrice', FIELD_TYPES.int), + TX_FIELD('gasUsed', FIELD_TYPES.int), + TX_FIELD('returnValue', FIELD_TYPES.binary, 'cb'), + TX_FIELD('returnType', FIELD_TYPES.callReturnType), + // TODO: add serialization for :: [ {
:: id, [ :: binary() ], :: binary() } ] + TX_FIELD('log', FIELD_TYPES.rawBinary) +] + const ORACLE_REGISTER_TX = [ ...BASE_TX, TX_FIELD('accountId', FIELD_TYPES.id, 'ak'), @@ -417,6 +516,28 @@ const CHANNEL_CLOSE_MUTUAL_TX = [ TX_FIELD('nonce', FIELD_TYPES.int) ] +const CHANNEL_CLOSE_SOLO_TX = [ + ...BASE_TX, + TX_FIELD('channelId', FIELD_TYPES.id, 'ch'), + TX_FIELD('fromId', FIELD_TYPES.id, 'ak'), + TX_FIELD('payload', FIELD_TYPES.binary, 'tx'), + TX_FIELD('poi', FIELD_TYPES.binary, 'pi'), + TX_FIELD('ttl', FIELD_TYPES.int), + TX_FIELD('fee', FIELD_TYPES.int), + TX_FIELD('nonce', FIELD_TYPES.int) +] + +const CHANNEL_SLASH_TX = [ + ...BASE_TX, + TX_FIELD('channelId', FIELD_TYPES.id, 'ch'), + TX_FIELD('fromId', FIELD_TYPES.id, 'ak'), + TX_FIELD('payload', FIELD_TYPES.binary, 'tx'), + TX_FIELD('poi', FIELD_TYPES.binary, 'pi'), + TX_FIELD('ttl', FIELD_TYPES.int), + TX_FIELD('fee', FIELD_TYPES.int), + TX_FIELD('nonce', FIELD_TYPES.int) +] + const CHANNEL_SETTLE_TX = [ ...BASE_TX, TX_FIELD('channelId', FIELD_TYPES.id, 'ch'), @@ -436,6 +557,32 @@ const CHANNEL_OFFCHAIN_TX = [ TX_FIELD('stateHash', FIELD_TYPES.binary, 'st') ] +const CHANNEL_TX = [ + ...BASE_TX, + TX_FIELD('initiator', FIELD_TYPES.id, 'ak'), + TX_FIELD('responder', FIELD_TYPES.id, 'ak'), + TX_FIELD('channelAmount', FIELD_TYPES.int), + TX_FIELD('initiatorAmount', FIELD_TYPES.int), + TX_FIELD('responderAmount', FIELD_TYPES.int), + TX_FIELD('channelReserve', FIELD_TYPES.int), + TX_FIELD('delegateIds', FIELD_TYPES.ids), + TX_FIELD('stateHash', FIELD_TYPES.hex), + TX_FIELD('round', FIELD_TYPES.int), + TX_FIELD('soloRound', FIELD_TYPES.int), + TX_FIELD('lockPeriod', FIELD_TYPES.int), + TX_FIELD('lockedUntil', FIELD_TYPES.int) +] + +const CHANNEL_SNAPSHOT_SOLO_TX = [ + ...BASE_TX, + TX_FIELD('channelId', FIELD_TYPES.id, 'ch'), + TX_FIELD('fromId', FIELD_TYPES.id, 'ak'), + TX_FIELD('payload', FIELD_TYPES.binary, 'tx'), + TX_FIELD('ttl', FIELD_TYPES.int), + TX_FIELD('fee', FIELD_TYPES.int), + TX_FIELD('nonce', FIELD_TYPES.int) +] + const CHANNEL_OFFCHAIN_CREATE_CONTRACT_TX = [ ...BASE_TX, TX_FIELD('owner', FIELD_TYPES.id, 'ak'), @@ -457,7 +604,88 @@ const CHANNEL_OFFCHAIN_CALL_CONTRACT_TX = [ TX_FIELD('gasLimit', FIELD_TYPES.int) ] +const CHANNEL_OFFCHAIN_UPDATE_TRANSFER_TX = [ + ...BASE_TX, + TX_FIELD('from', FIELD_TYPES.id, 'ak'), + TX_FIELD('to', FIELD_TYPES.id, 'ak'), + TX_FIELD('amount', FIELD_TYPES.int) +] + +const CHANNEL_OFFCHAIN_UPDATE_DEPOSIT_TX = [ + ...BASE_TX, + TX_FIELD('from', FIELD_TYPES.id, 'ak'), + TX_FIELD('amount', FIELD_TYPES.int) +] + +const CHANNEL_OFFCHAIN_UPDATE_WITHDRAWAL_TX = [ + ...BASE_TX, + TX_FIELD('from', FIELD_TYPES.id, 'ak'), + TX_FIELD('amount', FIELD_TYPES.int) +] + +const PROOF_OF_INCLUSION_TX = [ + ...BASE_TX, + TX_FIELD('accounts', FIELD_TYPES.mptrees), + TX_FIELD('calls', FIELD_TYPES.mptrees), + TX_FIELD('channels', FIELD_TYPES.mptrees), + TX_FIELD('contracts', FIELD_TYPES.mptrees), + TX_FIELD('ns', FIELD_TYPES.mptrees), + TX_FIELD('oracles', FIELD_TYPES.mptrees) +] + +const STATE_TREES_TX = [ + ...BASE_TX, + TX_FIELD('contracts', FIELD_TYPES.rlpBinary), + TX_FIELD('calls', FIELD_TYPES.rlpBinary), + TX_FIELD('channels', FIELD_TYPES.rlpBinary), + TX_FIELD('ns', FIELD_TYPES.rlpBinary), + TX_FIELD('oracles', FIELD_TYPES.rlpBinary), + TX_FIELD('accounts', FIELD_TYPES.rlpBinary) +] + +const MERKLE_PATRICIA_TREE_TX = [ + ...BASE_TX, + TX_FIELD('values', FIELD_TYPES.rlpBinaries) +] + +const MERKLE_PATRICIA_TREE_VALUE_TX = [ + ...BASE_TX, + TX_FIELD('key', FIELD_TYPES.hex), + TX_FIELD('value', FIELD_TYPES.rawBinary) +] + +const CONTRACTS_TREE_TX = [ + ...BASE_TX, + TX_FIELD('contracts', FIELD_TYPES.rlpBinary) +] + +const CONTRACT_CALLS_TREE_TX = [ + ...BASE_TX, + TX_FIELD('calls', FIELD_TYPES.rlpBinary) +] + +const CHANNELS_TREE_TX = [ + ...BASE_TX, + TX_FIELD('channels', FIELD_TYPES.rlpBinary) +] + +const NAMESERVICE_TREE_TX = [ + ...BASE_TX, + TX_FIELD('mtree', FIELD_TYPES.rlpBinary) +] + +const ORACLES_TREE_TX = [ + ...BASE_TX, + TX_FIELD('otree', FIELD_TYPES.rlpBinary) +] + +const ACCOUNTS_TREE_TX = [ + ...BASE_TX, + TX_FIELD('accounts', FIELD_TYPES.rlpBinary) +] + export const TX_SERIALIZATION_SCHEMA = { + [TX_TYPE.account]: TX_SCHEMA_FIELD(ACCOUNT_TX, OBJECT_TAG_ACCOUNT), [TX_TYPE.signed]: TX_SCHEMA_FIELD(SIGNED_TX, OBJECT_TAG_SIGNED_TRANSACTION), [TX_TYPE.spend]: TX_SCHEMA_FIELD(SPEND_TX, OBJECT_TAG_SPEND_TRANSACTION), [TX_TYPE.namePreClaim]: TX_SCHEMA_FIELD(NAME_PRE_CLAIM_TX, OBJECT_TAG_NAME_SERVICE_PRECLAIM_TRANSACTION), @@ -465,23 +693,43 @@ export const TX_SERIALIZATION_SCHEMA = { [TX_TYPE.nameUpdate]: TX_SCHEMA_FIELD(NAME_UPDATE_TX, OBJECT_TAG_NAME_SERVICE_UPDATE_TRANSACTION), [TX_TYPE.nameTransfer]: TX_SCHEMA_FIELD(NAME_TRANSFER_TX, OBJECT_TAG_NAME_SERVICE_TRANSFER_TRANSACTION), [TX_TYPE.nameRevoke]: TX_SCHEMA_FIELD(NAME_REVOKE_TX, OBJECT_TAG_NAME_SERVICE_REVOKE_TRANSACTION), + [TX_TYPE.contract]: TX_SCHEMA_FIELD(CONTRACT_TX, OBJECT_TAG_CONTRACT), [TX_TYPE.contractCreate]: TX_SCHEMA_FIELD(CONTRACT_CREATE_TX, OBJECT_TAG_CONTRACT_CREATE_TRANSACTION), [TX_TYPE.contractCall]: TX_SCHEMA_FIELD(CONTRACT_CALL_TX, OBJECT_TAG_CONTRACT_CALL_TRANSACTION), + [TX_TYPE.contractCallResult]: TX_SCHEMA_FIELD(CONTRACT_CALL_RESULT_TX, OBJECT_TAG_CONTRACT_CALL), [TX_TYPE.oracleRegister]: TX_SCHEMA_FIELD(ORACLE_REGISTER_TX, OBJECT_TAG_ORACLE_REGISTER_TRANSACTION), [TX_TYPE.oracleExtend]: TX_SCHEMA_FIELD(ORACLE_EXTEND_TX, OBJECT_TAG_ORACLE_EXTEND_TRANSACTION), [TX_TYPE.oracleQuery]: TX_SCHEMA_FIELD(ORACLE_QUERY_TX, OBJECT_TAG_ORACLE_QUERY_TRANSACTION), [TX_TYPE.oracleResponse]: TX_SCHEMA_FIELD(ORACLE_RESPOND_TX, OBJECT_TAG_ORACLE_RESPONSE_TRANSACTION), [TX_TYPE.channelCreate]: TX_SCHEMA_FIELD(CHANNEL_CREATE_TX, OBJECT_TAG_CHANNEL_CREATE_TX), [TX_TYPE.channelCloseMutual]: TX_SCHEMA_FIELD(CHANNEL_CLOSE_MUTUAL_TX, OBJECT_TAG_CHANNEL_CLOSE_MUTUAL_TX), + [TX_TYPE.channelCloseSolo]: TX_SCHEMA_FIELD(CHANNEL_CLOSE_SOLO_TX, OBJECT_TAG_CHANNEL_CLOSE_SOLO_TX), + [TX_TYPE.channelSlash]: TX_SCHEMA_FIELD(CHANNEL_SLASH_TX, OBJECT_TAG_CHANNEL_SLASH_TX), [TX_TYPE.channelDeposit]: TX_SCHEMA_FIELD(CHANNEL_DEPOSIT_TX, OBJECT_TAG_CHANNEL_DEPOSIT_TX), [TX_TYPE.channelWithdraw]: TX_SCHEMA_FIELD(CHANNEL_WITHDRAW_TX, OBJECT_TAG_CHANNEL_WITHRAW_TX), [TX_TYPE.channelSettle]: TX_SCHEMA_FIELD(CHANNEL_SETTLE_TX, OBJECT_TAG_CHANNEL_SETTLE_TX), [TX_TYPE.channelOffChain]: TX_SCHEMA_FIELD(CHANNEL_OFFCHAIN_TX, OBJECT_TAG_CHANNEL_OFFCHAIN_TX), + [TX_TYPE.channel]: TX_SCHEMA_FIELD(CHANNEL_TX, OBJECT_TAG_CHANNEL), + [TX_TYPE.channelSnapshotSolo]: TX_SCHEMA_FIELD(CHANNEL_SNAPSHOT_SOLO_TX, OBJECT_TAG_CHANNEL_SNAPSHOT_SOLO_TX), + [TX_TYPE.channelOffChainUpdateTransfer]: TX_SCHEMA_FIELD(CHANNEL_OFFCHAIN_UPDATE_TRANSFER_TX, OBJECT_TAG_CHANNEL_OFFCHAIN_UPDATE_TRANSFER_TX), + [TX_TYPE.channelOffChainUpdateDeposit]: TX_SCHEMA_FIELD(CHANNEL_OFFCHAIN_UPDATE_DEPOSIT_TX, OBJECT_TAG_CHANNEL_OFFCHAIN_UPDATE_DEPOSIT_TX), + [TX_TYPE.channelOffChainUpdateWithdrawal]: TX_SCHEMA_FIELD(CHANNEL_OFFCHAIN_UPDATE_WITHDRAWAL_TX, OBJECT_TAG_CHANNEL_OFFCHAIN_UPDATE_WITHDRAWAL_TX), [TX_TYPE.channelOffChainCreateContract]: TX_SCHEMA_FIELD(CHANNEL_OFFCHAIN_CREATE_CONTRACT_TX, OBJECT_TAG_CHANNEL_OFFCHAIN_CREATE_CONTRACT_TX), - [TX_TYPE.channelOffChainCallContract]: TX_SCHEMA_FIELD(CHANNEL_OFFCHAIN_CALL_CONTRACT_TX, OBJECT_TAG_CHANNEL_OFFCHAIN_CALL_CONTRACT_TX) + [TX_TYPE.channelOffChainCallContract]: TX_SCHEMA_FIELD(CHANNEL_OFFCHAIN_CALL_CONTRACT_TX, OBJECT_TAG_CHANNEL_OFFCHAIN_CALL_CONTRACT_TX), + [TX_TYPE.proofOfInclusion]: TX_SCHEMA_FIELD(PROOF_OF_INCLUSION_TX, OBJECT_TAG_PROOF_OF_INCLUSION), + [TX_TYPE.stateTrees]: TX_SCHEMA_FIELD(STATE_TREES_TX, OBJECT_TAG_STATE_TREES), + [TX_TYPE.merklePatriciaTree]: TX_SCHEMA_FIELD(MERKLE_PATRICIA_TREE_TX, OBJECT_TAG_MERKLE_PATRICIA_TREE), + [TX_TYPE.merklePatriciaTreeValue]: TX_SCHEMA_FIELD(MERKLE_PATRICIA_TREE_VALUE_TX, OBJECT_TAG_MERKLE_PATRICIA_TREE_VALUE), + [TX_TYPE.contractsTree]: TX_SCHEMA_FIELD(CONTRACTS_TREE_TX, OBJECT_TAG_CONTRACTS_TREE), + [TX_TYPE.contractCallsTree]: TX_SCHEMA_FIELD(CONTRACT_CALLS_TREE_TX, OBJECT_TAG_CONTRACT_CALLS_TREE), + [TX_TYPE.channelsTree]: TX_SCHEMA_FIELD(CHANNELS_TREE_TX, OBJECT_TAG_CHANNELS_TREE), + [TX_TYPE.nameserviceTree]: TX_SCHEMA_FIELD(NAMESERVICE_TREE_TX, OBJECT_TAG_NAMESERVICE_TREE), + [TX_TYPE.oraclesTree]: TX_SCHEMA_FIELD(ORACLES_TREE_TX, OBJECT_TAG_ORACLES_TREE), + [TX_TYPE.accountsTree]: TX_SCHEMA_FIELD(ACCOUNTS_TREE_TX, OBJECT_TAG_ACCOUNTS_TREE) } export const TX_DESERIALIZATION_SCHEMA = { + [OBJECT_TAG_ACCOUNT]: TX_SCHEMA_FIELD(ACCOUNT_TX, OBJECT_TAG_ACCOUNT), [OBJECT_TAG_SIGNED_TRANSACTION]: TX_SCHEMA_FIELD(SIGNED_TX, OBJECT_TAG_SIGNED_TRANSACTION), [OBJECT_TAG_SPEND_TRANSACTION]: TX_SCHEMA_FIELD(SPEND_TX, OBJECT_TAG_SPEND_TRANSACTION), [OBJECT_TAG_NAME_SERVICE_PRECLAIM_TRANSACTION]: TX_SCHEMA_FIELD(NAME_PRE_CLAIM_TX, OBJECT_TAG_NAME_SERVICE_PRECLAIM_TRANSACTION), @@ -489,20 +737,39 @@ export const TX_DESERIALIZATION_SCHEMA = { [OBJECT_TAG_NAME_SERVICE_UPDATE_TRANSACTION]: TX_SCHEMA_FIELD(NAME_UPDATE_TX, OBJECT_TAG_NAME_SERVICE_UPDATE_TRANSACTION), [OBJECT_TAG_NAME_SERVICE_TRANSFER_TRANSACTION]: TX_SCHEMA_FIELD(NAME_TRANSFER_TX, OBJECT_TAG_NAME_SERVICE_TRANSFER_TRANSACTION), [OBJECT_TAG_NAME_SERVICE_REVOKE_TRANSACTION]: TX_SCHEMA_FIELD(NAME_REVOKE_TX, OBJECT_TAG_NAME_SERVICE_REVOKE_TRANSACTION), + [OBJECT_TAG_CONTRACT]: TX_SCHEMA_FIELD(CONTRACT_TX, OBJECT_TAG_CONTRACT), [OBJECT_TAG_CONTRACT_CREATE_TRANSACTION]: TX_SCHEMA_FIELD(CONTRACT_CREATE_TX, OBJECT_TAG_CONTRACT_CREATE_TRANSACTION), [OBJECT_TAG_CONTRACT_CALL_TRANSACTION]: TX_SCHEMA_FIELD(CONTRACT_CALL_TX, OBJECT_TAG_CONTRACT_CALL_TRANSACTION), + [OBJECT_TAG_CONTRACT_CALL]: TX_SCHEMA_FIELD(CONTRACT_CALL_RESULT_TX, OBJECT_TAG_CONTRACT_CALL), [OBJECT_TAG_ORACLE_REGISTER_TRANSACTION]: TX_SCHEMA_FIELD(ORACLE_REGISTER_TX, OBJECT_TAG_ORACLE_REGISTER_TRANSACTION), [OBJECT_TAG_ORACLE_EXTEND_TRANSACTION]: TX_SCHEMA_FIELD(ORACLE_EXTEND_TX, OBJECT_TAG_ORACLE_EXTEND_TRANSACTION), [OBJECT_TAG_ORACLE_QUERY_TRANSACTION]: TX_SCHEMA_FIELD(ORACLE_QUERY_TX, OBJECT_TAG_ORACLE_QUERY_TRANSACTION), [OBJECT_TAG_ORACLE_RESPONSE_TRANSACTION]: TX_SCHEMA_FIELD(ORACLE_RESPOND_TX, OBJECT_TAG_ORACLE_RESPONSE_TRANSACTION), [OBJECT_TAG_CHANNEL_CREATE_TX]: TX_SCHEMA_FIELD(CHANNEL_CREATE_TX, OBJECT_TAG_CHANNEL_CREATE_TX), [OBJECT_TAG_CHANNEL_CLOSE_MUTUAL_TX]: TX_SCHEMA_FIELD(CHANNEL_CLOSE_MUTUAL_TX, OBJECT_TAG_CHANNEL_CLOSE_MUTUAL_TX), + [OBJECT_TAG_CHANNEL_CLOSE_SOLO_TX]: TX_SCHEMA_FIELD(CHANNEL_CLOSE_SOLO_TX, OBJECT_TAG_CHANNEL_CLOSE_SOLO_TX), + [OBJECT_TAG_CHANNEL_SLASH_TX]: TX_SCHEMA_FIELD(CHANNEL_SLASH_TX, OBJECT_TAG_CHANNEL_SLASH_TX), [OBJECT_TAG_CHANNEL_DEPOSIT_TX]: TX_SCHEMA_FIELD(CHANNEL_DEPOSIT_TX, OBJECT_TAG_CHANNEL_DEPOSIT_TX), [OBJECT_TAG_CHANNEL_WITHRAW_TX]: TX_SCHEMA_FIELD(CHANNEL_WITHDRAW_TX, OBJECT_TAG_CHANNEL_WITHRAW_TX), [OBJECT_TAG_CHANNEL_SETTLE_TX]: TX_SCHEMA_FIELD(CHANNEL_SETTLE_TX, OBJECT_TAG_CHANNEL_SETTLE_TX), [OBJECT_TAG_CHANNEL_OFFCHAIN_TX]: TX_SCHEMA_FIELD(CHANNEL_OFFCHAIN_TX, OBJECT_TAG_CHANNEL_OFFCHAIN_TX), + [OBJECT_TAG_CHANNEL]: TX_SCHEMA_FIELD(CHANNEL_TX, OBJECT_TAG_CHANNEL), + [OBJECT_TAG_CHANNEL_SNAPSHOT_SOLO_TX]: TX_SCHEMA_FIELD(CHANNEL_SNAPSHOT_SOLO_TX, OBJECT_TAG_CHANNEL_SNAPSHOT_SOLO_TX), + [OBJECT_TAG_CHANNEL_OFFCHAIN_UPDATE_TRANSFER_TX]: TX_SCHEMA_FIELD(CHANNEL_OFFCHAIN_UPDATE_TRANSFER_TX, OBJECT_TAG_CHANNEL_OFFCHAIN_UPDATE_TRANSFER_TX), + [OBJECT_TAG_CHANNEL_OFFCHAIN_UPDATE_DEPOSIT_TX]: TX_SCHEMA_FIELD(CHANNEL_OFFCHAIN_UPDATE_DEPOSIT_TX, OBJECT_TAG_CHANNEL_OFFCHAIN_UPDATE_DEPOSIT_TX), + [OBJECT_TAG_CHANNEL_OFFCHAIN_UPDATE_WITHDRAWAL_TX]: TX_SCHEMA_FIELD(CHANNEL_OFFCHAIN_UPDATE_WITHDRAWAL_TX, OBJECT_TAG_CHANNEL_OFFCHAIN_UPDATE_WITHDRAWAL_TX), [OBJECT_TAG_CHANNEL_OFFCHAIN_CREATE_CONTRACT_TX]: TX_SCHEMA_FIELD(CHANNEL_OFFCHAIN_CREATE_CONTRACT_TX, OBJECT_TAG_CHANNEL_OFFCHAIN_CREATE_CONTRACT_TX), - [OBJECT_TAG_CHANNEL_OFFCHAIN_CALL_CONTRACT_TX]: TX_SCHEMA_FIELD(CHANNEL_OFFCHAIN_CALL_CONTRACT_TX, OBJECT_TAG_CHANNEL_OFFCHAIN_CALL_CONTRACT_TX) + [OBJECT_TAG_CHANNEL_OFFCHAIN_CALL_CONTRACT_TX]: TX_SCHEMA_FIELD(CHANNEL_OFFCHAIN_CALL_CONTRACT_TX, OBJECT_TAG_CHANNEL_OFFCHAIN_CALL_CONTRACT_TX), + [OBJECT_TAG_PROOF_OF_INCLUSION]: TX_SCHEMA_FIELD(PROOF_OF_INCLUSION_TX, OBJECT_TAG_PROOF_OF_INCLUSION), + [OBJECT_TAG_STATE_TREES]: TX_SCHEMA_FIELD(STATE_TREES_TX, OBJECT_TAG_STATE_TREES), + [OBJECT_TAG_MERKLE_PATRICIA_TREE]: TX_SCHEMA_FIELD(MERKLE_PATRICIA_TREE_TX, OBJECT_TAG_MERKLE_PATRICIA_TREE), + [OBJECT_TAG_MERKLE_PATRICIA_TREE_VALUE]: TX_SCHEMA_FIELD(MERKLE_PATRICIA_TREE_VALUE_TX, OBJECT_TAG_MERKLE_PATRICIA_TREE_VALUE), + [OBJECT_TAG_CONTRACTS_TREE]: TX_SCHEMA_FIELD(CONTRACTS_TREE_TX, OBJECT_TAG_CONTRACTS_TREE), + [OBJECT_TAG_CONTRACT_CALLS_TREE]: TX_SCHEMA_FIELD(CONTRACT_CALLS_TREE_TX, OBJECT_TAG_CONTRACT_CALLS_TREE), + [OBJECT_TAG_CHANNELS_TREE]: TX_SCHEMA_FIELD(CHANNELS_TREE_TX, OBJECT_TAG_CHANNELS_TREE), + [OBJECT_TAG_NAMESERVICE_TREE]: TX_SCHEMA_FIELD(NAMESERVICE_TREE_TX, OBJECT_TAG_NAMESERVICE_TREE), + [OBJECT_TAG_ORACLES_TREE]: TX_SCHEMA_FIELD(ORACLES_TREE_TX, OBJECT_TAG_ORACLES_TREE), + [OBJECT_TAG_ACCOUNTS_TREE]: TX_SCHEMA_FIELD(ACCOUNTS_TREE_TX, OBJECT_TAG_ACCOUNTS_TREE) } // VERIFICATION SCHEMA diff --git a/es/tx/tx.js b/es/tx/tx.js index db998838e8..c2073e8212 100644 --- a/es/tx/tx.js +++ b/es/tx/tx.js @@ -245,6 +245,116 @@ async function oracleRespondTx ({ oracleId, callerId, responseTtl, queryId, resp return tx } +async function channelCloseSoloTx ({ channelId, fromId, payload, poi }) { + // Calculate fee, get absolute ttl (ttl + height), get account nonce + const { fee, ttl, nonce } = await this.prepareTxParams(TX_TYPE.channelCloseSolo, { senderId: fromId, ...R.head(arguments), payload }) + + // Build transaction using sdk (if nativeMode) or build on `AETERNITY NODE` side + const { tx } = this.nativeMode + ? buildTx(R.merge(R.head(arguments), { + channelId, + fromId, + payload, + poi, + ttl, + fee, + nonce + }), TX_TYPE.channelCloseSolo) + : await this.api.postChannelCloseSolo(R.merge(R.head(arguments), { + channelId, + fromId, + payload, + poi, + ttl, + fee: parseInt(fee), + nonce + })) + + return tx +} + +async function channelSlashTx ({ channelId, fromId, payload, poi }) { + // Calculate fee, get absolute ttl (ttl + height), get account nonce + const { fee, ttl, nonce } = await this.prepareTxParams(TX_TYPE.channelSlash, { senderId: fromId, ...R.head(arguments), payload }) + + // Build transaction using sdk (if nativeMode) or build on `AETERNITY NODE` side + const { tx } = this.nativeMode + ? buildTx(R.merge(R.head(arguments), { + channelId, + fromId, + payload, + poi, + ttl, + fee, + nonce + }), TX_TYPE.channelSlash) + : await this.api.postChannelSlash(R.merge(R.head(arguments), { + channelId, + fromId, + payload, + poi, + ttl, + fee: parseInt(fee), + nonce + })) + + return tx +} + +async function channelSettleTx ({ channelId, fromId, initiatorAmountFinal, responderAmountFinal }) { + // Calculate fee, get absolute ttl (ttl + height), get account nonce + const { fee, ttl, nonce } = await this.prepareTxParams(TX_TYPE.channelSettle, { senderId: fromId, ...R.head(arguments) }) + + // Build transaction using sdk (if nativeMode) or build on `AETERNITY NODE` side + const { tx } = this.nativeMode + ? buildTx(R.merge(R.head(arguments), { + channelId, + fromId, + initiatorAmountFinal, + responderAmountFinal, + ttl, + fee, + nonce + }), TX_TYPE.channelSettle) + : await this.api.postChannelSettle(R.merge(R.head(arguments), { + channelId, + fromId, + initiatorAmountFinal: parseInt(initiatorAmountFinal), + responderAmountFinal: parseInt(responderAmountFinal), + ttl, + fee: parseInt(fee), + nonce + })) + + return tx +} + +async function channelSnapshotSoloTx ({ channelId, fromId, payload }) { + // Calculate fee, get absolute ttl (ttl + height), get account nonce + const { fee, ttl, nonce } = await this.prepareTxParams(TX_TYPE.channelSnapshotSolo, { senderId: fromId, ...R.head(arguments), payload }) + + // Build transaction using sdk (if nativeMode) or build on `AETERNITY NODE` side + const { tx } = this.nativeMode + ? buildTx(R.merge(R.head(arguments), { + channelId, + fromId, + payload, + ttl, + fee, + nonce + }), TX_TYPE.channelSnapshotSolo) + : await this.api.postChannelSnapshotSolo(R.merge(R.head(arguments), { + channelId, + fromId, + payload, + ttl, + fee: parseInt(fee), + nonce + })) + + return tx +} + /** * Compute the absolute ttl by adding the ttl to the current height of the chain * @@ -334,6 +444,10 @@ const Transaction = Node.compose(Tx, { oracleExtendTx, oraclePostQueryTx, oracleRespondTx, + channelCloseSoloTx, + channelSlashTx, + channelSettleTx, + channelSnapshotSoloTx, getAccountNonce } }) diff --git a/es/utils/mptree.js b/es/utils/mptree.js new file mode 100644 index 0000000000..97de0f8b7e --- /dev/null +++ b/es/utils/mptree.js @@ -0,0 +1,146 @@ +/* + * ISC License (ISC) + * Copyright (c) 2018 aeternity developers + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +import { rlp, hash } from './crypto' + +const NODE_TYPES = { + branch: 1, + extension: 2, + leaf: 3 +} + +function nodeType (node) { + if (node.length === 17) { + return NODE_TYPES.branch + } + if (node.length === 2) { + const nibble = node[0].toString('hex')[0] + if (nibble === '0' || nibble === '1') { + return NODE_TYPES.extension + } + if (nibble === '2' || nibble === '3') { + return NODE_TYPES.leaf + } + } +} + +function decodePath (path) { + if (path[0] === '0' || path[0] === '2') { + return path.slice(2) + } + if (path[0] === '1' || path[0] === '3') { + return path.slice(1) + } +} + +/** + * Deserialize Merkle Patricia Tree + * @rtype (binary: Array) => Object + * @param {Array} binary - Binary + * @return {Object} Merkle Patricia Tree + */ +export function deserialize (binary) { + return { + rootHash: binary[0].toString('hex'), + nodes: binary[1].reduce((prev, node) => ({ + ...prev, + [node[0].toString('hex')]: node[1] + }), {}) + } +} + +/** + * Serialize Merkle Patricia Tree + * @rtype (tree: Object) => Array + * @param {Object} tree - Merkle Patricia Tree + * @return {Array} Binary + */ +export function serialize (tree) { + return [ + Buffer.from(tree.rootHash, 'hex'), + Object.entries(tree.nodes).map(([mptHash, value]) => ([ + Buffer.from(mptHash, 'hex'), + value + ])) + ] +} + +/** + * Retrieve value from Merkle Patricia Tree + * @rtype (tree: Object, key: String) => Buffer + * @param {Object} tree - Merkle Patricia Tree + * @param {String} key - The key of the element to retrieve + * @return {Buffer} Value associated to the specified key + */ +export function get (tree, key, hash) { + const node = hash ? tree.nodes[hash] : tree.nodes[tree.rootHash] + const type = nodeType(node) + if (type === NODE_TYPES.branch) { + if (key.length) { + const nextHash = node[parseInt(key[0], 16)].toString('hex') + return get(tree, key.substr(1), nextHash) + } + return node[16] + } + if (type === NODE_TYPES.extension) { + const path = decodePath(node[0].toString('hex')) + if (key.substr(0, path.length) === path) { + return get(tree, key.substr(path.length), node[1].toString('hex')) + } + } + if (type === NODE_TYPES.leaf) { + if (node[0].toString('hex').substr(1) === key) { + return node[1] + } + } +} + +function nodeHash (node) { + return Buffer.from(hash(rlp.encode(node))).toString('hex') +} + +/** + * Verify if rootHash of Merkle Patricia Tree is correct + * @rtype (tree: Object) => Boolean + * @param {Object} tree - Merkle Patricia Tree + * @return {Boolean} Boolean indicating whether or not rootHash is correct + */ +export function verify (tree, key, verified = []) { + const hash = key || tree.rootHash + if (verified.includes(hash)) { + return true + } + const node = tree.nodes[hash] + const type = nodeType(node) + if (nodeHash(node) !== hash) { + return false + } + verified.push(hash) + if (type === NODE_TYPES.branch) { + return !node.some((n, i) => { + const nextKey = n.toString('hex') + if (i < 16) { + return !verify(tree, nextKey, verified) + } + return false + }) + } + if (type === NODE_TYPES.extension) { + return verify(tree, node[1].toString('hex'), verified) + } + return true +} diff --git a/test/integration/channel.js b/test/integration/channel.js index 62d25e4814..f787cbc759 100644 --- a/test/integration/channel.js +++ b/test/integration/channel.js @@ -17,9 +17,11 @@ import { describe, it, before } from 'mocha' import * as sinon from 'sinon' +import { BigNumber } from 'bignumber.js' import { configure, ready, plan, BaseAe, networkId } from './' import { generateKeyPair } from '../../es/utils/crypto' -import { unpackTx } from '../../es/tx/builder' +import { unpackTx, buildTx } from '../../es/tx/builder' +import { decode } from '../../es/tx/builder/helpers' import Channel from '../../es/channel' const wsUrl = process.env.WS_URL || 'ws://node:3014' @@ -71,7 +73,7 @@ describe('Channel', function () { ttl: 10000, host: 'localhost', port: 3001, - lockPeriod: 10 + lockPeriod: 1 } before(async function () { @@ -108,35 +110,77 @@ describe('Channel', function () { sinon.assert.calledWithExactly(initiatorSign, sinon.match('initiator_sign'), sinon.match.string) sinon.assert.calledOnce(responderSign) sinon.assert.calledWithExactly(responderSign, sinon.match('responder_sign'), sinon.match.string) + const expectedTxParams = { + initiator: await initiator.address(), + responder: await responder.address(), + initiatorAmount: sharedParams.initiatorAmount.toString(), + responderAmount: sharedParams.responderAmount.toString(), + channelReserve: sharedParams.channelReserve.toString(), + // TODO: investigate why ttl is "0" + // ttl: sharedParams.ttl.toString(), + lockPeriod: sharedParams.lockPeriod.toString() + } + const { txType: initiatorTxType, tx: initiatorTx } = unpackTx(initiatorSign.firstCall.args[1]) + const { txType: responderTxType, tx: responderTx } = unpackTx(responderSign.firstCall.args[1]) + initiatorTxType.should.equal('channelCreate') + initiatorTx.should.eql({ ...initiatorTx, ...expectedTxParams }) + responderTxType.should.equal('channelCreate') + responderTx.should.eql({ ...responderTx, ...expectedTxParams }) }) it('can post update and accept', async () => { responderShouldRejectUpdate = false + const sign = sinon.spy(initiator.signTransaction.bind(initiator)) + const amount = 1 const result = await initiatorCh.update( await initiator.address(), await responder.address(), - 1, - async (tx) => await initiator.signTransaction(tx) + amount, + sign ) result.accepted.should.equal(true) result.signedTx.should.be.a('string') sinon.assert.notCalled(initiatorSign) sinon.assert.calledOnce(responderSign) sinon.assert.calledWithExactly(responderSign, sinon.match('update_ack'), sinon.match.string) + sinon.assert.calledOnce(sign) + sinon.assert.calledWithExactly(sign, sinon.match.string) + const { txType, tx: { updates } } = unpackTx(sign.firstCall.args[0]) + txType.should.equal('channelOffChain') + updates[0].txType.should.equal('channelOffChainUpdateTransfer') + updates[0].tx.should.eql({ + ...updates[0].tx, + from: await initiator.address(), + to: await responder.address(), + amount: amount.toString() + }) }) it('can post update and reject', async () => { responderShouldRejectUpdate = true + const sign = sinon.spy(initiator.signTransaction.bind(initiator)) + const amount = 1 const result = await initiatorCh.update( await responder.address(), await initiator.address(), - 1, - async (tx) => await initiator.signTransaction(tx) + amount, + sign ) result.accepted.should.equal(false) sinon.assert.notCalled(initiatorSign) sinon.assert.calledOnce(responderSign) sinon.assert.calledWithExactly(responderSign, sinon.match('update_ack'), sinon.match.string) + sinon.assert.calledOnce(sign) + sinon.assert.calledWithExactly(sign, sinon.match.string) + const { txType, tx: { updates } } = unpackTx(sign.firstCall.args[0]) + txType.should.equal('channelOffChain') + updates[0].txType.should.equal('channelOffChainUpdateTransfer') + updates[0].tx.should.eql({ + ...updates[0].tx, + from: await responder.address(), + to: await initiator.address(), + amount: amount.toString() + }) }) it('can get proof of inclusion', async () => { @@ -147,6 +191,10 @@ describe('Channel', function () { const responderPoi = await responderCh.poi(params) initiatorPoi.should.be.a('string') responderPoi.should.be.a('string') + const unpackedInitiatorPoi = unpackTx(decode(initiatorPoi, 'pi'), true) + const unpackedResponderPoi = unpackTx(decode(responderPoi, 'pi'), true) + buildTx(unpackedInitiatorPoi.tx, unpackedInitiatorPoi.txType, { prefix: 'pi' }).tx.should.equal(initiatorPoi) + buildTx(unpackedResponderPoi.tx, unpackedResponderPoi.txType, { prefix: 'pi' }).tx.should.equal(responderPoi) }) it('can get balances', async () => { @@ -179,13 +227,15 @@ describe('Channel', function () { }) it('can request a withdraw and accept', async () => { + const sign = sinon.spy(initiator.signTransaction.bind(initiator)) + const amount = 2 const onOnChainTx = sinon.spy() const onOwnWithdrawLocked = sinon.spy() const onWithdrawLocked = sinon.spy() responderShouldRejectUpdate = false const result = await initiatorCh.withdraw( - 2, - async (tx) => initiator.signTransaction(tx), + amount, + sign, { onOnChainTx, onOwnWithdrawLocked, onWithdrawLocked } ) result.should.eql({ accepted: true, signedTx: (await initiatorCh.state()).signedTx }) @@ -196,16 +246,27 @@ describe('Channel', function () { sinon.assert.notCalled(initiatorSign) sinon.assert.calledOnce(responderSign) sinon.assert.calledWithExactly(responderSign, sinon.match('withdraw_ack'), sinon.match.string) + sinon.assert.calledOnce(sign) + sinon.assert.calledWithExactly(sign, sinon.match.string) + const { txType, tx } = unpackTx(sign.firstCall.args[0]) + txType.should.equal('channelWithdraw') + tx.should.eql({ + ...tx, + toId: await initiator.address(), + amount: amount.toString() + }) }) it('can request a withdraw and reject', async () => { + const sign = sinon.spy(initiator.signTransaction.bind(initiator)) + const amount = 2 const onOnChainTx = sinon.spy() const onOwnWithdrawLocked = sinon.spy() const onWithdrawLocked = sinon.spy() responderShouldRejectUpdate = true const result = await initiatorCh.withdraw( - 2, - async (tx) => initiator.signTransaction(tx), + amount, + sign, { onOnChainTx, onOwnWithdrawLocked, onWithdrawLocked } ) result.should.eql({ accepted: false }) @@ -215,16 +276,27 @@ describe('Channel', function () { sinon.assert.notCalled(initiatorSign) sinon.assert.calledOnce(responderSign) sinon.assert.calledWithExactly(responderSign, sinon.match('withdraw_ack'), sinon.match.string) + sinon.assert.calledOnce(sign) + sinon.assert.calledWithExactly(sign, sinon.match.string) + const { txType, tx } = unpackTx(sign.firstCall.args[0]) + txType.should.equal('channelWithdraw') + tx.should.eql({ + ...tx, + toId: await initiator.address(), + amount: amount.toString() + }) }) it('can request a deposit and accept', async () => { + const sign = sinon.spy(initiator.signTransaction.bind(initiator)) + const amount = 2 const onOnChainTx = sinon.spy() const onOwnDepositLocked = sinon.spy() const onDepositLocked = sinon.spy() responderShouldRejectUpdate = false const result = await initiatorCh.deposit( - 2, - async (tx) => initiator.signTransaction(tx), + amount, + sign, { onOnChainTx, onOwnDepositLocked, onDepositLocked } ) result.should.eql({ accepted: true, signedTx: (await initiatorCh.state()).signedTx }) @@ -235,16 +307,27 @@ describe('Channel', function () { sinon.assert.notCalled(initiatorSign) sinon.assert.calledOnce(responderSign) sinon.assert.calledWithExactly(responderSign, sinon.match('deposit_ack'), sinon.match.string) + sinon.assert.calledOnce(sign) + sinon.assert.calledWithExactly(sign, sinon.match.string) + const { txType, tx } = unpackTx(sign.firstCall.args[0]) + txType.should.equal('channelDeposit') + tx.should.eql({ + ...tx, + fromId: await initiator.address(), + amount: amount.toString() + }) }) it('can request a deposit and reject', async () => { + const sign = sinon.spy(initiator.signTransaction.bind(initiator)) + const amount = 2 const onOnChainTx = sinon.spy() const onOwnDepositLocked = sinon.spy() const onDepositLocked = sinon.spy() responderShouldRejectUpdate = true const result = await initiatorCh.deposit( - 2, - async (tx) => initiator.signTransaction(tx), + amount, + sign, { onOnChainTx, onOwnDepositLocked, onDepositLocked } ) result.should.eql({ accepted: false }) @@ -254,14 +337,31 @@ describe('Channel', function () { sinon.assert.notCalled(initiatorSign) sinon.assert.calledOnce(responderSign) sinon.assert.calledWithExactly(responderSign, sinon.match('deposit_ack'), sinon.match.string) + const { txType, tx } = unpackTx(sign.firstCall.args[0]) + txType.should.equal('channelDeposit') + tx.should.eql({ + ...tx, + fromId: await initiator.address(), + amount: amount.toString() + }) }) it('can close a channel', async () => { - const tx = await initiatorCh.shutdown(async (tx) => await initiator.signTransaction(tx)) - tx.should.be.a('string') + const sign = sinon.spy(initiator.signTransaction.bind(initiator)) + const result = await initiatorCh.shutdown(sign) + result.should.be.a('string') sinon.assert.notCalled(initiatorSign) sinon.assert.calledOnce(responderSign) sinon.assert.calledWithExactly(responderSign, sinon.match('shutdown_sign_ack'), sinon.match.string) + sinon.assert.calledOnce(sign) + sinon.assert.calledWithExactly(sign, sinon.match.string) + const { txType, tx } = unpackTx(sign.firstCall.args[0]) + txType.should.equal('channelCloseMutual') + tx.should.eql({ + ...tx, + fromId: await initiator.address(), + // TODO: check `initiatorAmountFinal` and `responderAmountFinal` + }) }) it('can leave a channel', async () => { @@ -287,6 +387,7 @@ describe('Channel', function () { initiatorCh = await Channel({ ...sharedParams, role: 'initiator', + port: 3002, existingChannelId, offchainTx, sign: initiatorSign @@ -294,6 +395,7 @@ describe('Channel', function () { responderCh = await Channel({ ...sharedParams, role: 'responder', + port: 3002, existingChannelId, offchainTx, sign: responderSign @@ -304,7 +406,7 @@ describe('Channel', function () { await initiatorCh.leave() }) - it('can create a contract and accept', async () => { + it('can solo close a channel', async () => { initiatorCh = await Channel({ ...sharedParams, role: 'initiator', @@ -318,6 +420,124 @@ describe('Channel', function () { sign: responderSign }) await Promise.all([waitForChannel(initiatorCh), waitForChannel(responderCh)]) + + const initiatorAddr = await initiator.address() + const responderAddr = await responder.address() + const { signedTx } = await initiatorCh.update( + await initiator.address(), + await responder.address(), + 100, + tx => initiator.signTransaction(tx) + ) + const poi = await initiatorCh.poi({ + accounts: [initiatorAddr, responderAddr], + }) + const balances = await initiatorCh.balances([initiatorAddr, responderAddr]) + const initiatorBalanceBeforeClose = await initiator.balance(initiatorAddr) + const responderBalanceBeforeClose = await responder.balance(responderAddr) + const closeSoloTx = await initiator.channelCloseSoloTx({ + channelId: await initiatorCh.id(), + fromId: initiatorAddr, + poi, + payload: signedTx + }) + const closeSoloTxFee = unpackTx(closeSoloTx).tx.fee + await initiator.sendTransaction(await initiator.signTransaction(closeSoloTx), { waitMined: true }) + const settleTx = await initiator.channelSettleTx({ + channelId: await initiatorCh.id(), + fromId: initiatorAddr, + initiatorAmountFinal: balances[initiatorAddr], + responderAmountFinal: balances[responderAddr] + }) + const settleTxFee = unpackTx(settleTx).tx.fee + await initiator.sendTransaction(await initiator.signTransaction(settleTx), { waitMined: true }) + const initiatorBalanceAfterClose = await initiator.balance(initiatorAddr) + const responderBalanceAfterClose = await responder.balance(responderAddr) + new BigNumber(initiatorBalanceAfterClose).minus(initiatorBalanceBeforeClose).plus(closeSoloTxFee).plus(settleTxFee).isEqualTo( + new BigNumber(balances[initiatorAddr]) + ).should.be.equal(true) + new BigNumber(responderBalanceAfterClose).minus(responderBalanceBeforeClose).isEqualTo( + new BigNumber(balances[responderAddr]) + ).should.be.equal(true) + }) + + it('can dispute via slash tx', async () => { + const initiatorAddr = await initiator.address() + const responderAddr = await responder.address() + initiatorCh = await Channel({ + ...sharedParams, + lockPeriod: 5, + role: 'initiator', + sign: initiatorSign, + port: 3004 + }) + responderCh = await Channel({ + ...sharedParams, + lockPeriod: 5, + role: 'responder', + sign: responderSign, + port: 3004 + }) + await Promise.all([waitForChannel(initiatorCh), waitForChannel(responderCh)]) + const initiatorBalanceBeforeClose = await initiator.balance(initiatorAddr) + const responderBalanceBeforeClose = await responder.balance(responderAddr) + const oldUpdate = await initiatorCh.update(initiatorAddr, responderAddr, 100, (tx) => initiator.signTransaction(tx)) + const oldPoi = await initiatorCh.poi({ + accounts: [initiatorAddr, responderAddr] + }) + const recentUpdate = await initiatorCh.update(initiatorAddr, responderAddr, 100, (tx) => initiator.signTransaction(tx)) + const recentPoi = await responderCh.poi({ + accounts: [initiatorAddr, responderAddr] + }) + const recentBalances = await responderCh.balances([initiatorAddr, responderAddr]) + const closeSoloTx = await initiator.channelCloseSoloTx({ + channelId: initiatorCh.id(), + fromId: initiatorAddr, + poi: oldPoi, + payload: oldUpdate.signedTx + }) + const closeSoloTxFee = unpackTx(closeSoloTx).tx.fee + await initiator.sendTransaction(await initiator.signTransaction(closeSoloTx), { waitMined: true }) + const slashTx = await responder.channelSlashTx({ + channelId: responderCh.id(), + fromId: responderAddr, + poi: recentPoi, + payload: recentUpdate.signedTx + }) + const slashTxFee = unpackTx(slashTx).tx.fee + await responder.sendTransaction(await responder.signTransaction(slashTx), { waitMined: true }) + const settleTx = await responder.channelSettleTx({ + channelId: responderCh.id(), + fromId: responderAddr, + initiatorAmountFinal: recentBalances[initiatorAddr], + responderAmountFinal: recentBalances[responderAddr] + }) + const settleTxFee = unpackTx(settleTx).tx.fee + await responder.sendTransaction(await responder.signTransaction(settleTx), { waitMined: true }) + const initiatorBalanceAfterClose = await initiator.balance(initiatorAddr) + const responderBalanceAfterClose = await responder.balance(responderAddr) + new BigNumber(initiatorBalanceAfterClose).minus(initiatorBalanceBeforeClose).plus(closeSoloTxFee).isEqualTo( + new BigNumber(recentBalances[initiatorAddr]) + ).should.be.equal(true) + new BigNumber(responderBalanceAfterClose).minus(responderBalanceBeforeClose).plus(slashTxFee).plus(settleTxFee).isEqualTo( + new BigNumber(recentBalances[responderAddr]) + ).should.be.equal(true) + }) + + it('can create a contract and accept', async () => { + initiatorCh = await Channel({ + ...sharedParams, + role: 'initiator', + port: 3005, + sign: initiatorSign + }) + responderCh = await Channel({ + ...sharedParams, + role: 'responder', + port: 3005, + sign: responderSign + }) + await Promise.all([waitForChannel(initiatorCh), waitForChannel(responderCh)]) const code = await initiator.compileContractAPI(identityContract) const callData = await initiator.contractEncodeCallDataAPI(identityContract, 'init', []) const result = await initiatorCh.createContract({ @@ -368,16 +588,15 @@ describe('Channel', function () { result.should.eql({ accepted: false }) }) - it('can call a contract using dry-run', async () => { - const result = await initiatorCh.callContractStatic({ - amount: 0, - callData: await contractEncodeCall('main', ['42']), + it('can get contract call', async () => { + const result = await initiatorCh.getContractCall({ + caller: await initiator.address(), contract: contractAddress, - abiVersion: 1 + round: callerNonce }) result.should.eql({ callerId: await initiator.address(), - callerNonce: result.callerNonce, + callerNonce, contractId: contractAddress, gasPrice: result.gasPrice, gasUsed: result.gasUsed, @@ -390,15 +609,16 @@ describe('Channel', function () { value.should.eql({ type: 'word', value: 42 }) }) - it('can get contract call', async () => { - const result = await initiatorCh.getContractCall({ - caller: await initiator.address(), + it('can call a contract using dry-run', async () => { + const result = await initiatorCh.callContractStatic({ + amount: 0, + callData: await contractEncodeCall('main', ['42']), contract: contractAddress, - round: callerNonce + abiVersion: 1 }) result.should.eql({ callerId: await initiator.address(), - callerNonce, + callerNonce: result.callerNonce, contractId: contractAddress, gasPrice: result.gasPrice, gasUsed: result.gasUsed, @@ -410,7 +630,7 @@ describe('Channel', function () { const value = await initiator.contractDecodeDataAPI('int', result.returnValue) value.should.eql({ type: 'word', value: 42 }) }) - + it('can get contract state', async () => { const result = await initiatorCh.getContractState(contractAddress) result.should.eql({ @@ -428,7 +648,32 @@ describe('Channel', function () { // TODO: contractState deserialization }) + it('can post snapshot solo transaction', async () => { + const snapshotSoloTx = await initiator.channelSnapshotSoloTx({ + channelId: initiatorCh.id(), + fromId: await initiator.address(), + payload: (await initiatorCh.state()).signedTx + }) + await initiator.sendTransaction(await initiator.signTransaction(snapshotSoloTx), { waitMined: true }) + }) + describe('throws errors', function () { + before(async function () { + initiatorCh = await Channel({ + ...sharedParams, + role: 'initiator', + port: 3006, + sign: initiatorSign + }) + responderCh = await Channel({ + ...sharedParams, + role: 'responder', + port: 3006, + sign: responderSign + }) + await Promise.all([waitForChannel(initiatorCh), waitForChannel(responderCh)]) + }) + async function update ({ from, to, amount, sign }) { return initiatorCh.update( from || await initiator.address(), diff --git a/test/unit/mptree.js b/test/unit/mptree.js new file mode 100644 index 0000000000..0c7879a40c --- /dev/null +++ b/test/unit/mptree.js @@ -0,0 +1,55 @@ +/* + * ISC License (ISC) + * Copyright (c) 2018 aeternity developers + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +import '../' +import { describe, it } from 'mocha' +import { rlp } from '../../es/utils/crypto' +import { serialize, deserialize, get, verify } from '../../es/utils/mptree' + +describe('Merkle Patricia Tree', function () { + const binary = Buffer.from('f9013ea0d4b40fbf270d982d9c9bebc8acd6711db9a2465459f1cb67450f495e3a78f5d2f9011af850a0056232c6f764553f472dacd7bba764e4d630adce971e4437dcf07421e20d6cf3eea03e2e29b62366a6b1e363ebf174fce8e4d9ad61abdc2dde65e3f74923dcd629c48ccb0a010087038d7ea4c67ffcf850a065657db43209ef7d57acb7aaf2e2c38f8828f9d425e4bec0d7de5bfa26496c61eea03269a8e17fffe495df7b47bf0ffb94897e1060baf3192e99978d91010325b62d8ccb0a010087038d7ea4c68004f874a0d4b40fbf270d982d9c9bebc8acd6711db9a2465459f1cb67450f495e3a78f5d2f85180a065657db43209ef7d57acb7aaf2e2c38f8828f9d425e4bec0d7de5bfa26496c618080a0056232c6f764553f472dacd7bba764e4d630adce971e4437dcf07421e20d6cf3808080808080808080808080', 'hex') + const map = { + '4e2e29b62366a6b1e363ebf174fce8e4d9ad61abdc2dde65e3f74923dcd629c4': 'cb0a010087038d7ea4c67ffc', + '1269a8e17fffe495df7b47bf0ffb94897e1060baf3192e99978d91010325b62d': 'cb0a010087038d7ea4c68004' + } + + it('can deserialize', () => { + const tree = deserialize(rlp.decode(binary)) + tree.should.be.an('object') + tree.rootHash.should.be.a('string') + tree.nodes.should.be.an('object') + }) + + it('can serialize', () => { + const serialized = rlp.encode(serialize(deserialize(rlp.decode(binary)))) + serialized.toString('hex').should.equal(binary.toString('hex')) + }) + + it('can retrieve values', () => { + const tree = deserialize(rlp.decode(binary)) + Object.entries(map).forEach(([key, value]) => { + get(tree, key).toString('hex').should.equal(value) + }) + }) + + it('can verify root hash', () => { + const tree = deserialize(rlp.decode(binary)) + verify(tree).should.equal(true) + tree.nodes['65657db43209ef7d57acb7aaf2e2c38f8828f9d425e4bec0d7de5bfa26496c61'][1][3] = 13 + verify(tree).should.equal(false) + }) +}) From 778159aa4cc2b3ee237312fdc7cc4954f69bee29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Powaga?= Date: Tue, 16 Apr 2019 16:18:53 +0100 Subject: [PATCH 06/16] feat(State Channels): Add cleanContractCalls method (#338) * feat(State Channels): Add cleanContractCalls method * force Jenkins * Add documentation for cleanContractCalls method --- .env | 1 + es/channel/handlers.js | 9 ++++++++ es/channel/index.js | 41 +++++++++++++++++++++++++++++-------- es/channel/internal.js | 12 ++++++++--- test/integration/channel.js | 11 +++++++++- 5 files changed, 62 insertions(+), 12 deletions(-) diff --git a/.env b/.env index 81096ddd67..45221a325a 100644 --- a/.env +++ b/.env @@ -1,2 +1,3 @@ TAG=v2.2.0 COMPILER_TAG=v2.1.0 + diff --git a/es/channel/handlers.js b/es/channel/handlers.js index 1d43dcd699..110d238783 100644 --- a/es/channel/handlers.js +++ b/es/channel/handlers.js @@ -361,6 +361,15 @@ export function awaitingCallContractCompletion (channel, message, state) { } } +export function awaitingCallsPruned (channels, message, state) { + if (message.method === 'channels.calls_pruned.reply') { + state.resolve() + return { handler: channelOpen } + } + state.reject(new Error('Unexpected message received')) + return { handler: channelClosed } +} + export function channelClosed (channel, message, state) { return { handler: channelClosed } } diff --git a/es/channel/index.js b/es/channel/index.js index ba1e9cb989..e42e0f0ff3 100644 --- a/es/channel/index.js +++ b/es/channel/index.js @@ -451,13 +451,7 @@ async function callContractStatic ({ amount, callData, contract, abiVersion }) { * }) */ async function getContractCall ({ caller, contract, round }) { - const result = await call(this, 'channels.get.contract_call', { caller, contract, round }) - return R.fromPairs( - R.map( - ([key, value]) => ([snakeToPascal(key), value]), - R.toPairs(result) - ) - ) + return snakeToPascalObjKeys(await call(this, 'channels.get.contract_call', { caller, contract, round })) } /** @@ -479,6 +473,36 @@ async function getContractState (contract) { }) } +/** + * Clean up all locally stored contract calls + * + * Contract calls are kept locally in order for the participant to be able to look them up. + * They consume memory and in order for the participant to free it - one can prune all messages. + * This cleans up all locally stored contract calls and those will no longer be available for + * fetching and inspection. + * + * @return {Promise} + */ +function cleanContractCalls () { + return new Promise((resolve, reject) => { + enqueueAction( + this, + (channel, state) => state.handler === handlers.channelOpen, + (channel, state) => { + send(channel, { + jsonrpc: '2.0', + method: 'channels.clean_contract_calls', + params: {} + }) + return { + handler: handlers.awaitingCallsPruned, + state: { resolve, reject } + } + } + ) + }) +} + /** * Send generic message * @@ -569,7 +593,8 @@ const Channel = AsyncInit.compose({ callContract, callContractStatic, getContractCall, - getContractState + getContractState, + cleanContractCalls } }) diff --git a/es/channel/internal.js b/es/channel/internal.js index aaa710b755..38ddac3719 100644 --- a/es/channel/internal.js +++ b/es/channel/internal.js @@ -124,8 +124,6 @@ function onMessage (channel, data) { const callback = rpcCallbacks.get(channel).get(message.id) try { callback(message) - } catch (error) { - emit(channel, 'error', error) } finally { rpcCallbacks.get(channel).delete(message.id) } @@ -137,12 +135,20 @@ function onMessage (channel, data) { } } +function wrapCallErrorMessage (message) { + const [{ message: details } = {}] = message.error.data || [] + if (details) { + return Error(`${message.error.message}: ${details}`) + } + return Error(message.error.message) +} + function call (channel, method, params) { return new Promise((resolve, reject) => { const id = sequence.set(channel, sequence.get(channel) + 1).get(channel) rpcCallbacks.get(channel).set(id, (message) => { if (message.result) return resolve(message.result) - if (message.error) return reject(new Error(message.error.message)) + if (message.error) return reject(wrapCallErrorMessage(message)) }) send(channel, { jsonrpc: '2.0', method, id, params }) }) diff --git a/test/integration/channel.js b/test/integration/channel.js index f787cbc759..627566a72c 100644 --- a/test/integration/channel.js +++ b/test/integration/channel.js @@ -630,7 +630,16 @@ describe('Channel', function () { const value = await initiator.contractDecodeDataAPI('int', result.returnValue) value.should.eql({ type: 'word', value: 42 }) }) - + + it('can clean contract calls', async () => { + await initiatorCh.cleanContractCalls() + initiatorCh.getContractCall({ + caller: await initiator.address(), + contract: contractAddress, + round: callerNonce + }).should.eventually.be.rejectedWith('Rejected: Call not found') + }) + it('can get contract state', async () => { const result = await initiatorCh.getContractState(contractAddress) result.should.eql({ From 9e4221791648fc459749f2c9e7ee38067a50e532 Mon Sep 17 00:00:00 2001 From: nduchak Date: Tue, 16 Apr 2019 18:20:01 +0300 Subject: [PATCH 07/16] chore(bump version in package): --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5e4356d9ef..0f60bff7ac 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@aeternity/aepp-sdk", - "version": "2.4.1", + "version": "3.0.0", "description": "SDK for the æternity blockchain", "main": "dist/aepp-sdk.js", "browser": "dist/aepp-sdk.browser.js", From 525f5ea1a0ab933642cbf3789705e771e8d64f45 Mon Sep 17 00:00:00 2001 From: nduchak Date: Wed, 17 Apr 2019 14:54:07 +0300 Subject: [PATCH 08/16] chore(CHANGELOG): Adjust changelog to conventional changelog style --- CHANGELOG.md | 1007 +++++++++++++++++++++++++------------------------- 1 file changed, 495 insertions(+), 512 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index daa98f540c..acf01d4482 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,25 +1,42 @@ -# Change Log -All notable changes to this project will be documented in this file. This change -log follows the conventions of [keepachangelog.com](http://keepachangelog.com/). - -## [2.4.1] -### Added -- feat(ACI): Add transform decoded data for 'address' type -- feat(Aepp): Add Compiler to Aepp rpc methods. Update example app -- feat(Channel): Add call contract static support -- feat(Channel): Add get contract state support -- feat(Channel): Get full channel state support -- docs(*): Adjust ACI, Contract and Usage -### Changed -- refactor(Http): Handle no response in http stamp error handler -- fix(Crypto): Fix crypto `formatAddress` -- fix(Crypto): Move ADDRESS_FORMAT to crypto +# [3.0.0](https://github.com/aeternity/aepp-sdk-js/compare/2.4.1...3.0.0) (2019-04-17) + + +### Bug Fixes + +* **ACI:** Fix address type transformation when decoding data ([#335](https://github.com/aeternity/aepp-sdk-js/issues/335)) ([e37cdfc](https://github.com/aeternity/aepp-sdk-js/commit/e37cdfc)) + + +### Features + +* **ACI:** Update due to compiler API changes ([#331](https://github.com/aeternity/aepp-sdk-js/issues/331)) ([e047f3b](https://github.com/aeternity/aepp-sdk-js/commit/e047f3b)) +* **Aepp:** Add Compiler to Aepp rpc methods. Update example app ([#312](https://github.com/aeternity/aepp-sdk-js/issues/312)) ([9c72521](https://github.com/aeternity/aepp-sdk-js/commit/9c72521)) +* **State Channels:** Add cleanContractCalls method ([#338](https://github.com/aeternity/aepp-sdk-js/issues/338)) ([778159a](https://github.com/aeternity/aepp-sdk-js/commit/778159a)) + + + +# [2.4.1](https://github.com/aeternity/aepp-sdk-js/compare/2.4.0...2.4.1) (2019-04-17) + + +### Features + +* **ACI:** Add transform decoded data for 'address' type +* **AEPP:** Add Compiler to Aepp rpc methods. Update example app +* **Channel:** Add call contract static support +* **Channel:** Add get contract state support +* **Channel:** Get full channel state support +* **DOCS:** Adjust ACI, Contract and Usage - ### Removed -- none - ### Breaking Changes -- State Channel: +### Bug Fixes + +* **HTTP:** Handle no response in http stamp error handler +* **Crypto:** Fix crypto `formatAddress` +* **Crypto:** Move ADDRESS_FORMAT to crypto + + +### BREAKING CHANGES + +* **Channels:** - `channel.state()` now returns offchain state instead of last co-signed offchain transaction - `channel.update(...).state` has been renamed to `signedTx` - `channel.withdraw(...).state` has been renamed to `signedTx` @@ -28,635 +45,601 @@ log follows the conventions of [keepachangelog.com](http://keepachangelog.com/). - `channel.createContract(...).state` has been renamed to `signedTx` - `channel.callContract(...).state` has been renamed to `signedTx` - ### Notes and known Issues -- none - - -## [2.4.0] -### Added -- Install and configure `commitizen` -- Add `formatAddress` function to `Crypto` -- Add Contract Compiler API stamp to `es/contract` (now using instead contract node API) -- Add basic `http` client stamp (`es/utils/http`) -- ACI stamp (New Contract interface base on contract ACI schema) -Usage: -``` -const contractIns = await client.getContractInstance(contractSourceCode) -console.log(contract) - { - interface: String, // Contract interface source code - aci: String, // Contract interface json schema - source: String, // Contract source code - compiled: String, // Compiled contract code - deployInfo: { address: contractAddress } // Object with deploy transaction, - // Function - compile: () => this, // Compile contract, - deploy: (init = [], options = { skipArgsConvert: false }) => this, // Deploy contract (compile before if needed) - call: (fn, params = [], options = { skipArgsConvert: false, skipTransformDecoded: false, callStatic: false } => CallRersult: Object // Call contract function - } -``` -### Changed -- Extend `Account.address()` with `accountFormatter` now you can do -``` -export const ADDRESS_FORMAT = { - sophia: 1, // return address like `0xHEX_ADDRESS` - api: 2, // return address like `ak_9LJ8ne9tks78hTD2Tp571f7w2MJmzQMRsiZxKCkMA2d2Sbrc4` -} - -// - -export { ADDRESS_FORMAT } from 'es/account' -await account.address(format: ADDRESS_FORMAT) // default ADDRESS_FORMAT.api -``` -- decode node error coming from contract `call` and `callStatic` -- Throw native error instead of object in chain `chain.sendTransaction` -- fix arguments parsing in `Crypto.sing` -- Add `{ compilerUrl }` to `Universal, Contract, Wallet` stamp initialization -- Add ability to get `account/balance` on specific block `hash/height` -- Fix `name hash` function arguments parsing in `Crypto` -- Improve channel rpc usage -- Improve channel tests and error handling -- Improve state channel params handling - - ### Removed -- `ContractNodeAPI` stamp - - ### Breaking Changes -- Contract stamp API -``` -1) Use Compiler instead of node API for encode/decode call-data and compile. -2) Change Contract interface: - - contractCallStatic (address, abi = 'sophia-address', name, { top, args = '()', call, options = {} } = {}) -> (source, address, name, args = [], { top, options = {} } = {})) - - contractCall (code, abi, address, name, { args = '()', options = {}, call } = {}) -> (source, address, name, args = [], options = {}) - - contractDeploy (code, abi, { initState = '()', options = {} } = {}) -> (code, source, initState = [], options = {}) - - contractEncodeCall (code, abi, name, args, call) -> (source, name, args) // 'source' is -> Contract source code or ACI interface source -``` - - ### Notes and known Issues -- none - -## [2.3.2] -### Added -- none +# [2.4.0](https://github.com/aeternity/aepp-sdk-js/compare/2.3.2...2.4.0) (2019-04-17) -### Changed -- Change default `gasPrice` from `1e6` to `1e9z -- Fix `AEPP` example app -- Force `image` pull before `builds` - ### Removed -- none +### Features - ### Breaking Changes -- none +* **Chore:** Install and configure `commitizen` +* **Crypto:** Add `formatAddress` function to `Crypto` +* **Contract:** Add Contract Compiler API stamp to `es/contract` (now using instead contract node API) +* **Utils:** Add basic `http` client stamp (`es/utils/http`) +* **Contract:** ACI stamp (New Contract interface base on contract ACI schema) + ``` + const contractIns = await client.getContractInstance(contractSourceCode) + console.log(contract) + { + interface: String, // Contract interface source code + aci: String, // Contract interface json schema + source: String, // Contract source code + compiled: String, // Compiled contract code + deployInfo: { address: contractAddress } // Object with deploy transaction, + // Function + compile: () => this, // Compile contract, + deploy: (init = [], options = { skipArgsConvert: false }) => this, // Deploy contract (compile before if needed) + call: (fn, params = [], options = { skipArgsConvert: false, skipTransformDecoded: false, callStatic: false } => CallRersult: Object // Call contract function + } + ``` +* **Account:** Extend `Account.address()` with `accountFormatter` now you can do + ``` + export const ADDRESS_FORMAT = { + sophia: 1, // return address like `0xHEX_ADDRESS` + api: 2, // return address like `ak_9LJ8ne9tks78hTD2Tp571f7w2MJmzQMRsiZxKCkMA2d2Sbrc4` + } + + // + + export { ADDRESS_FORMAT } from 'es/account' + await account.address(format: ADDRESS_FORMAT) // default ADDRESS_FORMAT.api + ``` +* **Channel:** Improve channel rpc usage +* **Channel:** Improve channel tests and error handling +* **Channel:** Improve state channel params handling +* **Chain:** Add ability to get `account/balance` on specific block `hash/height` +* **Universal:** Add `{ compilerUrl }` to `Universal, Contract, Wallet` stamp initialization - ### Notes and known Issues -- none -## [2.3.1] -### Added -- `Oracle` fee calculation -- `getAccountNonce` function to `tx` stamp +### Bug Fixes -### Changed -- Change `FEE_BYTE_SIZE` from 1 to 8 bytes in `fee` calculation -- Improve error handling in `tx` builder +* **Contract:** decode node error coming from contract `call` and `callStatic` +* **Chain:** Throw native error instead of object in chain `chain.sendTransaction` +* **Crypto:** fix arguments parsing in `Crypto.sing` +* **Crypto:** Fix `name hash` function arguments parsing in `Crypto` - ### Removed -- none - ### Breaking Changes -- none + ### BREAKING CHANGES + * **Contract:** Remove `ContractNodeAPI` stamp + * **Contract:** Change Contract stamp API + ``` + 1) Use Compiler instead of node API for encode/decode call-data and compile. + 2) Change Contract interface: + - contractCallStatic (address, abi = 'sophia-address', name, { top, args = '()', call, options = {} } = {}) -> (source, address, name, args = [], { top, options = {} } = {})) + - contractCall (code, abi, address, name, { args = '()', options = {}, call } = {}) -> (source, address, name, args = [], options = {}) + - contractDeploy (code, abi, { initState = '()', options = {} } = {}) -> (code, source, initState = [], options = {}) + - contractEncodeCall (code, abi, name, args, call) -> (source, name, args) // 'source' is -> Contract source code or ACI interface source + ``` - ### Notes and known Issues -- none -## [2.3.0] -### Added -- `Minerva` comparability -- Add `Mnemonic` wallet implementation `es/utils/hd-wallet` +## [2.3.2](https://github.com/aeternity/aepp-sdk-js/compare/2.3.1...2.3.2) (2019-03-04) - ### Changed -- Change Channel `legacy` API to `JSON RPC` -- Change default `gasPrice` to `1e6` -- Change `minFee` calculation, multiply min fee by `1e9` - ### Removed -- none +### Features - ### Breaking Changes -- none +* **Contract:** Change default `gasPrice` from `1e6` to `1e9z +* **AEPP:** Fix `AEPP` example app +* **Build:** Force `image` pull before `builds` - ### Notes and known Issues -- Change supported node version range to `1.4.0 <= version < 3.0.0` -- This release contain changes from: [2.3.0-next](https://github.com/aeternity/aepp-sdk-js/releases/tag/2.3.0-next), [2.2.1-next](https://github.com/aeternity/aepp-sdk-js/releases/tag/2.2.1-next), [2.1.1-0.1.0-next](https://github.com/aeternity/aepp-sdk-js/releases/tag/2.1.1-0.1.0-next), [2.1.0](https://github.com/aeternity/aepp-sdk-js/releases/tag/2.1.0) - ## [2.3.0-next] -### Added -- Add `channel` `withdraw` and `deposit` methods +# [2.3.1](https://github.com/aeternity/aepp-sdk-js/compare/2.3.0...2.3.1) (2019-02-22) - ### Changed -- Change default `gasPrice` in `Contract` stamp and `Tx` stamp to `1e9` -- Fix `contract` tx `fee` calculation -- Refactor error handling in `sendTransaction` function -- Change default `gasPrice` to `1e9` -- Change `Fee` byte_size to 1 - ### Removed -- none +### Features - ### Breaking Changes -- none +* **Oracle:** `Oracle` fee calculation +* **Tx:** `getAccountNonce` function to `tx` stamp +* **TX_BUILDER:** Change `FEE_BYTE_SIZE` from 1 to 8 bytes in `fee` calculation +* **TX_BUILDER:** Improve error handling in `tx` builder - ### Notes and known Issues -- none -## [2.2.1-next] -### Added -- Add `deserialization` schema for `Channel` transactions(`channelCreate`, `channelCloseMutual`, `channelDeposit`, `channelWithdraw`, `channelSettle`) -- Add `rawTx` and `verifyTx` to error from poll function(when you wait for transaction will mined) +# [2.3.0](https://github.com/aeternity/aepp-sdk-js/compare/2.3.0-next...2.3.0) (2019-02-22) -### Changed -- Change Channel `legacy` API to `JSON RPC` -- Change `minFee` calculation, multiply min fee by 10^9 -### Removed -- none +### Features -### Breaking Changes -- none +* **Node:** `Minerva` comparability +* **Utils:** `Mnemonic` wallet implementation `es/utils/hd-wallet` +* **Oracle:** Change Channel `legacy` API to `JSON RPC` +* **Oracle:** Change default `gasPrice` to `1e6` +* **Oracle:** Change `minFee` calculation, multiply min fee by `1e9` -### Notes and known Issues -- Depend on `bip39` from npm instead of git repo +### BREAKING CHANGES +* **Node:** Change supported node version range to `1.4.0 <= version < 3.0.0` +* This release contain changes from: [2.3.0-next](https://github.com/aeternity/aepp-sdk-js/releases/tag/2.3.0-next), [2.2.1-next](https://github.com/aeternity/aepp-sdk-js/releases/tag/2.2.1-next), [2.1.1-0.1.0-next](https://github.com/aeternity/aepp-sdk-js/releases/tag/2.1.1-0.1.0-next), [2.1.0](https://github.com/aeternity/aepp-sdk-js/releases/tag/2.1.0) -## [2.1.1-0.1.0-next] -### Added -- none -### Changed -- Fix linter errors -### Removed -- none +# [2.3.0-next](https://github.com/aeternity/aepp-sdk-js/compare/2.2.1-next...2.3.0-next) (2019-02-21) -### Breaking Changes -- none -### Notes and known Issues -- none +### Features -## [2.1.0] -### Added -- `Minerva` comparability -- Add `Mnemonic` wallet implementation `es/utils/hd-wallet` +* **Channel:** `channel` `withdraw` and `deposit` methods +* **TX_BUILDER:** Change default `gasPrice` in `Contract` stamp and `Tx` stamp to `1e9` +* **TX:** Fix `contract` tx `fee` calculation +* **Chain:** Refactor error handling in `sendTransaction` function +* **Contract:** Change default `gasPrice` to `1e9` +* **TX_BUILDER:** Change `Fee` byte_size to 1 -### Changed -- Change supported node version range to `1.4.0 <= version < 3.0.0` -### Removed -- none -### Breaking Changes -- none +# [2.2.1-next](https://github.com/aeternity/aepp-sdk-js/compare/2.1.1-0.1.0-next...2.2.1-next) (2019-02-21) -### Notes and known Issues -- Broken build(linter errors) - fixed in next release +### Feature -## [2.0.0] -### Added -- Add `unpackedTx`, `txType` and `signature` to `validate` transaction function -- Add `top` param to contract `static call(dry-run)` -- Add errors handling for `dry-run` -- Add `keystore` docs -- Add `verify` options to `send` function which verify tx before broadcasting and throw error if tx is invalid -- Add `dryRun` to `RPC` methods -- Add `Oracle` transaction creation to `Aepp` rpc -- Add `tx builder` docs -- Add doc's for `utils/bytes` and tx builder `schema` +* **TX_BUILDER:** Add `deserialization` schema for `Channel` transactions(`channelCreate`, `channelCloseMutual`, `channelDeposit`, `channelWithdraw`, `channelSettle`) +* **Chain:** Add `rawTx` and `verifyTx` to error from poll function(when you wait for transaction will mined) +* **Chore:** Depend on `bip39` from npm instead of git repo +* **Channel:** Change Channel `legacy` API to `JSON RPC` +* **TX_BUILDER:** Change `minFee` calculation, multiply min fee by 10^9 -### Changed -- refactor `calculateFee` function in `TxBuilder`(use BigNumber) -- `RpcServer`: Avoid storing of `window` in `instance` properties -- Disable `balance formatting` by default -- Extend response of `Oracle`, `Aens`, `Contrat` with `rawTx` -- Change response of `send` function now it's and object with transaction data(hash, rawTxHash, ...) -- Move `verification of transaction` to `chain` stamp -- Move `Contract` and `Oracle` API wrapper's to `Chain` stamp -- Rename `epoch` in `CHANGELOG`, `README`, `HACKING` -- Retrieve `node` version from `/api` -- Fix unpack tx example in `bin/aecrypto.js` - -### Removed -- Remove unused function's from `crypto.js` -### Breaking Changes -- Remove old transaction builder `es/tx/js.js` (Please use `es/tx/builder` instead) -- Rename `es/epoch.js` to `es/node.js` -- Rename `Oracle`, `Contract`, `Chain` API wrapper files from `epoch` to `node` -- Rename `Contract` api wrapper method's +# [2.1.1-0.1.0-next](https://github.com/aeternity/aepp-sdk-js/compare/2.1.0...2.1.1-0.1.0-next) (2019-02-21) -### Notes and known Issues -- none +### Bug Fixes +* **Chore:** Fix linter errors -## [1.3.2] -### Added -- Add `destroyInstance` function to `Ae` stamp which remove all listeners for RPC event's -- Add docs for `TransactionValidator` and `TxBuilder` stamp's -- Add `TxBuilderHelper` to bundle -### Changed -- Adjust doc's for `Contract` and `Aens` stamp's -- Fix decoding of address from contract call -- Contract call static now using `dry-run` API -- Improve test's for Transaction verification -### Removed -- none -### Breaking Changes -- none +# [2.1.0](https://github.com/aeternity/aepp-sdk-js/compare/2.0.0...2.1.0) (2019-02-21) -### Notes and known Issues -- none +### Features -## [1.3.1] +* **Node:** `Minerva` comparability +* **Utils:** Add `Mnemonic` wallet implementation `es/utils/hd-wallet` + + +### BREAKING CHANGES + +* **Node:** Change supported node version range to `1.4.0 <= version < 3.0.0` + + + +# [2.0.0](https://github.com/aeternity/aepp-sdk-js/compare/1.3.2...2.0.0) (2019-02-21) + + +### Features + +* **TX_BUILDER:** Add `unpackedTx`, `txType` and `signature` to `validate` transaction function +* **Contract:** Add `top` param to contract `static call(dry-run)` +* **Contract:** Add errors handling for `dry-run` +* **Docs:** Add `keystore` docs +* **Ae:** Add `verify` options to `send` function which verify tx before broadcasting and throw error if tx is invalid +* **Rpc:** Add `dryRun` to `RPC` methods +* **Rpc:** Add `Oracle` transaction creation to `Aepp` rpc +* **Docs:** Add `tx builder` docs +* **Docs:** Add doc's for `utils/bytes` and tx builder `schema` +* **TX_BUILDER:** refactor `calculateFee` function in `TxBuilder`(use BigNumber) +* **TX_BUILDER:** Extend response of `Oracle`, `Aens`, `Contrat` with `rawTx` +* **Ae:** Change response of `send` function now it's and object with transaction data(hash, rawTxHash, ...) +* **Chain:** Move `Contract` and `Oracle` API wrapper's to `Chain` stamp +* **Chore:** Rename `epoch` in `CHANGELOG`, `README`, `HACKING` + + +### Bug Fixes + +* **Rpc:** `RpcServer`: Avoid storing of `window` in `instance` properties +* **Chain:** Disable `balance formatting` by default +* **Chain:** Move `verification of transaction` to `chain` stamp +* **Node:** Retrieve `node` version from `/api` +* **Chore:** Fix unpack tx example in `bin/aecrypto.js` +* **Chore:** Remove unused function's from `crypto.js` + + +### BREAKING CHANGES + +* **TX:** Remove old transaction builder `es/tx/js.js` (Please use `es/tx/builder` instead) +* **Chore:** Rename `es/epoch.js` to `es/node.js` +* **Chore:** Rename `Oracle`, `Contract`, `Chain` API wrapper files from `epoch` to `node` +* **Chore:** Rename `Contract` api wrapper method's -### Changed -- Remove KeyStore from bundle due to build issue(for now you can export it only using tree-shaking `import * as Keystore from '@aeternity/aepp-sdk/utils/keystore'`) -## [1.3.0] -### Added -- Add support for State Channels -- New transaction builder going through schema(build, unpack) -- Add new stamp `TransactionValidator` which can verify your transaction +## [1.3.2](https://github.com/aeternity/aepp-sdk-js/compare/1.3.1...1.3.2) (2019-02-01) + + +### Features + +* **Ae:** Add `destroyInstance` function to `Ae` stamp which remove all listeners for RPC event's +* **Docs:** Add docs for `TransactionValidator` and `TxBuilder` stamp's +* **Build:** Add `TxBuilderHelper` to bundle +* **Chore:** Contract call static now using `dry-run` API +* **Test:** Improve test's for Transaction verification + + ### Changed -- Rename epoch to aeternity node(docker configs, some docs) -- Use new tx builder in TX stamp -- Set default values for amount and deposit to 0 for `contract` transaction -- Improve RPC server -### Removed -- none -### Breaking Changes -- none +* **Docs:** Adjust doc's for `Contract` and `Aens` stamp's +* **Chore:** Fix decoding of address from contract call + + + +## [1.3.1](https://github.com/aeternity/aepp-sdk-js/compare/1.3.0...1.3.1) (2019-01-29) + + +### Features + +* **Build:** Remove KeyStore from bundle due to build issue(for now you can export it only using tree-shaking `import * as Keystore from '@aeternity/aepp-sdk/utils/keystore'`) + + + +# [1.3.0](https://github.com/aeternity/aepp-sdk-js/compare/1.2.1...1.3.0) (2019-01-29) + + +### Features + +* **Channel:** Add support for State Channels +* **TX_BUILDER:** New transaction builder going through schema(build, unpack) +* **TX_VALIDATOR:** Add new stamp `TransactionValidator` which can verify your transaction +* **Chore:** Rename epoch to aeternity node(docker configs, some docs) +* **Tx:** Use new tx builder in TX stamp +* **Contract:** Set default values for amount and deposit to 0 for `contract` transaction +* **Rpc:** Improve RPC server + ### Notes and known Issues - Old transaction builder `es/tx/js.js` will be removed in next major release. -## [1.2.1] -### Added -- amount formatter -- amount format balance `client.balance('AK_PUBLICKEY', { format: true })` -- Oracle and Contracts API to Aepp stamp -### Changed -- Use `prepare` instead of `postinstall-build` (thanks @davidyuk) -- Fix Import RLP package (thanks @davidyuk) -- Fix for NetworkId propagation and override -- TxJS is not a stamp anymore, and instead: it exports helper functions -- Refreshed Docs: README.md + docs/usage.md -### Removed -- TxJs stamp (not a stamp anymore) +## [1.2.1](https://github.com/aeternity/aepp-sdk-js/compare/1.1.2...1.2.1) (2018-12-21) -### Breaking Changes -- TxJs stamp (not a stamp anymore) -- balance now answer a formatted string composed of `AMOUNT + ' ' + unit` (eg. `10 exa` for 10 AE) -### Notes and known Issues -- `10 exa` should be `10 ae` -- format shouldn't be a flag, but a request for `unit` eg. `{ format: `ae` }` +### Features +* **Chain:** amount formatter +* **Chain:** amount format balance `client.balance('AK_PUBLICKEY', { format: true })` +* **Aepp:** Oracle and Contracts API to Aepp stamp +* **Chore:** Use `prepare` instead of `postinstall-build` (thanks @davidyuk) +* **Docs:** Refreshed Docs: README.md + docs/usage.md -## [1.1.2] -### Added -- isAddressValid check +### Bug Fixes -### Changed -- Compatibility with Node >= 1.0.0 and <= 1.1.0 -- Fixed networkId propagation (and overriding on init of Flavors) -- Tx Fee formulas -- Fixed encodeBase58Check by feeding Buffered input +* **Chr:** Fix Import RLP package (thanks @davidyuk) +* **Rpc:** Fix for NetworkId propagation and override +* **Tx:** TxJS is not a stamp anymore, and instead: it exports helper functions -### Removed -- none -### Breaking Changes -- none +### BREAKING CHANGES + +* **Tx:** TxJs stamp (not a stamp anymore) +* **Chain:** balance now answer a formatted string composed of `AMOUNT + ' ' + unit` (eg. `10 exa` for 10 AE) ### Notes and known Issues -- none +* **Chore:** `10 exa` should be `10 ae` +* **Chain:** format shouldn't be a flag, but a request for `unit` eg. `{ format: `ae` }` -## [1.1.1] -### Added -- none -### Changed -- Fix Testing -- Added a command to remove images after CI testing -- Fixed Oracle error for Wallet flavor -### Removed -- none +## [1.1.2](https://github.com/aeternity/aepp-sdk-js/compare/1.1.1...1.1.2) (2018-12-15) -### Breaking Changes -- none -### Notes and known Issues -- none +### Feature -## [1.1.0] -### Added -- Oracles functionality and flavor -- Simple example of aepp-in-aepp (see `/examples` folder) +* **Chore:** isAddressValid check +* **Tx:** Tx Fee formulas -### Changed -- Fixed issue with big numbers and `TX` -### Removed -- none +### Bug Fixes -### Breaking Changes -- none +* **Rpc:** Fixed networkId propagation (and overriding on init of Flavors) +* **Crypto:** Fixed encodeBase58Check by feeding Buffered input -### Notes and known Issues -- none -## [1.0.1] -### Added -- ability to support Node range(s) using semver package (see https://www.npmjs.com/package/semver#ranges) +### BREAKING CHANGES -### Changed -- Support for Node >= 1.0.0 and < 2.0.0 +* **Chore:** Compatibility with Node >= 1.0.0 and <= 1.1.0 -### Removed -- none -### Breaking Changes -- none -### Notes and known Issues -- none +## [1.1.1](https://github.com/aeternity/aepp-sdk-js/compare/1.1.0...1.1.1) (2018-12-11) +### Features -## [1.0.0] -### Added -- Contract native Transactions +* **Rpc:** Added a command to remove images after CI testing -### Changed -- Rolled back to bignumbers.js for easier fix with axios.get/post -### Removed -- Support for Node < 1.0.0 +### Bug Fixes -### Breaking Changes -- New NETWORK_ID (also used in docker/sdk.env for CI tests) -- Encoding of transaction (and other objects) [changed from base58check to base64check](https://github.com/aeternity/protocol/blob/master/node/api/api_encoding.md) +* **Rpc:** Fix Testing +* **Rpc:** Fixed Oracle error for Wallet flavor -### Notes and known Issues -- State Channels have been excluded for problems with CI, will be included in next release -## [0.25.0-0.1.1] -### Added -- see [0.25.0-0.1.0] +# [1.1.0](https://github.com/aeternity/aepp-sdk-js/compare/1.0.1...1.1.0) (2018-12-11) -### Changed -- Change bignumbers.js with [bn.js](https://github.com/indutny/bn.js/) due to binding errors in browser's package -### Removed -- see [0.25.0-0.1.0] +### Features -### Breaking Changes -- see [0.25.0-0.1.0] +* **Oracle:** Oracles functionality and flavor +* **Aepp:** Simple example of aepp-in-aepp (see `/examples` folder) -### Notes and known Issues -- none, see [0.25.0-0.1.0] +### Bug Fixes -## [0.25.0-0.1.0] -### Added -- Parsing of `fee` using `bignum.js` -- Add `networkId` as param to `Account` flavor(default: `ae_mainnet`) -- Implement native build of `AENS` transaction. +* **Tx:** Fixed issue with big numbers and `TX` -### Changed -- Update keystore for new [requirements](https://www.pivotaltracker.com/n/projects/2124891/stories/155155204) -- -### Removed -- Support for < 0.25.0 -- [AE CLI](https://github.com/aeternity/aecli-js) and [AE PROJECT CLI](https://github.com/aeternity/aeproject) moved to separate repos and packages -### Breaking Changes -- Use NETWORK_ID for signing (see [here](https://github.com/aeternity/aepp-sdk-js/commit/9c252f937f7ea501c4aaacbbef53c4c1833e48e4#diff-ffb275ebb09085c85c59f140998199e0R28)) -- Keystore format [changes](https://www.pivotaltracker.com/n/projects/2124891/stories/155155204) + +## [1.0.1](https://github.com/aeternity/aepp-sdk-js/compare/1.0.0...1.0.1) (2018-11-30) + + + +### Features + +* **Node:** ability to support Node range(s) using semver package (see https://www.npmjs.com/package/semver#ranges) + + +### BREAKING CHANGES + +* **Node:** Support for Node >= 1.0.0 and < 2.0.0 + + + +## [1.0.0](https://github.com/aeternity/aepp-sdk-js/compare/0.25.0-0.1.1...1.0.0) (2018-11-30) + + + +### Features + +* **Contract:** Contract native Transactions + + +### Bug Fixes + +* **BigNumber:** Rolled back to bignumbers.js for easier fix with axios.get/post + + +### BREAKING CHANGES + +* **Node:** Support for Node < 1.0.0 +* **Build:** New NETWORK_ID (also used in docker/sdk.env for CI tests) +* **Protocol:** Encoding of transaction (and other objects) [changed from base58check to base64check](https://github.com/aeternity/protocol/blob/master/node/api/api_encoding.md) + ### Notes and known Issues -- none +* **Channel:** State Channels have been excluded for problems with CI, will be included in next release -## [0.25.0-0.1.0-next] -### Added -- Contract type checked call (Ability to call contract using contract address) -### Changed -- Use ES methods instead of Ramda, where possible -- Fixed keystore by adding a salt param for derivedKey function -### Removed -- Support for < 0.25.0 -- [AE CLI](https://github.com/aeternity/aecli-js) and [AE PROJECT CLI](https://github.com/aeternity/aeproject) moved to separate repos and packages +## [0.25.0-0.1.1](https://github.com/aeternity/aepp-sdk-js/compare/0.25.0-0.1.0...0.25.0-0.1.1) (2018-11-30) -### Breaking Changes -- Aens use domain `.test` instead of `.aet` (see [here](https://github.com/aeternity/aepp-sdk-js/commit/9c252f937f7ea501c4aaacbbef53c4c1833e48e4#diff-8ef3b328d008ef3dbb72a0bca42eba37L24)) -- Use NETWORK_ID for signing (see [here](https://github.com/aeternity/aepp-sdk-js/commit/9c252f937f7ea501c4aaacbbef53c4c1833e48e4#diff-ffb275ebb09085c85c59f140998199e0R28)) ### Notes and known Issues +* **Chore:** See [0.25.0-0.1.0] -## [0.24.0-0.2.0] -### Added -- RPC Client improvements -- (RPC) `onContract` Guard -- (AE PROJECT CLI) born -### Changed -- (CLI) New keystore following these specifications: https://www.pivotaltracker.com/n/projects/2124891/stories/155155204 -- (CLI) `Host` parameter became `Url`. (`-u` for hostname, `-U` for internal) + +## [0.25.0-0.1.0](https://github.com/aeternity/aepp-sdk-js/compare/0.25.0-0.1.0-next...0.25.0-0.1.0) (2018-11-30) + + +### Features + +* **Utils** Parsing of `fee` using `bignum.js` +* **Account** Add `networkId` as param to `Account` flavor(default: `ae_mainnet`) +* **Tx** Implement native build of `AENS` transaction. +* **Keystore** Update keystore for new [requirements](https://www.pivotaltracker.com/n/projects/2124891/stories/155155204) + + +### BREAKING CHANGES + +* **CLI** [AE CLI](https://github.com/aeternity/aecli-js) and [AE PROJECT CLI](https://github.com/aeternity/aeproject) moved to separate repos and packages +* **Node** Support for < 0.25.0 + + + +## [0.25.0-0.1.0-next](https://github.com/aeternity/aepp-sdk-js/compare/0.24.0-0.2.0...0.25.0-0.1.0-next) (2018-11-30) + + +### Features + +* **Contract** Contract type checked call (Ability to call contract using contract address) +* **Contract** Use ES methods instead of Ramda, where possible + +### Bug Fixes + +* **Contract** Fixed keystore by adding a salt param for derivedKey function + ### Breaking Changes -- The `Cli` flavor is now `Universal` -- the keypair keys changed from `{ pub, priv }` to `{ publicKey, secretKey }` for consistency with other systems using them (eg. AirGap and [HD Wallet](https://github.com/aeternity/hd-wallet-js)) -### Notes and known Issues -- CLI and AE PROJECT CLI will move to a separate package +* **Contract** Support for < 0.25.0 +* **Contract** Aens use domain `.test` instead of `.aet` (see [here](https://github.com/aeternity/aepp-sdk-js/commit/9c252f937f7ea501c4aaacbbef53c4c1833e48e4#diff-8ef3b328d008ef3dbb72a0bca42eba37L24)) +* **Contract** Use NETWORK_ID for signing (see [here](https://github.com/aeternity/aepp-sdk-js/commit/9c252f937f7ea501c4aaacbbef53c4c1833e48e4#diff-ffb275ebb09085c85c59f140998199e0R28)) -## [0.24.0-0.1.0] -### Added -- Full support of [Node-0.24.0](https://github.com/aeternity/aeternity/releases/tag/v0.24.0) -- (CLI) Develop `decode base58` address command in `crypto` module -- (CLI) Add `nonce` param to all tx command's -- (CLI) Add `gas` param to `deploy` and `call` commands -- Add ability to create `spend` transaction natively -- Implement `ethereum keystore` using `AES-126-CTR` and `SCRYPT` as key derivation function +# [0.24.0-0.2.0](https://github.com/aeternity/aepp-sdk-js/compare/v0.24.0-0.1.0...v0.24.0-0.2.0) (2018-10-30) -### Changed -- (CLI) Change `--privateKey` to `flag` on `ACCOUNT ADDRESS` command -- Change `node version` in `Dockerfile` -- API endpoints to meet new Node specifications -- Update `docco` config and change `rename` package to `recursive-rename` -- Improved documentation -### Removed -- Support for < 0.24.0 + +### Features + +* **Rpc** RPC Client improvements +* **Rpc** `onContract` Guard +* **CLI** born +* **CLI** `Host` parameter became `Url`. (`-u` for hostname, `-U` for internal) +* **CLI** New keystore following these specifications: https://www.pivotaltracker.com/n/projects/2124891/stories/155155204 + + +### BREAKING CHANGES + +* **Chore** The `Cli` flavor is now `Universal` +* **Chore** the keypair keys changed from `{ pub, priv }` to `{ publicKey, secretKey }` for consistency with other systems using them (eg. AirGap and [HD Wallet](https://github.com/aeternity/hd-wallet-js)) ### Notes and known Issues -- `ethereum keystore` usage will be removed in the next release -- CLI will move to a separate package +* **Chore** CLI and AE PROJECT CLI will move to a separate package -## [0.22.0-0.1.0-beta.1] -### Added -- Add **CLI** implementation -- nameId function for commitment hash calculations -### Changed -- API endpoints to meet new Node specifications -- Add Nonce calculation on SDK side -- Add check for MAX_GAS in call and deploy contract -- change hash prefix separator from $ to _ -- Add keywords ('SDK', 'CLI') to package.json -- Link aecli to `./bin/aecli.js` in package.json (After "npm link" you can use CLI globally) -- Wait until pre-claim transaction block was mined before send claim transaction -- Updated `webpack`, `webpack-cli` and added new dev deps accordingly -- Add Node Compatibility Check -- Add SDK nonce calculations -- Fixes commitment hash calculations in naming system, to be `Hash(nameId(name) + name_salt)` instead of `Hash(Hash(name + name_salt))`. - -### Removed -- Support for < 0.22.0 - -## [0.18.0-0.1.1] -### Added -- Lots of new documentation (prose and API) -- Fancy badges to README -- Transitive dev dependencies for standard-loader not covered by pnpm -- CI Dockerfile to include pnpm -- Fancy-shmancy diagram in README -- Generated documentation files since they are linked in static docs -### Changed -- Switch from Yarn to pnpm for building -- Structure of documentation -- Generate Markdown from Docco - -## [0.18.0-0.1.0] -### Added -- Support for Node 0.18.0 (changed endpoints) -- Wallet/Aepp RPC support -- Contract call result decoding support -- Per-module API documentation (Markdown based on JSDoc) -- More API documentation (still incomplete) -- SDK entrypoint factories (in `/es/ae/universal.js`) - -### Removed -- Support for < 0.18.0 (changed endpoints) -### Changed -- Module load path (src -> es) -- Lower mining rate (5s) in docker-compose +# [0.24.0-0.1.0](https://github.com/aeternity/aepp-sdk-js/compare/0.22.0-0.1.0-beta.1...v0.24.0-0.1.0) (2018-10-23) -### Fixed -- Symmetric key encryption/decryption -## [0.15.0-0.1.0] -### Removed -- Legacy Swagger file loading -- Compatibility with < 0.15.0 +### Features -### Fixed -- Contract unit state initialization -- Missing required parameter for name transfers (workaround for - [Swagger file bug]) +* **Node** Full support of [Node-0.24.0](https://github.com/aeternity/aeternity/releases/tag/v0.24.0) +* **CLI** Develop `decode base58` address command in `crypto` module +* **CLI** Add `nonce` param to all tx command's +* **CLI** Add `gas` param to `deploy` and `call` commands +* **Tx** Add ability to create `spend` transaction natively +* **Keystore** Implement `ethereum keystore` using `AES-126-CTR` and `SCRYPT` as key derivation function +* **CLI** Change `--privateKey` to `flag` on `ACCOUNT ADDRESS` command +* **Build** Change `node version` in `Dockerfile` +* **Node** API endpoints to meet new Node specifications +* **Chore** Update `docco` config and change `rename` package to `recursive-rename` +* **Docs** Improved documentation -[Swagger file bug]: https://www.pivotaltracker.com/n/projects/2124891 -## [0.14.0-0.1.0] -### Added -- New, opinionated top-level API +### BREAKING CHANGES -### Changed -- Rest of legacy API now uses new API as well -- Generated API now encapsulated in `api` object -- Automatic case conversion for remote parameter names -- Remaining tests to use new API -- Adapted new method of obtaining transaction hash, breaks compatibility (see +* **Node** Support for < 0.24.0 +* **Keystore** `ethereum keystore` usage will be removed in the next release +* **CLI** CLI will move to a separate package + + + +# [0.22.0-0.1.0-beta.1](https://github.com/aeternity/aepp-sdk-js/compare/v0.18.0-0.1.1...0.22.0-0.1.0-beta.1) (2018-10-02) + +### Features + +* **CLI** Add **CLI** implementation +* **Crypto** nameId function for commitment hash calculations +* **Node** API endpoints to meet new Node specifications +* **Tx** Add Nonce calculation on SDK side +* **Contract** Add check for MAX_GAS in call and deploy contract +* **Chore** change hash prefix separator from $ to _ +* **Chore** Add keywords ('SDK', 'CLI') to package.json +* **CLI** Link aecli to `./bin/aecli.js` in package.json (After "npm link" you can use CLI globally) +* **Aens** Wait until pre-claim transaction block was mined before send claim transaction +* **Build** Updated `webpack`, `webpack-cli` and added new dev deps accordingly +* **Node** Add Node Compatibility Check + +### Bug Fixes + +* **Crypto** Fixes commitment hash calculations in naming system, to be `Hash(nameId(name) + name_salt)` instead of `Hash(Hash(name + name_salt))`. + +### BREAKING CHANGES + +* **Node** Support for < 0.22.0 + + + +# [0.18.0-0.1.1](https://github.com/aeternity/aepp-sdk-js/compare/v0.18.0-0.1.0...v0.18.0-0.1.1) (2018-07-31) + +### Features + +* **Docs** Lots of new documentation (prose and API) +* **Docs** Fancy badges to README +* **Build** Transitive dev dependencies for standard-loader not covered by pnpm +* **Build** CI Dockerfile to include pnpm +* **Docs** Fancy-shmancy diagram in README +* **Docs**Generated documentation files since they are linked in static docs +* **Build** Switch from Yarn to pnpm for building +* **Docs** Structure of documentation +* **Docs** Generate Markdown from Docco + + + +# [0.18.0-0.1.0](https://github.com/aeternity/aepp-sdk-js/compare/v0.15.0-0.1.0...v0.18.0-0.1.0) (2018-07-24) + + +### Features + +* **Node** Support for Node 0.18.0 (changed endpoints) +* **RPC** Wallet/Aepp RPC support +* **Contract** Contract call result decoding support +* **Docs** Per-module API documentation (Markdown based on JSDoc) +* **Docs** More API documentation (still incomplete) +* **Build** SDK entrypoint factories (in `/es/ae/universal.js`) +* **Build** Module load path (src -> es) +* **Chore** Lower mining rate (5s) in docker-compose + + +### Bug Fixes + +* **Crypto** Symmetric key encryption/decryption + + +### BREAKING CHANGES + +* **Node** Support for < 0.18.0 (changed endpoints) + + + + +# [0.15.0-0.1.0](https://github.com/aeternity/aepp-sdk-js/compare/v0.14.0-0.1.0...v0.15.0-0.1.0) (2018-06-12) + + +### Features + +* **Node** Legacy Swagger file loading +* **Node** Compatibility with < 0.15.0 + + +### Bug Fixes + +* **Contract** Contract unit state initialization +* **Node** Missing required parameter for name transfers (workaround for + [Swagger file bug](https://www.pivotaltracker.com/n/projects/2124891)) + + + +# [0.14.0-0.1.0](https://github.com/aeternity/aepp-sdk-js/compare/v0.13.0-0.1.1...v0.14.0-0.1.0) (2018-06-11) + + +### Features + +* **API** New, opinionated top-level API +* **API** Rest of legacy API now uses new API as well +* **API** Generated API now encapsulated in `api` object +* **API** Automatic case conversion for remote parameter names +* **API** Remaining tests to use new API +* **API** Adapted new method of obtaining transaction hash, breaks compatibility (see below) -### Removed -- Oracle API (for the time being) -- Legacy API and tests -- Compatibility with older versions of Node which provide the transaction hash + +### Bug Fixes + +* **API** [GH-49]: Handle existing path components correctly + + +### BREAKING CHANGES +* **API** Remove Oracle API (for the time being) +* **API** Remove Legacy API and tests +* **API** Remove Compatibility with older versions of Node which provide the transaction hash the old way -### Fixed -- [GH-49]: Handle existing path components correctly -## [0.13.0-0.1.0] -### Added -- This change log file -### Changed -- Switch to curve ed25519 (from secp256k1) to align with Node protocol changes -- Generate basic API directly from Swagger files, also validate input data -- Compiled library now self-contained with all dependencies -- Use Webpack 4 based cross-platform (Node/Web) compilation -- Package description now reads `SDK for the æternity blockchain` -- Authors are now taken from `AUTHORS` instead of `package.json` -- Moved code examples from README to separate file in docs - -### Removed -- Defunct scripts; will be brought back later - -### Fixed -- More consistent code examples - -[0.13.0-0.1.0]: https://github.com/aeternity/aepp-sdk-js/compare/v0.10.0-0.1.0...v0.13.0-0.1.0 -[0.14.0-0.1.0]: https://github.com/aeternity/aepp-sdk-js/compare/v0.13.0-0.1.0...v0.14.0-0.1.0 -[0.15.0-0.1.0]: https://github.com/aeternity/aepp-sdk-js/compare/v0.14.0-0.1.0...v0.15.0-0.1.0 -[0.18.0-0.1.0]: https://github.com/aeternity/aepp-sdk-js/compare/v0.15.0-0.1.0...v0.18.0-0.1.0 -[0.18.0-0.1.1]: https://github.com/aeternity/aepp-sdk-js/compare/v0.18.0-0.1.0...v0.18.0-0.1.1 -[0.22.0-0.1.0-beta.1]: https://github.com/aeternity/aepp-sdk-js/compare/v0.18.0-0.1.1...v0.22.0-0.1.0-beta.1 -[0.24.0-0.1.0]: https://github.com/aeternity/aepp-sdk-js/compare/v0.22.0-0.1.0-beta.1...v0.24.0-0.1.0 -[0.24.0-0.2.0]: https://github.com/aeternity/aepp-sdk-js/compare/v0.24.0-0.1.0...v0.24.0-0.2.0 -[0.25.0-0.1.0-next]: https://github.com/aeternity/aepp-sdk-js/compare/v0.24.0-0.2.0...v0.25.0-0.1.0-next -[0.25.0-0.1.0]: https://github.com/aeternity/aepp-sdk-js/compare/v0.25.0-0.1.0-next...v0.25.0-0.1.0 -[0.25.0-0.1.1]: https://github.com/aeternity/aepp-sdk-js/compare/v0.25.0-0.1.0...v0.25.0-0.1.1 -[1.0.0]: https://github.com/aeternity/aepp-sdk-js/compare/v0.25.0-0.1.0...1.0.0 -[1.0.1]: https://github.com/aeternity/aepp-sdk-js/compare/1.0.0...1.0.1 -[1.1.0]: https://github.com/aeternity/aepp-sdk-js/compare/1.0.0...1.1.0 -[1.1.1]: https://github.com/aeternity/aepp-sdk-js/compare/1.1.0...1.1.1 -[1.1.2]: https://github.com/aeternity/aepp-sdk-js/compare/1.1.1...1.1.2 -[1.2.1]: https://github.com/aeternity/aepp-sdk-js/compare/1.1.2...1.2.1 -[1.3.0]: https://github.com/aeternity/aepp-sdk-js/compare/1.2.1...1.3.0 -[1.3.1]: https://github.com/aeternity/aepp-sdk-js/compare/1.3.0...1.3.1 -[1.3.2]: https://github.com/aeternity/aepp-sdk-js/compare/1.3.1...1.3.2 -[2.0.0]: https://github.com/aeternity/aepp-sdk-js/compare/1.3.2...2.0.0 -[2.1.0]: https://github.com/aeternity/aepp-sdk-js/compare/2.0.0...2.1.0 -[2.1.1-0.1.0-next]: https://github.com/aeternity/aepp-sdk-js/compare/2.1.0...2.1.1-0.1.0-next -[2.2.1-next]: https://github.com/aeternity/aepp-sdk-js/compare/2.1.1-0.1.0-next...2.2.1-next -[2.3.0-next]: https://github.com/aeternity/aepp-sdk-js/compare/2.2.1-next...2.3.0-next -[2.3.0]: https://github.com/aeternity/aepp-sdk-js/compare/2.3.0-next...2.3.0 -[2.3.1]: https://github.com/aeternity/aepp-sdk-js/compare/2.3.0...2.3.1 -[2.3.2]: https://github.com/aeternity/aepp-sdk-js/compare/2.3.1...2.3.2 -[2.4.0]: https://github.com/aeternity/aepp-sdk-js/compare/2.3.2...2.4.0 -[2.4.1]: https://github.com/aeternity/aepp-sdk-js/compare/2.4.0...2.4.1 +# [0.13.0-0.1.1](https://github.com/aeternity/aepp-sdk-js/compare/v0.13.0-0.1.0...v0.13.0-0.1.1) (2018-05-24) + + +### Features + +* **Node** Switch to curve ed25519 (from secp256k1) to align with Node protocol changes +* **Node** Generate basic API directly from Swagger files, also validate input data +* **Build** Compiled library now self-contained with all dependencies +* **Build** Use Webpack 4 based cross-platform (Node/Web) compilation +* **Docs** Package description now reads `SDK for the æternity blockchain` +* **Chore** Authors are now taken from `AUTHORS` instead of `package.json` +* **Docs** Moved code examples from README to separate file in docs + + +### BREAKING CHANGES + +* **Node** Defunct scripts; will be brought back later + + +### Bug Fixes + +* **Chore** More consistent code examples From fffdf1295882b2471af00c9749773232d4099e18 Mon Sep 17 00:00:00 2001 From: nduchak Date: Wed, 17 Apr 2019 14:54:57 +0300 Subject: [PATCH 09/16] chore(Docker): Update node version tot 2.3.0 --- .env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env b/.env index 45221a325a..10bf699537 100644 --- a/.env +++ b/.env @@ -1,3 +1,3 @@ -TAG=v2.2.0 +TAG=v2.3.0 COMPILER_TAG=v2.1.0 From eb3d4be13c6f20260e2eb5e8f5734dc8d5641417 Mon Sep 17 00:00:00 2001 From: nduchak Date: Wed, 17 Apr 2019 15:00:14 +0300 Subject: [PATCH 10/16] docs(CHANGELOG): Adjust release --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index acf01d4482..3b74bfb07d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -# [3.0.0](https://github.com/aeternity/aepp-sdk-js/compare/2.4.1...3.0.0) (2019-04-17) +# [3.0.0](https://github.com/aeternity/aepp-sdk-js/compare/2.4.0...3.0.0) (2019-04-17) ### Bug Fixes @@ -8,6 +8,8 @@ ### Features +* **TX_BUILDER:** Channel tx serializations +* **TxValidator:** Add minGasPrice validation to contract transactions * **ACI:** Update due to compiler API changes ([#331](https://github.com/aeternity/aepp-sdk-js/issues/331)) ([e047f3b](https://github.com/aeternity/aepp-sdk-js/commit/e047f3b)) * **Aepp:** Add Compiler to Aepp rpc methods. Update example app ([#312](https://github.com/aeternity/aepp-sdk-js/issues/312)) ([9c72521](https://github.com/aeternity/aepp-sdk-js/commit/9c72521)) * **State Channels:** Add cleanContractCalls method ([#338](https://github.com/aeternity/aepp-sdk-js/issues/338)) ([778159a](https://github.com/aeternity/aepp-sdk-js/commit/778159a)) From 97c2a3c31747763a6a2c00a19b0bfaae27dc81de Mon Sep 17 00:00:00 2001 From: nduchak Date: Wed, 17 Apr 2019 15:03:09 +0300 Subject: [PATCH 11/16] feat(npm): Add script for auto-generating changelog --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 0f60bff7ac..f3f535ae21 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "test:watch": "mocha --recursive --require @babel/register --watch", "test-jenkins": "mocha --recursive --require @babel/register --reporter mocha-junit-reporter", "prepare": "npm run build", + "genChangelog": "conventional-changelog -p angular -i CHANGELOG.md -s", "prepublishOnly": "npm run docs:docco && npm run docs:api" }, "license": "ISC", From 77cfbc8fd6e45b1ad6647b828acbf5af5b957d47 Mon Sep 17 00:00:00 2001 From: nduchak Date: Wed, 17 Apr 2019 15:30:06 +0300 Subject: [PATCH 12/16] chore(Node): downgrade to 2.2.0 due to failed channel test --- .env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env b/.env index 10bf699537..45221a325a 100644 --- a/.env +++ b/.env @@ -1,3 +1,3 @@ -TAG=v2.3.0 +TAG=v2.2.0 COMPILER_TAG=v2.1.0 From 55a289132d472a6c233be6984a4425c692f72d6c Mon Sep 17 00:00:00 2001 From: nduchak Date: Wed, 17 Apr 2019 15:31:37 +0300 Subject: [PATCH 13/16] fix(Channel): Fix failing test on 2.3.0 node --- .env | 2 +- test/integration/channel.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.env b/.env index 45221a325a..10bf699537 100644 --- a/.env +++ b/.env @@ -1,3 +1,3 @@ -TAG=v2.2.0 +TAG=v2.3.0 COMPILER_TAG=v2.1.0 diff --git a/test/integration/channel.js b/test/integration/channel.js index 627566a72c..60a909b2e2 100644 --- a/test/integration/channel.js +++ b/test/integration/channel.js @@ -701,7 +701,7 @@ describe('Channel', function () { }) it('when posting an update with incorrect address', async () => { - return update({ from: 'ak_123' }).should.eventually.be.rejectedWith('Rejected') + return update({ from: 'ak_123' }).should.eventually.be.rejectedWith('Internal error') }) it('when posting an update with incorrect amount', async () => { From ed82eb625f856b8707943c8f879d01a4245301cc Mon Sep 17 00:00:00 2001 From: nduchak Date: Wed, 17 Apr 2019 15:44:26 +0300 Subject: [PATCH 14/16] chore(package-lock): adjust package-lock --- CHANGELOG.md | 17 +++ package-lock.json | 257 +++++++++++++++++++++++----------------------- 2 files changed, 146 insertions(+), 128 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b74bfb07d..83b53cc23d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,20 @@ +# [3.0.0](https://github.com/aeternity/aepp-sdk-js/compare/2.4.1...3.0.0) (2019-04-17) + + +### Bug Fixes + +* **ACI:** Fix address type transformation when decoding data ([#335](https://github.com/aeternity/aepp-sdk-js/issues/335)) ([e37cdfc](https://github.com/aeternity/aepp-sdk-js/commit/e37cdfc)) +* **Channel:** Fix failing test on 2.3.0 node ([55a2891](https://github.com/aeternity/aepp-sdk-js/commit/55a2891)) + + +### Features + +* **ACI:** Update due to compiler API changes ([#331](https://github.com/aeternity/aepp-sdk-js/issues/331)) ([e047f3b](https://github.com/aeternity/aepp-sdk-js/commit/e047f3b)) +* **npm:** Add script for auto-generating changelog ([97c2a3c](https://github.com/aeternity/aepp-sdk-js/commit/97c2a3c)) +* **State Channels:** Add cleanContractCalls method ([#338](https://github.com/aeternity/aepp-sdk-js/issues/338)) ([778159a](https://github.com/aeternity/aepp-sdk-js/commit/778159a)) + + + # [3.0.0](https://github.com/aeternity/aepp-sdk-js/compare/2.4.0...3.0.0) (2019-04-17) diff --git a/package-lock.json b/package-lock.json index 7e0fa12296..02ac2d3f45 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@aeternity/aepp-sdk", - "version": "2.3.0", + "version": "3.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -1836,8 +1836,7 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-2.7.0.tgz", "integrity": "sha1-q259nYhqrKiwhbwzEreaGYQz8Oc=", - "dev": true, - "optional": true + "dev": true }, "acorn-dynamic-import": { "version": "3.0.0", @@ -1954,15 +1953,6 @@ "nan": "^2.10.0" } }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, "argv-tools": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/argv-tools/-/argv-tools-0.1.1.tgz", @@ -2094,8 +2084,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true, - "optional": true + "dev": true }, "assertion-error": { "version": "1.1.0", @@ -3197,7 +3186,6 @@ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", "dev": true, - "optional": true, "requires": { "delayed-stream": "~1.0.0" } @@ -3323,6 +3311,12 @@ "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", "dev": true }, + "conventional-commit-types": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/conventional-commit-types/-/conventional-commit-types-2.1.1.tgz", + "integrity": "sha512-0Ts+fEdmjqYDOQ1yZ+LNgdSPO335XZw9qC10M7CxtLP3nIMGmeMhmkM8Taffa4+MXN13bRPlp0CtH+QfOzKTzw==", + "dev": true + }, "convert-source-map": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz", @@ -3440,8 +3434,7 @@ "version": "0.3.4", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.4.tgz", "integrity": "sha512-+7prCSORpXNeR4/fUP3rL+TzqtiFfhMvTd7uEqMdgPvLPt4+uzFUeufx5RHjGTACCargg/DiEt/moMQmvnfkog==", - "dev": true, - "optional": true + "dev": true }, "cssstyle": { "version": "0.2.37", @@ -3458,6 +3451,19 @@ "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz", "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=" }, + "cz-conventional-changelog": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cz-conventional-changelog/-/cz-conventional-changelog-2.1.0.tgz", + "integrity": "sha1-L0vHOQ4yROTfKT5ro1Hkx0Cnx2Q=", + "dev": true, + "requires": { + "conventional-commit-types": "^2.0.0", + "lodash.map": "^4.5.1", + "longest": "^1.0.1", + "right-pad": "^1.0.1", + "word-wrap": "^1.0.3" + } + }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", @@ -3629,8 +3635,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true, - "optional": true + "dev": true }, "delegates": { "version": "1.0.0", @@ -3681,9 +3686,9 @@ } }, "dmd": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/dmd/-/dmd-3.0.12.tgz", - "integrity": "sha512-79w644JdsB2TthYpVl2bDurX7i9Abaegg2E7X46Ajc135aASTMXxrHzJ9mOa5X5nbmnXwlBYiF68K+1baX+BzQ==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/dmd/-/dmd-3.0.13.tgz", + "integrity": "sha512-FV/417bH2c/CYpe8BjFEAHoaHaItcJnPlKELi/qyPZdmUom8joyuC78OhhfPUdyKD/WcouTQ2LxQT4M/RoiJ3w==", "dev": true, "requires": { "array-back": "^2.0.0", @@ -4662,8 +4667,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true, - "optional": true + "dev": true }, "fast-deep-equal": { "version": "1.1.0", @@ -4949,14 +4953,14 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "fsevents": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz", - "integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.8.tgz", + "integrity": "sha512-tPvHgPGB7m40CZ68xqFGkKuzN+RnpGmSV+hgeKxhRpbxdqKXUFJGC3yonBOLzQBcJyGpdZFDfCsdOC2KFsXzeA==", "dev": true, "optional": true, "requires": { - "nan": "^2.9.2", - "node-pre-gyp": "^0.10.0" + "nan": "^2.12.1", + "node-pre-gyp": "^0.12.0" }, "dependencies": { "abbrev": { @@ -4968,8 +4972,7 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -4978,7 +4981,7 @@ "optional": true }, "are-we-there-yet": { - "version": "1.1.4", + "version": "1.1.5", "bundled": true, "dev": true, "optional": true, @@ -4990,21 +4993,19 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "chownr": { - "version": "1.0.1", + "version": "1.1.1", "bundled": true, "dev": true, "optional": true @@ -5012,20 +5013,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -5034,16 +5032,16 @@ "optional": true }, "debug": { - "version": "2.6.9", + "version": "4.1.1", "bundled": true, "dev": true, "optional": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "deep-extend": { - "version": "0.5.1", + "version": "0.6.0", "bundled": true, "dev": true, "optional": true @@ -5092,7 +5090,7 @@ } }, "glob": { - "version": "7.1.2", + "version": "7.1.3", "bundled": true, "dev": true, "optional": true, @@ -5112,12 +5110,12 @@ "optional": true }, "iconv-lite": { - "version": "0.4.21", + "version": "0.4.24", "bundled": true, "dev": true, "optional": true, "requires": { - "safer-buffer": "^2.1.0" + "safer-buffer": ">= 2.1.2 < 3" } }, "ignore-walk": { @@ -5142,8 +5140,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -5155,7 +5152,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -5170,7 +5166,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -5178,21 +5173,19 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { - "version": "2.2.4", + "version": "2.3.5", "bundled": true, "dev": true, - "optional": true, "requires": { - "safe-buffer": "^5.1.1", + "safe-buffer": "^5.1.2", "yallist": "^3.0.0" } }, "minizlib": { - "version": "1.1.0", + "version": "1.2.1", "bundled": true, "dev": true, "optional": true, @@ -5204,41 +5197,47 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } }, "ms": { - "version": "2.0.0", + "version": "2.1.1", "bundled": true, "dev": true, "optional": true }, + "nan": { + "version": "2.13.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.13.2.tgz", + "integrity": "sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw==", + "dev": true, + "optional": true + }, "needle": { - "version": "2.2.0", + "version": "2.3.0", "bundled": true, "dev": true, "optional": true, "requires": { - "debug": "^2.1.2", + "debug": "^4.1.0", "iconv-lite": "^0.4.4", "sax": "^1.2.4" } }, "node-pre-gyp": { - "version": "0.10.0", + "version": "0.12.0", "bundled": true, "dev": true, "optional": true, "requires": { "detect-libc": "^1.0.2", "mkdirp": "^0.5.1", - "needle": "^2.2.0", + "needle": "^2.2.1", "nopt": "^4.0.1", "npm-packlist": "^1.1.6", "npmlog": "^4.0.2", - "rc": "^1.1.7", + "rc": "^1.2.7", "rimraf": "^2.6.1", "semver": "^5.3.0", "tar": "^4" @@ -5255,13 +5254,13 @@ } }, "npm-bundled": { - "version": "1.0.3", + "version": "1.0.6", "bundled": true, "dev": true, "optional": true }, "npm-packlist": { - "version": "1.1.10", + "version": "1.4.1", "bundled": true, "dev": true, "optional": true, @@ -5285,8 +5284,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -5298,7 +5296,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -5338,12 +5335,12 @@ "optional": true }, "rc": { - "version": "1.2.7", + "version": "1.2.8", "bundled": true, "dev": true, "optional": true, "requires": { - "deep-extend": "^0.5.1", + "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" @@ -5373,19 +5370,18 @@ } }, "rimraf": { - "version": "2.6.2", + "version": "2.6.3", "bundled": true, "dev": true, "optional": true, "requires": { - "glob": "^7.0.5" + "glob": "^7.1.3" } }, "safe-buffer": { - "version": "5.1.1", + "version": "5.1.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -5400,7 +5396,7 @@ "optional": true }, "semver": { - "version": "5.5.0", + "version": "5.7.0", "bundled": true, "dev": true, "optional": true @@ -5421,7 +5417,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -5441,7 +5436,6 @@ "version": "3.0.1", "bundled": true, "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -5453,17 +5447,17 @@ "optional": true }, "tar": { - "version": "4.4.1", + "version": "4.4.8", "bundled": true, "dev": true, "optional": true, "requires": { - "chownr": "^1.0.1", + "chownr": "^1.1.1", "fs-minipass": "^1.2.5", - "minipass": "^2.2.4", - "minizlib": "^1.1.0", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.1", + "safe-buffer": "^5.1.2", "yallist": "^3.0.2" } }, @@ -5474,25 +5468,23 @@ "optional": true }, "wide-align": { - "version": "1.1.2", + "version": "1.1.3", "bundled": true, "dev": true, "optional": true, "requires": { - "string-width": "^1.0.2" + "string-width": "^1.0.2 || 2" } }, "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "yallist": { - "version": "3.0.2", + "version": "3.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true } } }, @@ -5666,25 +5658,29 @@ "dev": true }, "handlebars": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.0.tgz", - "integrity": "sha512-l2jRuU1NAWK6AW5qqcTATWQJvNPEwkM7NEKSiv/gqOsoSQbVoWyqVEY5GS+XPQ88zLNmqASRpzfdm8d79hJS+w==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.2.tgz", + "integrity": "sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==", "dev": true, "requires": { - "async": "^2.5.0", + "neo-async": "^2.6.0", "optimist": "^0.6.1", "source-map": "^0.6.1", "uglify-js": "^3.1.4" }, "dependencies": { - "async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", - "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", + "commander": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", "dev": true, - "requires": { - "lodash": "^4.17.11" - } + "optional": true + }, + "neo-async": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.0.tgz", + "integrity": "sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA==", + "dev": true }, "source-map": { "version": "0.6.1", @@ -5693,13 +5689,13 @@ "dev": true }, "uglify-js": { - "version": "3.4.9", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz", - "integrity": "sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==", + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.5.4.tgz", + "integrity": "sha512-GpKo28q/7Bm5BcX9vOu4S46FwisbPbAmkkqPnGIpKvKTM96I85N6XHQV+k4I6FA2wxgLhcsSyHoNhzucwCflvA==", "dev": true, "optional": true, "requires": { - "commander": "~2.17.1", + "commander": "~2.20.0", "source-map": "~0.6.1" } } @@ -6387,11 +6383,9 @@ }, "js-yaml": { "version": "3.12.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", - "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", + "resolved": "", "dev": true, "requires": { - "argparse": "^1.0.7", "esprima": "^4.0.0" }, "dependencies": { @@ -6839,6 +6833,12 @@ "integrity": "sha512-Oo2Si3RMKV3+lV5MsSWplDQFoTClz/24S0MMHYcgGWWmFXr6TMlqcqk/l1GtH+d5wLBwNRiqGnwDRMirtFalJw==", "dev": true }, + "longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", + "dev": true + }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -6891,9 +6891,9 @@ } }, "marked": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-0.5.0.tgz", - "integrity": "sha512-UhjmkCWKu1SS/BIePL2a59BMJ7V42EYtTfksodPRXzPEGEph3Inp5dylseqt+KbU9Jglsx8xcMKmlumfJMBXAA==", + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-0.6.2.tgz", + "integrity": "sha512-LqxwVH3P/rqKX4EKGz7+c2G9r98WeM/SW34ybhgNGhUQNKtf1GmmSkJ6cDGJ/t6tiyae49qRkpyTw2B9HOrgUA==", "dev": true }, "md5": { @@ -6972,15 +6972,13 @@ "version": "1.35.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.35.0.tgz", "integrity": "sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg==", - "dev": true, - "optional": true + "dev": true }, "mime-types": { "version": "2.1.19", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.19.tgz", "integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==", "dev": true, - "optional": true, "requires": { "mime-db": "~1.35.0" } @@ -7960,8 +7958,7 @@ "version": "1.1.29", "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz", "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==", - "dev": true, - "optional": true + "dev": true }, "public-encrypt": { "version": "4.0.2", @@ -8122,7 +8119,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" } } @@ -8553,6 +8550,12 @@ "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", "dev": true }, + "right-pad": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/right-pad/-/right-pad-1.0.1.tgz", + "integrity": "sha1-jKCMLLtbVedNr6lr9/0aJ9VoyNA=", + "dev": true + }, "rimraf": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", @@ -9102,12 +9105,6 @@ "extend-shallow": "^3.0.0" } }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, "sshpk": { "version": "1.14.2", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz", @@ -9768,7 +9765,6 @@ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", "dev": true, - "optional": true, "requires": { "psl": "^1.1.24", "punycode": "^1.4.1" @@ -9778,8 +9774,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true, - "optional": true + "dev": true } } }, @@ -10469,6 +10464,12 @@ "string-width": "^1.0.2 || 2" } }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", From a059273494b561152a676df2be22efd016b6d6e4 Mon Sep 17 00:00:00 2001 From: nduchak Date: Wed, 17 Apr 2019 15:46:46 +0300 Subject: [PATCH 15/16] chore(Channel): Revert to 2.2.0 --- .env | 2 +- CHANGELOG.md | 17 ----------------- test/integration/channel.js | 2 +- 3 files changed, 2 insertions(+), 19 deletions(-) diff --git a/.env b/.env index 10bf699537..45221a325a 100644 --- a/.env +++ b/.env @@ -1,3 +1,3 @@ -TAG=v2.3.0 +TAG=v2.2.0 COMPILER_TAG=v2.1.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index 83b53cc23d..3b74bfb07d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,20 +1,3 @@ -# [3.0.0](https://github.com/aeternity/aepp-sdk-js/compare/2.4.1...3.0.0) (2019-04-17) - - -### Bug Fixes - -* **ACI:** Fix address type transformation when decoding data ([#335](https://github.com/aeternity/aepp-sdk-js/issues/335)) ([e37cdfc](https://github.com/aeternity/aepp-sdk-js/commit/e37cdfc)) -* **Channel:** Fix failing test on 2.3.0 node ([55a2891](https://github.com/aeternity/aepp-sdk-js/commit/55a2891)) - - -### Features - -* **ACI:** Update due to compiler API changes ([#331](https://github.com/aeternity/aepp-sdk-js/issues/331)) ([e047f3b](https://github.com/aeternity/aepp-sdk-js/commit/e047f3b)) -* **npm:** Add script for auto-generating changelog ([97c2a3c](https://github.com/aeternity/aepp-sdk-js/commit/97c2a3c)) -* **State Channels:** Add cleanContractCalls method ([#338](https://github.com/aeternity/aepp-sdk-js/issues/338)) ([778159a](https://github.com/aeternity/aepp-sdk-js/commit/778159a)) - - - # [3.0.0](https://github.com/aeternity/aepp-sdk-js/compare/2.4.0...3.0.0) (2019-04-17) diff --git a/test/integration/channel.js b/test/integration/channel.js index 60a909b2e2..627566a72c 100644 --- a/test/integration/channel.js +++ b/test/integration/channel.js @@ -701,7 +701,7 @@ describe('Channel', function () { }) it('when posting an update with incorrect address', async () => { - return update({ from: 'ak_123' }).should.eventually.be.rejectedWith('Internal error') + return update({ from: 'ak_123' }).should.eventually.be.rejectedWith('Rejected') }) it('when posting an update with incorrect amount', async () => { From 71b0d0578115341c437ca9117f309d6bcb68fe9f Mon Sep 17 00:00:00 2001 From: nduchak Date: Wed, 17 Apr 2019 15:59:38 +0300 Subject: [PATCH 16/16] docs(Docs): Regenerate docs --- CHANGELOG.md | 5 +++++ docs/api/channel/index.md | 19 +++++++++++++++++++ docs/api/tx/builder.md | 1 + 3 files changed, 25 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b74bfb07d..32d760e552 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,11 @@ * **State Channels:** Add cleanContractCalls method ([#338](https://github.com/aeternity/aepp-sdk-js/issues/338)) ([778159a](https://github.com/aeternity/aepp-sdk-js/commit/778159a)) +### BREAKING CHANGES + +* **ACI** Remove 2.0.0 compiler compatibility + + # [2.4.1](https://github.com/aeternity/aepp-sdk-js/compare/2.4.0...2.4.1) (2019-04-17) diff --git a/docs/api/channel/index.md b/docs/api/channel/index.md index 7219ee5d6f..ee8662dc97 100644 --- a/docs/api/channel/index.md +++ b/docs/api/channel/index.md @@ -14,6 +14,7 @@ import Channel from '@aeternity/aepp-sdk/es/channel/index' * [~on(event, callback)](#module_@aeternity/aepp-sdk/es/channel/index--Channel..on) * [~status()](#module_@aeternity/aepp-sdk/es/channel/index--Channel..status) ⇒ `string` * [~state()](#module_@aeternity/aepp-sdk/es/channel/index--Channel..state) ⇒ `object` + * [~id()](#module_@aeternity/aepp-sdk/es/channel/index--Channel..id) ⇒ `string` * [~update(from, to, amount, sign)](#module_@aeternity/aepp-sdk/es/channel/index--Channel..update) ⇒ `Promise.<object>` * [~poi(addresses)](#module_@aeternity/aepp-sdk/es/channel/index--Channel..poi) ⇒ `Promise.<string>` * [~balances(accounts)](#module_@aeternity/aepp-sdk/es/channel/index--Channel..balances) ⇒ `Promise.<object>` @@ -26,6 +27,7 @@ import Channel from '@aeternity/aepp-sdk/es/channel/index' * [~callContractStatic(options)](#module_@aeternity/aepp-sdk/es/channel/index--Channel..callContractStatic) ⇒ `Promise.<object>` * [~getContractCall(options)](#module_@aeternity/aepp-sdk/es/channel/index--Channel..getContractCall) ⇒ `Promise.<object>` * [~getContractState(contract)](#module_@aeternity/aepp-sdk/es/channel/index--Channel..getContractState) ⇒ `Promise.<object>` + * [~cleanContractCalls()](#module_@aeternity/aepp-sdk/es/channel/index--Channel..cleanContractCalls) ⇒ `Promise` * [~sendMessage(message, recipient)](#module_@aeternity/aepp-sdk/es/channel/index--Channel..sendMessage) @@ -97,6 +99,12 @@ Get current status #### Channel~state() ⇒ `object` Get current state +**Kind**: inner method of [`Channel`](#exp_module_@aeternity/aepp-sdk/es/channel/index--Channel) + + +#### Channel~id() ⇒ `string` +Get channel id + **Kind**: inner method of [`Channel`](#exp_module_@aeternity/aepp-sdk/es/channel/index--Channel) @@ -395,6 +403,17 @@ channel.getContractState( console.log('deposit:', contract.deposit) }) ``` + + +#### Channel~cleanContractCalls() ⇒ `Promise` +Clean up all locally stored contract calls + +Contract calls are kept locally in order for the participant to be able to look them up. +They consume memory and in order for the participant to free it - one can prune all messages. +This cleans up all locally stored contract calls and those will no longer be available for +fetching and inspection. + +**Kind**: inner method of [`Channel`](#exp_module_@aeternity/aepp-sdk/es/channel/index--Channel) #### Channel~sendMessage(message, recipient) diff --git a/docs/api/tx/builder.md b/docs/api/tx/builder.md index f16c668fac..7344617a9b 100644 --- a/docs/api/tx/builder.md +++ b/docs/api/tx/builder.md @@ -101,6 +101,7 @@ Build transaction hash | type | `String` | | Transaction type | | [options] | `Object` | {} | options | | [options.excludeKeys] | `Object` | | excludeKeys Array of keys to exclude for validation and build | +| [options.prefix] | `String` | | Prefix of transaction |