Skip to content

Commit 591ea29

Browse files
Merge pull request #1072 from input-output-hk/chore/cherry-pick-conway-era-client-changes
Chore/cherry pick conway era client changes
2 parents 94bdbd0 + 3a59317 commit 591ea29

File tree

15 files changed

+531
-296
lines changed

15 files changed

+531
-296
lines changed

packages/core/src/Cardano/types/Certificate.ts

+49
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,46 @@ export type Certificate =
175175
| UnRegisterDelegateRepresentativeCertificate
176176
| UpdateDelegateRepresentativeCertificate;
177177

178+
export const StakeRegistrationCertificateTypes = [
179+
CertificateType.StakeRegistration,
180+
CertificateType.Registration,
181+
CertificateType.VoteRegistrationDelegation,
182+
CertificateType.StakeRegistrationDelegation,
183+
CertificateType.StakeVoteRegistrationDelegation
184+
] as const;
185+
186+
export type StakeRegistrationCertificateTypes = typeof StakeRegistrationCertificateTypes[number];
187+
188+
export type StakeDelegationCertificateUnion =
189+
| StakeDelegationCertificate
190+
| StakeVoteDelegationCertificate
191+
| StakeRegistrationDelegationCertificate
192+
| StakeVoteRegistrationDelegationCertificate;
193+
194+
export const StakeDelegationCertificateTypes = [
195+
CertificateType.StakeDelegation,
196+
CertificateType.StakeVoteDelegation,
197+
CertificateType.StakeRegistrationDelegation,
198+
CertificateType.StakeVoteRegistrationDelegation
199+
] as const;
200+
201+
export type StakeDelegationCertificateTypes = typeof StakeDelegationCertificateTypes[number];
202+
203+
export type RegAndDeregCertificateUnion =
204+
| StakeAddressCertificate
205+
| NewStakeAddressCertificate
206+
| VoteRegistrationDelegationCertificate
207+
| StakeRegistrationDelegationCertificate
208+
| StakeVoteRegistrationDelegationCertificate;
209+
210+
export const RegAndDeregCertificateTypes = [
211+
...StakeRegistrationCertificateTypes,
212+
CertificateType.Unregistration,
213+
CertificateType.StakeDeregistration
214+
] as const;
215+
216+
export type RegAndDeregCertificateTypes = typeof RegAndDeregCertificateTypes[number];
217+
178218
/**
179219
* Creates a stake key registration certificate from a given reward account.
180220
*
@@ -215,3 +255,12 @@ export const createDelegationCert = (rewardAccount: RewardAccount, poolId: PoolI
215255
type: CredentialType.KeyHash
216256
}
217257
});
258+
259+
/** Filters certificates, returning only stake key register/deregister certificates */
260+
export const stakeKeyCertificates = (certificates?: Certificate[]) =>
261+
certificates?.filter((certificate): certificate is RegAndDeregCertificateUnion =>
262+
RegAndDeregCertificateTypes.includes(certificate.__typename as RegAndDeregCertificateTypes)
263+
) || [];
264+
265+
export const includesAnyCertificate = (haystack: Certificate[], needle: readonly CertificateType[]) =>
266+
haystack.some(({ __typename }) => needle.includes(__typename)) || false;

