Skip to content

Commit 0c27328

Browse files
Merge pull request #1602 from input-output-hk/fix/LW-12198-incorrect-withdrawal-calculation
fix(core): withdrawal calculation in computeImplicitCoin [LW-12198]
2 parents a78683f + 46771ce commit 0c27328

File tree

2 files changed

+42
-5
lines changed

2 files changed

+42
-5
lines changed

packages/core/src/Cardano/util/computeImplicitCoin.ts

+9-2
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,11 @@ const getTxDeposits = (
146146
};
147147
};
148148

149+
const getOwnWithdrawalsTotal = (withdrawals: Cardano.Withdrawal[], rewardAccounts: Address.RewardAccount[]) =>
150+
BigIntMath.sum(
151+
withdrawals.filter(({ stakeAddress }) => rewardAccounts.includes(stakeAddress)).map(({ quantity }) => quantity)
152+
);
153+
149154
/**
150155
* Computes the implicit coin from the given transaction.
151156
* If rewardAccounts is provided, it will only count the deposits from
@@ -166,7 +171,7 @@ export const computeImplicitCoin = (
166171
{
167172
certificates,
168173
proposalProcedures,
169-
withdrawals
174+
withdrawals = []
170175
}: Pick<Cardano.HydratedTxBody, 'certificates' | 'proposalProcedures' | 'withdrawals'>,
171176
rewardAccounts?: Address.RewardAccount[],
172177
dRepKeyHash?: Crypto.Ed25519KeyHashHex
@@ -179,7 +184,9 @@ export const computeImplicitCoin = (
179184
proposalProcedures
180185
);
181186

182-
const withdrawalsTotal = (withdrawals && BigIntMath.sum(withdrawals.map(({ quantity }) => quantity))) || 0n;
187+
const hasRewardAccount = !!rewardAccounts?.length;
188+
const allWithdrawalsTotal = BigIntMath.sum(withdrawals.map(({ quantity }) => quantity));
189+
const withdrawalsTotal = hasRewardAccount ? getOwnWithdrawalsTotal(withdrawals, rewardAccounts) : allWithdrawalsTotal;
183190

184191
return {
185192
deposit,

packages/core/test/Cardano/util/computeImplicitCoin.test.ts

+33-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as Crypto from '@cardano-sdk/crypto';
22
import { Cardano } from '../../../src';
3+
import { Ed25519KeyHashHex } from '@cardano-sdk/crypto';
34

45
describe('Cardano.util.computeImplicitCoin', () => {
56
let rewardAccount: Cardano.RewardAccount;
@@ -61,18 +62,19 @@ describe('Cardano.util.computeImplicitCoin', () => {
6162

6263
it('sums registrations for deposit, withdrawals and deregistrations for input', () => {
6364
const protocolParameters = { dRepDeposit: 5, poolDeposit: 3, stakeKeyDeposit: 2 } as Cardano.ProtocolParameters;
65+
const poolId = Cardano.PoolId.fromKeyHash(Ed25519KeyHashHex(Cardano.RewardAccount.toHash(rewardAccount)));
6466
const certificates: Cardano.Certificate[] = [
6567
{ __typename: Cardano.CertificateType.StakeRegistration, stakeCredential },
6668
{ __typename: Cardano.CertificateType.StakeDeregistration, stakeCredential },
6769
{ __typename: Cardano.CertificateType.StakeRegistration, stakeCredential },
6870
{
6971
__typename: Cardano.CertificateType.PoolRetirement,
7072
epoch: Cardano.EpochNo(500),
71-
poolId: Cardano.PoolId('pool1zuevzm3xlrhmwjw87ec38mzs02tlkwec9wxpgafcaykmwg7efhh')
73+
poolId
7274
},
7375
{
7476
__typename: Cardano.CertificateType.StakeDelegation,
75-
poolId: Cardano.PoolId('pool1zuevzm3xlrhmwjw87ec38mzs02tlkwec9wxpgafcaykmwg7efhh'),
77+
poolId,
7678
stakeCredential
7779
},
7880
{
@@ -88,7 +90,7 @@ describe('Cardano.util.computeImplicitCoin', () => {
8890
}
8991
];
9092
const withdrawals: Cardano.Withdrawal[] = [{ quantity: 5n, stakeAddress: rewardAccount }];
91-
const coin = Cardano.util.computeImplicitCoin(protocolParameters, { certificates, withdrawals });
93+
const coin = Cardano.util.computeImplicitCoin(protocolParameters, { certificates, withdrawals }, [rewardAccount]);
9294
expect(coin.deposit).toBe(2n + 2n + 7n);
9395
expect(coin.input).toBe(2n + 3n + 5n + 7n);
9496
expect(coin.withdrawals).toBe(5n);
@@ -203,6 +205,34 @@ describe('Cardano.util.computeImplicitCoin', () => {
203205
expect(coin.withdrawals).toBe(withdrawals[0].quantity);
204206
});
205207

208+
it('sums withdrawals for input for own reward accounts', () => {
209+
const protocolParameters = { dRepDeposit: 5, poolDeposit: 3, stakeKeyDeposit: 2 } as Cardano.ProtocolParameters;
210+
const certificates: Cardano.Certificate[] = [];
211+
const foreignRewardAccount = Cardano.RewardAccount(
212+
'stake_test17rphkx6acpnf78fuvxn0mkew3l0fd058hzquvz7w36x4gtcljw6kf'
213+
);
214+
const withdrawals: Cardano.Withdrawal[] = [
215+
{ quantity: 15n, stakeAddress: foreignRewardAccount },
216+
{ quantity: 5n, stakeAddress: rewardAccount }
217+
];
218+
const coin = Cardano.util.computeImplicitCoin(protocolParameters, { certificates, withdrawals }, [rewardAccount]);
219+
expect(coin.withdrawals).toBe(5n);
220+
});
221+
222+
it('sums all withdrawals for input if there are no reward accounts provided', () => {
223+
const protocolParameters = { dRepDeposit: 5, poolDeposit: 3, stakeKeyDeposit: 2 } as Cardano.ProtocolParameters;
224+
const certificates: Cardano.Certificate[] = [];
225+
const foreignRewardAccount = Cardano.RewardAccount(
226+
'stake_test17rphkx6acpnf78fuvxn0mkew3l0fd058hzquvz7w36x4gtcljw6kf'
227+
);
228+
const withdrawals: Cardano.Withdrawal[] = [
229+
{ quantity: 15n, stakeAddress: foreignRewardAccount },
230+
{ quantity: 5n, stakeAddress: rewardAccount }
231+
];
232+
const coin = Cardano.util.computeImplicitCoin(protocolParameters, { certificates, withdrawals });
233+
expect(coin.withdrawals).toBe(20n);
234+
});
235+
206236
it('sums certificates and proposal procedures for deposit', () => {
207237
const protocolParameters = { governanceActionDeposit: 4, stakeKeyDeposit: 2 } as Cardano.ProtocolParameters;
208238
const governanceActionDeposit = BigInt(protocolParameters.governanceActionDeposit!);

0 commit comments

Comments
 (0)