Skip to content

Commit eceb8d9

Browse files
nooxxloicttn
authored andcommitted
rebase
1 parent 44ea208 commit eceb8d9

File tree

6 files changed

+95
-111
lines changed

6 files changed

+95
-111
lines changed

examples/accounts.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { Kiln } from "../src/kiln";
33
const f = async () => {
44
const k = new Kiln({
55
testnet: true,
6-
apiToken: 'kiln_dTkxUTFRdHBMZm9vNFFycFhDSTZCdlJsbjJZang5VnY6bVE3bUYyUExZeDd3LUM2Ty01THJ2QTlyMmVtUG92NzI5ejRqU19FVzQ3UFdkUFdZTmgyMHJ2VWcxcUdjWXNsMg',
6+
apiToken: 'kiln_dTkxUTFRdHBMZm9vNFFycFhDSTZCdlJsbjJZang5VnY6ejJoV3FCSTlyZlBtM2ZIM0RFRVVaM3NwTkZReHJXTDZWZUxJMWtWWlVrb3VNYUVzcE9Lakt4ZVplOG9vd1oyVw',
77
});
88

99
try {

examples/ada.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const f = async () => {
77
try {
88
const k = new Kiln({
99
testnet: true,
10-
apiToken: 'kiln_dTkxUTFRdHBMZm9vNFFycFhDSTZCdlJsbjJZang5VnY6bVE3bUYyUExZeDd3LUM2Ty01THJ2QTlyMmVtUG92NzI5ejRqU19FVzQ3UFdkUFdZTmgyMHJ2VWcxcUdjWXNsMg',
10+
apiToken: 'kiln_dTkxUTFRdHBMZm9vNFFycFhDSTZCdlJsbjJZang5VnY6ejJoV3FCSTlyZlBtM2ZIM0RFRVVaM3NwTkZReHJXTDZWZUxJMWtWWlVrb3VNYUVzcE9Lakt4ZVplOG9vd1oyVw',
1111
integrations: [
1212
{
1313
name: 'vault1',
@@ -23,7 +23,6 @@ const f = async () => {
2323
'376acfff-e35d-4b7c-90da-c6acb8ea7197',
2424
'addr_test1qpy358g8glafrucevf0rjpmzx2k5esn5uvjh7dzuakpdhv4g2egyt3y3qw6jrguz0lmyhxygjdg2ytaf5z6ueaety7dsmpcee5',
2525
);
26-
2726
const txSigned = await k.ada.sign('vault1', tx);
2827
const hash = await k.ada.broadcast(txSigned);
2928
console.log(hash);

examples/atom.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const apiSecret = fs.readFileSync(__dirname + '/fireblocks_secret.key', 'utf8');
66
const f = async () => {
77
const k = new Kiln({
88
testnet: true,
9-
apiToken: 'kiln_dTkxUTFRdHBMZm9vNFFycFhDSTZCdlJsbjJZang5VnY6bVE3bUYyUExZeDd3LUM2Ty01THJ2QTlyMmVtUG92NzI5ejRqU19FVzQ3UFdkUFdZTmgyMHJ2VWcxcUdjWXNsMg',
9+
apiToken: 'kiln_dTkxUTFRdHBMZm9vNFFycFhDSTZCdlJsbjJZang5VnY6ejJoV3FCSTlyZlBtM2ZIM0RFRVVaM3NwTkZReHJXTDZWZUxJMWtWWlVrb3VNYUVzcE9Lakt4ZVplOG9vd1oyVw',
1010
integrations: [
1111
{
1212
name: 'vault1',

examples/eth.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const apiSecret = fs.readFileSync(__dirname + '/fireblocks_secret.key', 'utf8');
77
const f = async () => {
88
const k = new Kiln({
99
testnet: true,
10-
// apiToken: 'kiln_dTkxUTFRdHBMZm9vNFFycFhDSTZCdlJsbjJZang5VnY6bVE3bUYyUExZeDd3LUM2Ty01THJ2QTlyMmVtUG92NzI5ejRqU19FVzQ3UFdkUFdZTmgyMHJ2VWcxcUdjWXNsMg',
10+
// apiToken: 'kiln_dTkxUTFRdHBMZm9vNFFycFhDSTZCdlJsbjJZang5VnY6ejJoV3FCSTlyZlBtM2ZIM0RFRVVaM3NwTkZReHJXTDZWZUxJMWtWWlVrb3VNYUVzcE9Lakt4ZVplOG9vd1oyVw',
1111
apiToken: 'kiln_V1JKOW55SkZMOFZvMzBJYmw0aGQ3bkM3UFpIM2IzeXA6YkN6VG9BZW56OWQtUVlGRjNqRW10c1E3R0w2YkRKdjAxQW1Cem5ONnF4Sm1WLUx6STNoRWE2XzdXSVZIc2s0Ug',
1212
integrations: [
1313
{

src/services/ada.ts

Lines changed: 87 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import * as CardanoWasm from '@emurgo/cardano-serialization-lib-nodejs';
22
import { Transaction } from '@emurgo/cardano-serialization-lib-nodejs';
3-
import { mnemonicToEntropy } from 'bip39';
3+
import { mnemonicToEntropy, generateMnemonic } from 'bip39';
44
import { Service } from "./service";
5-
import { InternalAdaConfig, UTXO } from "../types/ada";
5+
import { AdaStakeOptions, InternalAdaConfig, UTXO } from "../types/ada";
66
import {
77
BlockFrostAPI,
88
BlockfrostServerError,
@@ -24,46 +24,115 @@ export class AdaService extends Service {
2424
}
2525

2626
/**
27-
* Craft ada delegate transaction
27+
* Craft ada delegate transaction, all the wallet's balance will be delegated to the pool
2828
* @param accountId id of the kiln account to use for the stake transaction
2929
* @param walletAddress withdrawal creds /!\ losing it => losing the ability to withdraw
30+
* @param options
3031
*/
3132
async craftStakeTx(
3233
accountId: string,
3334
walletAddress: string,
35+
options?: AdaStakeOptions,
3436
): Promise<Transaction> {
3537

3638
let utxo: UTXO = [];
3739
try {
3840
utxo = await this.client.addressesUtxosAll(walletAddress);
3941
} catch (error) {
4042
if (error instanceof BlockfrostServerError && error.status_code === 404) {
41-
// Address derived from the seed was not used yet
42-
// In this case Blockfrost API will return 404
43-
utxo = [];
43+
throw new Error(`You should send ADA to ${walletAddress} to have enough funds to sent a transaction`);
4444
} else {
4545
throw error;
4646
}
4747
}
4848

49-
if (utxo.length === 0) {
50-
throw new Error(`You should send ADA to ${walletAddress} to have enough funds to sent a transaction`);
51-
}
52-
53-
// Get current blockchain slot from latest block
5449
const latestBlock = await this.client.blocksLatest();
5550
const currentSlot = latestBlock.slot;
5651
if (!currentSlot) {
5752
throw Error('Failed to fetch slot number');
5853
}
5954

60-
return this.composeTransaction(
61-
walletAddress,
62-
'addr_test1qqh2fphcgd0qsmwsqf4v8v9z2w3cpmzw5y9nx6h8z9v85qj7mjg5eydjgyvn3md3fwlyt2e4veynlwutp7u99m4l6q2sp3rdkv',
63-
'1000000',
64-
utxo,
65-
currentSlot,
55+
const txBuilder = CardanoWasm.TransactionBuilder.new(
56+
CardanoWasm.TransactionBuilderConfigBuilder.new()
57+
.fee_algo(
58+
CardanoWasm.LinearFee.new(
59+
CardanoWasm.BigNum.from_str('44'),
60+
CardanoWasm.BigNum.from_str('155381'),
61+
),
62+
)
63+
.pool_deposit(CardanoWasm.BigNum.from_str('500000000'))
64+
.key_deposit(CardanoWasm.BigNum.from_str('2000000'))
65+
.coins_per_utxo_word(
66+
CardanoWasm.BigNum.from_str(CARDANO_PARAMS.COINS_PER_UTXO_WORD),
67+
)
68+
.max_value_size(CARDANO_PARAMS.MAX_VALUE_SIZE)
69+
.max_tx_size(CARDANO_PARAMS.MAX_TX_SIZE)
70+
.build(),
71+
);
72+
73+
const poolHash = this.testnet ? '3496527c1e1b20d56cc9d4e5615c76ba2421ad3f13e2561a1ad4d6c6' : '78da8fa2f5089964963a0ab7ad1402e8c656f203bef622cf9f5ee3c6';
74+
const wasmWalletAddress = CardanoWasm.Address.from_bech32(walletAddress);
75+
const baseWalletAddress = CardanoWasm.BaseAddress.from_address(wasmWalletAddress);
76+
77+
78+
// Set TTL to +2h from currentSlot
79+
// If the transaction is not included in a block before that slot it will be cancelled.
80+
const ttl = currentSlot + 7200;
81+
txBuilder.set_ttl(ttl);
82+
83+
// Add delegation
84+
const poolKeyHash = CardanoWasm.Ed25519KeyHash.from_hex(poolHash);
85+
const stakeCredentials = baseWalletAddress?.stake_cred();
86+
if(!stakeCredentials){
87+
throw new Error('Could not generate stake credentials');
88+
}
89+
90+
const certificates = CardanoWasm.Certificates.new();
91+
const stakeRegistration = CardanoWasm.StakeRegistration.new(stakeCredentials);
92+
const stakeDelegation = CardanoWasm.StakeDelegation.new(stakeCredentials, poolKeyHash);
93+
const stakeRegistrationCertificate = CardanoWasm.Certificate.new_stake_registration(stakeRegistration);
94+
const delegationCertificate = CardanoWasm.Certificate.new_stake_delegation(stakeDelegation);
95+
certificates.add(stakeRegistrationCertificate);
96+
certificates.add(delegationCertificate);
97+
txBuilder.set_certs(certificates);
98+
99+
// Filter out multi asset utxo to keep this simple
100+
const lovelaceUtxos = utxo.filter(
101+
(u: any) => !u.amount.find((a: any) => a.unit !== 'lovelace'),
102+
);
103+
104+
// Create TransactionUnspentOutputs from utxos fetched from Blockfrost
105+
const unspentOutputs = CardanoWasm.TransactionUnspentOutputs.new();
106+
for (const utxo of lovelaceUtxos) {
107+
const amount = utxo.amount.find(
108+
(a: any) => a.unit === 'lovelace',
109+
)?.quantity;
110+
111+
if (!amount) continue;
112+
113+
const inputValue = CardanoWasm.Value.new(
114+
CardanoWasm.BigNum.from_str(amount.toString()),
115+
);
116+
117+
const input = CardanoWasm.TransactionInput.new(
118+
CardanoWasm.TransactionHash.from_bytes(Buffer.from(utxo.tx_hash, 'hex')),
119+
utxo.output_index,
120+
);
121+
const output = CardanoWasm.TransactionOutput.new(wasmWalletAddress, inputValue);
122+
unspentOutputs.add(CardanoWasm.TransactionUnspentOutput.new(input, output));
123+
}
124+
125+
txBuilder.add_inputs_from(
126+
unspentOutputs,
127+
CardanoWasm.CoinSelectionStrategyCIP2.LargestFirst,
66128
);
129+
130+
// Adds a change output if there are more ADA in utxo than we need for the transaction,
131+
// these coins will be returned to change address
132+
txBuilder.add_change_if_needed(wasmWalletAddress);
133+
134+
// Build transaction
135+
return txBuilder.build_tx();
67136
}
68137

69138
/**
@@ -86,7 +155,7 @@ export class AdaService extends Service {
86155
throw new InvalidIntegration(`Could not retrieve fireblocks signer.`);
87156
}
88157

89-
const message = transaction.to_hex();
158+
const message = CardanoWasm.hash_transaction(transaction.body()).to_hex();
90159

91160
const payload = {
92161
rawMessageData: {
@@ -132,90 +201,6 @@ export class AdaService extends Service {
132201
}
133202
}
134203

135-
private composeTransaction (
136-
address: string,
137-
outputAddress: string,
138-
outputAmount: string,
139-
utxos: UTXO,
140-
currentSlot: number,
141-
): Transaction {
142-
if (!utxos || utxos.length === 0) {
143-
throw Error(`No utxo on address ${address}`);
144-
}
145-
146-
const txBuilder = CardanoWasm.TransactionBuilder.new(
147-
CardanoWasm.TransactionBuilderConfigBuilder.new()
148-
.fee_algo(
149-
CardanoWasm.LinearFee.new(
150-
CardanoWasm.BigNum.from_str('44'),
151-
CardanoWasm.BigNum.from_str('155381'),
152-
),
153-
)
154-
.pool_deposit(CardanoWasm.BigNum.from_str('500000000'))
155-
.key_deposit(CardanoWasm.BigNum.from_str('2000000'))
156-
.coins_per_utxo_word(
157-
CardanoWasm.BigNum.from_str(CARDANO_PARAMS.COINS_PER_UTXO_WORD),
158-
)
159-
.max_value_size(CARDANO_PARAMS.MAX_VALUE_SIZE)
160-
.max_tx_size(CARDANO_PARAMS.MAX_TX_SIZE)
161-
.build(),
162-
);
163-
164-
const outputAddr = CardanoWasm.Address.from_bech32(outputAddress);
165-
const changeAddr = CardanoWasm.Address.from_bech32(address);
166-
167-
// Set TTL to +2h from currentSlot
168-
// If the transaction is not included in a block before that slot it will be cancelled.
169-
const ttl = currentSlot + 7200;
170-
txBuilder.set_ttl(ttl);
171-
172-
// Add output to the tx
173-
txBuilder.add_output(
174-
CardanoWasm.TransactionOutput.new(
175-
outputAddr,
176-
CardanoWasm.Value.new(CardanoWasm.BigNum.from_str(outputAmount)),
177-
),
178-
);
179-
180-
// Filter out multi asset utxo to keep this simple
181-
const lovelaceUtxos = utxos.filter(
182-
(u: any) => !u.amount.find((a: any) => a.unit !== 'lovelace'),
183-
);
184-
185-
// Create TransactionUnspentOutputs from utxos fetched from Blockfrost
186-
const unspentOutputs = CardanoWasm.TransactionUnspentOutputs.new();
187-
for (const utxo of lovelaceUtxos) {
188-
const amount = utxo.amount.find(
189-
(a: any) => a.unit === 'lovelace',
190-
)?.quantity;
191-
192-
if (!amount) continue;
193-
194-
const inputValue = CardanoWasm.Value.new(
195-
CardanoWasm.BigNum.from_str(amount.toString()),
196-
);
197-
198-
const input = CardanoWasm.TransactionInput.new(
199-
CardanoWasm.TransactionHash.from_bytes(Buffer.from(utxo.tx_hash, 'hex')),
200-
utxo.output_index,
201-
);
202-
const output = CardanoWasm.TransactionOutput.new(changeAddr, inputValue);
203-
unspentOutputs.add(CardanoWasm.TransactionUnspentOutput.new(input, output));
204-
}
205-
206-
txBuilder.add_inputs_from(
207-
unspentOutputs,
208-
CardanoWasm.CoinSelectionStrategyCIP2.LargestFirst,
209-
);
210-
211-
// Adds a change output if there are more ADA in utxo than we need for the transaction,
212-
// these coins will be returned to change address
213-
txBuilder.add_change_if_needed(changeAddr);
214-
215-
// Build transaction
216-
return txBuilder.build_tx();
217-
};
218-
219204
private harden (num: number): number {
220205
return 0x80000000 + num;
221206
};

src/types/ada.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export type AdaTx = {
1919
txHash: string;
2020
txBody: CardanoWasm.TransactionBody;
2121
};
22-
//
23-
// export type AtomStakeOptions = {
24-
// validatorAddress?: string;
25-
// };
22+
23+
export type AdaStakeOptions = {
24+
poolId: string;
25+
};

0 commit comments

Comments
 (0)