From a1077f79811f53167145cbee1cf20319569e73df Mon Sep 17 00:00:00 2001 From: Richard B Date: Fri, 28 Nov 2025 17:22:32 +0000 Subject: [PATCH 1/7] initial working for configure validator --- packages/sdk/src/accountTransactions.ts | 92 +++++++++++++++++++++++- packages/sdk/src/transactions/Payload.ts | 2 +- 2 files changed, 91 insertions(+), 3 deletions(-) diff --git a/packages/sdk/src/accountTransactions.ts b/packages/sdk/src/accountTransactions.ts index 18262da28..f2c9ed17a 100644 --- a/packages/sdk/src/accountTransactions.ts +++ b/packages/sdk/src/accountTransactions.ts @@ -659,6 +659,20 @@ export interface ConfigureBakerPayloadJSON { export class ConfigureBakerHandler implements AccountTransactionHandler { + //TODO: need to figure out what to do with the versions and hasSuspended + //for now assume version 8 only onwards + ALLOWED_BITS = 0x100; + VALIDATION_MASK = 0xffff - this.ALLOWED_BITS; + HAS_SUSPENDED = 0x0200; + HAS_FINALIZATION_REWARD_COMMISSION = 0x0080; + HAS_BAKING_REWARD_COMMISSION = 0x0040; + HAS_TRANSACTION_FEE_COMMISSION = 0x0020; + HAS_METADATA_URL = 0x0010; + HAS_KEYS_WITH_PROOF = 0x0008; + HAS_OPEN_FOR_DELEGATION = 0x004; + HAS_RESTAKE_EARNINGS = 0x0002; + HAS_CAPITAL = 0x0001; + getBaseEnergyCost(payload: ConfigureBakerPayload): bigint { if (payload.keys) { return 4050n; @@ -671,8 +685,82 @@ export class ConfigureBakerHandler return serializeConfigureBakerPayload(payload); } - deserialize(): ConfigureBakerPayload { - throw new Error('deserialize not supported'); + deserialize(serializedPayload: Cursor): ConfigureBakerPayload { + const serializedBitmap = serializedPayload.read(2).readUInt16BE(0); + + if ((serializedBitmap & this.VALIDATION_MASK) !== 0) + throw new Error('Found unsupported bits in bitmap, only version 8 onwards'); + + const hasCapital = (serializedBitmap & this.HAS_CAPITAL) !== 0; + const hasRestakeEarnings = (serializedBitmap & this.HAS_RESTAKE_EARNINGS) !== 0; + const hasOpenForDelegation = (serializedBitmap & this.HAS_OPEN_FOR_DELEGATION) !== 0; + const hasKeysWithProof = (serializedBitmap & this.HAS_KEYS_WITH_PROOF) !== 0; + const hasMetadataUrl = (serializedBitmap & this.HAS_METADATA_URL) !== 0; + const hasTransactionFeeCommission = (serializedBitmap & this.HAS_TRANSACTION_FEE_COMMISSION) !== 0; + const hasBakingRewardCommission = (serializedBitmap & this.HAS_BAKING_REWARD_COMMISSION) !== 0; + const hasFinalizationRewardCommission = (serializedBitmap & this.HAS_FINALIZATION_REWARD_COMMISSION) !== 0; + const hasSuspended = (serializedBitmap & this.HAS_SUSPENDED) !== 0; + + const result: any = {}; + + const capital = hasCapital + ? CcdAmount.fromMicroCcd(serializedPayload.read(8).readBigUInt64BE(0)) + : CcdAmount.zero(); + result.capital = capital; + + const restakeEarnings = hasRestakeEarnings ? serializedPayload.read(1).readUInt8(0) !== 0 : false; + result.restakeEarnings = restakeEarnings; + + const openForDelegation = hasOpenForDelegation ? serializedPayload.read(1).readUInt8(0) : undefined; + let currentOpenStatus; + if (openForDelegation !== undefined) { + result.openForDelegation = OpenStatus[openForDelegation]; + } + + if (hasKeysWithProof) { + result.electionVerifyKey = serializedPayload.read(32).toString('hex'); + + result.proofElection = serializedPayload.read(64).toString('hex'); + //TODO: bluepaper has these two below, i am combining for the above + //result.proofElection.challenge = serializedPayload.read(32).toString('hex'); + //result.proofElection.response = serializedPayload.read(32).toString('hex'); + + result.signatureVerifyKey.key = serializedPayload.read(32).toString('hex'); + + result.proofSig = serializedPayload.read(64).toString('hex'); + //TODO: bluepaper has these two below, i am combining for the above + //const proofSigChallenge = serializedPayload.read(32); + //const proofSigResponse = serializedPayload.read(32); + + result.aggregationVerifyKey = serializedPayload.read(96).toString('hex'); + + result.proofAggregation = serializedPayload.read(64).toString('hex'); + } + + if (hasMetadataUrl) { + const urlLength = serializedPayload.read(2).readUInt16BE(0); + + const url = serializedPayload.read(urlLength); + result.metadataUrl = url; + } + + if (hasTransactionFeeCommission) { + result.transactionFeeCommission = serializedPayload.read(4).readUInt32BE(0); + } + + if (hasBakingRewardCommission) { + result.bakingRewardCommission = serializedPayload.read(4).readUInt32BE(0); + } + + if (hasFinalizationRewardCommission) { + result.finalizationCommission = serializedPayload.read(4).readUInt32BE(0); + } + + if (hasSuspended) { + result.suspended = serializedPayload.read(1).readUInt8(0); + } + + return result; } toJSON(payload: ConfigureBakerPayload): ConfigureBakerPayloadJSON { diff --git a/packages/sdk/src/transactions/Payload.ts b/packages/sdk/src/transactions/Payload.ts index c3d118dd4..a0936d6f2 100644 --- a/packages/sdk/src/transactions/Payload.ts +++ b/packages/sdk/src/transactions/Payload.ts @@ -612,7 +612,7 @@ export function deserialize(value: Cursor | ArrayBuffer): Payload { payload = configureDelegation(getAccountTransactionHandler(type).deserialize()); break; case AccountTransactionType.ConfigureBaker: - payload = configureValidator(getAccountTransactionHandler(type).deserialize()); + payload = configureValidator(getAccountTransactionHandler(type).deserialize(cursor)); break; case AccountTransactionType.TokenUpdate: payload = tokenUpdate(getAccountTransactionHandler(type).deserialize(cursor)); From f92ef9e1787790c5ffa8ef7dd0141b5b766a58ca Mon Sep 17 00:00:00 2001 From: Richard B Date: Mon, 1 Dec 2025 09:11:38 +0000 Subject: [PATCH 2/7] removed unused variable --- packages/sdk/src/accountTransactions.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/sdk/src/accountTransactions.ts b/packages/sdk/src/accountTransactions.ts index f2c9ed17a..b7c517981 100644 --- a/packages/sdk/src/accountTransactions.ts +++ b/packages/sdk/src/accountTransactions.ts @@ -712,7 +712,6 @@ export class ConfigureBakerHandler result.restakeEarnings = restakeEarnings; const openForDelegation = hasOpenForDelegation ? serializedPayload.read(1).readUInt8(0) : undefined; - let currentOpenStatus; if (openForDelegation !== undefined) { result.openForDelegation = OpenStatus[openForDelegation]; } From 7c3a03c8bef050d099ab94ca6b809f46cdd74294 Mon Sep 17 00:00:00 2001 From: Richard B Date: Mon, 1 Dec 2025 15:10:54 +0000 Subject: [PATCH 3/7] added a test and fixed some incorrect results --- packages/sdk/CHANGELOG.md | 1 + packages/sdk/src/accountTransactions.ts | 40 ++++++++---------- packages/sdk/test/ci/deserialization.test.ts | 43 ++++++++++++++++++++ 3 files changed, 62 insertions(+), 22 deletions(-) diff --git a/packages/sdk/CHANGELOG.md b/packages/sdk/CHANGELOG.md index c5a9888b1..24127a4e5 100644 --- a/packages/sdk/CHANGELOG.md +++ b/packages/sdk/CHANGELOG.md @@ -5,6 +5,7 @@ ### Added - `UpdateCredentialKeysPayload` and corresponding deserialize and serialize functions implemented +- `ConfigureBakerPayload` deserialization supported ## 12.0.0-alpha.3 diff --git a/packages/sdk/src/accountTransactions.ts b/packages/sdk/src/accountTransactions.ts index b7c517981..a9456d682 100644 --- a/packages/sdk/src/accountTransactions.ts +++ b/packages/sdk/src/accountTransactions.ts @@ -659,11 +659,10 @@ export interface ConfigureBakerPayloadJSON { export class ConfigureBakerHandler implements AccountTransactionHandler { - //TODO: need to figure out what to do with the versions and hasSuspended - //for now assume version 8 only onwards - ALLOWED_BITS = 0x100; + //support version 8 only onwards + ALLOWED_BITS = 0x1ff; VALIDATION_MASK = 0xffff - this.ALLOWED_BITS; - HAS_SUSPENDED = 0x0200; + HAS_SUSPENDED = 0x0100; HAS_FINALIZATION_REWARD_COMMISSION = 0x0080; HAS_BAKING_REWARD_COMMISSION = 0x0040; HAS_TRANSACTION_FEE_COMMISSION = 0x0020; @@ -701,46 +700,43 @@ export class ConfigureBakerHandler const hasFinalizationRewardCommission = (serializedBitmap & this.HAS_FINALIZATION_REWARD_COMMISSION) !== 0; const hasSuspended = (serializedBitmap & this.HAS_SUSPENDED) !== 0; - const result: any = {}; + const result: ConfigureBakerPayload = {}; const capital = hasCapital ? CcdAmount.fromMicroCcd(serializedPayload.read(8).readBigUInt64BE(0)) : CcdAmount.zero(); - result.capital = capital; + result.stake = capital; const restakeEarnings = hasRestakeEarnings ? serializedPayload.read(1).readUInt8(0) !== 0 : false; result.restakeEarnings = restakeEarnings; const openForDelegation = hasOpenForDelegation ? serializedPayload.read(1).readUInt8(0) : undefined; if (openForDelegation !== undefined) { - result.openForDelegation = OpenStatus[openForDelegation]; + result.openForDelegation = openForDelegation; } if (hasKeysWithProof) { - result.electionVerifyKey = serializedPayload.read(32).toString('hex'); + if (!result.keys) { + result.keys = {} as BakerKeysWithProofs; + } + result.keys.electionVerifyKey = serializedPayload.read(32).toString('hex'); - result.proofElection = serializedPayload.read(64).toString('hex'); - //TODO: bluepaper has these two below, i am combining for the above - //result.proofElection.challenge = serializedPayload.read(32).toString('hex'); - //result.proofElection.response = serializedPayload.read(32).toString('hex'); + result.keys.proofElection = serializedPayload.read(64).toString('hex'); - result.signatureVerifyKey.key = serializedPayload.read(32).toString('hex'); + result.keys.signatureVerifyKey = serializedPayload.read(32).toString('hex'); - result.proofSig = serializedPayload.read(64).toString('hex'); - //TODO: bluepaper has these two below, i am combining for the above - //const proofSigChallenge = serializedPayload.read(32); - //const proofSigResponse = serializedPayload.read(32); + result.keys.proofSig = serializedPayload.read(64).toString('hex'); - result.aggregationVerifyKey = serializedPayload.read(96).toString('hex'); + result.keys.aggregationVerifyKey = serializedPayload.read(96).toString('hex'); - result.proofAggregation = serializedPayload.read(64).toString('hex'); + result.keys.proofAggregation = serializedPayload.read(64).toString('hex'); } if (hasMetadataUrl) { const urlLength = serializedPayload.read(2).readUInt16BE(0); const url = serializedPayload.read(urlLength); - result.metadataUrl = url; + result.metadataUrl = url.toString(); } if (hasTransactionFeeCommission) { @@ -752,11 +748,11 @@ export class ConfigureBakerHandler } if (hasFinalizationRewardCommission) { - result.finalizationCommission = serializedPayload.read(4).readUInt32BE(0); + result.finalizationRewardCommission = serializedPayload.read(4).readUInt32BE(0); } if (hasSuspended) { - result.suspended = serializedPayload.read(1).readUInt8(0); + result.suspended = serializedPayload.read(1).readUInt8(0) !== 0; } return result; diff --git a/packages/sdk/test/ci/deserialization.test.ts b/packages/sdk/test/ci/deserialization.test.ts index 6ae8b490a..24e66fceb 100644 --- a/packages/sdk/test/ci/deserialization.test.ts +++ b/packages/sdk/test/ci/deserialization.test.ts @@ -13,6 +13,7 @@ import { CIS2, Cbor, CcdAmount, + ConfigureBakerPayload, ContractAddress, ContractName, CredentialPublicKeys, @@ -23,6 +24,7 @@ import { IndexedCredentialDeploymentInfo, InitContractInput, ModuleReference, + OpenStatus, Parameter, ReceiveName, RegisterDataPayload, @@ -317,3 +319,44 @@ test('test deserialize UpdateCredentialKeys', () => { }; deserializeAccountTransactionBase(transaction); }); + +test('test deserialize ConfigureBaker', () => { + const payload: ConfigureBakerPayload = { + stake: CcdAmount.fromMicroCcd(1000), + + restakeEarnings: true, + + openForDelegation: OpenStatus.OpenForAll, + + keys: { + electionVerifyKey: 'aa'.repeat(32), + + proofElection: 'bb'.repeat(64), + + signatureVerifyKey: 'cc'.repeat(32), + + proofSig: 'dd'.repeat(64), + + aggregationVerifyKey: 'ee'.repeat(96), + + proofAggregation: 'ff'.repeat(64), + }, + + metadataUrl: 'g'.repeat(16), + + transactionFeeCommission: 10, + + bakingRewardCommission: 5, + + finalizationRewardCommission: 2, + + suspended: true, + }; + + const transaction: AccountTransaction = { + header, + type: AccountTransactionType.ConfigureBaker, + payload, + }; + deserializeAccountTransactionBase(transaction); +}); From 0d2f748d6c5032e5d9fa6a090764d5fd2808a1bb Mon Sep 17 00:00:00 2001 From: Richard B Date: Mon, 1 Dec 2025 15:16:56 +0000 Subject: [PATCH 4/7] fixed the formatting --- packages/sdk/src/accountTransactions.ts | 31 +++++++++++++++++-------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/packages/sdk/src/accountTransactions.ts b/packages/sdk/src/accountTransactions.ts index a9456d682..84c7c79e7 100644 --- a/packages/sdk/src/accountTransactions.ts +++ b/packages/sdk/src/accountTransactions.ts @@ -660,17 +660,28 @@ export class ConfigureBakerHandler implements AccountTransactionHandler { //support version 8 only onwards - ALLOWED_BITS = 0x1ff; + HAS_CAPITAL = 1 << 0; // bit 0 + HAS_RESTAKE_EARNINGS = 1 << 1; // bit 1 + HAS_OPEN_FOR_DELEGATION = 1 << 2; // bit 2 + HAS_KEYS_WITH_PROOF = 1 << 3; // bit 3 + HAS_METADATA_URL = 1 << 4; // bit 4 + HAS_TRANSACTION_FEE_COMMISSION = 1 << 5; // bit 5 + HAS_BAKING_REWARD_COMMISSION = 1 << 6; // bit 6 + HAS_FINALIZATION_REWARD_COMMISSION = 1 << 7; // bit 7 + HAS_SUSPENDED = 1 << 8; // bit 8 + + ALLOWED_BITS = + this.HAS_CAPITAL | + this.HAS_RESTAKE_EARNINGS | + this.HAS_OPEN_FOR_DELEGATION | + this.HAS_KEYS_WITH_PROOF | + this.HAS_METADATA_URL | + this.HAS_TRANSACTION_FEE_COMMISSION | + this.HAS_BAKING_REWARD_COMMISSION | + this.HAS_FINALIZATION_REWARD_COMMISSION | + this.HAS_SUSPENDED; + VALIDATION_MASK = 0xffff - this.ALLOWED_BITS; - HAS_SUSPENDED = 0x0100; - HAS_FINALIZATION_REWARD_COMMISSION = 0x0080; - HAS_BAKING_REWARD_COMMISSION = 0x0040; - HAS_TRANSACTION_FEE_COMMISSION = 0x0020; - HAS_METADATA_URL = 0x0010; - HAS_KEYS_WITH_PROOF = 0x0008; - HAS_OPEN_FOR_DELEGATION = 0x004; - HAS_RESTAKE_EARNINGS = 0x0002; - HAS_CAPITAL = 0x0001; getBaseEnergyCost(payload: ConfigureBakerPayload): bigint { if (payload.keys) { From 364b751a8e1c7623fccc88752ad7e3e675062b3a Mon Sep 17 00:00:00 2001 From: Richard B Date: Mon, 1 Dec 2025 16:15:27 +0000 Subject: [PATCH 5/7] increased package size limit by 0.5 kB --- packages/sdk/.size-limit.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sdk/.size-limit.ts b/packages/sdk/.size-limit.ts index 62c54610a..7206d9e7a 100644 --- a/packages/sdk/.size-limit.ts +++ b/packages/sdk/.size-limit.ts @@ -4,7 +4,7 @@ module.exports = [ { name: 'GRPC web client tree shaking', path: 'lib/esm/index.js', - limit: '59 KB', + limit: '59.5 KB', import: '{ ConcordiumGRPCWebClient }', }, ] satisfies SizeLimitConfig; From e3ea62bedf328a2a59737e89af7d9cfd15ed7b2e Mon Sep 17 00:00:00 2001 From: Richard B Date: Mon, 1 Dec 2025 16:18:04 +0000 Subject: [PATCH 6/7] fixed syntax issue due to resolve conflict step --- packages/sdk/test/ci/deserialization.test.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/sdk/test/ci/deserialization.test.ts b/packages/sdk/test/ci/deserialization.test.ts index 1cddb155a..bbaa8e383 100644 --- a/packages/sdk/test/ci/deserialization.test.ts +++ b/packages/sdk/test/ci/deserialization.test.ts @@ -353,6 +353,15 @@ test('test deserialize ConfigureBaker', () => { finalizationRewardCommission: 2, suspended: true, + }; + const transaction: AccountTransaction = { + header, + type: AccountTransactionType.ConfigureBaker, + payload, + }; + deserializeAccountTransactionBase(transaction); +}); + test('test deserialize ConfigureDelegation', () => { const payload: ConfigureDelegationPayload = { stake: CcdAmount.fromMicroCcd(0), @@ -400,7 +409,6 @@ test('test deserialize ConfigureDelegation with no delegation', () => { const transaction: AccountTransaction = { header, - type: AccountTransactionType.ConfigureBaker, type: AccountTransactionType.ConfigureDelegation, payload, }; From ee9c8831f6f979fedd357b8ed8f0b950e0dc4db9 Mon Sep 17 00:00:00 2001 From: Richard B Date: Tue, 2 Dec 2025 08:52:46 +0000 Subject: [PATCH 7/7] tidy up --- packages/sdk/test/ci/deserialization.test.ts | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/packages/sdk/test/ci/deserialization.test.ts b/packages/sdk/test/ci/deserialization.test.ts index bbaa8e383..7b0f6de4a 100644 --- a/packages/sdk/test/ci/deserialization.test.ts +++ b/packages/sdk/test/ci/deserialization.test.ts @@ -325,33 +325,22 @@ test('test deserialize UpdateCredentialKeys', () => { test('test deserialize ConfigureBaker', () => { const payload: ConfigureBakerPayload = { stake: CcdAmount.fromMicroCcd(1000), - restakeEarnings: true, - openForDelegation: OpenStatus.OpenForAll, keys: { electionVerifyKey: 'aa'.repeat(32), - proofElection: 'bb'.repeat(64), - signatureVerifyKey: 'cc'.repeat(32), - proofSig: 'dd'.repeat(64), - aggregationVerifyKey: 'ee'.repeat(96), - proofAggregation: 'ff'.repeat(64), }, metadataUrl: 'g'.repeat(16), - transactionFeeCommission: 10, - bakingRewardCommission: 5, - finalizationRewardCommission: 2, - suspended: true, }; const transaction: AccountTransaction = {