diff --git a/examples/cis2/transfer.ts b/examples/cis2/transfer.ts index 59c694863..068d8caee 100644 --- a/examples/cis2/transfer.ts +++ b/examples/cis2/transfer.ts @@ -106,7 +106,7 @@ const client = createConcordiumClient( const txHash = await contract.transfer( { senderAddress: from, - energy: Energy.create(10000n), + energy: Energy.create(10000), }, { from, diff --git a/examples/cis2/updateOperator.ts b/examples/cis2/updateOperator.ts index 8a02fffd1..aa205d774 100644 --- a/examples/cis2/updateOperator.ts +++ b/examples/cis2/updateOperator.ts @@ -86,7 +86,7 @@ const client = createConcordiumClient( const txHash = await contract.updateOperator( { senderAddress: owner, - energy: Energy.create(10000n), + energy: Energy.create(10000), }, { type: cli.flags.updateType as 'add' | 'remove', diff --git a/examples/cis4/registerCredential.ts b/examples/cis4/registerCredential.ts index 720aeb368..8e3109934 100644 --- a/examples/cis4/registerCredential.ts +++ b/examples/cis4/registerCredential.ts @@ -137,7 +137,7 @@ const signer = buildAccountSigner(wallet); signer, { senderAddress: AccountAddress.fromBase58(wallet.value.address), - energy: Energy.create(10000n), + energy: Energy.create(10000), }, credential, cli.flags.data diff --git a/examples/cis4/registerRevocationKeys.ts b/examples/cis4/registerRevocationKeys.ts index edd934dbc..aa48d48d7 100644 --- a/examples/cis4/registerRevocationKeys.ts +++ b/examples/cis4/registerRevocationKeys.ts @@ -103,7 +103,7 @@ const signer = buildAccountSigner(wallet); signer, { senderAddress: AccountAddress.fromBase58(wallet.value.address), - energy: Energy.create(10000n), + energy: Energy.create(10000), }, keys, cli.flags.data diff --git a/examples/cis4/removeRevocationKeys.ts b/examples/cis4/removeRevocationKeys.ts index 3855aa53b..036ae0235 100644 --- a/examples/cis4/removeRevocationKeys.ts +++ b/examples/cis4/removeRevocationKeys.ts @@ -88,7 +88,7 @@ const signer = buildAccountSigner(wallet); signer, { senderAddress: AccountAddress.fromBase58(wallet.value.address), - energy: Energy.create(10000n), + energy: Energy.create(10000), }, cli.flags.keys, cli.flags.data diff --git a/examples/cis4/revokeCredentialAsHolder.ts b/examples/cis4/revokeCredentialAsHolder.ts index 0c778fa85..7b1c7da99 100644 --- a/examples/cis4/revokeCredentialAsHolder.ts +++ b/examples/cis4/revokeCredentialAsHolder.ts @@ -99,7 +99,7 @@ const signer = buildAccountSigner(wallet); signer, { senderAddress: AccountAddress.fromBase58(wallet.value.address), - energy: Energy.create(10000n), + energy: Energy.create(10000), }, hSigner, nonce, diff --git a/examples/cis4/revokeCredentialAsIssuer.ts b/examples/cis4/revokeCredentialAsIssuer.ts index 106714e70..001b388f2 100644 --- a/examples/cis4/revokeCredentialAsIssuer.ts +++ b/examples/cis4/revokeCredentialAsIssuer.ts @@ -92,7 +92,7 @@ const signer = buildAccountSigner(wallet); signer, { senderAddress: AccountAddress.fromBase58(wallet.value.address), - energy: Energy.create(10000n), + energy: Energy.create(10000), }, cli.flags.credId, cli.flags.reason, diff --git a/examples/cis4/revokeCredentialAsOther.ts b/examples/cis4/revokeCredentialAsOther.ts index add3623ef..a9854e8fc 100644 --- a/examples/cis4/revokeCredentialAsOther.ts +++ b/examples/cis4/revokeCredentialAsOther.ts @@ -105,7 +105,7 @@ const signer = buildAccountSigner(wallet); signer, { senderAddress: AccountAddress.fromBase58(wallet.value.address), - energy: Energy.create(10000n), + energy: Energy.create(10000), }, rSigner, cli.flags.credId, diff --git a/packages/ccd-js-gen/src/lib.ts b/packages/ccd-js-gen/src/lib.ts index 679c294f2..cc186e778 100644 --- a/packages/ccd-js-gen/src/lib.ts +++ b/packages/ccd-js-gen/src/lib.ts @@ -843,12 +843,18 @@ function schemaToTypeAndMapper( }; case 'U64': case 'I64': + return { + type: 'number | bigint', + mapper(id) { + return `BigInt(${id})`; + }, + }; case 'U128': case 'I128': return { type: 'number | bigint', mapper(id) { - return `BigInt(${id}).toString()`; // TODO: check that the schema JSON actually use a string here. + return `BigInt(${id}).toString()`; }, }; case 'Amount': diff --git a/packages/common/src/accountTransactions.ts b/packages/common/src/accountTransactions.ts index 6a6aa9219..c777e3086 100644 --- a/packages/common/src/accountTransactions.ts +++ b/packages/common/src/accountTransactions.ts @@ -47,7 +47,7 @@ export class SimpleTransferHandler } serialize(transfer: SimpleTransferPayload): Buffer { - const serializedToAddress = transfer.toAddress.decodedAddress; + const serializedToAddress = AccountAddress.toBuffer(transfer.toAddress); const serializedAmount = encodeWord64(transfer.amount.microCcdAmount); return Buffer.concat([serializedToAddress, serializedAmount]); } @@ -71,7 +71,7 @@ export class SimpleTransferWithMemoHandler implements AccountTransactionHandler { serialize(transfer: SimpleTransferWithMemoPayload): Buffer { - const serializedToAddress = transfer.toAddress.decodedAddress; + const serializedToAddress = AccountAddress.toBuffer(transfer.toAddress); const serializedMemo = encodeDataBlob(transfer.memo); const serializedAmount = encodeWord64(transfer.amount.microCcdAmount); return Buffer.concat([ diff --git a/packages/common/src/deserialization.ts b/packages/common/src/deserialization.ts index b85ee6c01..68ad74259 100644 --- a/packages/common/src/deserialization.ts +++ b/packages/common/src/deserialization.ts @@ -1,4 +1,3 @@ -import { Buffer } from 'buffer/index.js'; import { getAccountTransactionHandler } from './accountTransactions.js'; import { Cursor } from './deserializationHelpers.js'; import { @@ -8,6 +7,7 @@ import { isAccountTransactionType, } from './types.js'; import * as AccountAddress from './types/AccountAddress.js'; +import * as AccountSequenceNumber from './types/SequenceNumber.js'; import { TransactionExpiry } from './types/transactionExpiry.js'; /** @@ -61,10 +61,10 @@ function deserializeAccountTransactionSignature( function deserializeTransactionHeader( serializedHeader: Cursor ): AccountTransactionHeader { - const sender = AccountAddress.fromBuffer( - Buffer.from(serializedHeader.read(32)) + const sender = AccountAddress.fromBuffer(serializedHeader.read(32)); + const nonce = AccountSequenceNumber.create( + serializedHeader.read(8).readBigUInt64BE(0) ); - const nonce = serializedHeader.read(8).readBigUInt64BE(0); // TODO: extract payloadSize and energyAmount? // energyAmount serializedHeader.read(8).readBigUInt64BE(0); diff --git a/packages/common/src/energyCost.ts b/packages/common/src/energyCost.ts index 99bb4879a..2261eb0f6 100644 --- a/packages/common/src/energyCost.ts +++ b/packages/common/src/energyCost.ts @@ -6,6 +6,7 @@ import { ChainParameters, Ratio, } from './types.js'; +import * as Energy from './types/Energy.js'; /** * These constants must be consistent with constA and constB in: @@ -31,11 +32,11 @@ export function calculateEnergyCost( signatureCount: bigint, payloadSize: bigint, transactionSpecificCost: bigint -): bigint { - return ( +): Energy.Type { + return Energy.create( constantA * signatureCount + - constantB * (accountTransactionHeaderSize + payloadSize) + - transactionSpecificCost + constantB * (accountTransactionHeaderSize + payloadSize) + + transactionSpecificCost ); } @@ -48,7 +49,7 @@ export function getEnergyCost( transactionType: AccountTransactionType, payload: AccountTransactionPayload, signatureCount = 1n -): bigint { +): Energy.Type { const handler = getAccountTransactionHandler(transactionType); const size = handler.serialize(payload).length; return calculateEnergyCost( diff --git a/packages/common/src/grpc/GRPCClient.ts b/packages/common/src/grpc/GRPCClient.ts index b1e6f4d93..811ae154a 100644 --- a/packages/common/src/grpc/GRPCClient.ts +++ b/packages/common/src/grpc/GRPCClient.ts @@ -39,6 +39,7 @@ import * as TransactionHash from '../types/TransactionHash.js'; import * as ContractAddress from '../types/ContractAddress.js'; import * as Parameter from '../types/Parameter.js'; import * as Energy from '../types/Energy.js'; +import * as SequenceNumber from '../types/SequenceNumber.js'; /** * @hidden @@ -364,7 +365,7 @@ export class ConcordiumGRPCClient { */ async sendRawAccountTransaction( header: v1.AccountTransactionHeader, - energyAmount: bigint, + energyAmount: Energy.Type, payload: Uint8Array, signature: v1.AccountTransactionSignature ): Promise { @@ -373,9 +374,9 @@ export class ConcordiumGRPCClient { // Put together sendBlockItemRequest const convertedHeader: v2.AccountTransactionHeader = { - sender: { value: header.sender.decodedAddress }, - sequenceNumber: { value: header.nonce }, - energyAmount: { value: energyAmount }, + sender: AccountAddress.toProto(header.sender), + sequenceNumber: SequenceNumber.toProto(header.nonce), + energyAmount: Energy.toProto(energyAmount), expiry: { value: header.expiry.expiryEpochSeconds }, }; const accountTransaction: v2.AccountTransaction = { diff --git a/packages/common/src/grpc/translation.ts b/packages/common/src/grpc/translation.ts index 46bd3bb53..cc4828777 100644 --- a/packages/common/src/grpc/translation.ts +++ b/packages/common/src/grpc/translation.ts @@ -15,6 +15,7 @@ import * as ContractAddress from '../types/ContractAddress.js'; import * as Energy from '../types/Energy.js'; import * as Duration from '../types/Duration.js'; import * as Timestamp from '../types/Timestamp.js'; +import * as SequenceNumber from '../types/SequenceNumber.js'; function unwrapToHex(bytes: Uint8Array | undefined): v1.HexString { return Buffer.from(unwrap(bytes)).toString('hex'); @@ -374,7 +375,7 @@ export function accountInfo(acc: v2.AccountInfo): v1.AccountInfo { }; const accInfoCommon: v1.AccountInfoSimple = { accountAddress: AccountAddress.fromProto(unwrap(acc.address)), - accountNonce: unwrap(acc.sequenceNumber?.value), + accountNonce: SequenceNumber.fromProto(unwrap(acc.sequenceNumber)), accountAmount: unwrap(acc.amount?.value), accountIndex: unwrap(acc.index?.value), accountThreshold: unwrap(acc.threshold?.value), @@ -403,7 +404,7 @@ export function nextAccountSequenceNumber( nasn: v2.NextAccountSequenceNumber ): v1.NextAccountNonce { return { - nonce: unwrap(nasn.sequenceNumber?.value), + nonce: SequenceNumber.fromProto(unwrap(nasn.sequenceNumber)), allFinal: nasn.allFinal, }; } @@ -2226,8 +2227,8 @@ export function invokeInstanceResponse( case 'failure': return { tag: 'failure', - usedEnergy: unwrap( - invokeResponse.result.failure.usedEnergy?.value + usedEnergy: Energy.fromProto( + unwrap(invokeResponse.result.failure.usedEnergy) ), reason: trRejectReason(invokeResponse.result.failure.reason), }; @@ -2235,7 +2236,7 @@ export function invokeInstanceResponse( const result = invokeResponse.result.success; return { tag: 'success', - usedEnergy: unwrap(result.usedEnergy?.value), + usedEnergy: Energy.fromProto(unwrap(result.usedEnergy)), returnValue: result.returnValue ? Buffer.from(unwrap(result.returnValue)).toString('hex') : undefined, diff --git a/packages/common/src/pub/types.ts b/packages/common/src/pub/types.ts index e19c7a82d..04092c5ea 100644 --- a/packages/common/src/pub/types.ts +++ b/packages/common/src/pub/types.ts @@ -51,7 +51,7 @@ export { import * as ModuleClient from '../types/ModuleClient.js'; import * as Parameter from '../types/Parameter.js'; -import * as AccountSequenceNumber from '../types/AccountSequenceNumber.js'; +import * as SequenceNumber from '../types/SequenceNumber.js'; import * as Energy from '../types/Energy.js'; import * as TransactionHash from '../types/TransactionHash.js'; import * as BlockHash from '../types/BlockHash.js'; @@ -69,7 +69,7 @@ import * as Timestamp from '../types/Timestamp.js'; export { ModuleClient, Parameter, - AccountSequenceNumber, + SequenceNumber, Energy, TransactionHash, BlockHash, diff --git a/packages/common/src/serialization.ts b/packages/common/src/serialization.ts index b6f9bb6e1..d2964ec51 100644 --- a/packages/common/src/serialization.ts +++ b/packages/common/src/serialization.ts @@ -28,6 +28,7 @@ import { import { calculateEnergyCost } from './energyCost.js'; import { countSignatures } from './util.js'; import * as AccountAddress from './types/AccountAddress.js'; +import * as Energy from './types/Energy.js'; import { sha256 } from './hash.js'; function serializeAccountTransactionType(type: AccountTransactionType): Buffer { @@ -46,11 +47,11 @@ function serializeAccountTransactionType(type: AccountTransactionType): Buffer { function serializeAccountTransactionHeader( header: AccountTransactionHeader, payloadSize: number, - energyAmount: bigint + energyAmount: Energy.Type ) { - const serializedSender = header.sender.decodedAddress; - const serializedNonce = encodeWord64(header.nonce); - const serializedEnergyAmount = encodeWord64(energyAmount); + const serializedSender = AccountAddress.toBuffer(header.sender); + const serializedNonce = encodeWord64(header.nonce.value); + const serializedEnergyAmount = encodeWord64(energyAmount.value); const serializedPayloadSize = encodeWord32(payloadSize); const serializedExpiry = encodeWord64(header.expiry.expiryEpochSeconds); return Buffer.concat([ diff --git a/packages/common/src/types.ts b/packages/common/src/types.ts index a05537651..c9f09ff48 100644 --- a/packages/common/src/types.ts +++ b/packages/common/src/types.ts @@ -13,6 +13,7 @@ import * as Parameter from './types/Parameter.js'; import type * as InitName from './types/InitName.js'; import type * as ContractName from './types/ContractName.js'; import type * as ReceiveName from './types/ReceiveName.js'; +import type * as AccountSequenceNumber from './types/SequenceNumber.js'; import { CcdAmount } from './types/ccdAmount.js'; import { DataBlob } from './types/DataBlob.js'; import { TransactionExpiry } from './types/transactionExpiry.js'; @@ -948,7 +949,7 @@ export interface CryptographicParameters { } export interface NextAccountNonce { - nonce: bigint; + nonce: AccountSequenceNumber.Type; allFinal: boolean; } @@ -1349,7 +1350,7 @@ export type AccountCredential = Versioned< interface AccountInfoCommon { accountAddress: AccountAddress.Type; - accountNonce: bigint; + accountNonce: AccountSequenceNumber.Type; accountAmount: bigint; accountIndex: bigint; @@ -1593,7 +1594,7 @@ export interface AccountTransactionHeader { * the nonce for the transaction, usually acquired by * getting the next account nonce from the node */ - nonce: bigint; + nonce: AccountSequenceNumber.Type; /** expiration of the transaction */ expiry: TransactionExpiry; @@ -1893,14 +1894,14 @@ export function buildInvoker( export interface InvokeContractSuccessResult { tag: 'success'; - usedEnergy: bigint; + usedEnergy: Energy.Type; events: ContractTraceEvent[]; returnValue?: string; } export interface InvokeContractFailedResult { tag: 'failure'; - usedEnergy: bigint; + usedEnergy: Energy.Type; reason: RejectReason; } @@ -1909,7 +1910,7 @@ export interface InvokeContractFailedResult { */ export interface InvokeContractFailedResultV1 { tag: 'failure'; - usedEnergy: bigint; + usedEnergy: Energy.Type; reason: RejectReasonV1; } diff --git a/packages/common/src/types/AccountSequenceNumber.ts b/packages/common/src/types/AccountSequenceNumber.ts deleted file mode 100644 index 69e00ba20..000000000 --- a/packages/common/src/types/AccountSequenceNumber.ts +++ /dev/null @@ -1,27 +0,0 @@ -/** Account transaction sequence number. (Formerly refered as Nonce) */ -class AccountSequenceNumber { - /** Having a private field prevents similar structured objects to be considered the same type (similar to nominal typing). */ - private __nominal = true; - constructor( - /** Internal value representing the sequence number. */ - public readonly value: bigint - ) {} -} - -/** Account transaction sequence number. (Formerly refered as Nonce) */ -export type Type = AccountSequenceNumber; - -/** - * Construct an AccountSequenceNumber type. - * @param {bigint | number} sequenceNumber The account sequence number. - * @throws If `sequenceNumber` is not at least 1. - * @returns {AccountSequenceNumber} - */ -export function create(sequenceNumber: bigint | number): AccountSequenceNumber { - if (sequenceNumber < 1) { - throw new Error( - 'Invalid account sequence number: Must be 1 or higher.' - ); - } - return new AccountSequenceNumber(BigInt(sequenceNumber)); -} diff --git a/packages/common/src/types/SequenceNumber.ts b/packages/common/src/types/SequenceNumber.ts new file mode 100644 index 000000000..408a777fb --- /dev/null +++ b/packages/common/src/types/SequenceNumber.ts @@ -0,0 +1,51 @@ +import type * as Proto from '../grpc-api/v2/concordium/types.js'; + +/** Transaction sequence number. (Formerly refered as Nonce) */ +class SequenceNumber { + /** Having a private field prevents similar structured objects to be considered the same type (similar to nominal typing). */ + private __nominal = true; + constructor( + /** Internal value representing the sequence number. */ + public readonly value: bigint + ) {} +} + +/** A transaction sequence number. (Formerly refered as Nonce) */ +export type Type = SequenceNumber; + +/** + * Construct an SequenceNumber type. + * @param {bigint | number} sequenceNumber The account sequence number. + * @throws If `sequenceNumber` is not at least 1. + * @returns {SequenceNumber} + */ +export function create(sequenceNumber: bigint | number): SequenceNumber { + if (sequenceNumber < 1) { + throw new Error( + 'Invalid account sequence number: Must be 1 or higher.' + ); + } + return new SequenceNumber(BigInt(sequenceNumber)); +} + +/** + * Convert a SequenceNumber from its protobuf encoding. + * @param {Proto.SequenceNumber} sequenceNumber The sequence number in protobuf. + * @returns {SequenceNumber} The sequence number. + */ +export function fromProto( + sequenceNumber: Proto.SequenceNumber +): SequenceNumber { + return create(sequenceNumber.value); +} + +/** + * Convert a sequence number into its protobuf encoding. + * @param {SequenceNumber} sequenceNumber The duration. + * @returns {Proto.SequenceNumber} The protobuf encoding. + */ +export function toProto(sequenceNumber: SequenceNumber): Proto.SequenceNumber { + return { + value: sequenceNumber.value, + }; +}