From abf86e236b4b9c12078c9e31c0c9428168f5103c Mon Sep 17 00:00:00 2001 From: Evan Zheng Date: Thu, 29 Jun 2023 22:50:38 -0700 Subject: [PATCH] chore(sdk-coin-ada): parse detailed pledging information EA-656 --- modules/sdk-coin-ada/src/lib/transaction.ts | 96 +++++++++++++++++++ modules/sdk-coin-ada/test/unit/ada.ts | 1 + .../test/unit/stakingPledgeBuilder.ts | 37 +++++++ 3 files changed, 134 insertions(+) diff --git a/modules/sdk-coin-ada/src/lib/transaction.ts b/modules/sdk-coin-ada/src/lib/transaction.ts index b779ff4b57..df645a1dc3 100644 --- a/modules/sdk-coin-ada/src/lib/transaction.ts +++ b/modules/sdk-coin-ada/src/lib/transaction.ts @@ -41,6 +41,27 @@ export interface Withdrawal { stakeAddress: string; value: string; } + +export type StakeKeyRegistrationCert = Cert; + +export type StakeKeyDelegationCert = Cert; + +export interface StakePoolRegistrationCert extends Cert { + vrfKeyHash: string; + pledge: string; + cost: string; + marginNumerator: string; + marginDenominator: string; + rewardAccount: string; + poolOwners: string[]; +} + +export interface PledgeDetails { + stakeKeyRegsitration?: StakeKeyRegistrationCert; + stakeKeyDelegation?: StakeKeyDelegationCert; + stakePoolRegistration: StakePoolRegistrationCert; +} + /** * The transaction data returned from the toJson() function of a transaction */ @@ -52,11 +73,13 @@ export interface TxData { witnesses: Witness[]; certs: Cert[]; withdrawals: Withdrawal[]; + pledgeDetails?: PledgeDetails; } export class Transaction extends BaseTransaction { private _transaction: CardanoWasm.Transaction; private _fee: string; + private _pledgeDetails?: PledgeDetails; constructor(coinConfig: Readonly) { super(coinConfig); @@ -155,6 +178,8 @@ export class Transaction extends BaseTransaction { } } + result.pledgeDetails = this._pledgeDetails; + if (this._transaction.body().withdrawals()) { const withdrawals = this._transaction.body().withdrawals() as CardanoWasm.Withdrawals; const keys = withdrawals.keys(); @@ -233,6 +258,15 @@ export class Transaction extends BaseTransaction { if (certs.some((c) => c.as_pool_registration() !== undefined)) { this._type = TransactionType.StakingPledge; + const stakeKeyRegistration = certs.find((c) => c.as_stake_registration() !== undefined); + const stakeKeyDelegation = certs.find((c) => c.as_stake_delegation() !== undefined); + const stakePoolRegistration = certs.find((c) => c.as_pool_registration() !== undefined); + + this._pledgeDetails = { + stakeKeyRegsitration: this.loadStakeKeyRegistration(stakeKeyRegistration), + stakeKeyDelegation: this.loadStakeKeyDelegation(stakeKeyDelegation), + stakePoolRegistration: this.loadStakePoolRegistration(stakePoolRegistration!), + }; } else if (certs.some((c) => c.as_stake_registration() !== undefined)) { this._type = TransactionType.StakingActivate; } else if (certs.some((c) => c.as_stake_deregistration() !== undefined)) { @@ -258,6 +292,62 @@ export class Transaction extends BaseTransaction { } } + private loadStakeKeyRegistration( + certificate: CardanoWasm.Certificate | undefined + ): StakeKeyRegistrationCert | undefined { + if (certificate === undefined) { + return undefined; + } + const stakeRegistration = certificate.as_stake_registration(); + if (stakeRegistration !== undefined && stakeRegistration!.stake_credential().to_keyhash() !== undefined) { + return { + type: CertType.StakeKeyRegistration, + stakeCredentialHash: stakeRegistration!.stake_credential().to_keyhash()!.to_hex(), + }; + } else { + return undefined; + } + } + + private loadStakeKeyDelegation(certificate: CardanoWasm.Certificate | undefined): StakeKeyDelegationCert | undefined { + if (certificate === undefined) { + return undefined; + } + const stakeDelegation = certificate.as_stake_delegation(); + if (stakeDelegation !== undefined && stakeDelegation!.stake_credential().to_keyhash() !== undefined) { + return { + type: CertType.StakeKeyDelegation, + stakeCredentialHash: stakeDelegation!.stake_credential().to_keyhash()!.to_hex(), + poolKeyHash: stakeDelegation!.pool_keyhash().to_hex(), + }; + } else { + return undefined; + } + } + + private loadStakePoolRegistration(certificate: CardanoWasm.Certificate): StakePoolRegistrationCert { + const poolRegistration = certificate.as_pool_registration(); + const rewardAccount = poolRegistration!.pool_params().reward_account(); + const networkId = rewardAccount.to_address().network_id(); + const owners: string[] = []; + for (let i = 0; i < poolRegistration!.pool_params().pool_owners().len(); i++) { + const poolOwner = poolRegistration!.pool_params().pool_owners().get(i); + const ownerStakeKey = CardanoWasm.StakeCredential.from_keyhash(poolOwner); + owners.push(CardanoWasm.RewardAddress.new(networkId, ownerStakeKey).to_address().to_bech32()); + } + return { + type: CertType.StakePoolRegistration, + poolKeyHash: poolRegistration!.pool_params().operator().to_hex(), + vrfKeyHash: poolRegistration!.pool_params().vrf_keyhash().to_hex(), + pledge: poolRegistration!.pool_params().pledge().to_str(), + cost: poolRegistration!.pool_params().cost().to_str(), + marginNumerator: poolRegistration!.pool_params().margin().numerator().to_str(), + marginDenominator: poolRegistration!.pool_params().margin().denominator().to_str(), + rewardAccount: rewardAccount.to_address().to_bech32(), + poolOwners: owners, + }; + } + /** * Set the transaction type. * @@ -279,6 +369,7 @@ export class Transaction extends BaseTransaction { changeAmount: string; type: string; withdrawals: Withdrawal[]; + pledgeDetails?: PledgeDetails; } { const txJson = this.toJson(); const displayOrder = ['id', 'outputAmount', 'changeAmount', 'outputs', 'changeOutputs', 'fee', 'type']; @@ -307,9 +398,14 @@ export class Transaction extends BaseTransaction { type, certificates: txJson.certs, withdrawals: txJson.withdrawals, + pledgeDetails: this._pledgeDetails, }; } + getPledgeDetails(): PledgeDetails | undefined { + return this._pledgeDetails; + } + /** * Get transaction fee */ diff --git a/modules/sdk-coin-ada/test/unit/ada.ts b/modules/sdk-coin-ada/test/unit/ada.ts index 79bad616b6..d77e180ae9 100644 --- a/modules/sdk-coin-ada/test/unit/ada.ts +++ b/modules/sdk-coin-ada/test/unit/ada.ts @@ -69,6 +69,7 @@ describe('ADA', function () { type: 'Transfer', certificates: [], withdrawals: [], + pledgeDetails: undefined, }; before(function () { diff --git a/modules/sdk-coin-ada/test/unit/stakingPledgeBuilder.ts b/modules/sdk-coin-ada/test/unit/stakingPledgeBuilder.ts index 2e67852729..e604a13720 100644 --- a/modules/sdk-coin-ada/test/unit/stakingPledgeBuilder.ts +++ b/modules/sdk-coin-ada/test/unit/stakingPledgeBuilder.ts @@ -24,6 +24,21 @@ describe('ADA Staking Pledge Transaction Builder', async () => { txData.certs[0].poolKeyHash!.should.equal('10324dc34187735de46f6260d94620cdcc819f7ed1f93e3fc58d06a0'); txData.withdrawals.length.should.equal(0); txData.witnesses.length.should.equal(0); + should.exist(txData.pledgeDetails); + should.not.exist(txData.pledgeDetails!.stakeKeyRegsitration); + should.exist(txData.pledgeDetails!.stakeKeyDelegation); + should.exist(txData.pledgeDetails!.stakePoolRegistration); + should.equal( + txData.pledgeDetails!.stakeKeyDelegation!.poolKeyHash, + txData.pledgeDetails!.stakePoolRegistration!.poolKeyHash + ); + txData.pledgeDetails!.stakePoolRegistration!.pledge.should.equal('100000000'); + txData.pledgeDetails!.stakePoolRegistration!.cost.should.equal('500000000'); + txData.pledgeDetails!.stakePoolRegistration!.marginNumerator.should.equal('3'); + txData.pledgeDetails!.stakePoolRegistration!.marginDenominator.should.equal('20'); + txData.pledgeDetails!.stakePoolRegistration!.rewardAccount.should.equal( + txData.pledgeDetails!.stakePoolRegistration!.poolOwners[0] + ); const fee = tx.getFee; fee.should.equal('1000000'); @@ -50,6 +65,17 @@ describe('ADA Staking Pledge Transaction Builder', async () => { txData.certs[0].poolKeyHash!.should.equal('10324dc34187735de46f6260d94620cdcc819f7ed1f93e3fc58d06a0'); txData.withdrawals.length.should.equal(0); txData.witnesses.length.should.equal(0); + should.exist(txData.pledgeDetails); + should.not.exist(txData.pledgeDetails!.stakeKeyRegsitration); + should.not.exist(txData.pledgeDetails!.stakeKeyDelegation); + should.exist(txData.pledgeDetails!.stakePoolRegistration); + txData.pledgeDetails!.stakePoolRegistration!.pledge.should.equal('100000000'); + txData.pledgeDetails!.stakePoolRegistration!.cost.should.equal('500000000'); + txData.pledgeDetails!.stakePoolRegistration!.marginNumerator.should.equal('3'); + txData.pledgeDetails!.stakePoolRegistration!.marginDenominator.should.equal('20'); + txData.pledgeDetails!.stakePoolRegistration!.rewardAccount.should.equal( + txData.pledgeDetails!.stakePoolRegistration!.poolOwners[0] + ); const fee = tx.getFee; fee.should.equal('1000000'); @@ -70,6 +96,17 @@ describe('ADA Staking Pledge Transaction Builder', async () => { tx.signature.length.should.equal(1); const txData = tx.toJson(); txData.witnesses.length.should.equal(1); + should.exist(txData.pledgeDetails); + should.not.exist(txData.pledgeDetails!.stakeKeyRegsitration); + should.not.exist(txData.pledgeDetails!.stakeKeyDelegation); + should.exist(txData.pledgeDetails!.stakePoolRegistration); + txData.pledgeDetails!.stakePoolRegistration!.pledge.should.equal('100000000'); + txData.pledgeDetails!.stakePoolRegistration!.cost.should.equal('500000000'); + txData.pledgeDetails!.stakePoolRegistration!.marginNumerator.should.equal('3'); + txData.pledgeDetails!.stakePoolRegistration!.marginDenominator.should.equal('20'); + txData.pledgeDetails!.stakePoolRegistration!.rewardAccount.should.equal( + txData.pledgeDetails!.stakePoolRegistration!.poolOwners[0] + ); const rebuiltTx = new Transaction(coins.get('tada')); rebuiltTx.fromRawTransaction(tx.toBroadcastFormat());