-
Notifications
You must be signed in to change notification settings - Fork 18
/
transferBalance.ts
111 lines (105 loc) · 4.04 KB
/
transferBalance.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import { ApiPromise } from '@polkadot/api'
import { SubmittableExtrinsicFunction } from '@polkadot/api/types'
import { AccountId, EventRecord } from '@polkadot/types/interfaces'
import { AnyTuple, Callback, IKeyringPair, ISubmittableResult } from '@polkadot/types/types'
import { BN, bnToBn } from '@polkadot/util'
import { checkIfBalanceSufficient } from './checkIfBalanceSufficient'
import { ExstrinsicThrowErrorMessage, getExtrinsicErrorMessage } from './getExtrinsicErrorMessage'
export type TransferBalanceResult = {
result?: ISubmittableResult
errorMessage?: ExstrinsicThrowErrorMessage | 'ExtrinsicFailed'
errorEvent?: EventRecord
}
/**
* Transfers a given amount of tokens from one account to another.
*/
export const transferBalance = async (
api: ApiPromise,
fromAccount: IKeyringPair | string,
toAddress: string | AccountId,
amount: bigint | BN | string | number,
allowDeath?: boolean,
statusCb?: Callback<ISubmittableResult>,
): Promise<TransferBalanceResult> => {
const hasSufficientBalance = await checkIfBalanceSufficient(api, fromAccount, amount)
if (!hasSufficientBalance) {
return Promise.reject({ errorMessage: 'TokenBelowMinimum' } satisfies TransferBalanceResult)
}
return new Promise(async (resolve, reject) => {
try {
const transferFn = (api.tx.balances[
allowDeath ? 'transferAllowDeath' : 'transferKeepAlive'
] || api.tx.balances['transfer']) as SubmittableExtrinsicFunction<'promise', AnyTuple>
const unsub = await transferFn(toAddress, bnToBn(amount)).signAndSend(
fromAccount,
(result: ISubmittableResult) => {
statusCb?.(result)
const isInBlock = result?.status?.isInBlock
if (!isInBlock) return
const errorEvent = result?.events.find(
({ event: { method } }: any) => method === 'ExtrinsicFailed',
)
if (isInBlock && errorEvent) {
// Reject if `ExtrinsicFailed` event was found
reject({ errorMessage: 'ExtrinsicFailed', errorEvent } satisfies TransferBalanceResult)
unsub?.()
} else if (isInBlock) {
// Otherwise resolve succesfully if transaction is in block
resolve({ result })
unsub?.()
}
},
)
} catch (e: any) {
console.error('Error while transferring balance:', e)
reject({
errorMessage: getExtrinsicErrorMessage(e),
errorEvent: e,
} satisfies TransferBalanceResult)
}
})
}
/**
* Transfers all available tokens from one account to another.
*/
export const transferFullBalance = async (
api: ApiPromise,
fromAccount: IKeyringPair | string,
toAddress: string | AccountId,
keepAlive?: boolean,
statusCb?: Callback<ISubmittableResult>,
): Promise<TransferBalanceResult> => {
const hasSufficientBalance = await checkIfBalanceSufficient(api, fromAccount)
if (!hasSufficientBalance) {
return Promise.reject({ errorMessage: 'TokenBelowMinimum' } satisfies TransferBalanceResult)
}
return new Promise(async (resolve, reject) => {
try {
const unsub = await api.tx.balances
.transferAll(toAddress, !!keepAlive)
.signAndSend(fromAccount, (result: ISubmittableResult) => {
statusCb?.(result)
const isInBlock = result?.status?.isInBlock
if (!isInBlock) return
const errorEvent = result?.events.find(
({ event: { method } }: any) => method === 'ExtrinsicFailed',
)
if (isInBlock && errorEvent) {
// Reject if `ExtrinsicFailed` event was found
reject({ errorMessage: 'ExtrinsicFailed', errorEvent } satisfies TransferBalanceResult)
unsub?.()
} else if (isInBlock) {
// Otherwise resolve succesfully if transaction is in block
resolve({ result })
unsub?.()
}
})
} catch (e: any) {
console.error('Error while transferring full balance:', e)
reject({
errorMessage: getExtrinsicErrorMessage(e),
errorEvent: e,
} satisfies TransferBalanceResult)
}
})
}