Repository navigation
Improves compatibility with Casper 2.x nodes and fixes bugs in RPC queries, SSE event handling, serialization and key handling.
Added
Keyreads and writes the two variants a 2.x node emits that the SDK did not know:Key::State(state-…,KeyTypeID.State = 24) andKey::RewardsHandling(rewards-handling-…,KeyTypeID.RewardsHandling = 25, introduced by node 2.2.0).Key.newKey()throws on a prefix it does not recognise, so one such key anywhere in a response took the whole payload down with it.PrefixNamegainsState,RewardsHandlingandSystemEntityRegistry, andKeygains astatememberKey.newKey()accepts thesystem-entity-registry-…spelling a 2.x node emits for the system registry key, alongside the 1.xsystem-contract-registry-…form
Changed
Key.toPrefixedString()writes the system registry key assystem-entity-registry-…, the only spelling a 2.x node accepts back; it wrote the 1.xsystem-contract-registry-…form, which a node rejects. Both still parse, so keys recorded by earlier versions keep loading — but code comparing key strings against a recorded value will see the new oneeventsource2 → 3. Stream errors arrive as an exportedSseErrorcarrying the HTTP status code (401,403, …) instead of a raw event object with no message or stack, andSseClient.start()accepts an optional error callbackSseClient.start()no longer throws when no error callback is supplied — it logs and lets the stream reconnect. The oldthroweither died silently or terminated the host process, cancelling the reconnect it was about to schedule. Pass the callback if you relied on itTransactionAcceptedEvent,TransactionExpiredEvent,TransactionProcessedEventandFinalitySignatureEventthrow fromfromJSON()instead of returning anError, narrowing the return type fromX | ErrortoX. The old branch was never usable:parseAs*Event()handed the returnedErrorback as the parsed event. Replaceinstanceof Errorchecks withtry/catch; the thrown error carries the original ascauseRpcClient.waitForTransaction()rejects with aTimeouterror once its deadline passes. The timeout previously threw from asetTimeoutcallback, where it could not reject the promise: it escaped as an uncaught exception while the promise stayed pending and polling continued indefinitely. A timeout during a retry carries the retried error ascauseCLValueMap.fromBytes()throws on an entry it cannot parse instead of skipping it. It previously returned a map silently missing entries, and a read offset that misaligned everything decoded after it. Malformed input onlyCasperNetwork.putTransaction()rejects with anErrorrather than a bare string for a non-legacy transaction on a 1.5 network. Same text, now reachable aserr.message- Rethrown errors carry the original as
cause, so a network or parse failure is no longer reduced to its wrapper message - secp256k1 key import rejects keys that are structurally valid but not secp256k1 — a P-256 or P-384 PEM, a private key of the wrong length, an unexpected
ECPrivateKeyversion. These were previously imported silently and used as secp256k1 keys PublicKey.fromBuffer()accepts aUint8Arrayas well as anArrayBufferHash.fromBuffer()and the secp256k1encodePrivate()/encodePublic()helpers declareUint8Arraywhere they declaredBuffer, so the published.d.tsno longer requires@types/node. Every existing call still type-checksencodePrivate()returnsstringrather thanany. Visible only to deep importers ofcasper-js-sdk/dist/types/keypair/secp256k1/encoders
Fixed
queryGlobalStateByBlockHash(),queryGlobalStateByBlockHeight()andqueryGlobalStateByStateHash()sent nostate_identifier, so all three queried the node's latest state and silently ignored the block or state root passed inPublicKey.accountHash().toJSON()emittedaccount-hash<hex>without the separator, so anEntityIdentifierorAccountIdentifierbuilt from it sent a malformed account hash to the node.toPrefixedString()was always correctStateGetEntityResultignored theAccountkey a 2.x node uses for an account entity, yielding an entity with nothing set and no error. BothAccountand the 1.xLegacyAccountnow resolve toentity.legacyAccount; the node's own payload stays onrawJSON- Messages in speculative execution results and
TransactionProcessedevents came backundefinedfrom a 2.x node, which emitsentity_addrwhere the SDK readhash_addr. The field is nowMessage.entityAddr: EntityAddr, replacingMessage.hashAddr: Hash, which no 2.x node ever populated SpeculativeExecResult.apiVersionheld the JSON-RPC protocol version ("2.0") instead of the node'sapi_versionSpeculativeExecResult.blockHashwasundefinedfor a 1.5 node response, which carries the block hash besideexecution_resultrather than inside itSeigniorageAllocation.fromJSON()read 2.x era data with the 1.x reader and dropped the delegator key — both shapes nest underDelegator, but 2.x carries adelegator_kindobject where 1.x carries a flat public key. Both now parseDelegationKindserialized a delegator'sPublicKeyas{"cryptoAlg":1}and aPurseas{"data":[…],"access":4}instead of their string forms, so anyEraInfo,EraEndorAuctionStatedocument the SDK wrote identified no delegatorEntryPointAccess.toJSON()emitted a lowercasegroupskey where the node writesGroupsparseAsStepEvent().stepwas alwaysundefined— the payload member was declaredstepwhere the node writesStepInfoGetStatusResultemitted noavailable_block_range. Parsing it was never affectedBalanceHoldAddr.fromJSON()andBlockGlobalAddr.fromString()threw on the prefixed form their owntoJSON()/toPrefixedString()emits, decodingbalance-hold-andblock-global-as part of the address- Five byte decoders returned wrong values, and a wrong remainder to whatever decoded next:
BalanceHoldAddrread itsblockTimefrom unrelated bytes when reached throughKey.fromBytes(),EntryPointAddrread its name one byte early,MessageAddrandNamedKeyAddrre-read the entity address in place of their topic hash and name, andKey.fromBytes()dropped thetransfer-prefix from aTransferHash toBytesU512()threwvalue out-of-boundsfor every value above2^256 - 1— the entire upper half of the legal U512 range.2^512and above still throwsparseU32()returned a negative number for any value with the high bit set:0xFFFFFFFFparsed as-1Hash.equals()bypassed subclass overrides, sodeployHash.equals(transaction.hash)and the reverse disagreed for the same pairerror instanceof SseErrorwas false for a genuineSseErrorin the ES5 bundle. ASseError.isSseError()guard is also available, for instances originating in a second copy of the SDK- The PEM writer emitted a blank line before the footer when the base64 body was an exact multiple of 64 characters, producing a file OpenSSL and Node's
crypto.createPrivateKeyboth reject TransferHashandTransactionHashleft the object half-built on some construction paths — harmless in the ES5 bundle, a hard failure when consuming the sources directly or bundling to modern output- Two import cycles (
Key↔Account,Transform↔TransformRaw) that threw at import time under native ES modules. Every existing import path still resolves StoredTarget.toBytes(),splitAt()andparseKey()had no declared return type, so TypeScript 6 inferredUint8Array<ArrayBufferLike>into the emitted declarations, which does not compile on TypeScript below 5.7 withskipLibCheck: false
Removed
asn1.jsandbn.js, replaced by@peculiar/asn1-ecc. The emitted DER and PEM are byte-identical, so existing key files keep parsing unchanged- The
/// <reference types="node" />directives from the emitted.d.tsfiles. The published types now compile withcompilerOptions.typesset to[]andskipLibCheck: false, which they did not in5.1.0
Full Changelog: 5.1.1...5.2.0
Contributors: @Comp0te, @alexmyshchyshyn