Skip to content

Commit 96b20c4

Browse files
committed
feat(sdk-coin-ada): support vote delegation
support voting to DRep in Chang hardfork Ticket: SC-660
1 parent 13c9dd6 commit 96b20c4

File tree

4 files changed

+72
-2
lines changed

4 files changed

+72
-2
lines changed

modules/sdk-coin-ada/src/lib/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ export { StakingClaimRewardsBuilder } from './stakingClaimRewardsBuilder';
1010
export { StakingDeactivateBuilder } from './stakingDeactivateBuilder';
1111
export { StakingWithdrawBuilder } from './stakingWithdrawBuilder';
1212
export { StakingPledgeBuilder } from './stakingPledgeBuilder';
13+
export { StakingVoteDelegationBuilder } from './stakingVoteDelegationBuilder';
1314
export { Utils };
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { BaseKey, TransactionType } from '@bitgo/sdk-core';
2+
import { BaseCoin as CoinConfig } from '@bitgo/statics';
3+
import { TransactionBuilder } from './transactionBuilder';
4+
import { Transaction } from './transaction';
5+
import * as CardanoWasm from '@emurgo/cardano-serialization-lib-nodejs';
6+
import { bech32 } from 'bech32';
7+
8+
export class StakingVoteDelegationBuilder extends TransactionBuilder {
9+
constructor(_coinConfig: Readonly<CoinConfig>) {
10+
super(_coinConfig);
11+
this._type = TransactionType.StakingVote;
12+
}
13+
protected get transactionType(): TransactionType {
14+
return TransactionType.StakingVote;
15+
}
16+
/** @inheritdoc */
17+
initBuilder(tx: Transaction): void {
18+
super.initBuilder(tx);
19+
}
20+
/** @inheritdoc */
21+
protected async buildImplementation(): Promise<Transaction> {
22+
const tx = await super.buildImplementation();
23+
tx.setTransactionType(TransactionType.StakingVote);
24+
return tx;
25+
}
26+
/** @inheritdoc */
27+
protected fromImplementation(rawTransaction: string): Transaction {
28+
return super.fromImplementation(rawTransaction);
29+
}
30+
protected signImplementation(key: BaseKey): Transaction {
31+
return super.signImplementation(key);
32+
}
33+
34+
voteDelegationCredential(stakingPublicKey: string, dRepId: string): this {
35+
const stakeCredential = CardanoWasm.Credential.from_keyhash(
36+
CardanoWasm.PublicKey.from_bytes(Buffer.from(stakingPublicKey, 'hex')).hash()
37+
);
38+
const decoded = bech32.decode(dRepId);
39+
const decodedKeyHash = Buffer.from(bech32.fromWords(decoded.words)).toString('hex');
40+
const voteDelegationCert = CardanoWasm.Certificate.new_vote_delegation(
41+
CardanoWasm.VoteDelegation.new(
42+
stakeCredential,
43+
CardanoWasm.DRep.new_key_hash(CardanoWasm.Ed25519KeyHash.from_hex(decodedKeyHash))
44+
)
45+
);
46+
this._certs.push(voteDelegationCert);
47+
return this;
48+
}
49+
}

modules/sdk-coin-ada/src/lib/transaction.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,14 @@ enum CertType {
3636
StakeKeyDelegation,
3737
StakeKeyDeregistration,
3838
StakePoolRegistration,
39+
StakeVoteDelegation,
3940
}
4041

4142
export interface Cert {
4243
type: CertType;
4344
stakeCredentialHash?: string;
4445
poolKeyHash?: string;
46+
dRepId?: string;
4547
}
4648

4749
export interface Withdrawal {
@@ -183,6 +185,14 @@ export class Transaction extends BaseTransaction {
183185
poolKeyHash: Buffer.from(stakePoolRegistration.pool_params().operator().to_bytes()).toString('hex'),
184186
});
185187
}
188+
if (cert.as_vote_delegation() !== undefined) {
189+
const voteDelegation = cert.as_vote_delegation() as CardanoWasm.VoteDelegation;
190+
result.certs.push({
191+
type: CertType.StakeVoteDelegation,
192+
stakeCredentialHash: Buffer.from(voteDelegation.stake_credential().to_bytes()).toString('hex'),
193+
dRepId: Buffer.from(voteDelegation.drep().to_bytes()).toString('hex'),
194+
});
195+
}
186196
}
187197
}
188198

@@ -263,8 +273,9 @@ export class Transaction extends BaseTransaction {
263273
const cert = this._transaction.body().certs()!.get(i);
264274
certs.push(cert);
265275
}
266-
267-
if (certs.some((c) => c.as_pool_registration() !== undefined)) {
276+
if (certs.some((c) => c.as_vote_delegation() !== undefined)) {
277+
this._type = TransactionType.StakingVote;
278+
} else if (certs.some((c) => c.as_pool_registration() !== undefined)) {
268279
this._type = TransactionType.StakingPledge;
269280
const stakeKeyRegistration = certs.find((c) => c.as_stake_registration() !== undefined);
270281
const stakeKeyDelegation = certs.find((c) => c.as_stake_delegation() !== undefined);
@@ -394,6 +405,8 @@ export class Transaction extends BaseTransaction {
394405
? 'StakingDeactivate'
395406
: this._type === TransactionType.StakingPledge
396407
? 'StakingPledge'
408+
: this._type === TransactionType.StakingVote
409+
? 'StakingVote'
397410
: 'undefined';
398411
return {
399412
displayOrder,

modules/sdk-coin-ada/src/lib/transactionBuilderFactory.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { StakingDeactivateBuilder } from './stakingDeactivateBuilder';
99
import { StakingWithdrawBuilder } from './stakingWithdrawBuilder';
1010
import { StakingPledgeBuilder } from './stakingPledgeBuilder';
1111
import { StakingClaimRewardsBuilder } from './stakingClaimRewardsBuilder';
12+
import { StakingVoteDelegationBuilder } from '..';
1213

1314
export class TransactionBuilderFactory extends BaseTransactionBuilderFactory {
1415
constructor(_coinConfig: Readonly<CoinConfig>) {
@@ -38,6 +39,8 @@ export class TransactionBuilderFactory extends BaseTransactionBuilderFactory {
3839
return this.getWalletInitializationBuilder(tx);
3940
case TransactionType.StakingPledge:
4041
return this.getStakingPledgeBuilder(tx);
42+
case TransactionType.StakingVote:
43+
return this.getStakingVoteDelegationBuilder(tx);
4144
default:
4245
throw new InvalidTransactionError('unsupported transaction');
4346
}
@@ -76,6 +79,10 @@ export class TransactionBuilderFactory extends BaseTransactionBuilderFactory {
7679
return TransactionBuilderFactory.initializeBuilder(tx, new StakingPledgeBuilder(this._coinConfig));
7780
}
7881

82+
getStakingVoteDelegationBuilder(tx?: Transaction) {
83+
return TransactionBuilderFactory.initializeBuilder(tx, new StakingVoteDelegationBuilder(this._coinConfig));
84+
}
85+
7986
/**
8087
* Initialize the builder with the given transaction
8188
*

0 commit comments

Comments
 (0)