Skip to content

Commit e480d8c

Browse files
nooxxloicttn
authored andcommitted
cardano: craft staking transactions
1 parent c0681c4 commit e480d8c

File tree

1 file changed

+50
-23
lines changed

1 file changed

+50
-23
lines changed

src/services/ada.ts

Lines changed: 50 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,17 @@ import {
2424
TransactionUnspentOutputs,
2525
TransactionWitnessSet,
2626
Value,
27-
Vkey, Vkeywitness, Vkeywitnesses,
27+
Vkey,
28+
Vkeywitness,
29+
Vkeywitnesses,
2830
} from '@emurgo/cardano-serialization-lib-nodejs';
2931
import { Service } from "./service";
3032
import { AdaStakeOptions, InternalAdaConfig, UTXO } from "../types/ada";
3133
import {
3234
BlockFrostAPI,
3335
BlockfrostServerError,
3436
} from "@blockfrost/blockfrost-js";
35-
import { InvalidIntegration } from "../errors/integrations";
37+
import { InvalidIntegration, InvalidSignature } from "../errors/integrations";
3638

3739
const CARDANO_PARAMS = {
3840
COINS_PER_UTXO_WORD: '34482',
@@ -63,9 +65,9 @@ export class AdaService extends Service {
6365
walletAddress: string,
6466
options?: AdaStakeOptions,
6567
): Promise<Transaction> {
66-
const poolId = this.testnet ? 'pool1xjt9ylq7rvsd2mxf6njkzhrkhgjzrtflz039vxs66ntvv82rdky' : 'pool10rdglgh4pzvkf936p2m669qzarr9dusrhmmz9nultm3uvq4eh5k';
67-
const poolHash = this.testnet ? '3496527c1e1b20d56cc9d4e5615c76ba2421ad3f13e2561a1ad4d6c6' : '78da8fa2f5089964963a0ab7ad1402e8c656f203bef622cf9f5ee3c6';
68-
const poolKeyHash = Ed25519KeyHash.from_hex(poolHash);
68+
const poolId = options?.poolId ? options.poolId :
69+
this.testnet ? 'pool1xjt9ylq7rvsd2mxf6njkzhrkhgjzrtflz039vxs66ntvv82rdky' :
70+
'pool10rdglgh4pzvkf936p2m669qzarr9dusrhmmz9nultm3uvq4eh5k';
6971

7072
try {
7173
const utxos = await this.getUtxos(walletAddress);
@@ -74,14 +76,16 @@ export class AdaService extends Service {
7476
if (!address.stake_address) {
7577
throw Error('No stake address');
7678
}
79+
7780
const stakeKeyHash = await this.getStakeKeyHash(address.stake_address);
7881
if (!stakeKeyHash) {
7982
throw Error('Could not hash stake key');
8083
}
8184
const certificates = Certificates.new();
8285

8386
const registrations = await this.client.accountsRegistrations(address.stake_address);
84-
// const pool = await this.client.poolsById(poolId);
87+
const pool = await this.client.poolsById(poolId);
88+
const poolKeyHash = Ed25519KeyHash.from_hex(pool.hex);
8589

8690
// Register stake key if not done already
8791
if (registrations.length === 0) {
@@ -111,6 +115,12 @@ export class AdaService extends Service {
111115
}
112116
}
113117

118+
/**
119+
* Prepare outputs (destination addresses and amounts) for a transaction
120+
* @param lovelaceValue
121+
* @param paymentAddress
122+
* @private
123+
*/
114124
private prepareTx(lovelaceValue: string, paymentAddress: string): TransactionOutputs {
115125
const outputs = TransactionOutputs.new();
116126

@@ -124,6 +134,14 @@ export class AdaService extends Service {
124134
return outputs;
125135
}
126136

137+
/**
138+
* Build transaction with correct fees, inputs, outputs and certificates
139+
* @param changeAddress
140+
* @param utxos
141+
* @param outputs
142+
* @param certificates
143+
* @private
144+
*/
127145
private async buildTx(changeAddress: string, utxos: UTXO, outputs: TransactionOutputs, certificates: Certificates | null = null) {
128146
const txBuilder = TransactionBuilder.new(
129147
TransactionBuilderConfigBuilder.new()
@@ -180,7 +198,6 @@ export class AdaService extends Service {
180198
// Outputs
181199
txBuilder.add_output(outputs.get(0));
182200

183-
184201
const latestBlock = await this.client.blocksLatest();
185202
const currentSlot = latestBlock.slot;
186203
if (!currentSlot) {
@@ -201,18 +218,15 @@ export class AdaService extends Service {
201218
return (parseFloat(value || '1') * 1000000).toFixed();
202219
}
203220

204-
private hexToBytes(string: string) {
205-
return Buffer.from(string, 'hex');
206-
}
207-
208-
private hexToBech32(address: string) {
209-
return Address.from_bytes(this.hexToBytes(address)).to_bech32();
210-
}
211-
212-
private async getUtxos(walletAddress: string) {
221+
/**
222+
* Get addresses to spend from wallet
223+
* @param walletAddress
224+
* @private
225+
*/
226+
private async getUtxos(walletAddress: string): Promise<UTXO> {
213227
let utxo: UTXO = [];
214228
try {
215-
utxo = await this.client.addressesUtxosAll(walletAddress);
229+
utxo = await this.client.addressesUtxos(walletAddress);
216230
} catch (error) {
217231
if (error instanceof BlockfrostServerError && error.status_code === 404) {
218232
throw new Error(`You should send ADA to ${walletAddress} to have enough funds to sent a transaction`);
@@ -224,7 +238,7 @@ export class AdaService extends Service {
224238
}
225239

226240
/**
227-
* Get
241+
* Get stake key keyhash
228242
* @param stakeKey
229243
* @private
230244
*/
@@ -263,6 +277,10 @@ export class AdaService extends Service {
263277
{
264278
"content": message,
265279
},
280+
{
281+
"content": message,
282+
"bip44change": 2,
283+
},
266284
],
267285
},
268286
inputsSelection: {
@@ -272,13 +290,22 @@ export class AdaService extends Service {
272290

273291
const fbTx = await this.fbSigner.signWithFB(payload, this.testnet ? 'ADA_TEST' : 'ADA');
274292

275-
const pubKey = PublicKey.from_hex(fbTx.signedMessages![0].publicKey);
276-
const vKey = Vkey.new(pubKey);
277-
const signature = Ed25519Signature.from_hex(fbTx.signedMessages![0].signature.fullSig);
293+
if (!fbTx.signedMessages) {
294+
throw new InvalidSignature(`Could not sign the transaction.`);
295+
}
296+
297+
// Add signatures
278298
const witnesses = TransactionWitnessSet.new();
279299
const vkeyWitnesses = Vkeywitnesses.new();
280-
const vkeyWitness = Vkeywitness.new(vKey, signature);
281-
vkeyWitnesses.add(vkeyWitness);
300+
301+
for (const signedMessage of fbTx.signedMessages) {
302+
const pubKey = PublicKey.from_hex(signedMessage.publicKey);
303+
const vKey = Vkey.new(pubKey);
304+
const signature = Ed25519Signature.from_hex(signedMessage.signature.fullSig);
305+
const vkeyWitness = Vkeywitness.new(vKey, signature);
306+
vkeyWitnesses.add(vkeyWitness);
307+
}
308+
282309
witnesses.set_vkeys(vkeyWitnesses);
283310
return Transaction.new(transaction.body(), witnesses);
284311
}

0 commit comments

Comments
 (0)