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
import { expect } from 'chai'
import { BigNumber } from '@ethersproject/bignumber'
import { sleep } from './misc'
interface deviationRanges {
percentUpperDeviation?: number
percentLowerDeviation?: number
absoluteUpperDeviation?: number
absoluteLowerDeviation?: number
}
export const awaitCondition = async (
cond: () => Promise<boolean>,
rate = 1000,
attempts = 10
) => {
for (let i = 0; i < attempts; i++) {
const ok = await cond()
if (ok) {
return
}
await sleep(rate)
}
throw new Error('Timed out.')
}
/**
* Assert that a number lies within a custom defined range of the target.
*/
export const expectApprox = (
actual: BigNumber | number,
target: BigNumber | number,
{
percentUpperDeviation,
percentLowerDeviation,
absoluteUpperDeviation,
absoluteLowerDeviation,
}: deviationRanges
): void => {
actual = BigNumber.from(actual)
target = BigNumber.from(target)
// Ensure at least one deviation parameter is defined
const nonNullDeviations =
percentUpperDeviation ||
percentLowerDeviation ||
absoluteUpperDeviation ||
absoluteLowerDeviation
if (!nonNullDeviations) {
throw new Error(
'Must define at least one parameter to limit the deviation of the actual value.'
)
}
// Upper bound calculation.
let upper: BigNumber
// Set the two possible upper bounds if and only if they are defined.
const upperPcnt: BigNumber = !percentUpperDeviation
? null
: target.mul(100 + percentUpperDeviation).div(100)
const upperAbs: BigNumber = !absoluteUpperDeviation
? null
: target.add(absoluteUpperDeviation)
if (upperPcnt && upperAbs) {
// If both are set, take the lesser of the two upper bounds.
upper = upperPcnt.lte(upperAbs) ? upperPcnt : upperAbs
} else {
// Else take whichever is not undefined or set to null.
upper = upperPcnt || upperAbs
}
// Lower bound calculation.
let lower: BigNumber
// Set the two possible lower bounds if and only if they are defined.
const lowerPcnt: BigNumber = !percentLowerDeviation
? null
: target.mul(100 - percentLowerDeviation).div(100)
const lowerAbs: BigNumber = !absoluteLowerDeviation
? null
: target.sub(absoluteLowerDeviation)
if (lowerPcnt && lowerAbs) {
// If both are set, take the greater of the two lower bounds.
lower = lowerPcnt.gte(lowerAbs) ? lowerPcnt : lowerAbs
} else {
// Else take whichever is not undefined or set to null.
lower = lowerPcnt || lowerAbs
}
// Apply the assertions if they are non-null.
if (upper) {
expect(
actual.lte(upper),
`Actual value (${actual}) is greater than the calculated upper bound of (${upper})`
).to.be.true
}
if (lower) {
expect(
actual.gte(lower),
`Actual value (${actual}) is less than the calculated lower bound of (${lower})`
).to.be.true
}
}