diff --git a/packages/sdk/CHANGELOG.md b/packages/sdk/CHANGELOG.md index 9511aded..b2160eae 100644 --- a/packages/sdk/CHANGELOG.md +++ b/packages/sdk/CHANGELOG.md @@ -2,12 +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`. +- Casper balances checks return `BigNumber` now. ## [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()`. 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/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 b6341bd3..56011db5 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,23 @@ 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 +826,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 +952,27 @@ 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.'); + } + + const deployParams = new DeployUtil.DeployParams( + deploy.header.account, + deploy.header.chainName, + deploy.header.gasPrice, + deploy.header.ttl, + deploy.header.dependencies, + deploy.header.timestamp + ); + + const session = deploy.session; + session.setArg(name, value); + + return makeDeploy(deployParams, session, deploy.payment); +}; 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 a270ee6b..a9c0bf6f 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,8 +43,10 @@ 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()); @@ -74,4 +76,99 @@ 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.'); + }); }); 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()); } } }