diff --git a/CHANGELOG.md b/CHANGELOG.md index d0efea773..4fd0b6851 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,15 @@ All notable changes to casper-client-sdk. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 1.3.0 + +### Changed + +- Removed EventStore from codebase. +- `CasperClient.getDeployByHashFromRPC` is now `CasperClient.getDeploy`. +- Fixed problems with `deployFromJson` caused by missing support for deserialization TTL values other than `ms`. + ## 1.2.0 ### Changed diff --git a/index.js b/index.js new file mode 100644 index 000000000..e69de29bb diff --git a/package.json b/package.json index 1a9a8963f..4bc35600e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "casper-client-sdk", - "version": "1.2.0", + "version": "1.3.0", "license": "Apache 2.0", "description": "SDK to interact with the Casper blockchain", "main": "dist/lib.node.js", diff --git a/src/lib/CasperClient.ts b/src/lib/CasperClient.ts index bc162f1c3..8dbc6fe55 100644 --- a/src/lib/CasperClient.ts +++ b/src/lib/CasperClient.ts @@ -1,10 +1,6 @@ import { - AccountDeploy, CasperServiceByJsonRPC, - DeployResult, - EventService, - GetDeployResult, - TransferResult + GetDeployResult } from '../services'; import { DeployUtil, Keys, PublicKey } from './index'; import { encodeBase16 } from './Conversions'; @@ -15,11 +11,9 @@ import { BigNumber } from '@ethersproject/bignumber'; export class CasperClient { private nodeClient: CasperServiceByJsonRPC; - private eventStoreClient: EventService; - constructor(nodeUrl: string, eventStoreUrl: string) { + constructor(nodeUrl: string) { this.nodeClient = new CasperServiceByJsonRPC(nodeUrl); - this.eventStoreClient = new EventService(eventStoreUrl); } /** @@ -228,39 +222,12 @@ export class CasperClient { } } - /** - * Get deploys for specified account - * @param publicKey - * @param page - * @param limit - */ - public async getAccountsDeploys( - publicKey: PublicKey, - page = 0, - limit = 20 - ): Promise { - const data = await this.eventStoreClient.getAccountDeploys( - publicKey.toAccountHex(), - page, - limit - ); - return data.data; - } - - /** - * Get deploy by hash - * @param deployHash - */ - public async getDeployByHash(deployHash: string): Promise { - return await this.eventStoreClient.getDeployByHash(deployHash); - } - /** * Get deploy by hash from RPC. * @param deployHash * @returns Tuple of Deploy and raw RPC response. */ - public async getDeployByHashFromRPC( + public async getDeploy( deployHash: string ): Promise<[Deploy, GetDeployResult]> { return await this.nodeClient @@ -292,16 +259,4 @@ export class CasperClient { return balanceUref; } - - /** - * Get transfers to and from the specified public key, including sending and receiving transactions. - * @param publicKey - */ - public async getTransfersByPublicKey( - publicKey: PublicKey - ): Promise { - return await this.eventStoreClient.getTransfersByAccountHash( - encodeBase16(publicKey.toAccountHash()) - ); - } } diff --git a/src/lib/DeployUtil.ts b/src/lib/DeployUtil.ts index 2c5193e6b..f18e6fd97 100644 --- a/src/lib/DeployUtil.ts +++ b/src/lib/DeployUtil.ts @@ -36,14 +36,13 @@ import { Result, Ok, Err } from 'ts-results'; const shortEnglishHumanizer = humanizeDuration.humanizer({ spacer: '', serialComma: false, + conjunction: " ", + delimiter: " ", language: 'shortEn', languages: { // https://docs.rs/humantime/2.0.1/humantime/fn.parse_duration.html shortEn: { - y: () => 'y', - mo: () => 'M', - w: () => 'w', - d: () => 'd', + d: () => 'day', h: () => 'h', m: () => 'm', s: () => 's', @@ -65,13 +64,41 @@ const byteArrayJsonDeserializer: (str: string) => Uint8Array = ( }; /** - * Return a humanizer duration + * Returns a humanizer duration * @param ttl in milliseconds */ export const humanizerTTL = (ttl: number) => { return shortEnglishHumanizer(ttl); }; + +/** + * Returns duration in ms + * @param ttl in humanized string + */ +export const dehumanizerTTL = (ttl: string): number => { + const dehumanizeUnit = (s: string): number => { + if (s.includes("ms")) { + return Number(s.replace('ms', '')); + }; + if (s.includes('s') && !s.includes('m')) { + return Number(s.replace('s', '')) * 1000; + } + if (s.includes('m') && !s.includes('s')) { + return Number(s.replace('m', '')) * 60 * 1000; + } + if (s.includes('h')) { + return Number(s.replace('h', '')) * 60 * 60 * 1000; + } + if (s.includes('day')) { + return Number(s.replace('day', '')) * 24 * 60 * 60 * 1000; + } + throw Error("Unsuported TTL unit"); + }; + + return ttl.split(" ").map(dehumanizeUnit).reduce((acc, val) => acc += val); +}; + @jsonObject export class DeployHeader implements ToBytes { @jsonMember({ @@ -91,8 +118,8 @@ export class DeployHeader implements ToBytes { public timestamp: number; @jsonMember({ - serializer: (n: number) => String(n) + 'ms', - deserializer: (s: string) => Number(s.replace('ms', '')) + serializer: humanizerTTL, + deserializer: dehumanizerTTL }) public ttl: number; diff --git a/src/services/EventService.ts b/src/services/EventService.ts deleted file mode 100644 index a7b645274..000000000 --- a/src/services/EventService.ts +++ /dev/null @@ -1,109 +0,0 @@ -import axios from 'axios'; - -export interface BlockResult { - blockHash: string; - parentHash: string; - timestamp: string; - eraId: number; - proposer: string; - state: string; - deployCount: number; - height: number; - deploys: string[]; -} - -export interface Page { - number: number; - url: string; -} - -export interface BlocksResult { - data: BlockResult[] | null; - pageCount: number; - itemCount: number; - pages: Page[]; -} - -export interface DeployResult { - deployHash: string; - state: string; - cost: number; - errorMessage: string; - account: string; - blockHash: string; -} - -export interface Deployhash { - blockHash: string; - deployHash: string; - state: string; - cost: number; - errormessage: string; -} - -export interface AccountDeploy { - deployHash: string; - account: string; - state: string; - cost: number; - errorMessage: string; - blockHash: string; -} - -export interface AccountDeploysResult { - data: AccountDeploy[]; - pageCount: number; - itemCount: number; - pages: Page[]; -} - -export interface TransferResult { - deployHash: string; - sourcePurse: string; - targetPurse: string; - amount: string; - id: string; - fromAccount: string; - toAccount: string; -} - -export class EventService { - private url?: string; - - constructor(url?: string) { - this.url = url; - } - - private async getResponseData(endPoint: string): Promise { - const response = await axios.get(`${this.url}${endPoint}`); - return response.data; - } - - public async getBlocks(page: number, count: number): Promise { - return this.getResponseData(`/blocks?page=${page}&limit=${count}`); - } - - public async getDeployByHash(deployHash: string): Promise { - return this.getResponseData(`/deploy/${deployHash}`); - } - - public async getBlockByHash(blockHash: string): Promise { - return this.getResponseData(`/block/${blockHash}`); - } - - public async getAccountDeploys( - accountHex: string, - page: number, - limit: number - ): Promise { - return this.getResponseData( - `/accountDeploys/${accountHex}?page=${page}&limit=${limit}` - ); - } - - public async getTransfersByAccountHash( - accountHash: string - ): Promise { - return this.getResponseData(`/transfers/${accountHash}`); - } -} diff --git a/src/services/index.ts b/src/services/index.ts index 97362b6fb..dc5608721 100644 --- a/src/services/index.ts +++ b/src/services/index.ts @@ -1,3 +1,2 @@ export * from './CasperServiceByJsonRPC'; export * from './BalanceServiceByJsonRPC'; -export * from './EventService'; diff --git a/test/lib/CasperClient.test.ts b/test/lib/CasperClient.test.ts index 86ee23be5..3570e1b73 100644 --- a/test/lib/CasperClient.test.ts +++ b/test/lib/CasperClient.test.ts @@ -1,5 +1,6 @@ import { expect } from 'chai'; import { CasperClient } from '../../src/lib/CasperClient'; +import { Deploy } from '../../src/lib/DeployUtil'; import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; @@ -11,8 +12,7 @@ let casperClient: CasperClient; describe('CasperClient', () => { before(() => { casperClient = new CasperClient( - 'http://192.168.2.166:40101/rpc', - 'http://mock2:7777' + 'http://192.168.2.166:40101/rpc' ); }); @@ -117,7 +117,7 @@ describe('CasperClient', () => { expect(loadedKeyPair.privateKey).to.deep.equal(edKeyPair.privateKey); }); - it('should create a HK wallet and derive child account correctly', function () { + it('should create a HK wallet and derive child account correctly', function() { const seed = 'fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542'; const hdKey = casperClient.newHdWallet(decodeBase16(seed)); @@ -130,4 +130,86 @@ describe('CasperClient', () => { const signature2 = secpKey2.sign(msg); expect(secpKey2.verify(signature2, msg)).to.be.equal(true); }); + + it('should create deploy from Deploy JSON with ttl in minutes', function() { + const json = { + deploy: { + approvals: [ + { + signature: '130 chars', + signer: + '012d9dded24145247421eb8b904dda5cce8a7c77ae18de819a25628c4a01adbf76' + } + ], + hash: + 'ceaaa76e7fb850a09d5c9d16ac995cb52eff2944066cfd8cac27f3595f11b652', + header: { + account: + '012d9dded24145247421eb8b904dda5cce8a7c77ae18de819a25628c4a01adbf76', + body_hash: + '0e68d66a9dfab19bb1898d5f4d11a4f55dd06a0cae3917afc1eae4a5b56352e7', + chain_name: 'casper-test', + dependencies: [], + gas_price: 1, + timestamp: '2021-05-06T07:49:32.583Z', + ttl: '30m' + }, + payment: { + ModuleBytes: { + args: [ + [ + 'amount', + { + bytes: '0500e40b5402', + cl_type: 'U512', + parsed: '10000000000' + } + ] + ], + module_bytes: '' + } + }, + session: { + Transfer: { + args: [ + [ + 'amount', + { + bytes: '0500743ba40b', + cl_type: 'U512', + parsed: '50000000000' + } + ], + [ + 'target', + { + bytes: + '1541566bdad3a3cfa9eb4cba3dcf33ee6583e0733ae4b2ccdfe92cd1bd92ee16', + cl_type: { + ByteArray: 32 + }, + parsed: + '1541566bdad3a3cfa9eb4cba3dcf33ee6583e0733ae4b2ccdfe92cd1bd92ee16' + } + ], + [ + 'id', + { + bytes: '01a086010000000000', + cl_type: { + Option: 'U64' + }, + parsed: 100000 + } + ] + ] + } + } + } + }; + const fromJson = casperClient.deployFromJson(json); + + expect(fromJson).to.be.an.instanceof(Deploy); + expect(fromJson!.header.ttl).to.be.eq(1800000); + }); }); diff --git a/test/lib/DeployUtil.test.ts b/test/lib/DeployUtil.test.ts index 7461c3113..ddb7af893 100644 --- a/test/lib/DeployUtil.test.ts +++ b/test/lib/DeployUtil.test.ts @@ -1,5 +1,6 @@ import { expect, assert } from 'chai'; import { Keys, DeployUtil, CLValue } from '../../src/lib'; +import { humanizerTTL, dehumanizerTTL } from '../../src/lib/DeployUtil'; import { TypedJSON } from 'typedjson'; const testDeploy = () => { @@ -229,6 +230,38 @@ describe('DeployUtil', () => { assert.isUndefined(DeployUtil.deployFromJson(json)); }); + it('Should convert ms to humanized string', function () { + const strTtl30m = humanizerTTL(1800000); + const strTtl45m = humanizerTTL(2700000); + const strTtl1h = humanizerTTL(3600000); + const strTtl1h30m = humanizerTTL(5400000); + const strTtl1day = humanizerTTL(86400000); + const strTtlCustom = humanizerTTL(86103000); + + expect(strTtl30m).to.be.eq("30m"); + expect(strTtl45m).to.be.eq("45m"); + expect(strTtl1h).to.be.eq("1h"); + expect(strTtl1h30m).to.be.eq("1h 30m"); + expect(strTtl1day).to.be.eq("1day"); + expect(strTtlCustom).to.be.eq("23h 55m 3s"); + }); + + it('Should convert humanized string to ms', function () { + const msTtl30m = dehumanizerTTL("30m"); + const msTtl45m = dehumanizerTTL("45m"); + const msTtl1h = dehumanizerTTL("1h"); + const msTtl1h30m = dehumanizerTTL("1h 30m"); + const msTtl1day = dehumanizerTTL("1day"); + const msTtlCustom = dehumanizerTTL("23h 55m 3s"); + + expect(msTtl30m).to.be.eq(1800000); + expect(msTtl45m).to.be.eq(2700000); + expect(msTtl1h).to.be.eq(3600000); + expect(msTtl1h30m).to.be.eq(5400000); + expect(msTtl1day).to.be.eq(86400000); + expect(msTtlCustom).to.be.eq(86103000); + }); + it('Should not allow to create new transfer without providing transfer-id', () => { const recipientKey = Keys.Ed25519.new(); const transferAmount = 10;