|
1 | | -import { Service } from "./service"; |
2 | | -import { DotRewardDestination, DotSignedTx, DotTx, DotTxHash, DotTxStatus } from "../types/dot"; |
3 | | -import { ServiceProps } from "../types/service"; |
4 | | -import { Integration } from "../types/integrations"; |
5 | | -import api from "../api"; |
6 | | -import { UnsignedTransaction } from "@substrate/txwrapper-polkadot"; |
7 | 1 | import { parseUnits } from "viem"; |
| 2 | +import { ServiceProps } from "../types/service"; |
| 3 | +import { SubstrateService } from "./substrate"; |
8 | 4 |
|
9 | 5 | /** |
10 | 6 | * Staking docs: https://polkadot.js.org/docs/substrate/extrinsics#staking |
11 | 7 | * Nomination pools docs: https://polkadot.js.org/docs/substrate/extrinsics#nominationpools |
12 | 8 | */ |
13 | | -export class DotService extends Service { |
14 | | - constructor({ testnet }: ServiceProps) { |
15 | | - super({ testnet }); |
| 9 | +export class DotService extends SubstrateService { |
| 10 | + constructor(props: ServiceProps) { |
| 11 | + super(props, "DOT"); |
16 | 12 | } |
17 | 13 |
|
18 | | - /** |
19 | | - * Convert WND (testnet token) to PLANCK |
20 | | - * To be used in testnet (Westend) |
21 | | - * @param amountWnd |
22 | | - */ |
23 | | - wndToPlanck(amountWnd: string): string { |
24 | | - return parseUnits(amountWnd, 12).toString(); |
| 14 | + mainToPlanck(amount: string): string { |
| 15 | + return this.dotToPlanck(amount); |
25 | 16 | } |
26 | 17 |
|
27 | 18 | /** |
28 | | - * Convert DOT to PLANCK |
29 | | - * To be used in mainnet |
30 | | - * @param amountDot |
| 19 | + * Convert DOT to planck |
| 20 | + * @param amountDot amount in planck |
31 | 21 | */ |
32 | 22 | dotToPlanck(amountDot: string): string { |
33 | 23 | return parseUnits(amountDot, 10).toString(); |
34 | 24 | } |
35 | | - |
36 | | - /** |
37 | | - * Craft dot bonding transaction |
38 | | - * @param accountId id of the kiln account to use for the stake transaction |
39 | | - * @param stashAccount stash account address (your most secure cold wallet) |
40 | | - * @param amountDot amount to bond in DOT |
41 | | - * @param rewardDestination |
42 | | - */ |
43 | | - async craftBondTx( |
44 | | - accountId: string, |
45 | | - stashAccount: string, |
46 | | - amountDot: number, |
47 | | - rewardDestination: DotRewardDestination, |
48 | | - ): Promise<DotTx> { |
49 | | - const amountPlanck = this.testnet ? this.wndToPlanck(amountDot.toString()) : this.dotToPlanck(amountDot.toString()); |
50 | | - |
51 | | - const { data } = await api.post<DotTx>(`/v1/dot/transaction/bond`, { |
52 | | - account_id: accountId, |
53 | | - stash_account: stashAccount, |
54 | | - amount_planck: amountPlanck, |
55 | | - reward_destination: rewardDestination, |
56 | | - }); |
57 | | - return data; |
58 | | - } |
59 | | - |
60 | | - /** |
61 | | - * Craft dot bonding extra token transaction (to be used if you already bonded tokens) |
62 | | - * @param stashAccount stash account address |
63 | | - * @param amountDot amount to bond extra in DOT |
64 | | - */ |
65 | | - async craftBondExtraTx(stashAccount: string, amountDot: number): Promise<DotTx> { |
66 | | - const amountPlanck = this.testnet ? this.wndToPlanck(amountDot.toString()) : this.dotToPlanck(amountDot.toString()); |
67 | | - |
68 | | - const { data } = await api.post<DotTx>(`/v1/dot/transaction/bond-extra`, { |
69 | | - stash_account: stashAccount, |
70 | | - amount_planck: amountPlanck, |
71 | | - }); |
72 | | - return data; |
73 | | - } |
74 | | - |
75 | | - /** |
76 | | - * Craft dot rebond transaction (to be used to rebond unbonding token) |
77 | | - * @param stashAccount stash account address |
78 | | - * @param amountDot amount to rebond in DOT |
79 | | - */ |
80 | | - async craftRebondTx(stashAccount: string, amountDot: number): Promise<DotTx> { |
81 | | - const amountPlanck = this.testnet ? this.wndToPlanck(amountDot.toString()) : this.dotToPlanck(amountDot.toString()); |
82 | | - |
83 | | - const { data } = await api.post<DotTx>(`/v1/dot/transaction/rebond`, { |
84 | | - stash_account: stashAccount, |
85 | | - amount_planck: amountPlanck, |
86 | | - }); |
87 | | - return data; |
88 | | - } |
89 | | - |
90 | | - /** |
91 | | - * Craft dot nominate transaction |
92 | | - * @param stashAccount stash account address |
93 | | - * @param validatorAddresses validator addresses to nominate to |
94 | | - */ |
95 | | - async craftNominateTx(stashAccount: string, validatorAddresses: string[]): Promise<DotTx> { |
96 | | - const { data } = await api.post<DotTx>(`/v1/dot/transaction/nominate`, { |
97 | | - stash_account: stashAccount, |
98 | | - validator_addresses: validatorAddresses, |
99 | | - }); |
100 | | - return data; |
101 | | - } |
102 | | - |
103 | | - /** |
104 | | - * Craft dot unbonding transaction, there is an unbonding period before your tokens can be withdrawn |
105 | | - * @param stashAccount stash account address |
106 | | - * @param amountDot amount to unrebond in DOT |
107 | | - */ |
108 | | - async craftUnbondTx(stashAccount: string, amountDot: number): Promise<DotTx> { |
109 | | - const amountPlanck = this.testnet ? this.wndToPlanck(amountDot.toString()) : this.dotToPlanck(amountDot.toString()); |
110 | | - |
111 | | - const { data } = await api.post<DotTx>(`/v1/dot/transaction/unbond`, { |
112 | | - stash_account: stashAccount, |
113 | | - amount_planck: amountPlanck, |
114 | | - }); |
115 | | - return data; |
116 | | - } |
117 | | - |
118 | | - /** |
119 | | - * Craft dot withdraw unbonded token transaction |
120 | | - * @param stashAccount stash account address |
121 | | - */ |
122 | | - async craftWithdrawUnbondedTx(stashAccount: string): Promise<DotTx> { |
123 | | - const { data } = await api.post<DotTx>(`/v1/dot/transaction/withdraw-unbonded`, { |
124 | | - stash_account: stashAccount, |
125 | | - }); |
126 | | - return data; |
127 | | - } |
128 | | - |
129 | | - /** |
130 | | - * Craft dot chill transaction that chills the stash account, |
131 | | - * meaning that given account will not nominate |
132 | | - * any validator anymore, so you will stop earning rewards at the beginning |
133 | | - * of the next era. |
134 | | - * @param stashAccount stash account address |
135 | | - */ |
136 | | - async craftChillTx(stashAccount: string): Promise<DotTx> { |
137 | | - const { data } = await api.post<DotTx>(`/v1/dot/transaction/chill`, { |
138 | | - stash_account: stashAccount, |
139 | | - }); |
140 | | - return data; |
141 | | - } |
142 | | - |
143 | | - /** |
144 | | - * Craft dot set reward destination transaction that updates the destination rewards address for the given stash account |
145 | | - * @param stashAccount stash account address |
146 | | - * @param rewardsDestination: |
147 | | - * 'Staked': rewards are paid into the stash account, increasing the amount at stake accordingly. |
148 | | - * 'Stash': rewards are paid into the stash account, not increasing the amount at stake. |
149 | | - * 'Controller': rewards are paid into the controller account |
150 | | - * Custom account address: rewards are paid into the custom account address |
151 | | - */ |
152 | | - async craftSetPayeeTx(stashAccount: string, rewardsDestination: DotRewardDestination): Promise<DotTx> { |
153 | | - const { data } = await api.post<DotTx>(`/v1/dot/transaction/set-payee`, { |
154 | | - stash_account: stashAccount, |
155 | | - reward_destination: rewardsDestination, |
156 | | - }); |
157 | | - return data; |
158 | | - } |
159 | | - |
160 | | - /** |
161 | | - * Craft dot join pool transaction |
162 | | - * The amount to bond is transferred from the member to the pools account and immediately increases the pools bond. |
163 | | - * @param accountId |
164 | | - * @param memberAccount |
165 | | - * @param amountDot |
166 | | - * @param poolId |
167 | | - */ |
168 | | - async craftJoinPoolTx(accountId: string, memberAccount: string, amountDot: number, poolId: string): Promise<DotTx> { |
169 | | - const amountPlanck = this.testnet ? this.wndToPlanck(amountDot.toString()) : this.dotToPlanck(amountDot.toString()); |
170 | | - const { data } = await api.post<DotTx>(`/v1/dot/transaction/join-pool`, { |
171 | | - account_id: accountId, |
172 | | - member_account: memberAccount, |
173 | | - amount_planck: amountPlanck, |
174 | | - pool_id: poolId, |
175 | | - }); |
176 | | - return data; |
177 | | - } |
178 | | - |
179 | | - /** |
180 | | - * Craft a pool bond extra transaction |
181 | | - * Bond extra more funds from origin into the pool to which they already belong. |
182 | | - * Bonding extra funds implies an automatic payout of all pending rewards as well. |
183 | | - * @param memberAccount |
184 | | - * @param amountDot |
185 | | - */ |
186 | | - async craftBondExtraToPoolTx(memberAccount: string, amountDot: number): Promise<DotTx> { |
187 | | - const amountPlanck = this.testnet ? this.wndToPlanck(amountDot.toString()) : this.dotToPlanck(amountDot.toString()); |
188 | | - const { data } = await api.post<DotTx>(`/v1/dot/transaction/bond-extra-pool`, { |
189 | | - member_account: memberAccount, |
190 | | - amount_planck: amountPlanck, |
191 | | - }); |
192 | | - return data; |
193 | | - } |
194 | | - |
195 | | - /** |
196 | | - * Craft a pool bond extra transaction to bond available rewards into the pool to which they already belong. |
197 | | - * @param memberAccount |
198 | | - */ |
199 | | - async craftBondRewardsToPoolTx(memberAccount: string): Promise<DotTx> { |
200 | | - const { data } = await api.post<DotTx>(`/v1/dot/transaction/bond-rewards-pool`, { |
201 | | - member_account: memberAccount, |
202 | | - }); |
203 | | - return data; |
204 | | - } |
205 | | - |
206 | | - /** |
207 | | - * Craft a pool claim payout transaction |
208 | | - * A bonded member can use this to claim their payout based on the rewards that |
209 | | - * the pool has accumulated since their last claimed payout (OR since joining |
210 | | - * if this is their first time claiming rewards). |
211 | | - * The payout will be transferred to the member's account. |
212 | | - * The member will earn rewards pro rata based on the members stake vs the sum of the members in the pools stake. Rewards do not "expire". |
213 | | - * @param memberAccount |
214 | | - */ |
215 | | - async craftClaimPayoutFromPoolTx(memberAccount: string): Promise<DotTx> { |
216 | | - const { data } = await api.post<DotTx>(`/v1/dot/transaction/claim-payout-pool`, { |
217 | | - member_account: memberAccount, |
218 | | - }); |
219 | | - return data; |
220 | | - } |
221 | | - |
222 | | - /** |
223 | | - * Craft a pool unbond transaction |
224 | | - * Unbond amount funds from the pool. |
225 | | - * It implicitly collects the rewards one last time, since not doing so would mean some rewards would be forfeited. |
226 | | - * Warning: you cannot rebond during the unbonding period with a nomination pool. If you change your mind, you must wait for the unbonding period to end before you can join a nomination pool again. |
227 | | - * @param memberAccount |
228 | | - * @param amountDot |
229 | | - */ |
230 | | - async craftUnbondFromPoolTx(memberAccount: string, amountDot: number): Promise<DotTx> { |
231 | | - const amountPlanck = this.testnet ? this.wndToPlanck(amountDot.toString()) : this.dotToPlanck(amountDot.toString()); |
232 | | - const { data } = await api.post<DotTx>(`/v1/dot/transaction/unbond-pool`, { |
233 | | - member_account: memberAccount, |
234 | | - amount_planck: amountPlanck, |
235 | | - }); |
236 | | - return data; |
237 | | - } |
238 | | - |
239 | | - /** |
240 | | - * Craft a pool withdraw unbonded transaction |
241 | | - * Withdraw unbonded funds from member_account. |
242 | | - * @param memberAccount |
243 | | - */ |
244 | | - async craftWithdrawUnbondedFromPoolTx(memberAccount: string): Promise<DotTx> { |
245 | | - const { data } = await api.post<DotTx>(`/v1/dot/transaction/withdraw-unbonded-pool`, { |
246 | | - member_account: memberAccount, |
247 | | - }); |
248 | | - return data; |
249 | | - } |
250 | | - |
251 | | - /** |
252 | | - * Sign transaction with given integration |
253 | | - * @param integration custody solution to sign with |
254 | | - * @param tx raw transaction |
255 | | - * @param note note to identify the transaction in your custody solution |
256 | | - */ |
257 | | - async sign(integration: Integration, tx: DotTx, note?: string): Promise<DotSignedTx> { |
258 | | - const payload = { |
259 | | - rawMessageData: { |
260 | | - messages: [ |
261 | | - { |
262 | | - content: tx.data.unsigned_tx_payload.substring(2), |
263 | | - }, |
264 | | - ], |
265 | | - }, |
266 | | - }; |
267 | | - |
268 | | - const fbSigner = this.getFbSigner(integration); |
269 | | - const fbNote = note ? note : "DOT tx from @kilnfi/sdk"; |
270 | | - const fbTx = await fbSigner.sign(payload, this.testnet ? "WND" : "DOT", fbNote); |
271 | | - const signature = `0x00${fbTx.signedMessages![0].signature.fullSig}`; |
272 | | - |
273 | | - const { data } = await api.post<DotSignedTx>(`/v1/dot/transaction/prepare`, { |
274 | | - unsigned_tx_serialized: tx.data.unsigned_tx_serialized, |
275 | | - signature: signature, |
276 | | - }); |
277 | | - data.data.fireblocks_tx = fbTx; |
278 | | - return data; |
279 | | - } |
280 | | - |
281 | | - /** |
282 | | - * Broadcast signed transaction |
283 | | - * @param signedTx |
284 | | - */ |
285 | | - async broadcast(signedTx: DotSignedTx): Promise<DotTxHash> { |
286 | | - const { data } = await api.post<DotTxHash>(`/v1/dot/transaction/broadcast`, { |
287 | | - tx_serialized: signedTx.data.signed_tx_serialized, |
288 | | - }); |
289 | | - return data; |
290 | | - } |
291 | | - |
292 | | - /** |
293 | | - * Get transaction status |
294 | | - * @param txHash transaction hash |
295 | | - */ |
296 | | - async getTxStatus(txHash: string): Promise<DotTxStatus> { |
297 | | - const { data } = await api.get<DotTxStatus>(`/v1/dot/transaction/status?tx_hash=${txHash}`); |
298 | | - return data; |
299 | | - } |
300 | | - |
301 | | - /** |
302 | | - * Decode transaction |
303 | | - * @param txSerialized transaction serialized |
304 | | - */ |
305 | | - async decodeTx(txSerialized: string): Promise<UnsignedTransaction> { |
306 | | - const { data } = await api.get<UnsignedTransaction>(`/v1/dot/transaction/decode?tx_serialized=${txSerialized}`); |
307 | | - return data; |
308 | | - } |
309 | 25 | } |
0 commit comments