From 1bfd90167c8b15f6e84395d6650c4db1e2325199 Mon Sep 17 00:00:00 2001 From: Maciej Zielinski Date: Thu, 4 Feb 2021 16:54:29 +0100 Subject: [PATCH 1/2] Add DeployUtil.addArgToDeploy --- packages/sdk/CHANGELOG.md | 10 ++- packages/sdk/package.json | 2 +- packages/sdk/src/lib/DeployUtil.ts | 50 ++++++++++- packages/sdk/test/lib/DeployUtil.test.ts | 101 ++++++++++++++++++++++- 4 files changed, 154 insertions(+), 9 deletions(-) diff --git a/packages/sdk/CHANGELOG.md b/packages/sdk/CHANGELOG.md index 9511aded..1526f81b 100644 --- a/packages/sdk/CHANGELOG.md +++ b/packages/sdk/CHANGELOG.md @@ -5,9 +5,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.0.17] +### Added +- Added `DeployUtils.addArgToDeploy(deploy: Deploy, name: string, value: CLValue)` to be able to modify Deploy's session arguments. It creates a new deploy instance. Can not be used on signed deploys. +### Changed +- Default `gasPrice` changed from `10` to `1`. + ## [1.0.15] ### Added -- Start using CHANGELOG.md. +- Started using CHANGELOG.md. ### Changed -- Change CLValue's `value` to `value()` and `remainder` to `remainder()`. \ No newline at end of file +- Changed CLValue's `value` to `value()` and `remainder` to `remainder()`. \ No newline at end of file diff --git a/packages/sdk/package.json b/packages/sdk/package.json index df1b43a2..d25e5ea5 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "casper-client-sdk", - "version": "1.0.16", + "version": "1.0.17", "license": "Apache 2.0", "description": "SDK to interact with the Casper blockchain", "main": "dist/index.js", diff --git a/packages/sdk/src/lib/DeployUtil.ts b/packages/sdk/src/lib/DeployUtil.ts index b6341bd3..c29d6b18 100644 --- a/packages/sdk/src/lib/DeployUtil.ts +++ b/packages/sdk/src/lib/DeployUtil.ts @@ -26,7 +26,7 @@ import { } from './byterepr'; import { RuntimeArgs } from './RuntimeArgs'; // import JSBI from 'jsbi'; -import { Keys, URef } from './index'; +import { DeployUtil, Keys, URef } from './index'; import { AsymmetricKey, SignatureAlgorithm } from './Keys'; import { BigNumberish } from '@ethersproject/bignumber'; import { jsonArrayMember, jsonMember, jsonObject, TypedJSON } from 'typedjson'; @@ -193,8 +193,12 @@ abstract class ExecutableDeployItemInternal implements ToBytes { public abstract toBytes(): Uint8Array; - public getArgByName(argName: string): CLValue | undefined { - return this.args.args.get(argName); + public getArgByName(name: string): CLValue | undefined { + return this.args.args.get(name); + } + + public setArg(name: string, value: CLValue) { + this.args.args.set(name, value); } } @@ -532,6 +536,24 @@ export class ExecutableDeployItem implements ToBytes { throw new Error('failed to serialize ExecutableDeployItemJsonWrapper'); } + + public setArg(name: string, value: CLValue) { + if (this.isModuleBytes()) { + return this.moduleBytes!.setArg(name, value); + } else if (this.isStoredContractByHash()) { + return this.storedContractByHash!.setArg(name, value); + } else if (this.isStoredContractByName()) { + return this.storedContractByName!.setArg(name, value); + } else if (this.isStoredVersionContractByHash()) { + return this.storedVersionedContractByHash!.setArg(name, value); + } else if (this.isStoredVersionContractByName()) { + return this.storedVersionedContractByName!.setArg(name, value); + } else if (this.isTransfer()) { + return this.transfer!.setArg(name, value); + } + throw new Error('failed to serialize ExecutableDeployItemJsonWrapper'); + } + public static fromExecutableDeployItemInternal( item: ExecutableDeployItemInternal ) { @@ -805,7 +827,7 @@ export class DeployParams { constructor( public accountPublicKey: PublicKey, public chainName: string, - public gasPrice: number = 10, + public gasPrice: number = 1, public ttl: number = 3600000, public dependencies: Uint8Array[] = [], public timestamp?: number @@ -931,3 +953,23 @@ export const deployFromJson = (json: any) => { const serializer = new TypedJSON(Deploy); return serializer.parse(json.deploy); }; + +export const addArgToDeploy = (deploy: Deploy, name: string, value: CLValue): Deploy => { + if(deploy.approvals.length != 0) { + throw Error("Can not add argument to already signed deploy."); + } + + let deployParams = new DeployUtil.DeployParams( + deploy.header.account, + deploy.header.chainName, + deploy.header.gasPrice, + deploy.header.ttl, + deploy.header.dependencies, + deploy.header.timestamp + ); + + let session = deploy.session; + session.setArg(name, value); + + return makeDeploy(deployParams, session, deploy.payment); +} \ No newline at end of file diff --git a/packages/sdk/test/lib/DeployUtil.test.ts b/packages/sdk/test/lib/DeployUtil.test.ts index a270ee6b..28947443 100644 --- a/packages/sdk/test/lib/DeployUtil.test.ts +++ b/packages/sdk/test/lib/DeployUtil.test.ts @@ -1,5 +1,5 @@ import { expect, assert } from 'chai'; -import { Keys, DeployUtil } from '../../src/lib'; +import { Keys, DeployUtil, CLValue } from '../../src/lib'; import { TypedJSON } from 'typedjson'; describe('DeployUtil', () => { @@ -43,9 +43,12 @@ describe('DeployUtil', () => { deploy = DeployUtil.signDeploy(deploy, senderKey); deploy = DeployUtil.signDeploy(deploy, recipientKey); + // Serialize deploy to JSON. let json = DeployUtil.deployToJson(deploy); - // console.log(json); + + // Deserialize deploy from JSON. deploy = DeployUtil.deployFromJson(json)!; + assert.isTrue(deploy.isTransfer()); assert.isTrue(deploy.isStandardPayment()); @@ -74,4 +77,98 @@ describe('DeployUtil', () => { assert.deepEqual(deploy.approvals[0].signer, senderKey.accountHex()); assert.deepEqual(deploy.approvals[1].signer, recipientKey.accountHex()); }); + + it('should allow to add arg to Deploy', function () { + const senderKey = Keys.Ed25519.new(); + const recipientKey = Keys.Ed25519.new(); + const networkName = 'test-network'; + const paymentAmount = 10000000000000; + const transferAmount = 10; + const id = 34; + const customId = 60; + + let deployParams = new DeployUtil.DeployParams( + senderKey.publicKey, + networkName + ); + let session = DeployUtil.ExecutableDeployItem.newTransfer( + transferAmount, + recipientKey.publicKey, + undefined, + id + ); + let payment = DeployUtil.standardPayment(paymentAmount); + let oldDeploy = DeployUtil.makeDeploy(deployParams, session, payment); + + // Add new argument. + let deploy = DeployUtil.addArgToDeploy(oldDeploy, "custom_id", CLValue.u32(customId)); + + // Serialize and deserialize deploy. + let json = DeployUtil.deployToJson(deploy); + deploy = DeployUtil.deployFromJson(json)!; + + assert.deepEqual( + deploy.session.getArgByName('custom_id')!.asBigNumber().toNumber(), + customId + ); + assert.isTrue(deploy.isTransfer()); + assert.isTrue(deploy.isStandardPayment()); + assert.deepEqual(deploy.header.account, senderKey.publicKey); + assert.deepEqual( + deploy.payment.getArgByName('amount')!.asBigNumber().toNumber(), + paymentAmount + ); + assert.deepEqual( + deploy.session.getArgByName('amount')!.asBigNumber().toNumber(), + transferAmount + ); + assert.deepEqual( + deploy.session.getArgByName('target')!.asBytesArray(), + recipientKey.accountHash() + ); + assert.deepEqual( + deploy.session + .getArgByName('id')! + .asOption() + .getSome() + .asBigNumber() + .toNumber(), + id + ); + + assert.notEqual(oldDeploy.hash, deploy.hash); + assert.notEqual(oldDeploy.header.bodyHash, deploy.header.bodyHash); + }); + + it('should not allow to add arg to a signed Deploy', function () { + const senderKey = Keys.Ed25519.new(); + const recipientKey = Keys.Ed25519.new(); + const networkName = 'test-network'; + const paymentAmount = 10000000000000; + const transferAmount = 10; + const id = 34; + const customId = 60; + + let deployParams = new DeployUtil.DeployParams( + senderKey.publicKey, + networkName + ); + let session = DeployUtil.ExecutableDeployItem.newTransfer( + transferAmount, + recipientKey.publicKey, + undefined, + id + ); + let payment = DeployUtil.standardPayment(paymentAmount); + let deploy = DeployUtil.makeDeploy(deployParams, session, payment); + deploy = DeployUtil.signDeploy(deploy, senderKey); + + expect(() => { + // Add new argument. + DeployUtil.addArgToDeploy(deploy, "custom_id", CLValue.u32(customId)); + }).to.throw("Can not add argument to already signed deploy."); + + }); + + }); From 66b9a44431c33dc2eaedc0cd37585183ee84824d Mon Sep 17 00:00:00 2001 From: Maciej Zielinski Date: Thu, 4 Feb 2021 17:24:09 +0100 Subject: [PATCH 2/2] Change return type of balance queries to BigNumber --- packages/sdk/CHANGELOG.md | 14 +++++++++---- packages/sdk/src/lib/CasperClient.ts | 13 +++++++----- packages/sdk/src/lib/DeployUtil.ts | 21 +++++++++++-------- .../src/services/BalanceServiceByJsonRPC.ts | 3 ++- .../src/services/CasperServiceByJsonRPC.ts | 5 +++-- packages/sdk/test/lib/DeployUtil.test.ts | 18 ++++++++-------- packages/ui/src/containers/AuthContainer.ts | 2 +- packages/ui/src/containers/BlockContainer.ts | 2 +- 8 files changed, 46 insertions(+), 32 deletions(-) diff --git a/packages/sdk/CHANGELOG.md b/packages/sdk/CHANGELOG.md index 1526f81b..b2160eae 100644 --- a/packages/sdk/CHANGELOG.md +++ b/packages/sdk/CHANGELOG.md @@ -2,18 +2,24 @@ 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). +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.0.17] + ### Added + - Added `DeployUtils.addArgToDeploy(deploy: Deploy, name: string, value: CLValue)` to be able to modify Deploy's session arguments. It creates a new deploy instance. Can not be used on signed deploys. + ### Changed -- Default `gasPrice` changed from `10` to `1`. +- Default `gasPrice` changed from `10` to `1`. +- Casper balances checks return `BigNumber` now. ## [1.0.15] + ### Added + - Started using CHANGELOG.md. ### Changed -- Changed CLValue's `value` to `value()` and `remainder` to `remainder()`. \ No newline at end of file + +- Changed CLValue's `value` to `value()` and `remainder` to `remainder()`. diff --git a/packages/sdk/src/lib/CasperClient.ts b/packages/sdk/src/lib/CasperClient.ts index 5f5fd54b..d0cada37 100644 --- a/packages/sdk/src/lib/CasperClient.ts +++ b/packages/sdk/src/lib/CasperClient.ts @@ -10,6 +10,7 @@ import { encodeBase16 } from './Conversions'; import { Deploy, DeployParams, ExecutableDeployItem } from './DeployUtil'; import { AsymmetricKey, SignatureAlgorithm } from './Keys'; import { CasperHDKey } from './CasperHDKey'; +import { BigNumber } from '@ethersproject/bignumber'; export class CasperClient { private nodeClient: CasperServiceByJsonRPC; @@ -190,21 +191,23 @@ export class CasperClient { /** * Get the balance of public key */ - public async balanceOfByPublicKey(publicKey: PublicKey): Promise { + public async balanceOfByPublicKey(publicKey: PublicKey): Promise { return this.balanceOfByAccountHash(encodeBase16(publicKey.toAccountHash())); } /** * Get the balance by account hash */ - public async balanceOfByAccountHash(accountHashStr: string): Promise { + public async balanceOfByAccountHash( + accountHashStr: string + ): Promise { try { const stateRootHash = await this.nodeClient .getLatestBlockInfo() .then(it => it.block?.header.state_root_hash); // Find the balance Uref and cache it if we don't have it. if (!stateRootHash) { - return 0; + return BigNumber.from(0); } const balanceUref = await this.nodeClient.getAccountBalanceUrefByPublicKeyHash( stateRootHash, @@ -212,7 +215,7 @@ export class CasperClient { ); if (!balanceUref) { - return 0; + return BigNumber.from(0); } return await this.nodeClient.getAccountBalance( @@ -220,7 +223,7 @@ export class CasperClient { balanceUref ); } catch (e) { - return 0; + return BigNumber.from(0); } } diff --git a/packages/sdk/src/lib/DeployUtil.ts b/packages/sdk/src/lib/DeployUtil.ts index c29d6b18..56011db5 100644 --- a/packages/sdk/src/lib/DeployUtil.ts +++ b/packages/sdk/src/lib/DeployUtil.ts @@ -536,7 +536,6 @@ export class ExecutableDeployItem implements ToBytes { throw new Error('failed to serialize ExecutableDeployItemJsonWrapper'); } - public setArg(name: string, value: CLValue) { if (this.isModuleBytes()) { return this.moduleBytes!.setArg(name, value); @@ -954,12 +953,16 @@ export const deployFromJson = (json: any) => { return serializer.parse(json.deploy); }; -export const addArgToDeploy = (deploy: Deploy, name: string, value: CLValue): Deploy => { - if(deploy.approvals.length != 0) { - throw Error("Can not add argument to already signed deploy."); +export const addArgToDeploy = ( + deploy: Deploy, + name: string, + value: CLValue +): Deploy => { + if (deploy.approvals.length !== 0) { + throw Error('Can not add argument to already signed deploy.'); } - - let deployParams = new DeployUtil.DeployParams( + + const deployParams = new DeployUtil.DeployParams( deploy.header.account, deploy.header.chainName, deploy.header.gasPrice, @@ -967,9 +970,9 @@ export const addArgToDeploy = (deploy: Deploy, name: string, value: CLValue): De deploy.header.dependencies, deploy.header.timestamp ); - - let session = deploy.session; + + const session = deploy.session; session.setArg(name, value); return makeDeploy(deployParams, session, deploy.payment); -} \ No newline at end of file +}; diff --git a/packages/sdk/src/services/BalanceServiceByJsonRPC.ts b/packages/sdk/src/services/BalanceServiceByJsonRPC.ts index dfb186e0..89e81776 100644 --- a/packages/sdk/src/services/BalanceServiceByJsonRPC.ts +++ b/packages/sdk/src/services/BalanceServiceByJsonRPC.ts @@ -3,6 +3,7 @@ */ import { CasperServiceByJsonRPC } from './CasperServiceByJsonRPC'; import { PublicKey } from '../lib'; +import { BigNumber } from '@ethersproject/bignumber'; export class BalanceServiceByJsonRPC { private balanceUrefs = new Map(); @@ -20,7 +21,7 @@ export class BalanceServiceByJsonRPC { public async getAccountBalance( blockHashBase16: string, publicKey: PublicKey - ): Promise { + ): Promise { try { const stateRootHash = await this.casperService.getStateRootHash( blockHashBase16 diff --git a/packages/sdk/src/services/CasperServiceByJsonRPC.ts b/packages/sdk/src/services/CasperServiceByJsonRPC.ts index a91bc4b0..c0b0928d 100644 --- a/packages/sdk/src/services/CasperServiceByJsonRPC.ts +++ b/packages/sdk/src/services/CasperServiceByJsonRPC.ts @@ -3,6 +3,7 @@ import { DeployUtil, encodeBase16, PublicKey } from '..'; import { deployToJson } from '../lib/DeployUtil'; import { TypedJSON } from 'typedjson'; import { StoredValue } from '../lib/StoredValue'; +import { BigNumber } from '@ethersproject/bignumber'; interface RpcResult { api_version: string; @@ -236,7 +237,7 @@ export class CasperServiceByJsonRPC { public async getAccountBalance( stateRootHash: string, balanceUref: string - ): Promise { + ): Promise { return await this.client .request({ method: 'state_get_balance', @@ -245,7 +246,7 @@ export class CasperServiceByJsonRPC { purse_uref: balanceUref } }) - .then(res => parseInt(res.balance_value, 10)); + .then(res => BigNumber.from(res.balance_value)); } public async getStateRootHash( diff --git a/packages/sdk/test/lib/DeployUtil.test.ts b/packages/sdk/test/lib/DeployUtil.test.ts index 28947443..a9c0bf6f 100644 --- a/packages/sdk/test/lib/DeployUtil.test.ts +++ b/packages/sdk/test/lib/DeployUtil.test.ts @@ -45,10 +45,9 @@ describe('DeployUtil', () => { // Serialize deploy to JSON. let json = DeployUtil.deployToJson(deploy); - + // Deserialize deploy from JSON. deploy = DeployUtil.deployFromJson(json)!; - assert.isTrue(deploy.isTransfer()); assert.isTrue(deploy.isStandardPayment()); @@ -101,7 +100,11 @@ describe('DeployUtil', () => { let oldDeploy = DeployUtil.makeDeploy(deployParams, session, payment); // Add new argument. - let deploy = DeployUtil.addArgToDeploy(oldDeploy, "custom_id", CLValue.u32(customId)); + let deploy = DeployUtil.addArgToDeploy( + oldDeploy, + 'custom_id', + CLValue.u32(customId) + ); // Serialize and deserialize deploy. let json = DeployUtil.deployToJson(deploy); @@ -162,13 +165,10 @@ describe('DeployUtil', () => { let payment = DeployUtil.standardPayment(paymentAmount); let deploy = DeployUtil.makeDeploy(deployParams, session, payment); deploy = DeployUtil.signDeploy(deploy, senderKey); - + expect(() => { // Add new argument. - DeployUtil.addArgToDeploy(deploy, "custom_id", CLValue.u32(customId)); - }).to.throw("Can not add argument to already signed deploy."); - + DeployUtil.addArgToDeploy(deploy, 'custom_id', CLValue.u32(customId)); + }).to.throw('Can not add argument to already signed deploy.'); }); - - }); diff --git a/packages/ui/src/containers/AuthContainer.ts b/packages/ui/src/containers/AuthContainer.ts index 3e38152b..9616aa33 100644 --- a/packages/ui/src/containers/AuthContainer.ts +++ b/packages/ui/src/containers/AuthContainer.ts @@ -157,7 +157,7 @@ export class AuthContainer { this.balances.set(accountHash, { checkedAt: now, blockHashBase16: latestBlockHash, - balance: latestAccountBalance + balance: latestAccountBalance?.toNumber() }); } } diff --git a/packages/ui/src/containers/BlockContainer.ts b/packages/ui/src/containers/BlockContainer.ts index 4568162a..69e265ed 100644 --- a/packages/ui/src/containers/BlockContainer.ts +++ b/packages/ui/src/containers/BlockContainer.ts @@ -77,7 +77,7 @@ export class BlockContainer { PublicKey.fromEd25519(decodeBase16(accountKey.slice(2))) ); if (balance !== undefined) { - this.balances.set(accountKey, balance); + this.balances.set(accountKey, balance.toNumber()); } } }