packages/core/src/util/txInspector.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ export const totalAddressOutputsValueInspector: SendReceiveValueInspector = (own
163163
export const getCertificatesByType = (
164164
tx: Tx,
165165
rewardAccounts: RewardAccount[],
166-
certificateTypes?: CertificateType[]
166+
certificateTypes?: readonly CertificateType[]
167167
) => {
168168
if (!tx.body.certificates || tx.body.certificates.length === 0) return [];
169169
const certificates = certificateTypes

packages/core/test/Cardano/types/Certificates.test.ts

+19-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import {
66
RewardAccount,
77
createDelegationCert,
88
createStakeDeregistrationCert,
9-
createStakeRegistrationCert
9+
createStakeRegistrationCert,
10+
stakeKeyCertificates
1011
} from '../../../src/Cardano';
1112

1213
const rewardAccount = RewardAccount('stake1u89sasnfyjtmgk8ydqfv3fdl52f36x3djedfnzfc9rkgzrcss5vgr');
@@ -47,4 +48,21 @@ describe('Certificate', () => {
4748
});
4849
});
4950
});
51+
52+
it('can identify stake key certificates', () => {
53+
const certificates = stakeKeyCertificates([
54+
{ __typename: Cardano.CertificateType.StakeDelegation } as Cardano.Certificate, // does not register stake key
55+
{ __typename: Cardano.CertificateType.StakeRegistration } as Cardano.Certificate,
56+
{ __typename: Cardano.CertificateType.StakeDeregistration } as Cardano.Certificate,
57+
{ __typename: Cardano.CertificateType.StakeVoteDelegation } as Cardano.Certificate, // does not register stake key
58+
{ __typename: Cardano.CertificateType.StakeRegistrationDelegation } as Cardano.Certificate,
59+
{ __typename: Cardano.CertificateType.StakeVoteDelegation } as Cardano.Certificate, // does not register stake key
60+
{ __typename: Cardano.CertificateType.StakeVoteRegistrationDelegation } as Cardano.Certificate,
61+
{ __typename: Cardano.CertificateType.VoteRegistrationDelegation } as Cardano.Certificate,
62+
{ __typename: Cardano.CertificateType.Registration } as Cardano.Certificate
63+
]);
64+
expect(certificates).toHaveLength(6);
65+
expect(certificates[0].__typename).toBe(Cardano.CertificateType.StakeRegistration);
66+
expect(certificates[1].__typename).toBe(Cardano.CertificateType.StakeDeregistration);
67+
});
5068
});

