Skip to content

Commit b7bbf97

Browse files
committed
feat: Improve contractCall & decodeOutput error handling
1 parent c12fef5 commit b7bbf97

File tree

3 files changed

+61
-7
lines changed

3 files changed

+61
-7
lines changed

src/helpers/contractCall.ts

+45-6
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@ import {
1010
IKeyringPair,
1111
ISubmittableResult,
1212
} from '@polkadot/types/types'
13-
import { BN, stringCamelCase } from '@polkadot/util'
13+
import { BN, bnToBn, stringCamelCase } from '@polkadot/util'
1414
import { decodeOutput } from './decodeOutput'
1515
import { getAbiMessage } from './getAbiMessage'
16+
import { getBalance } from './getBalance'
1617
import { getMaxGasLimit } from './getGasLimit'
1718

1819
/**
@@ -68,8 +69,17 @@ export const contractQuery = async (
6869
export type ContractTxResult = {
6970
dryResult: ContractCallOutcome
7071
result?: ISubmittableResult
71-
errorMessage?: string | 'UserCancelled' | 'ExtrinsicFailed' | 'Error'
72+
errorMessage?:
73+
| string
74+
| 'UserCancelled'
75+
| 'ExtrinsicFailed'
76+
| 'TokenBelowMinimum'
77+
| 'Error'
7278
errorEvent?: EventRecord
79+
successEvent?: EventRecord
80+
extrinsicHash?: string
81+
extrinsicIndex?: number
82+
blockHash?: string
7383
}
7484
export const contractTx = async (
7585
api: ApiPromise,
@@ -80,6 +90,18 @@ export const contractTx = async (
8090
args = [] as unknown[],
8191
statusCb?: Callback<ISubmittableResult>,
8292
): Promise<ContractTxResult> => {
93+
// Check if account has sufficient balance
94+
const accountAddress = typeof account === 'string' ? account : account.address
95+
const { freeBalance } = await getBalance(api, accountAddress)
96+
const hasZeroBalance = !freeBalance || freeBalance.isZero()
97+
const hasBalanceBelowPassedValue =
98+
options?.value && freeBalance && freeBalance.lte(bnToBn(options.value))
99+
if (hasZeroBalance || hasBalanceBelowPassedValue) {
100+
return Promise.reject({
101+
errorMessage: 'TokenBelowMinimum',
102+
})
103+
}
104+
83105
// Dry run to determine required gas and potential errors
84106
delete options.gasLimit
85107
const dryResult = await contractCallDryRun(
@@ -155,10 +177,27 @@ export const contractTx = async (
155177
unsub?.()
156178
}
157179
})
158-
} catch (e) {
159-
console.error('Error while performing transaction:', e)
160-
// Assume transaction was cancelled by user
161-
reject({ errorMessage: 'UserCancelled' })
180+
} catch (e: any) {
181+
let errorMessage = 'Error'
182+
183+
if (e?.message?.match(/user reject request/i)) {
184+
errorMessage = 'UserCancelled'
185+
}
186+
187+
const errorText = e?.toString?.()
188+
const rpcErrorCode =
189+
errorText && typeof errorText === 'string'
190+
? errorText.match(/RpcError: (\d+):/i)?.[1]
191+
: null
192+
switch (rpcErrorCode) {
193+
case '1010':
194+
errorMessage = 'TokenBelowMinimum'
195+
break
196+
default:
197+
break
198+
}
199+
200+
reject({ errorMessage })
162201
}
163202
})
164203
}

src/helpers/decodeOutput.ts

+15
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,21 @@ export function decodeOutput(
7676
: JSON.stringify(output, null, '\t') ?? '()'
7777

7878
decodedOutput = isError ? errorText : okText
79+
} else if (result.isErr) {
80+
output = result.toHuman()
81+
82+
let errorText
83+
if (
84+
isErr(output) &&
85+
typeof output.Err === 'object' &&
86+
Object.keys(output.Err || {}).length &&
87+
typeof Object.values(output.Err || {})[0] === 'string'
88+
) {
89+
const [errorKey, errorValue] = Object.entries(output.Err || {})[0]
90+
errorText = `${errorKey}${errorValue}`
91+
}
92+
93+
decodedOutput = errorText || 'Error'
7994
}
8095

8196
return {

src/helpers/getBalance.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ export const getBalance = async (
1818
api: ApiPromise,
1919
address: string | AccountId | undefined,
2020
): Promise<BalanceData> => {
21-
const { tokenDecimals, tokenSymbol } = parseBalanceData(api)
2221
if (!address) {
22+
const { tokenDecimals, tokenSymbol } = parseBalanceData(api)
2323
return {
2424
tokenDecimals,
2525
tokenSymbol,

0 commit comments

Comments
 (0)