diff --git a/CHANGELOG.md b/CHANGELOG.md index e39af76a..6e64af68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,23 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ### Removed --> +## [5.0.0-rc3] - 2024-11-19 + +### Added + +- Deserializer function for InfoGetDeployResultV1Compatible - `fromJSON` +- Annotate RPC request params + +### Fixed + +- Args and CLType / CLValue parsers +- RPC serialization +- Updated names for RPC response/request +- Deserializer for Transform class +- Removed unnecessary object declaration for deploy/transaction during serialization + +**Full Changelog**: https://github.com/casper-ecosystem/casper-js-sdk/compare/5.0.0-rc2...5.0.0-rc3 + ## [5.0.0-rc1] - 2024-11-12 ### Added diff --git a/README.md b/README.md index 652e8dc9..91a33067 100644 --- a/README.md +++ b/README.md @@ -107,11 +107,7 @@ const deployHeader = DeployHeader.default(); deployHeader.account = senderKey.publicKey; deployHeader.chainName = 'casper-test'; -const deploy = Deploy.fromHeaderAndItems( - deployHeader, - payment, - session -); +const deploy = Deploy.makeDeploy(deployHeader, payment, session); await deploy.sign(senderKey); const result = await rpcClient.putDeploy(deploy); diff --git a/package-lock.json b/package-lock.json index 2bcba2af..61453a8d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "casper-js-sdk", - "version": "5.0.0-rc2", + "version": "5.0.0-rc3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "casper-js-sdk", - "version": "5.0.0-rc2", + "version": "5.0.0-rc3", "license": "Apache 2.0", "dependencies": { "@ethersproject/bignumber": "^5.0.8", @@ -20,7 +20,6 @@ "@scure/bip32": "^1.1.5", "@scure/bip39": "^1.2.0", "@types/ws": "^8.2.2", - "casper-js-sdk": "^5.0.0-rc2", "eventsource": "^2.0.2", "glob": "^7.1.6", "humanize-duration": "^3.24.0", @@ -2724,33 +2723,6 @@ "cdl": "bin/cdl.js" } }, - "node_modules/casper-js-sdk": { - "version": "5.0.0-rc2", - "resolved": "https://registry.npmjs.org/casper-js-sdk/-/casper-js-sdk-5.0.0-rc2.tgz", - "integrity": "sha512-q8K4ucyuZ0wzbbeHa4Sj4y1X/kI/+V0BWlPbOYhdRYI5nMoTO/N3siFB4jdtHEwUMndHazo5/1/QAhh3B2Jz2g==", - "dependencies": { - "@ethersproject/bignumber": "^5.0.8", - "@ethersproject/bytes": "^5.0.5", - "@ethersproject/constants": "^5.0.5", - "@noble/curves": "^1.1.0", - "@noble/ed25519": "^1.7.3", - "@noble/hashes": "^1.2.0", - "@noble/secp256k1": "^1.7.1", - "@open-rpc/client-js": "^1.8.1", - "@scure/bip32": "^1.1.5", - "@scure/bip39": "^1.2.0", - "@types/ws": "^8.2.2", - "eventsource": "^2.0.2", - "glob": "^7.1.6", - "humanize-duration": "^3.24.0", - "key-encoder": "^2.0.3", - "lodash": "^4.17.21", - "node-fetch": "2.6.13", - "reflect-metadata": "^0.1.13", - "ts-results": "npm:@casperlabs/ts-results@^3.3.4", - "typedjson": "^1.6.0-rc2" - } - }, "node_modules/casper-node-launcher-js": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/casper-node-launcher-js/-/casper-node-launcher-js-0.0.3.tgz", diff --git a/package.json b/package.json index 4140f425..179675c2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "casper-js-sdk", - "version": "5.0.0-rc2", + "version": "5.0.0-rc3", "license": "Apache 2.0", "description": "SDK to interact with the Casper blockchain", "homepage": "https://github.com/casper-ecosystem/casper-js-sdk#README.md", diff --git a/src/rpc/response.ts b/src/rpc/response.ts index a5278e21..c9b4a1ab 100644 --- a/src/rpc/response.ts +++ b/src/rpc/response.ts @@ -320,6 +320,13 @@ export class InfoGetDeployResultV1Compatible { blockHeight?: number; public rawJSON: any; + + public static fromJSON( + json: any + ): InfoGetDeployResultV1Compatible | undefined { + const serializer = new TypedJSON(InfoGetDeployResultV1Compatible); + return serializer.parse(json); + } } @jsonObject diff --git a/src/types/Deploy.test.ts b/src/types/Deploy.test.ts index 1ae041cf..20f34768 100644 --- a/src/types/Deploy.test.ts +++ b/src/types/Deploy.test.ts @@ -59,11 +59,7 @@ describe('Deploy', () => { ); const payment = ExecutableDeployItem.standardPayment(paymentAmount); - let deploy = Deploy.fromHeaderAndItems( - deployHeader, - payment, - executableDeployItem - ); + let deploy = Deploy.makeDeploy(deployHeader, payment, executableDeployItem); await deploy.sign(senderKey); await deploy.sign(recipientKey); @@ -152,7 +148,7 @@ describe('Deploy', () => { transferId ); - const firstDeploy = Deploy.fromHeaderAndItems( + const firstDeploy = Deploy.makeDeploy( deployHeader, payment, executableDeployItem @@ -171,7 +167,7 @@ describe('Deploy', () => { senderKey.publicKey ); - const secondDeploy = Deploy.fromHeaderAndItems( + const secondDeploy = Deploy.makeDeploy( secondDeployHeader, payment, executableDeployItem diff --git a/src/types/Deploy.ts b/src/types/Deploy.ts index 2129e5e5..3cda771f 100644 --- a/src/types/Deploy.ts +++ b/src/types/Deploy.ts @@ -19,8 +19,12 @@ import { ClassicMode, PricingMode } from './PricingMode'; import { TransactionTarget } from './TransactionTarget'; import { TransactionScheduling } from './TransactionScheduling'; import { ExecutableDeployItem } from './ExecutableDeployItem'; -import { byteHash, toBytesU32 } from './ByteConverters'; -import { Conversions } from './Conversions'; +import { + byteHash, + toBytesString, + toBytesU32, + toBytesU64 +} from './ByteConverters'; /** * Represents the header of a deploy in the blockchain. @@ -143,52 +147,18 @@ export class DeployHeader { * @returns A `Uint8Array` representing the deploy header in byte format. */ public toBytes(): Uint8Array { - const accountBytes = this.account?.bytes() ?? new Uint8Array(); - const timestampBytes = new Uint8Array( - new BigUint64Array([BigInt(this.timestamp.toMilliseconds())]).buffer - ); - const ttlBytes = new Uint8Array( - new BigUint64Array([BigInt(this.ttl.toMilliseconds())]).buffer - ); - const gasPriceBytes = new Uint8Array( - new BigUint64Array([BigInt(this.gasPrice)]).buffer - ); - const bodyHashBytes = this.bodyHash?.toBytes() ?? new Uint8Array(); - const chainNameBytes = new TextEncoder().encode(this.chainName); - - const totalLength = - accountBytes.length + - timestampBytes.length + - ttlBytes.length + - gasPriceBytes.length + - bodyHashBytes.length + - chainNameBytes.length; - const result = new Uint8Array(totalLength); - - result.set(accountBytes, 0); - result.set(timestampBytes, accountBytes.length); - result.set(ttlBytes, accountBytes.length + timestampBytes.length); - result.set( - gasPriceBytes, - accountBytes.length + timestampBytes.length + ttlBytes.length - ); - result.set( - bodyHashBytes, - accountBytes.length + - timestampBytes.length + - ttlBytes.length + - gasPriceBytes.length - ); - result.set( - chainNameBytes, - accountBytes.length + - timestampBytes.length + - ttlBytes.length + - gasPriceBytes.length + - bodyHashBytes.length - ); + const dependenciesBytes = this.dependencies.map(e => e.toBytes()); + dependenciesBytes.splice(0, 0, toBytesU32(this.dependencies?.length)); - return result; + return concat([ + this.account!.bytes(), + toBytesU64(Date.parse(this.timestamp.toJSON())), + toBytesU64(this.ttl.duration), + toBytesU64(this.gasPrice), + this.bodyHash!.toBytes(), + concat(dependenciesBytes), + toBytesString(this.chainName) + ]); } /** @@ -368,7 +338,7 @@ export class Deploy { * @param session The session logic of the deploy. * @returns A new `Deploy` object. */ - public static fromHeaderAndItems( + public static makeDeploy( deployHeader: DeployHeader, payment: ExecutableDeployItem, session: ExecutableDeployItem @@ -523,42 +493,6 @@ export class Deploy { } } -/** - * Builds a `Deploy` object from the given parameters, session logic, and payment logic. - * This method is deprecated. It is recommended to use `Deploy.fromHeaderAndItems` instead. - * - * @deprecated Use `Deploy.fromHeaderAndItems` instead - * @param deployParam The parameters used for creating the deploy. See [DeployParams](#L1323). - * @param session The session logic of the deploy, represented as an `ExecutableDeployItem`. - * @param payment The payment logic of the deploy, represented as an `ExecutableDeployItem`. - * @returns A new `Deploy` object that represents the entire deploy. - * - */ -export function makeDeploy( - deployParam: DeployParams, - session: ExecutableDeployItem, - payment: ExecutableDeployItem -): Deploy { - const serializedBody = concat([payment.bytes(), session.bytes()]); - const bodyHash = byteHash(serializedBody); - - if (!deployParam.timestamp) { - deployParam.timestamp = Date.now(); - } - - const header: DeployHeader = new DeployHeader( - deployParam.chainName, - deployParam.dependencies.map(d => new Hash(d)), - deployParam.gasPrice, - new Timestamp(new Date(deployParam.timestamp)), - new Duration(deployParam.ttl), - deployParam.accountPublicKey, - new Hash(bodyHash) - ); - - return Deploy.fromHeaderAndItems(header, payment, session); -} - /** * Serializes an array of `Approval`s into a `Uint8Array` typed byte array. * This is used to store or transmit the approvals associated with a deploy. @@ -583,42 +517,6 @@ export const serializeApprovals = (approvals: Approval[]): Uint8Array => { return concat([len, bytes]); }; -/** - * The parameters of a `Deploy` object. - * This class is deprecated. Use `Deploy.fromHeaderAndItems` instead. - * - * It is used to configure the construction of a `Deploy` object. - * - * @deprecated The parameters of a `Deploy` object. Use Deploy.fromHeaderAndItems - */ -export class DeployParams { - /** - * Constructor for `DeployParams`. - * - * @param accountPublicKey The public key of the deploying account as a `PublicKey`. - * @param chainName The name of the blockchain chain to avoid the `Deploy` from being accidentally or maliciously included in another chain. - * @param gasPrice The conversion rate between the cost of Wasm opcodes and the motes sent by the payment code. 1 mote = 1 * 10^-9 CSPR. - * @param ttl The time-to-live (TTL) for the deploy, in milliseconds. The default value is 30 minutes (1800000 milliseconds). - * @param dependencies Hex-encoded `Deploy` hashes of deploys that must be executed before this one. - * @param timestamp The timestamp when the deploy is created, in UTC. - */ - constructor( - public accountPublicKey: PublicKey, - public chainName: string, - public gasPrice: number = 1, - public ttl: number = DEFAULT_DEPLOY_TTL, - public dependencies: Uint8Array[] = [], - public timestamp?: number - ) { - this.dependencies = dependencies.filter( - d => - dependencies.filter( - t => Conversions.encodeBase16(d) === Conversions.encodeBase16(t) - ).length < 2 - ); - } -} - /** * Default TTL value used for deploys (30 minutes). */ diff --git a/src/types/Transaction.ts b/src/types/Transaction.ts index a6bbaeb6..8822a25b 100644 --- a/src/types/Transaction.ts +++ b/src/types/Transaction.ts @@ -386,7 +386,7 @@ export class TransactionV1 { * Validates the transaction by checking the body hash and the approval signatures. * @throws {TransactionError} Throws errors if validation fails. */ - public validate(): void { + public validate(): boolean { const bodyBytes = this.body.toBytes(); if (!arrayEquals(byteHash(bodyBytes), this.header.bodyHash.toBytes())) @@ -407,6 +407,8 @@ export class TransactionV1 { throw ErrInvalidApprovalSignature; } } + + return true; } /** diff --git a/src/types/clvalue/Bool.test.ts b/src/types/clvalue/Bool.test.ts index 88b2e611..afe9c65c 100644 --- a/src/types/clvalue/Bool.test.ts +++ b/src/types/clvalue/Bool.test.ts @@ -13,10 +13,10 @@ describe('CLBool', () => { }); it('toBytes() / fromBytes() do proper bytes serialization', () => { - const myBool = CLValueBool.fromBoolean(false); - const myBool2 = CLValueBool.fromBoolean(true); - const myBoolBytes = CLValueParser.toBytesWithType(myBool); - const myBool2Bytes = CLValueParser.toBytesWithType(myBool2); + const myBool = new CLValueBool(false); + const myBool2 = new CLValueBool(true); + const myBoolBytes = myBool.bytes(); + const myBool2Bytes = myBool2.bytes(); const fromBytes1 = CLValueParser.fromBytesByType(myBoolBytes, CLTypeBool) .result; @@ -26,8 +26,8 @@ describe('CLBool', () => { expect(myBoolBytes).to.be.deep.eq(Uint8Array.from([0])); expect(myBool2Bytes).to.be.deep.eq(Uint8Array.from([1])); - expect(fromBytes1).to.be.deep.eq(myBool); - expect(fromBytes2).to.be.deep.eq(myBool2); + expect(fromBytes1.bool).to.be.deep.eq(myBool); + expect(fromBytes2.bool).to.be.deep.eq(myBool2); }); it('toJSON() / fromJSON() do proper bytes serialization', () => { diff --git a/src/types/clvalue/ByteArray.test.ts b/src/types/clvalue/ByteArray.test.ts index 6dcfd497..15cb2059 100644 --- a/src/types/clvalue/ByteArray.test.ts +++ b/src/types/clvalue/ByteArray.test.ts @@ -14,7 +14,7 @@ describe('CLByteArray', () => { it('Should be able to return proper byte array by calling toBytes() / fromBytes()', () => { const expectedBytes = Uint8Array.from(Array(32).fill(42)); const hash = CLValueByteArray.newCLByteArray(expectedBytes); - const bytes = CLValueParser.toBytesWithType(hash); + const bytes = hash.bytes(); expect(bytes).to.deep.eq(expectedBytes); expect( diff --git a/src/types/clvalue/Parser.ts b/src/types/clvalue/Parser.ts index 22b98f8f..59785aa4 100644 --- a/src/types/clvalue/Parser.ts +++ b/src/types/clvalue/Parser.ts @@ -1,3 +1,5 @@ +import { concat } from '@ethersproject/bytes'; + import { CLValue, IResultWithBytes } from './CLValue'; import { Key, URef } from '../key'; import { PublicKey } from '../keypair'; @@ -35,6 +37,7 @@ import { CLValueTuple1 } from './Tuple1'; import { CLValueTuple2 } from './Tuple2'; import { CLValueTuple3 } from './Tuple3'; import { Conversions } from '../Conversions'; +import { toBytesArrayU8 } from '../ByteConverters'; /** * Error thrown when an unsupported CLType is encountered. @@ -85,7 +88,9 @@ export class CLValueParser { * @returns A Uint8Array containing the serialized CLValue with type information. */ static toBytesWithType(value: CLValue): Uint8Array { - return value.bytes(); + const clTypeBytes = value.getType().toBytes(); + const bytes = value.bytes(); + return concat([toBytesArrayU8(bytes), clTypeBytes]); } /** diff --git a/src/types/clvalue/String.test.ts b/src/types/clvalue/String.test.ts index 0fa9896a..c280146f 100644 --- a/src/types/clvalue/String.test.ts +++ b/src/types/clvalue/String.test.ts @@ -10,7 +10,7 @@ describe('CLString', () => { it('toBytes() / fromBytes()', () => { const str = CLValueString.newCLString('ABC'); - const bytes = CLValueParser.toBytesWithType(str); + const bytes = str.bytes(); const parsed = CLValueParser.fromBytesByType(bytes, str.type); expect(parsed.result).to.be.deep.eq(str); }); diff --git a/src/types/key/Uref.test.ts b/src/types/key/Uref.test.ts index a518e86d..6afc577a 100644 --- a/src/types/key/Uref.test.ts +++ b/src/types/key/Uref.test.ts @@ -39,7 +39,7 @@ describe('CLUref', () => { it('toBytes() / fromBytes() proper values', () => { const expectedBytes = Uint8Array.from([...Array(32).fill(42), 7]); const urefValue = CLValue.newCLUref(RWExampleURef); - const toBytes = CLValueParser.toBytesWithType(urefValue); + const toBytes = urefValue.bytes(); const fromBytes = CLValueParser.fromBytesByType( expectedBytes, urefValue.type