packages/projection/src/operators/Mappers/certificates/withStakeKeyRegistrations.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,15 @@ export const withStakeKeyRegistrations = unifiedProjectorOperator<WithCertificat
1919
...evt,
2020
stakeKeyRegistrations: evt.certificates
2121
.map(({ pointer, certificate }): StakeKeyRegistration | null => {
22-
if (certificate.__typename === Cardano.CertificateType.StakeRegistration) {
22+
if (
23+
Cardano.StakeRegistrationCertificateTypes.includes(
24+
certificate.__typename as Cardano.StakeRegistrationCertificateTypes
25+
)
26+
) {
2327
return {
2428
pointer,
25-
stakeKeyHash: certificate.stakeCredential.hash as unknown as Ed25519KeyHashHex
29+
stakeKeyHash: (certificate as Cardano.RegAndDeregCertificateUnion).stakeCredential
30+
.hash as unknown as Ed25519KeyHashHex
2631
};
2732
}
2833
return null;

packages/projection/src/operators/Mappers/certificates/withStakeKeys.ts

+24-15
Original file line numberDiff line numberDiff line change
@@ -20,25 +20,34 @@ export interface WithStakeKeys {
2020
* The intended use case of this operator is to keep track of the current set of active stake keys,
2121
* ignoring **when** they were registered or unregistered.
2222
*/
23+
// eslint-disable-next-line sonarjs/cognitive-complexity
2324
export const withStakeKeys = unifiedProjectorOperator<WithCertificates, WithStakeKeys>((evt) => {
2425
const register = new Set<Crypto.Hash28ByteBase16>();
2526
const deregister = new Set<Crypto.Hash28ByteBase16>();
2627
for (const { certificate } of evt.certificates) {
27-
switch (certificate.__typename) {
28-
case Cardano.CertificateType.StakeRegistration:
29-
if (deregister.has(certificate.stakeCredential.hash)) {
30-
deregister.delete(certificate.stakeCredential.hash);
31-
} else {
32-
register.add(certificate.stakeCredential.hash);
33-
}
34-
break;
35-
case Cardano.CertificateType.StakeDeregistration:
36-
if (register.has(certificate.stakeCredential.hash)) {
37-
register.delete(certificate.stakeCredential.hash);
38-
} else {
39-
deregister.add(certificate.stakeCredential.hash);
40-
}
41-
break;
28+
if (Cardano.RegAndDeregCertificateTypes.includes(certificate.__typename as Cardano.RegAndDeregCertificateTypes)) {
29+
const {
30+
stakeCredential: { hash: stakeCredentialHash }
31+
} = certificate as Cardano.RegAndDeregCertificateUnion;
32+
33+
switch (certificate.__typename) {
34+
case Cardano.CertificateType.StakeDeregistration:
35+
case Cardano.CertificateType.Unregistration:
36+
if (register.has(certificate.stakeCredential.hash)) {
37+
register.delete(certificate.stakeCredential.hash);
38+
} else {
39+
deregister.add(certificate.stakeCredential.hash);
40+
}
41+
break;
42+
default:
43+
// Stake registration
44+
if (deregister.has(stakeCredentialHash)) {
45+
deregister.delete(stakeCredentialHash);
46+
} else {
47+
register.add(stakeCredentialHash);
48+
}
49+
break;
50+
}
4251
}
4352
}
4453
const [insert, del] =

packages/projection/test/operators/Mappers/certificates/withStakeKeyRegistrations.test.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { firstValueFrom, of } from 'rxjs';
66
type EventData = Mappers.WithCertificates & { eventType: ChainSyncEventType };
77

88
describe('withStakeKeyRegistrations', () => {
9-
it('collects all key registration certificates', async () => {
9+
it.each(Cardano.StakeRegistrationCertificateTypes)('collects %s registration certificates', async (regCertType) => {
1010
const pointer: Cardano.Pointer = {
1111
certIndex: Cardano.CertIndex(1),
1212
slot: Cardano.Slot(123),
@@ -16,12 +16,12 @@ describe('withStakeKeyRegistrations', () => {
1616
certificates: [
1717
{
1818
certificate: {
19-
__typename: Cardano.CertificateType.StakeRegistration,
19+
__typename: regCertType,
2020
stakeCredential: {
2121
hash: Crypto.Hash28ByteBase16('3b62970858d61cf667701c1f34abef41659516b191d7d374e8b0857b'),
2222
type: Cardano.CredentialType.KeyHash
2323
}
24-
},
24+
} as Cardano.Certificate,
2525
pointer
2626
},
2727
{

packages/projection/test/operators/Mappers/certificates/withStakeKeys.test.ts

+34-31
Original file line numberDiff line numberDiff line change
@@ -7,39 +7,42 @@ type EventData = Mappers.WithCertificates & { eventType: ChainSyncEventType };
77

88
describe('withStakeKeys', () => {
99
describe('1 certificate per stake key', () => {
10-
it('collects all key registration and deregistration certificates', async () => {
11-
const data: EventData = {
12-
certificates: [
13-
{
14-
certificate: {
15-
__typename: Cardano.CertificateType.StakeRegistration,
16-
stakeCredential: {
17-
hash: Crypto.Hash28ByteBase16('3b62970858d61cf667701c1f34abef41659516b191d7d374e8b0857b'),
18-
type: Cardano.CredentialType.KeyHash
19-
}
20-
},
21-
pointer: {} as Cardano.Pointer
22-
},
23-
{
24-
certificate: {
25-
__typename: Cardano.CertificateType.StakeDeregistration,
26-
stakeCredential: {
27-
hash: Crypto.Hash28ByteBase16('3b62970858d61cf667701c1f34abef41659516b191d7d374e8b0857c'),
28-
type: Cardano.CredentialType.KeyHash
29-
}
10+
it.each(Cardano.StakeRegistrationCertificateTypes)(
11+
'collects all key registration [%s] and deregistration certificates',
12+
async (regCertType) => {
13+
const data: EventData = {
14+
certificates: [
15+
{
16+
certificate: {
17+
__typename: regCertType,
18+
stakeCredential: {
19+
hash: Crypto.Hash28ByteBase16('3b62970858d61cf667701c1f34abef41659516b191d7d374e8b0857b'),
20+
type: Cardano.CredentialType.KeyHash
21+
}
22+
} as Cardano.Certificate,
23+
pointer: {} as Cardano.Pointer
3024
},
31-
pointer: {} as Cardano.Pointer
32-
}
33-
],
34-
eventType: ChainSyncEventType.RollForward
35-
};
25+
{
26+
certificate: {
27+
__typename: Cardano.CertificateType.StakeDeregistration,
28+
stakeCredential: {
29+
hash: Crypto.Hash28ByteBase16('3b62970858d61cf667701c1f34abef41659516b191d7d374e8b0857c'),
30+
type: Cardano.CredentialType.KeyHash
31+
}
32+
},
33+
pointer: {} as Cardano.Pointer
34+
}
35+
],
36+
eventType: ChainSyncEventType.RollForward
37+
};
3638

37-
const result = await firstValueFrom(
38-
Mappers.withStakeKeys()(of(data as UnifiedExtChainSyncEvent<Mappers.WithCertificates & WithBlock>))
39-
);
40-
expect(result.stakeKeys.insert).toEqual(['3b62970858d61cf667701c1f34abef41659516b191d7d374e8b0857b']);
41-
expect(result.stakeKeys.del).toEqual(['3b62970858d61cf667701c1f34abef41659516b191d7d374e8b0857c']);
42-
});
39+
const result = await firstValueFrom(
40+
Mappers.withStakeKeys()(of(data as UnifiedExtChainSyncEvent<Mappers.WithCertificates & WithBlock>))
41+
);
42+
expect(result.stakeKeys.insert).toEqual(['3b62970858d61cf667701c1f34abef41659516b191d7d374e8b0857b']);
43+
expect(result.stakeKeys.del).toEqual(['3b62970858d61cf667701c1f34abef41659516b191d7d374e8b0857c']);
44+
}
45+
);
4346

4447
it('reverses the logic on RollBackward', async () => {
4548
const data: EventData = {

packages/wallet/src/services/DelegationTracker/DelegationTracker.ts

+8-24
Original file line numberDiff line numberDiff line change
@@ -71,25 +71,13 @@ export const certificateTransactionsWithEpochs = (
7171
)
7272
);
7373

74-
const hasDelegationCert = (certificates: Array<Cardano.Certificate> | undefined): boolean => {
75-
if (!certificates || certificates.length === 0) return false;
76-
77-
return certificates.some((cert) => {
78-
let hasCert = false;
79-
80-
switch (cert.__typename) {
81-
case Cardano.CertificateType.StakeDelegation:
82-
case Cardano.CertificateType.StakeRegistration:
83-
case Cardano.CertificateType.StakeDeregistration:
84-
hasCert = true;
85-
break;
86-
default:
87-
hasCert = false;
88-
}
89-
90-
return hasCert;
91-
});
92-
};
74+
const hasDelegationCert = (certificates: Array<Cardano.Certificate> | undefined): boolean =>
75+
!!certificates &&
76+
certificates.some((cert) =>
77+
[...Cardano.RegAndDeregCertificateTypes, ...Cardano.StakeDelegationCertificateTypes].includes(
78+
cert.__typename as Cardano.RegAndDeregCertificateTypes | Cardano.StakeDelegationCertificateTypes
79+
)
80+
);
9381

9482
export const createDelegationPortfolioTracker = (transactions: Observable<Cardano.HydratedTx[]>) =>
9583
transactions.pipe(
@@ -153,11 +141,7 @@ export const createDelegationTracker = ({
153141
transactionsTracker,
154142
rewardAccountAddresses$,
155143
slotEpochCalc$,
156-
[
157-
Cardano.CertificateType.StakeDelegation,
158-
Cardano.CertificateType.StakeRegistration,
159-
Cardano.CertificateType.StakeDeregistration
160-
]
144+
[...Cardano.RegAndDeregCertificateTypes, ...Cardano.StakeDelegationCertificateTypes]
161145
).pipe(tap((transactionsWithEpochs) => logger.debug(`Found ${transactionsWithEpochs.length} staking transactions`)));
162146

163147
const rewardsHistory$ = new TrackerSubject(

0 commit comments

Comments
 (0)