diff --git a/.eslintrc.js b/.eslintrc.js index 72f3f20b..b75ec88d 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -55,7 +55,8 @@ module.exports = { }] }, "globals": { - "BigInt": "readonly" + "BigInt": "readonly", + "globalThis": "readonly", }, "env": { "node": true, diff --git a/.gitignore b/.gitignore index 909e4228..b4a404d1 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,7 @@ packages/*/lib playground.ts #docs -docs +/docs # ignore for deploy docs package-lock.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 48ee58bf..0101b57c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,18 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.36.1](https://github.com/nervosnetwork/ckb-sdk-js/compare/v0.36.0...v0.36.1) (2020-09-26) + + +### Features + +* **utils:** disable blake2b-wasm when the host is iOS 11 ([4c70554](https://github.com/nervosnetwork/ckb-sdk-js/commit/4c7055466aeb2b8cd2fda2ae927e88cb699d161b)) +* **utils:** add a method to reconcile transactions ([1ae64cd](https://github.com/nervosnetwork/ckb-sdk-js/commit/1ae64cd258cacffcb77e664bb3853dd4c7ec9150)) + + + + + # [0.36.0](https://github.com/nervosnetwork/ckb-sdk-js/compare/v0.35.0...v0.36.0) (2020-09-21) diff --git a/lerna.json b/lerna.json index 65d24557..7de2aa56 100644 --- a/lerna.json +++ b/lerna.json @@ -4,5 +4,5 @@ ], "npmClient": "yarn", "useWorkspaces": true, - "version": "0.36.0" + "version": "0.36.1" } diff --git a/packages/ckb-sdk-core/CHANGELOG.md b/packages/ckb-sdk-core/CHANGELOG.md index 25d728c0..eebe0280 100644 --- a/packages/ckb-sdk-core/CHANGELOG.md +++ b/packages/ckb-sdk-core/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.36.1](https://github.com/nervosnetwork/ckb-sdk-js/compare/v0.36.0...v0.36.1) (2020-09-26) + +**Note:** Version bump only for package @nervosnetwork/ckb-sdk-core + + + + + # [0.36.0](https://github.com/nervosnetwork/ckb-sdk-js/compare/v0.35.0...v0.36.0) (2020-09-21) diff --git a/packages/ckb-sdk-core/package.json b/packages/ckb-sdk-core/package.json index e9990dfe..f235641e 100644 --- a/packages/ckb-sdk-core/package.json +++ b/packages/ckb-sdk-core/package.json @@ -1,6 +1,6 @@ { "name": "@nervosnetwork/ckb-sdk-core", - "version": "0.36.0", + "version": "0.36.1", "description": "JavaScript SDK for Nervos Network CKB Project", "author": "Nervos ", "homepage": "https://github.com/nervosnetwork/ckb-sdk-js#readme", @@ -31,10 +31,10 @@ "url": "https://github.com/nervosnetwork/ckb-sdk-js/issues" }, "dependencies": { - "@nervosnetwork/ckb-sdk-rpc": "0.36.0", - "@nervosnetwork/ckb-sdk-utils": "0.36.0", - "@nervosnetwork/ckb-types": "0.36.0", + "@nervosnetwork/ckb-sdk-rpc": "0.36.1", + "@nervosnetwork/ckb-sdk-utils": "0.36.1", + "@nervosnetwork/ckb-types": "0.36.1", "tslib": "2.0.1" }, - "gitHead": "d0adcbb7e6743fdcc049984534afab13f5ede178" + "gitHead": "b34332872a9168a1879d3020ca3546b72816823a" } diff --git a/packages/ckb-sdk-rpc/CHANGELOG.md b/packages/ckb-sdk-rpc/CHANGELOG.md index fa234a7f..cbf2c821 100644 --- a/packages/ckb-sdk-rpc/CHANGELOG.md +++ b/packages/ckb-sdk-rpc/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.36.1](https://github.com/nervosnetwork/ckb-sdk-js/compare/v0.36.0...v0.36.1) (2020-09-26) + +**Note:** Version bump only for package @nervosnetwork/ckb-sdk-rpc + + + + + # [0.36.0](https://github.com/nervosnetwork/ckb-sdk-js/compare/v0.35.0...v0.36.0) (2020-09-21) **Note:** Version bump only for package @nervosnetwork/ckb-sdk-rpc diff --git a/packages/ckb-sdk-rpc/package.json b/packages/ckb-sdk-rpc/package.json index 1587abf6..5b45f45a 100644 --- a/packages/ckb-sdk-rpc/package.json +++ b/packages/ckb-sdk-rpc/package.json @@ -1,6 +1,6 @@ { "name": "@nervosnetwork/ckb-sdk-rpc", - "version": "0.36.0", + "version": "0.36.1", "description": "RPC module of @nervosnetwork/ckb-sdk-core", "author": "Nervos ", "homepage": "https://github.com/nervosnetwork/ckb-sdk-js/packages/ckb-rpc#readme", @@ -33,12 +33,12 @@ "url": "https://github.com/nervosnetwork/ckb-sdk-js/issues" }, "dependencies": { - "@nervosnetwork/ckb-sdk-utils": "0.36.0", + "@nervosnetwork/ckb-sdk-utils": "0.36.1", "axios": "0.19.2", "tslib": "2.0.1" }, "devDependencies": { - "@nervosnetwork/ckb-types": "0.36.0" + "@nervosnetwork/ckb-types": "0.36.1" }, - "gitHead": "d0adcbb7e6743fdcc049984534afab13f5ede178" + "gitHead": "b34332872a9168a1879d3020ca3546b72816823a" } diff --git a/packages/ckb-sdk-utils/CHANGELOG.md b/packages/ckb-sdk-utils/CHANGELOG.md index c0b33447..482b0d60 100644 --- a/packages/ckb-sdk-utils/CHANGELOG.md +++ b/packages/ckb-sdk-utils/CHANGELOG.md @@ -3,6 +3,18 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.36.1](https://github.com/nervosnetwork/ckb-sdk-js/compare/v0.36.0...v0.36.1) (2020-09-26) + + +### Features + +* **utils:** disable blake2b-wasm when the host is iOS 11 ([4c70554](https://github.com/nervosnetwork/ckb-sdk-js/commit/4c7055466aeb2b8cd2fda2ae927e88cb699d161b)) +* **utils:** add a method to reconcile transactions ([1ae64cd](https://github.com/nervosnetwork/ckb-sdk-js/commit/1ae64cd258cacffcb77e664bb3853dd4c7ec9150)) + + + + + # [0.36.0](https://github.com/nervosnetwork/ckb-sdk-js/compare/v0.35.0...v0.36.0) (2020-09-21) diff --git a/packages/ckb-sdk-utils/__tests__/utils/bech32.fixtures.json b/packages/ckb-sdk-utils/__tests__/crypto/bech32.fixtures.json similarity index 100% rename from packages/ckb-sdk-utils/__tests__/utils/bech32.fixtures.json rename to packages/ckb-sdk-utils/__tests__/crypto/bech32.fixtures.json diff --git a/packages/ckb-sdk-utils/__tests__/crypto/bech32.test.js b/packages/ckb-sdk-utils/__tests__/crypto/bech32.test.js new file mode 100644 index 00000000..9833a6f5 --- /dev/null +++ b/packages/ckb-sdk-utils/__tests__/crypto/bech32.test.js @@ -0,0 +1,35 @@ +const { bech32 } = require('../..') +const fixtures = require('./bech32.fixtures.json') + +describe('bech32', () => { + fixtures.bech32.valid.forEach(f => { + it(`fromWords/toWords ${f.hex}`, () => { + if (f.hex) { + const words = bech32.toWords(Buffer.from(f.hex, 'hex')) + const bytes = Buffer.from(bech32.fromWords(f.words)) + expect(words.join('')).toEqual(f.words.join('')) + expect(bytes.toString('hex')).toBe(f.hex) + } + }) + + it(`encode ${f.prefix}`, () => { + const encoded = bech32.encode(f.prefix, f.words, f.limit) + expect(encoded).toBe(f.string.toLowerCase()) + }) + + it(`decode ${f.string}`, () => { + const decoded = bech32.decode(f.string, f.limit) + expect(decoded.prefix).toBe(f.prefix.toLowerCase()) + expect(decoded.words.join('')).toBe(f.words.join('')) + }) + + it(`fails for ${f.string} with 1 bit flipped`, () => { + const buf = Buffer.from(f.string, 'utf8') + buf[f.string.lastIndexOf('1') + 1] ^= 0x1 + const str = buf.toString('utf8') + expect(() => { + bech32.decode(str, f.limit) + }).toThrow() + }) + }) +}) diff --git a/packages/ckb-sdk-utils/__tests__/crypto/blake160.test.js b/packages/ckb-sdk-utils/__tests__/crypto/blake160.test.js new file mode 100644 index 00000000..23309027 --- /dev/null +++ b/packages/ckb-sdk-utils/__tests__/crypto/blake160.test.js @@ -0,0 +1,12 @@ +const { blake160 } = require('../..') + +describe('blake160', () => { + it('blake160', () => { + const fixture = { + message: '024a501efd328e062c8675f2365970728c859c592beeefd6be8ead3d901330bc01', + digest: '36c329ed630d6ce750712a477543672adab57f4c', + } + const digest = blake160(new Uint8Array(Buffer.from(fixture.message, 'hex')), 'hex') + expect(digest).toBe(fixture.digest) + }) +}) diff --git a/packages/ckb-sdk-utils/__tests__/utils/blake2b.fixtures.json b/packages/ckb-sdk-utils/__tests__/crypto/blake2b.fixtures.json similarity index 100% rename from packages/ckb-sdk-utils/__tests__/utils/blake2b.fixtures.json rename to packages/ckb-sdk-utils/__tests__/crypto/blake2b.fixtures.json diff --git a/packages/ckb-sdk-utils/__tests__/crypto/blake2b.test.js b/packages/ckb-sdk-utils/__tests__/crypto/blake2b.test.js new file mode 100644 index 00000000..6d890de8 --- /dev/null +++ b/packages/ckb-sdk-utils/__tests__/crypto/blake2b.test.js @@ -0,0 +1,101 @@ +const { blake2b, PERSONAL } = require('../..') +const { ready } = require('../../lib/crypto/blake2b') +const fixtures = require('./blake2b.fixtures.json') + +describe('blake2b', () => { + it('blake2b([]) with personal', () => { + const fixture = { + message: new Uint8Array(), + digest: '44f4c69744d5f8c55d642062949dcae49bc4e7ef43d388c5a12f42b5633d163e', + } + const s = blake2b(32, null, null, PERSONAL) + s.update(fixture.message) + const digest = s.digest('hex') + expect(digest).toBe(fixture.digest) + }) + + it('blake2b(Buffer.from("The quick brown fox jumps over the lazy dog")) with personal', () => { + const fixture = { + message: 'The quick brown fox jumps over the lazy dog', + digest: 'abfa2c08d62f6f567d088d6ba41d3bbbb9a45c241a8e3789ef39700060b5cee2', + } + const s = blake2b(32, null, null, PERSONAL) + s.update(new Uint8Array(Buffer.from(fixture.message, 'utf8'))) + const digest = s.digest('hex') + expect(digest).toBe(fixture.digest) + }) + + test.each(fixtures)('%s', ({ outlen, out, input, key, salt, personal }) => { + if (+outlen < 16) { + expect(() => { + blake2b( + outlen, + key ? new Uint8Array(Buffer.from(key, 'hex')) : null, + salt ? new Uint8Array(Buffer.from(salt, 'hex')) : null, + personal ? new Uint8Array(Buffer.from(personal, 'hex')) : null, + ) + }).toThrowError(`Expect outlen to be at least 16, but ${outlen} received`) + } else { + const s = blake2b( + outlen, + key ? new Uint8Array(Buffer.from(key, 'hex')) : null, + salt ? new Uint8Array(Buffer.from(salt, 'hex')) : null, + personal ? new Uint8Array(Buffer.from(personal, 'hex')) : null, + ) + s.update(new Uint8Array(Buffer.from(input, 'hex'))) + const digest = s.digest('hex') + expect(digest).toBe(out) + } + }) +}) + +describe('blake2b-wasm-ready', () => { + afterEach(() => { + delete globalThis.navigator + }) + + describe("When it's in browser but not iOS 11", () => { + beforeEach(() => { + Object.defineProperty(globalThis, 'navigator', { + value: { + userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 12_4_4 like Mac OS X)', + }, + }) + }) + + it('callback should be invoked without error', () => { + expect.assertions(1) + ready(err => { + expect(err).toBeUndefined() + }) + }) + }) + + describe("When it's not in browser and navigator is undefined", () => { + beforeEach(() => { + delete globalThis.navigator + }) + it('callback should be invoked without error', () => { + expect.assertions(1) + ready(err => { + expect(err).toBeUndefined() + }) + }) + }) + + describe("When it's iOS 11", () => { + beforeEach(() => { + Object.defineProperty(globalThis, 'navigator', { + value: { + userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_2_1 like Mac OS X)', + }, + }) + }) + it('callback should be invoked with error', () => { + expect.assertions(1) + ready(err => { + expect(err).toEqual(new Error('blake2b-wasm is unavailable on iOS 11')) + }) + }) + }) +}) diff --git a/packages/ckb-sdk-utils/__tests__/exceptions/fixtures.json b/packages/ckb-sdk-utils/__tests__/exceptions/fixtures.json index bc80792c..1aa66a4a 100644 --- a/packages/ckb-sdk-utils/__tests__/exceptions/fixtures.json +++ b/packages/ckb-sdk-utils/__tests__/exceptions/fixtures.json @@ -124,5 +124,12 @@ "code": 101, "message": "Expect PERSONAL length to be 16, but 32 received" } + }, + "ReconciliationException": { + "params": [], + "expected": { + "code": 105, + "message": "Fail to reconcile transaction, try to increase extra count or check the transaction" + } } } diff --git a/packages/ckb-sdk-utils/__tests__/reconciliation/extraInputs.fixtures.json b/packages/ckb-sdk-utils/__tests__/reconciliation/extraInputs.fixtures.json new file mode 100644 index 00000000..72a6a463 --- /dev/null +++ b/packages/ckb-sdk-utils/__tests__/reconciliation/extraInputs.fixtures.json @@ -0,0 +1,362 @@ +{ + "change is enough for fee": { + "params": [ + { + "tx": { + "version": "0x0", + "cellDeps": [ + { + "outPoint": { + "txHash": "0xc12386705b5cbb312b693874f3edf45c43a274482e27b8df0fd80c8d3f5feb8b", + "index": "0x0" + }, + "depType": "depGroup" + }, + { + "outPoint": { + "txHash": "0x0fb4945d52baf91e0dee2a686cdd9d84cad95b566a1d7409b970ee0a0f364f60", + "index": "0x2" + }, + "depType": "code" + } + ], + "headerDeps": [], + "inputs": [ + { + "previousOutput": { + "txHash": "0x31f695263423a4b05045dd25ce6692bb55d7bba2965d8be16b036e138e72cc65", + "index": "0x1" + }, + "since": "0x0" + } + ], + "outputs": [ + { + "capacity": "0x174876e800", + "lock": { + "codeHash": "0x68d5438ac952d2f584abf879527946a537e82c7f3c1cbf6d8ebf9767437d8e88", + "args": "0x59a27ef3ba84f061517d13f42cf44ed020610061", + "hashType": "type" + }, + "type": { + "codeHash": "0xece45e0979030e2f8909f76258631c42333b1e906fd9701ec3600a464a90b8f6", + "args": "0x", + "hashType": "data" + } + }, + { + "capacity": "0x16b969f18", + "lock": { + "codeHash": "0x68d5438ac952d2f584abf879527946a537e82c7f3c1cbf6d8ebf9767437d8e88", + "args": "0x59a27ef3ba84f061517d13f42cf44ed020610061", + "hashType": "type" + }, + "type": null + } + ], + "outputsData": ["0x1234", "0x"], + "witnesses": [ + "0x82df73581bcd08cb9aa270128d15e79996229ce8ea9e4f985b49fbf36762c5c37936caf3ea3784ee326f60b8992924fcf496f9503c907982525a3436f01ab32900" + ] + }, + "feeRate": "1000", + "changeThreshold": "6100000000", + "cells": [], + "extraCount": 1 + } + ], + "expected": { + "version": "0x0", + "cellDeps": [ + { + "outPoint": { + "txHash": "0xc12386705b5cbb312b693874f3edf45c43a274482e27b8df0fd80c8d3f5feb8b", + "index": "0x0" + }, + "depType": "depGroup" + }, + { + "outPoint": { + "txHash": "0x0fb4945d52baf91e0dee2a686cdd9d84cad95b566a1d7409b970ee0a0f364f60", + "index": "0x2" + }, + "depType": "code" + } + ], + "headerDeps": [], + "inputs": [ + { + "previousOutput": { + "txHash": "0x31f695263423a4b05045dd25ce6692bb55d7bba2965d8be16b036e138e72cc65", + "index": "0x1" + }, + "since": "0x0" + } + ], + "outputs": [ + { + "capacity": "0x174876e800", + "lock": { + "codeHash": "0x68d5438ac952d2f584abf879527946a537e82c7f3c1cbf6d8ebf9767437d8e88", + "args": "0x59a27ef3ba84f061517d13f42cf44ed020610061", + "hashType": "type" + }, + "type": { + "codeHash": "0xece45e0979030e2f8909f76258631c42333b1e906fd9701ec3600a464a90b8f6", + "args": "0x", + "hashType": "data" + } + }, + { + "capacity": "0x16b969d00", + "lock": { + "codeHash": "0x68d5438ac952d2f584abf879527946a537e82c7f3c1cbf6d8ebf9767437d8e88", + "args": "0x59a27ef3ba84f061517d13f42cf44ed020610061", + "hashType": "type" + }, + "type": null + } + ], + "outputsData": ["0x1234", "0x"], + "witnesses": [ + "0x82df73581bcd08cb9aa270128d15e79996229ce8ea9e4f985b49fbf36762c5c37936caf3ea3784ee326f60b8992924fcf496f9503c907982525a3436f01ab32900" + ] + } + }, + "Should add two input when \nfee: 5360000000\nfee rate: 10000000000\nchange: 7000000000\nlack: 4460000000\ncells: [2670000000, 2670000001]": { + "params": [ + { + "tx": { + "version": "0x0", + "cellDeps": [ + { + "outPoint": { + "txHash": "0xc12386705b5cbb312b693874f3edf45c43a274482e27b8df0fd80c8d3f5feb8b", + "index": "0x0" + }, + "depType": "depGroup" + }, + { + "outPoint": { + "txHash": "0x0fb4945d52baf91e0dee2a686cdd9d84cad95b566a1d7409b970ee0a0f364f60", + "index": "0x2" + }, + "depType": "code" + } + ], + "headerDeps": [], + "inputs": [ + { + "previousOutput": { + "txHash": "0x31f695263423a4b05045dd25ce6692bb55d7bba2965d8be16b036e138e72cc65", + "index": "0x1" + }, + "since": "0x0" + } + ], + "outputs": [ + { + "capacity": "0x174876e800", + "lock": { + "codeHash": "0x68d5438ac952d2f584abf879527946a537e82c7f3c1cbf6d8ebf9767437d8e88", + "args": "0x59a27ef3ba84f061517d13f42cf44ed020610061", + "hashType": "type" + }, + "type": { + "codeHash": "0xece45e0979030e2f8909f76258631c42333b1e906fd9701ec3600a464a90b8f6", + "args": "0x", + "hashType": "data" + } + }, + { + "capacity": "0x1a13b8600", + "lock": { + "codeHash": "0x68d5438ac952d2f584abf879527946a537e82c7f3c1cbf6d8ebf9767437d8e88", + "args": "0x59a27ef3ba84f061517d13f42cf44ed020610061", + "hashType": "type" + }, + "type": null + } + ], + "outputsData": ["0x1234", "0x"], + "witnesses": [ + "0x82df73581bcd08cb9aa270128d15e79996229ce8ea9e4f985b49fbf36762c5c37936caf3ea3784ee326f60b8992924fcf496f9503c907982525a3436f01ab32900" + ] + }, + "feeRate": "10000000000", + "changeThreshold": "6100000000", + "cells": [ + { + "capacity": "0x9f24f780", + "outPoint": { + "txHash": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "index": "0x1" + } + }, + { + "capacity": "0x9f24f781", + "outPoint": { + "txHash": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "index": "0x2" + } + } + ], + "extraCount": 3 + } + ], + "expected": { + "version": "0x0", + "cellDeps": [ + { + "outPoint": { + "txHash": "0xc12386705b5cbb312b693874f3edf45c43a274482e27b8df0fd80c8d3f5feb8b", + "index": "0x0" + }, + "depType": "depGroup" + }, + { + "outPoint": { + "txHash": "0x0fb4945d52baf91e0dee2a686cdd9d84cad95b566a1d7409b970ee0a0f364f60", + "index": "0x2" + }, + "depType": "code" + } + ], + "headerDeps": [], + "inputs": [ + { + "previousOutput": { + "txHash": "0x31f695263423a4b05045dd25ce6692bb55d7bba2965d8be16b036e138e72cc65", + "index": "0x1" + }, + "since": "0x0" + }, + { + "previousOutput": { + "txHash": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "index": "0x1" + }, + "since": "0x0" + }, + { + "previousOutput": { + "txHash": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "index": "0x2" + }, + "since": "0x0" + } + ], + "outputs": [ + { + "capacity": "0x174876e800", + "lock": { + "codeHash": "0x68d5438ac952d2f584abf879527946a537e82c7f3c1cbf6d8ebf9767437d8e88", + "args": "0x59a27ef3ba84f061517d13f42cf44ed020610061", + "hashType": "type" + }, + "type": { + "codeHash": "0xece45e0979030e2f8909f76258631c42333b1e906fd9701ec3600a464a90b8f6", + "args": "0x", + "hashType": "data" + } + }, + { + "capacity": "0x16b969d01", + "lock": { + "codeHash": "0x68d5438ac952d2f584abf879527946a537e82c7f3c1cbf6d8ebf9767437d8e88", + "args": "0x59a27ef3ba84f061517d13f42cf44ed020610061", + "hashType": "type" + }, + "type": null + } + ], + "outputsData": ["0x1234", "0x"], + "witnesses": [ + "0x82df73581bcd08cb9aa270128d15e79996229ce8ea9e4f985b49fbf36762c5c37936caf3ea3784ee326f60b8992924fcf496f9503c907982525a3436f01ab32900" + ] + } + }, + "Fail to reconcile when \nfee: 5360000000\nfee rate: 10000000000\nchange: 7000000000\nlack: 4460000000\ncells: [2670000000, 2669999999]": { + "params": [ + { + "tx": { + "version": "0x0", + "cellDeps": [ + { + "outPoint": { + "txHash": "0xc12386705b5cbb312b693874f3edf45c43a274482e27b8df0fd80c8d3f5feb8b", + "index": "0x0" + }, + "depType": "depGroup" + }, + { + "outPoint": { + "txHash": "0x0fb4945d52baf91e0dee2a686cdd9d84cad95b566a1d7409b970ee0a0f364f60", + "index": "0x2" + }, + "depType": "code" + } + ], + "headerDeps": [], + "inputs": [ + { + "previousOutput": { + "txHash": "0x31f695263423a4b05045dd25ce6692bb55d7bba2965d8be16b036e138e72cc65", + "index": "0x1" + }, + "since": "0x0" + } + ], + "outputs": [ + { + "capacity": "0x174876e800", + "lock": { + "codeHash": "0x68d5438ac952d2f584abf879527946a537e82c7f3c1cbf6d8ebf9767437d8e88", + "args": "0x59a27ef3ba84f061517d13f42cf44ed020610061", + "hashType": "type" + }, + "type": { + "codeHash": "0xece45e0979030e2f8909f76258631c42333b1e906fd9701ec3600a464a90b8f6", + "args": "0x", + "hashType": "data" + } + }, + { + "capacity": "0x1a13b8600", + "lock": { + "codeHash": "0x68d5438ac952d2f584abf879527946a537e82c7f3c1cbf6d8ebf9767437d8e88", + "args": "0x59a27ef3ba84f061517d13f42cf44ed020610061", + "hashType": "type" + }, + "type": null + } + ], + "outputsData": ["0x1234", "0x"], + "witnesses": [ + "0x82df73581bcd08cb9aa270128d15e79996229ce8ea9e4f985b49fbf36762c5c37936caf3ea3784ee326f60b8992924fcf496f9503c907982525a3436f01ab32900" + ] + }, + "feeRate": "10000000000", + "changeThreshold": "6100000000", + "cells": [ + { + "capacity": "0x9f24f780", + "outPoint": { + "txHash": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "index": "0x1" + } + }, + { + "capacity": "0x9f24f77f", + "outPoint": { + "txHash": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "index": "0x2" + } + } + ], + "extraCount": 3 + } + ], + "exception": "Fail to reconcile transaction, try to increase extra count or check the transaction" + } +} diff --git a/packages/ckb-sdk-utils/__tests__/reconciliation/extraInputs.test.js b/packages/ckb-sdk-utils/__tests__/reconciliation/extraInputs.test.js new file mode 100644 index 00000000..fcf66ffe --- /dev/null +++ b/packages/ckb-sdk-utils/__tests__/reconciliation/extraInputs.test.js @@ -0,0 +1,21 @@ +const fixtures = require('./extraInputs.fixtures.json') +const { extraInputs } = require('../../lib/reconciliation/extraInputs') + +describe('Test reconciliation by extra inputs strategy', () => { + const fixtureTable = Object.entries(fixtures).map(([title, { params, expected, exception }]) => [ + title, + params, + expected, + exception, + ]) + + test.each(fixtureTable)(`%s`, (_title, params, expected, exception) => { + expect.assertions(1) + + if (exception) { + expect(() => extraInputs(...params)).toThrow(exception) + } else { + expect(extraInputs(...params)).toEqual(expected) + } + }) +}) diff --git a/packages/ckb-sdk-utils/__tests__/sizes/fixtures.json b/packages/ckb-sdk-utils/__tests__/sizes/fixtures.json index 9f980b7b..c155ab97 100644 --- a/packages/ckb-sdk-utils/__tests__/sizes/fixtures.json +++ b/packages/ckb-sdk-utils/__tests__/sizes/fixtures.json @@ -127,6 +127,222 @@ } ], "expected": 556 + }, + "1 IN 1 OUT": { + "params": [ + { + "version": "0x0", + "cellDeps": [ + { + "outPoint": { + "txHash": "0xc12386705b5cbb312b693874f3edf45c43a274482e27b8df0fd80c8d3f5feb8b", + "index": "0x0" + }, + "depType": "depGroup" + } + ], + "headerDeps": [], + "inputs": [ + { + "previousOutput": { + "txHash": "0x31f695263423a4b05045dd25ce6692bb55d7bba2965d8be16b036e138e72cc65", + "index": "0x1" + }, + "since": "0x0" + } + ], + "outputs": [ + { + "capacity": "0x174876e800", + "lock": { + "codeHash": "0x68d5438ac952d2f584abf879527946a537e82c7f3c1cbf6d8ebf9767437d8e88", + "args": "0x59a27ef3ba84f061517d13f42cf44ed020610061", + "hashType": "type" + } + } + ], + "outputsData": ["0x"], + "witnesses": [ + { + "lock": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "inputType": "", + "outputType": "" + } + ] + } + ], + "expected": 355 + }, + "1 IN 2 OUT": { + "params": [ + { + "version": "0x0", + "cellDeps": [ + { + "outPoint": { + "txHash": "0xc12386705b5cbb312b693874f3edf45c43a274482e27b8df0fd80c8d3f5feb8b", + "index": "0x0" + }, + "depType": "depGroup" + } + ], + "headerDeps": [], + "inputs": [ + { + "previousOutput": { + "txHash": "0x31f695263423a4b05045dd25ce6692bb55d7bba2965d8be16b036e138e72cc65", + "index": "0x1" + }, + "since": "0x0" + } + ], + "outputs": [ + { + "capacity": "0x174876e800", + "lock": { + "codeHash": "0x68d5438ac952d2f584abf879527946a537e82c7f3c1cbf6d8ebf9767437d8e88", + "args": "0x59a27ef3ba84f061517d13f42cf44ed020610061", + "hashType": "type" + } + }, + { + "capacity": "0x174876e800", + "lock": { + "codeHash": "0x68d5438ac952d2f584abf879527946a537e82c7f3c1cbf6d8ebf9767437d8e88", + "args": "0x59a27ef3ba84f061517d13f42cf44ed020610061", + "hashType": "type" + } + } + ], + "outputsData": ["0x", "0x"], + "witnesses": [ + { + "lock": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "inputType": "", + "outputType": "" + } + ] + } + ], + "expected": 464 + }, + "2 IN 1 OUT": { + "params": [ + { + "version": "0x0", + "cellDeps": [ + { + "outPoint": { + "txHash": "0xc12386705b5cbb312b693874f3edf45c43a274482e27b8df0fd80c8d3f5feb8b", + "index": "0x0" + }, + "depType": "depGroup" + } + ], + "headerDeps": [], + "inputs": [ + { + "previousOutput": { + "txHash": "0x31f695263423a4b05045dd25ce6692bb55d7bba2965d8be16b036e138e72cc65", + "index": "0x1" + }, + "since": "0x0" + }, + { + "previousOutput": { + "txHash": "0x31f695263423a4b05045dd25ce6692bb55d7bba2965d8be16b036e138e72cc65", + "index": "0x1" + }, + "since": "0x0" + } + ], + "outputs": [ + { + "capacity": "0x174876e800", + "lock": { + "codeHash": "0x68d5438ac952d2f584abf879527946a537e82c7f3c1cbf6d8ebf9767437d8e88", + "args": "0x59a27ef3ba84f061517d13f42cf44ed020610061", + "hashType": "type" + } + } + ], + "outputsData": ["0x"], + "witnesses": [ + { + "lock": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "inputType": "", + "outputType": "" + }, + "0x" + ] + } + ], + "expected": 407 + }, + "2 IN 2 OUT": { + "params": [ + { + "version": "0x0", + "cellDeps": [ + { + "outPoint": { + "txHash": "0xc12386705b5cbb312b693874f3edf45c43a274482e27b8df0fd80c8d3f5feb8b", + "index": "0x0" + }, + "depType": "depGroup" + } + ], + "headerDeps": [], + "inputs": [ + { + "previousOutput": { + "txHash": "0x31f695263423a4b05045dd25ce6692bb55d7bba2965d8be16b036e138e72cc65", + "index": "0x1" + }, + "since": "0x0" + }, + { + "previousOutput": { + "txHash": "0x31f695263423a4b05045dd25ce6692bb55d7bba2965d8be16b036e138e72cc65", + "index": "0x1" + }, + "since": "0x0" + } + ], + "outputs": [ + { + "capacity": "0x174876e800", + "lock": { + "codeHash": "0x68d5438ac952d2f584abf879527946a537e82c7f3c1cbf6d8ebf9767437d8e88", + "args": "0x59a27ef3ba84f061517d13f42cf44ed020610061", + "hashType": "type" + } + }, + { + "capacity": "0x174876e800", + "lock": { + "codeHash": "0x68d5438ac952d2f584abf879527946a537e82c7f3c1cbf6d8ebf9767437d8e88", + "args": "0x59a27ef3ba84f061517d13f42cf44ed020610061", + "hashType": "type" + } + } + ], + "outputsData": ["0x", "0x"], + "witnesses": [ + { + "lock": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "inputType": "", + "outputType": "" + }, + { + "lock": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "inputType": "", + "outputType": "" + } + ] + } + ], + "expected": 601 } } } diff --git a/packages/ckb-sdk-utils/__tests__/utils/index.test.js b/packages/ckb-sdk-utils/__tests__/utils/index.test.js index 926317a4..a8adc22e 100644 --- a/packages/ckb-sdk-utils/__tests__/utils/index.test.js +++ b/packages/ckb-sdk-utils/__tests__/utils/index.test.js @@ -1,113 +1,16 @@ -const ckbUtils = require('../..') -const exceptions = require('../../lib/exceptions') -const bech32Fixtures = require('./bech32.fixtures.json') -const blake2bFixtures = require('./blake2b.fixtures.json') -const rawTransactionToHashFixtures = require('./rawTransactionToHash.fixtures.json') -const transactionFeeFixtures = require('./transactionFee.fixtures.json') - const { - blake2b, - blake160, - bech32, privateKeyToPublicKey, privateKeyToAddress, scriptToHash, rawTransactionToHash, - PERSONAL, calculateTransactionFee, -} = ckbUtils +} = require('../..') +const exceptions = require('../../lib/exceptions') +const rawTransactionToHashFixtures = require('./rawTransactionToHash.fixtures.json') +const transactionFeeFixtures = require('./transactionFee.fixtures.json') const { ParameterRequiredException } = exceptions -describe('blake', () => { - it('blake2b([]) with personal', () => { - const fixture = { - message: new Uint8Array(), - digest: '44f4c69744d5f8c55d642062949dcae49bc4e7ef43d388c5a12f42b5633d163e', - } - const s = blake2b(32, null, null, PERSONAL) - s.update(fixture.message) - const digest = s.digest('hex') - expect(digest).toBe(fixture.digest) - }) - - it('blake2b(Buffer.from("The quick brown fox jumps over the lazy dog")) with personal', () => { - const fixture = { - message: 'The quick brown fox jumps over the lazy dog', - digest: 'abfa2c08d62f6f567d088d6ba41d3bbbb9a45c241a8e3789ef39700060b5cee2', - } - const s = blake2b(32, null, null, PERSONAL) - s.update(new Uint8Array(Buffer.from(fixture.message, 'utf8'))) - const digest = s.digest('hex') - expect(digest).toBe(fixture.digest) - }) - - test.each(blake2bFixtures)('%s', ({ outlen, out, input, key, salt, personal }) => { - if (+outlen < 16) { - expect(() => { - blake2b( - outlen, - key ? new Uint8Array(Buffer.from(key, 'hex')) : null, - salt ? new Uint8Array(Buffer.from(salt, 'hex')) : null, - personal ? new Uint8Array(Buffer.from(personal, 'hex')) : null, - ) - }).toThrowError(`Expect outlen to be at least 16, but ${outlen} received`) - } else { - const s = blake2b( - outlen, - key ? new Uint8Array(Buffer.from(key, 'hex')) : null, - salt ? new Uint8Array(Buffer.from(salt, 'hex')) : null, - personal ? new Uint8Array(Buffer.from(personal, 'hex')) : null, - ) - s.update(new Uint8Array(Buffer.from(input, 'hex'))) - const digest = s.digest('hex') - expect(digest).toBe(out) - } - }) - - it('blake160', () => { - const fixture = { - message: '024a501efd328e062c8675f2365970728c859c592beeefd6be8ead3d901330bc01', - digest: '36c329ed630d6ce750712a477543672adab57f4c', - } - const digest = blake160(new Uint8Array(Buffer.from(fixture.message, 'hex')), 'hex') - expect(digest).toBe(fixture.digest) - }) -}) - -describe('bech32', () => { - bech32Fixtures.bech32.valid.forEach(f => { - it(`fromWords/toWords ${f.hex}`, () => { - if (f.hex) { - const words = bech32.toWords(Buffer.from(f.hex, 'hex')) - const bytes = Buffer.from(bech32.fromWords(f.words)) - expect(words.join('')).toEqual(f.words.join('')) - expect(bytes.toString('hex')).toBe(f.hex) - } - }) - - it(`encode ${f.prefix}`, () => { - const encoded = bech32.encode(f.prefix, f.words, f.limit) - expect(encoded).toBe(f.string.toLowerCase()) - }) - - it(`decode ${f.string}`, () => { - const decoded = bech32.decode(f.string, f.limit) - expect(decoded.prefix).toBe(f.prefix.toLowerCase()) - expect(decoded.words.join('')).toBe(f.words.join('')) - }) - - it(`fails for ${f.string} with 1 bit flipped`, () => { - const buf = Buffer.from(f.string, 'utf8') - buf[f.string.lastIndexOf('1') + 1] ^= 0x1 - const str = buf.toString('utf8') - expect(() => { - bech32.decode(str, f.limit) - }).toThrow() - }) - }) -}) - describe('scriptToHash', () => { const fixtures = { 'Empty script': { diff --git a/packages/ckb-sdk-utils/docs/Fee_and_fee_rate.md b/packages/ckb-sdk-utils/docs/Fee_and_fee_rate.md new file mode 100644 index 00000000..9f289e9b --- /dev/null +++ b/packages/ckb-sdk-utils/docs/Fee_and_fee_rate.md @@ -0,0 +1,62 @@ +# Fee + +## How to calculate transaction fee + +[Doc](https://docs.nervos.org/docs/essays/faq#how-do-you-calculate-transaction-fee) + +The size of a normal 2-in-2-out transaction is 597 bytes so that its virtual size is 601 bytes, there're 4 bytes extra cost in a block. + +The fee formula is + +``` +virtual_tx_size * fee_rate / 1000 +``` + +where: + +- virtual_tx_size: size cost in a block, in `bytes`, +- fee_rate: defined by user, in `shannons/kB`; + +Suppose the fee rate is `1000 shannons/kB`, the fee of a 2-in-2-out transaction is `601 * 1000 / 1000` shannons, namely **0.00000601 CKB** + +## Fee Rate + +Decided by users, impacts on the sequence of committing transactions by miners. + +## Generate Transaction with Fee Rate + +Suppose we have a transaction named `tx`, it has a change output of capacity `change` and it's size is `tx_size`. + +When the fee rate is set to `fee_rate`, apparently `fee = tx_size * fee_rate`. + +There are two cases: + +### change >= minimal_change + fee + +The transaction can be updated to have a change output of capacity `change - fee` and that's all. + +### change < minimal_change + fee + +It's hard to pay the fee by change, so extra inputs are required. There are also two strategies to increase inputs + +#### Increase inputs by replacing current inputs + +Say we have used an input of 1000 capacity, when we replace it with an input of 2000 capacity, obviously the fee will not change, and the capacity of change output will increase by `2000 - 1000 - fee`. + +#### Increase inputs by adding new input + +Say we add `n` new inputs, the size bumps to `tx_size + 44 * n` since each input has a size of 44 bytes. By that the fee is `fee + 44 * n * fee_rate`. + +In a word, `44 * n * fee_rate` extra cost is introduced by `n` inputs, so the capacity of `n` inputs should be at least `fee - (change - minimal_change) + 44 * n * fee_rate` + +Each input has at least 61 CKB, namely at least `61_00_000_000 * n` shannons will be introduced + +``` +6100000000 * n > (fee - (change - minimal_change) + 44 * n * fee_rate) -> +6100000000 * n - 44 * fee_rate * n > fee + minimal_change - change -> +n > (fee + minimal_change - change) / (6100000000 - 44 * fee_rate) +``` + +--- + +Since the dynamic picking of cells is not implemented yet, we're going to use the second strategy, increase inputs by adding new input, for now. diff --git a/packages/ckb-sdk-utils/package.json b/packages/ckb-sdk-utils/package.json index a585712e..045d1f8d 100644 --- a/packages/ckb-sdk-utils/package.json +++ b/packages/ckb-sdk-utils/package.json @@ -1,6 +1,6 @@ { "name": "@nervosnetwork/ckb-sdk-utils", - "version": "0.36.0", + "version": "0.36.1", "description": "Utils module of @nervosnetwork/ckb-sdk-core", "author": "Nervos ", "homepage": "https://github.com/nervosnetwork/ckb-sdk-js#readme", @@ -31,7 +31,7 @@ "url": "https://github.com/nervosnetwork/ckb-sdk-js/issues" }, "dependencies": { - "@nervosnetwork/ckb-types": "0.36.0", + "@nervosnetwork/ckb-types": "0.36.1", "blake2b-wasm": "2.1.0", "elliptic": "6.5.3", "jsbi": "3.1.3", @@ -41,5 +41,5 @@ "@types/bitcoinjs-lib": "5.0.0", "@types/elliptic": "6.4.12" }, - "gitHead": "d0adcbb7e6743fdcc049984534afab13f5ede178" + "gitHead": "b34332872a9168a1879d3020ca3546b72816823a" } diff --git a/packages/ckb-sdk-utils/src/crypto/blake2b.ts b/packages/ckb-sdk-utils/src/crypto/blake2b.ts index 4304f8e6..d5601072 100644 --- a/packages/ckb-sdk-utils/src/crypto/blake2b.ts +++ b/packages/ckb-sdk-utils/src/crypto/blake2b.ts @@ -1,5 +1,4 @@ /* eslint-disable no-param-reassign */ -const b2wasm = require('blake2b-wasm') const { OutLenTooSmallException, OutLenTooLargeException, @@ -375,8 +374,16 @@ export const blake2b = ( } export const ready = (cb: Function) => { - b2wasm.ready(() => { - cb() + const iOSVersion = globalThis?.navigator?.userAgent.match(/cpu iphone os (.*?) like mac os/i) + if (iOSVersion?.[1].startsWith('11_')) { + cb(new Error(`blake2b-wasm is unavailable on iOS 11`)) + return + } + + /* eslint-disable global-require */ + const b2wasm = require('blake2b-wasm') + b2wasm.ready((...args: unknown[]) => { + cb(...args) }) } diff --git a/packages/ckb-sdk-utils/src/exceptions/ErrorCode.ts b/packages/ckb-sdk-utils/src/exceptions/ErrorCode.ts index 639b2811..c0785b34 100644 --- a/packages/ckb-sdk-utils/src/exceptions/ErrorCode.ts +++ b/packages/ckb-sdk-utils/src/exceptions/ErrorCode.ts @@ -3,6 +3,7 @@ export enum ErrorCode { ParameterRequired, SignMessageFailed, AddressInvalid, + ReconciliationFailed, } export default ErrorCode diff --git a/packages/ckb-sdk-utils/src/exceptions/index.ts b/packages/ckb-sdk-utils/src/exceptions/index.ts index a94d51e3..96228b97 100644 --- a/packages/ckb-sdk-utils/src/exceptions/index.ts +++ b/packages/ckb-sdk-utils/src/exceptions/index.ts @@ -4,3 +4,4 @@ export * from './string' export * from './address' export * from './blake2b' export * from './privateKey' +export * from './transaction' diff --git a/packages/ckb-sdk-utils/src/exceptions/transaction.ts b/packages/ckb-sdk-utils/src/exceptions/transaction.ts new file mode 100644 index 00000000..d6889095 --- /dev/null +++ b/packages/ckb-sdk-utils/src/exceptions/transaction.ts @@ -0,0 +1,13 @@ +import ErrorCode from './ErrorCode' + +export class ReconciliationException extends Error { + code = ErrorCode.ReconciliationFailed + + constructor() { + super(`Fail to reconcile transaction, try to increase extra count or check the transaction`) + } +} + +export default { + ReconciliationException, +} diff --git a/packages/ckb-sdk-utils/src/reconciliation/extraInputs.ts b/packages/ckb-sdk-utils/src/reconciliation/extraInputs.ts new file mode 100644 index 00000000..8d3ed026 --- /dev/null +++ b/packages/ckb-sdk-utils/src/reconciliation/extraInputs.ts @@ -0,0 +1,69 @@ +import JSBI from 'jsbi' +import { getTransactionSize } from '../sizes' +import { ReconciliationException } from '../exceptions' + +declare namespace Reconciliation { + type Cell = { capacity: string; outPoint: CKBComponents.OutPoint } + interface ExtraInputsParams { + tx: CKBComponents.RawTransactionToSign + feeRate: string | bigint + changeThreshold: string | bigint + cells: Array + extraCount: number + } +} + +export const extraInputs = (params: Reconciliation.ExtraInputsParams): any => { + const feeRate = JSBI.BigInt(`${params.feeRate}`) + const changeThreshold = JSBI.BigInt(`${params.changeThreshold}`) + + const size = JSBI.BigInt(getTransactionSize(params.tx)) + const currentChangeOutput = params.tx.outputs[params.tx.outputs.length - 1] + const currentChange = JSBI.BigInt(currentChangeOutput.capacity) + + const fee = JSBI.divide(JSBI.multiply(size, feeRate), JSBI.BigInt(1000)) + const lack = JSBI.subtract(JSBI.add(fee, changeThreshold), currentChange) + + if (JSBI.LE(lack, JSBI.BigInt(0))) { + return { + ...params.tx, + outputs: [ + ...params.tx.outputs.slice(0, -1), + { + ...currentChangeOutput, + capacity: `0x${JSBI.subtract(currentChange, fee).toString(16)}`, + }, + ], + } + } + + params.cells.sort((c1, c2) => +JSBI.subtract(JSBI.BigInt(c1.capacity), JSBI.BigInt(c2.capacity))) + + const SIZE_PER_INPUT = JSBI.BigInt(44) + const FEE_PER_INPUT = JSBI.divide(JSBI.multiply(SIZE_PER_INPUT, feeRate), JSBI.BigInt(1000)) + + for (let i = 1; i <= Math.min(params.extraCount, params.cells.length); i++) { + const extraCost = JSBI.multiply(JSBI.BigInt(i), FEE_PER_INPUT) + const totalLack = JSBI.add(lack, extraCost) + const extraCapacity = params.cells + .slice(0, i) + .reduce((sum, c) => JSBI.add(sum, JSBI.BigInt(c.capacity)), JSBI.BigInt(0)) + if (JSBI.GE(extraCapacity, totalLack)) { + const inputs = [ + ...params.tx.inputs, + ...params.cells.slice(0, i).map(c => ({ + previousOutput: c.outPoint, + since: '0x0', + })), + ] + const change = JSBI.add(changeThreshold, JSBI.subtract(extraCapacity, totalLack)) + const changeOutput = { ...currentChangeOutput, capacity: `0x${change.toString(16)}` } + const outputs = [...params.tx.outputs.slice(0, -1), changeOutput] + const tx: CKBComponents.RawTransactionToSign = { ...params.tx, inputs, outputs } + return tx + } + } + throw new ReconciliationException() +} + +export default extraInputs diff --git a/packages/ckb-sdk-utils/src/reconciliation/index.ts b/packages/ckb-sdk-utils/src/reconciliation/index.ts new file mode 100644 index 00000000..66c32005 --- /dev/null +++ b/packages/ckb-sdk-utils/src/reconciliation/index.ts @@ -0,0 +1 @@ +export * from './extraInputs' diff --git a/packages/ckb-sdk-utils/src/sizes.ts b/packages/ckb-sdk-utils/src/sizes.ts index 11161460..1f65cebc 100644 --- a/packages/ckb-sdk-utils/src/sizes.ts +++ b/packages/ckb-sdk-utils/src/sizes.ts @@ -1,21 +1,20 @@ import { serializeWitnessArgs, serializeTransaction } from './serialization/transaction' -export enum Size { - SerializeOffset = 4, - Base = 72, - CellDep = 37, - HeaderDep = 32, - Input = 44, -} - -export const getTransactionSize = (transaction: CKBComponents.RawTransaction) => { +/** + * @name getTransactionSize + * @description return the size of a transaction cost in a block, 4 bytes more than the serialized transaction. + * @param {Object} transaction - Raw transaction + * @returns {String} Virtual size of a transaction in a block + */ +export const getTransactionSize = (transaction: CKBComponents.RawTransactionToSign) => { const tx = { ...transaction, witnesses: transaction.witnesses.map(wit => (typeof wit === 'string' ? wit : serializeWitnessArgs(wit))), } - const EXTRA_SIZE_IN_BLOCK = 4 + // extra 4 bytes size due to the cost of serialized tx in a block + const VIRTUAL_COST = 4 const serializedTransaction = serializeTransaction(tx) - return serializedTransaction.slice(2).length / 2 + EXTRA_SIZE_IN_BLOCK + return serializedTransaction.slice(2).length / 2 + VIRTUAL_COST } export default { getTransactionSize } diff --git a/packages/ckb-sdk-utils/tsconfig.json b/packages/ckb-sdk-utils/tsconfig.json index 05acd527..9b95cfeb 100644 --- a/packages/ckb-sdk-utils/tsconfig.json +++ b/packages/ckb-sdk-utils/tsconfig.json @@ -4,9 +4,9 @@ "moduleResolution": "node", "target": "es6", "outDir": "lib", - "lib": ["es2017"], + "lib": ["DOM"], "typeRoots": ["types", "node_modules/@types", "node_modules"], "types": ["@nervosnetwork/ckb-types", "node"] }, - "include": ["src"], + "include": ["src"] } diff --git a/packages/ckb-types/CHANGELOG.md b/packages/ckb-types/CHANGELOG.md index 9db762da..09d4d0c3 100644 --- a/packages/ckb-types/CHANGELOG.md +++ b/packages/ckb-types/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.36.1](https://github.com/nervosnetwork/ckb-sdk-js/compare/v0.36.0...v0.36.1) (2020-09-26) + +**Note:** Version bump only for package @nervosnetwork/ckb-types + + + + + # [0.36.0](https://github.com/nervosnetwork/ckb-sdk-js/compare/v0.35.0...v0.36.0) (2020-09-21) **Note:** Version bump only for package @nervosnetwork/ckb-types diff --git a/packages/ckb-types/package.json b/packages/ckb-types/package.json index 96ce6b14..1acb2876 100644 --- a/packages/ckb-types/package.json +++ b/packages/ckb-types/package.json @@ -1,6 +1,6 @@ { "name": "@nervosnetwork/ckb-types", - "version": "0.36.0", + "version": "0.36.1", "description": "Type module of @nervosnetwork/ckb-sdk-core", "author": "Nervos ", "homepage": "https://github.com/nervosnetwork/ckb-sdk-js#readme", @@ -23,5 +23,5 @@ "scripts": { "doc": "../../node_modules/.bin/typedoc --out docs ./index.d.ts --mode modules --includeDeclarations --excludeExternals --ignoreCompilerErrors --theme default --readme README.md" }, - "gitHead": "d0adcbb7e6743fdcc049984534afab13f5ede178" + "gitHead": "b34332872a9168a1879d3020ca3546b72816823a" }