Skip to content

Commit e7f6e5b

Browse files
nooxxloicttn
authored andcommitted
cardano: withdraw rewards
1 parent e480d8c commit e7f6e5b

File tree

3 files changed

+82
-6
lines changed

3 files changed

+82
-6
lines changed

examples/ada.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ const f = async () => {
1919
],
2020
});
2121

22-
const tx = await k.ada.craftStakeTx(
23-
'376acfff-e35d-4b7c-90da-c6acb8ea7197',
22+
const tx = await k.ada.craftWithdrawRewardsTx(
2423
'addr_test1qpy358g8glafrucevf0rjpmzx2k5esn5uvjh7dzuakpdhv4g2egyt3y3qw6jrguz0lmyhxygjdg2ytaf5z6ueaety7dsmpcee5',
2524
);
2625
const txSigned = await k.ada.sign('vault1', tx);

src/globals.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,13 @@ export const ADDRESSES = {
2323
mainnet: {
2424
validatorAddress: 'cosmosvaloper1uxlf7mvr8nep3gm7udf2u9remms2jyjqvwdul2'
2525
}
26+
},
27+
ada: {
28+
testnet: {
29+
poolId: 'pool1xjt9ylq7rvsd2mxf6njkzhrkhgjzrtflz039vxs66ntvv82rdky'
30+
},
31+
mainnet: {
32+
poolId: 'pool10rdglgh4pzvkf936p2m669qzarr9dusrhmmz9nultm3uvq4eh5k'
33+
}
2634
}
2735
};

src/services/ada.ts

Lines changed: 73 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import {
2626
Value,
2727
Vkey,
2828
Vkeywitness,
29-
Vkeywitnesses,
29+
Vkeywitnesses, Withdrawals,
3030
} from '@emurgo/cardano-serialization-lib-nodejs';
3131
import { Service } from "./service";
3232
import { AdaStakeOptions, InternalAdaConfig, UTXO } from "../types/ada";
@@ -35,6 +35,7 @@ import {
3535
BlockfrostServerError,
3636
} from "@blockfrost/blockfrost-js";
3737
import { InvalidIntegration, InvalidSignature } from "../errors/integrations";
38+
import { ADDRESSES } from "../globals";
3839

3940
const CARDANO_PARAMS = {
4041
COINS_PER_UTXO_WORD: '34482',
@@ -44,6 +45,7 @@ const CARDANO_PARAMS = {
4445
MIN_FEE_B: '155381',
4546
POOL_DEPOSIT: '500000000',
4647
KEY_DEPOSIT: '2000000',
48+
MIN_UTXO_VALUE_ADA_ONLY: 1000000,
4749
};
4850

4951
export class AdaService extends Service {
@@ -66,8 +68,8 @@ export class AdaService extends Service {
6668
options?: AdaStakeOptions,
6769
): Promise<Transaction> {
6870
const poolId = options?.poolId ? options.poolId :
69-
this.testnet ? 'pool1xjt9ylq7rvsd2mxf6njkzhrkhgjzrtflz039vxs66ntvv82rdky' :
70-
'pool10rdglgh4pzvkf936p2m669qzarr9dusrhmmz9nultm3uvq4eh5k';
71+
this.testnet ? ADDRESSES.ada.testnet.poolId :
72+
ADDRESSES.ada.mainnet.poolId;
7173

7274
try {
7375
const utxos = await this.getUtxos(walletAddress);
@@ -115,6 +117,62 @@ export class AdaService extends Service {
115117
}
116118
}
117119

120+
/**
121+
* Craft ada withdraw rewards transaction
122+
* @param walletAddress wallet delegating that will receive the rewards
123+
* @param amountToWithdraw amount of rewards to withdraw, if not provided all rewards are withdrawn
124+
*/
125+
async craftWithdrawRewardsTx(
126+
walletAddress: string,
127+
amountToWithdraw?: number,
128+
): Promise<Transaction> {
129+
130+
131+
try {
132+
const utxos = await this.getUtxos(walletAddress);
133+
const address = await this.client.addresses(walletAddress);
134+
if (!address.stake_address) {
135+
throw Error('No stake address');
136+
}
137+
138+
const stakeKeyHash = await this.getStakeKeyHash(address.stake_address);
139+
if (!stakeKeyHash) {
140+
throw Error('Could not hash stake key');
141+
}
142+
143+
const withdrawals = Withdrawals.new();
144+
const rewardAddress = RewardAddress.from_address(Address.from_bech32(address.stake_address));
145+
146+
if (!rewardAddress) {
147+
throw Error('Could not retrieve rewards address');
148+
}
149+
150+
const rewardsHistory = await this.client.accountsRewardsAll(address.stake_address);
151+
let totalRewards: number = 0;
152+
for(const rewards of rewardsHistory){
153+
totalRewards += Number(rewards.amount);
154+
}
155+
156+
const amountToWithdrawLovelace = amountToWithdraw ? this.adaToLovelace(amountToWithdraw.toString()) : totalRewards.toString();
157+
withdrawals.insert(rewardAddress, BigNum.from_str(amountToWithdrawLovelace));
158+
159+
let walletBalance = 0;
160+
for(const utxo of utxos){
161+
if(utxo.amount.length > 0 && utxo.amount[0].unit === 'lovelace'){
162+
walletBalance += Number(utxo.amount[0].quantity);
163+
}
164+
}
165+
// Not sure about this value (might need to be BALANCE + REWARDS + FEES)
166+
const outAmount = (CARDANO_PARAMS.MIN_UTXO_VALUE_ADA_ONLY + totalRewards).toString();
167+
const outputs = this.prepareTx(outAmount, walletAddress);
168+
169+
const tx = await this.buildTx(walletAddress, utxos, outputs, null, withdrawals);
170+
return tx;
171+
} catch (error) {
172+
throw error;
173+
}
174+
}
175+
118176
/**
119177
* Prepare outputs (destination addresses and amounts) for a transaction
120178
* @param lovelaceValue
@@ -140,9 +198,16 @@ export class AdaService extends Service {
140198
* @param utxos
141199
* @param outputs
142200
* @param certificates
201+
* @param withdrawals
143202
* @private
144203
*/
145-
private async buildTx(changeAddress: string, utxos: UTXO, outputs: TransactionOutputs, certificates: Certificates | null = null) {
204+
private async buildTx(
205+
changeAddress: string,
206+
utxos: UTXO,
207+
outputs: TransactionOutputs,
208+
certificates: Certificates | null = null,
209+
withdrawals: Withdrawals | null = null,
210+
): Promise<Transaction> {
146211
const txBuilder = TransactionBuilder.new(
147212
TransactionBuilderConfigBuilder.new()
148213
.fee_algo(
@@ -165,6 +230,10 @@ export class AdaService extends Service {
165230
txBuilder.set_certs(certificates);
166231
}
167232

233+
if(withdrawals){
234+
txBuilder.set_withdrawals(withdrawals);
235+
}
236+
168237
// Inputs
169238
const lovelaceUtxos = utxos.filter(
170239
(u: any) => !u.amount.find((a: any) => a.unit !== 'lovelace'),

0 commit comments

Comments
 (0)