@mimicprotocol/lib-ts 0.0.1-rc.28 → 0.0.1-rc.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/README.md +1 -1
- package/package.json +1 -1
- package/src/environment.ts +84 -59
- package/src/helpers/strings.ts +39 -0
- package/src/queries/EvmCallQuery.ts +39 -0
- package/src/queries/QueryResponse.ts +15 -0
- package/src/queries/{GetRelevantTokens.ts → RelevantTokensQuery.ts} +19 -7
- package/src/queries/SubgraphQuery.ts +13 -1
- package/src/queries/SvmAccountsInfoQuery.ts +57 -0
- package/src/queries/TokenPriceQuery.ts +40 -0
- package/src/queries/index.ts +5 -4
- package/src/tokens/ERC20Token.ts +39 -10
- package/src/tokens/SPLToken.ts +43 -14
- package/src/tokens/TokenAmount.ts +14 -8
- package/src/tokens/USD.ts +8 -5
- package/src/types/Result.ts +56 -0
- package/src/types/index.ts +1 -0
- package/src/queries/Call.ts +0 -27
- package/src/queries/GetAccountsInfo.ts +0 -46
- package/src/queries/GetPrice.ts +0 -28
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# @mimicprotocol/lib-ts
|
|
2
2
|
|
|
3
|
+
## 0.0.1-rc.30
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 213f37f: Fix class names overlapping
|
|
8
|
+
|
|
9
|
+
## 0.0.1-rc.29
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 72bb607: Fix relevant tokens query price filter
|
|
14
|
+
- 52b567d: Align oracle types naming convention
|
|
15
|
+
- 73a9cde: Fix npx init
|
|
16
|
+
- 0a6602a: Handle oracle query errors
|
|
17
|
+
|
|
3
18
|
## 0.0.1-rc.28
|
|
4
19
|
|
|
5
20
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -57,7 +57,7 @@ import { environment, ERC20Token } from '@mimicprotocol/lib-ts'
|
|
|
57
57
|
|
|
58
58
|
const USDC = ERC20Token.fromString('0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', 1)
|
|
59
59
|
|
|
60
|
-
environment.
|
|
60
|
+
environment.tokenPriceQuery(USDC, new Date(1744818017000))
|
|
61
61
|
```
|
|
62
62
|
|
|
63
63
|
For full task development guide and examples please visit [docs.mimic.fi](https://docs.mimic.fi/)
|
package/package.json
CHANGED
package/src/environment.ts
CHANGED
|
@@ -4,20 +4,23 @@ import { Context, SerializableContext } from './context'
|
|
|
4
4
|
import { ListType } from './helpers'
|
|
5
5
|
import { Swap, Transfer, EvmCall, SvmCall } from './intents'
|
|
6
6
|
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
GetRelevantTokensResponse,
|
|
13
|
-
RelevantTokenBalance,
|
|
14
|
-
SerializableGetAccountsInfoResponse,
|
|
7
|
+
EvmCallQuery,
|
|
8
|
+
RelevantTokensQuery,
|
|
9
|
+
RelevantTokensQueryResult,
|
|
10
|
+
TokenBalanceQuery,
|
|
11
|
+
RelevantTokensQueryResponse,
|
|
15
12
|
SubgraphQuery,
|
|
13
|
+
SvmAccountsInfoQuery,
|
|
14
|
+
SvmAccountsInfoQueryResponse,
|
|
15
|
+
SvmAccountsInfoQueryResult,
|
|
16
|
+
SubgraphQueryResult,
|
|
17
|
+
TokenPriceQuery,
|
|
18
|
+
EvmCallQueryResponse,
|
|
16
19
|
SubgraphQueryResponse,
|
|
20
|
+
TokenPriceQueryResponse,
|
|
17
21
|
} from './queries'
|
|
18
22
|
import { BlockchainToken, Token, TokenAmount, USD } from './tokens'
|
|
19
|
-
import { Address, BigInt, ChainId } from './types'
|
|
20
|
-
import { log } from './log'
|
|
23
|
+
import { Address, BigInt, ChainId, Result } from './types'
|
|
21
24
|
|
|
22
25
|
export namespace environment {
|
|
23
26
|
@external('environment', '_evmCall')
|
|
@@ -32,20 +35,20 @@ export namespace environment {
|
|
|
32
35
|
@external('environment', '_transfer')
|
|
33
36
|
declare function _transfer(params: string): void
|
|
34
37
|
|
|
35
|
-
@external('environment', '
|
|
36
|
-
declare function
|
|
38
|
+
@external('environment', '_tokenPriceQuery')
|
|
39
|
+
declare function _tokenPriceQuery(params: string): string
|
|
37
40
|
|
|
38
|
-
@external('environment', '
|
|
39
|
-
declare function
|
|
41
|
+
@external('environment', '_relevantTokensQuery')
|
|
42
|
+
declare function _relevantTokensQuery(params: string): string
|
|
40
43
|
|
|
41
|
-
@external('environment', '
|
|
42
|
-
declare function
|
|
44
|
+
@external('environment', '_evmCallQuery')
|
|
45
|
+
declare function _evmCallQuery(params: string): string
|
|
43
46
|
|
|
44
47
|
@external('environment', '_subgraphQuery')
|
|
45
48
|
declare function _subgraphQuery(params: string): string
|
|
46
49
|
|
|
47
|
-
@external('environment', '
|
|
48
|
-
declare function
|
|
50
|
+
@external('environment', '_svmAccountsInfoQuery')
|
|
51
|
+
declare function _svmAccountsInfoQuery(params: string): string
|
|
49
52
|
|
|
50
53
|
@external('environment', '_getContext')
|
|
51
54
|
declare function _getContext(): string
|
|
@@ -86,36 +89,49 @@ export namespace environment {
|
|
|
86
89
|
* Tells the prices from different sources for a token in USD at a specific timestamp.
|
|
87
90
|
* @param token - The token to get the price of
|
|
88
91
|
* @param timestamp - The timestamp for price lookup (optional, defaults to current time)
|
|
89
|
-
* @returns
|
|
92
|
+
* @returns Result containing either an array of USD prices or an error string
|
|
90
93
|
*/
|
|
91
|
-
export function
|
|
92
|
-
if (token.isUSD()) return [USD.fromI32(1)]
|
|
93
|
-
else if (!(token instanceof BlockchainToken))
|
|
94
|
-
|
|
95
|
-
|
|
94
|
+
export function rawTokenPriceQuery(token: Token, timestamp: Date | null = null): Result<USD[], string> {
|
|
95
|
+
if (token.isUSD()) return Result.ok<USD[], string>([USD.fromI32(1)])
|
|
96
|
+
else if (!(token instanceof BlockchainToken)) return Result.err<USD[], string>('Price query not supported for token ' + token.toString())
|
|
97
|
+
|
|
98
|
+
const responseStr = _tokenPriceQuery(JSON.stringify(TokenPriceQuery.fromToken(changetype<BlockchainToken>(token), timestamp)))
|
|
99
|
+
const parsed = TokenPriceQueryResponse.fromJson<TokenPriceQueryResponse>(responseStr)
|
|
100
|
+
|
|
101
|
+
if (parsed.success !== 'true') return Result.err<USD[], string>(parsed.error.length > 0 ? parsed.error : 'Unknown error getting price')
|
|
102
|
+
|
|
103
|
+
const prices = parsed.data.map<USD>((price) => USD.fromBigInt(BigInt.fromString(price)))
|
|
104
|
+
return Result.ok<USD[], string>(prices)
|
|
96
105
|
}
|
|
97
106
|
|
|
98
107
|
/**
|
|
99
108
|
* Tells the median price from different sources for a token in USD at a specific timestamp.
|
|
100
109
|
* @param token - The token to get the price of
|
|
101
110
|
* @param timestamp - The timestamp for price lookup (optional, defaults to current time)
|
|
102
|
-
* @returns
|
|
111
|
+
* @returns Result containing either the median USD price or an error string
|
|
103
112
|
*/
|
|
104
|
-
export function
|
|
105
|
-
const
|
|
106
|
-
|
|
113
|
+
export function tokenPriceQuery(token: Token, timestamp: Date | null = null): Result<USD, string> {
|
|
114
|
+
const pricesResult = rawTokenPriceQuery(token, timestamp)
|
|
115
|
+
|
|
116
|
+
if (pricesResult.isError) return Result.err<USD, string>(pricesResult.error)
|
|
117
|
+
|
|
118
|
+
const prices = pricesResult.value
|
|
119
|
+
if (prices.length === 0) return Result.err<USD, string>('Prices not found for token ' + token.toString())
|
|
107
120
|
|
|
108
121
|
const sortedPrices = prices.sort((a: USD, b: USD) => a.compare(b))
|
|
109
122
|
|
|
110
123
|
const length = sortedPrices.length
|
|
124
|
+
let median: USD
|
|
111
125
|
if (length % 2 === 1) {
|
|
112
|
-
|
|
126
|
+
median = sortedPrices[length / 2]
|
|
113
127
|
} else {
|
|
114
128
|
const left = sortedPrices[length / 2 - 1]
|
|
115
129
|
const right = sortedPrices[length / 2]
|
|
116
130
|
const sum = left.plus(right)
|
|
117
|
-
|
|
131
|
+
median = sum.div(BigInt.fromI32(2))
|
|
118
132
|
}
|
|
133
|
+
|
|
134
|
+
return Result.ok<USD, string>(median)
|
|
119
135
|
}
|
|
120
136
|
|
|
121
137
|
/**
|
|
@@ -125,12 +141,16 @@ export namespace environment {
|
|
|
125
141
|
* @param usdMinAmount - Minimum USD value threshold for tokens (optional, defaults to zero)
|
|
126
142
|
* @param tokensList - List of blockchain tokens to include/exclude (optional, defaults to empty array)
|
|
127
143
|
* @param listType - Whether to include (AllowList) or exclude (DenyList) the tokens in `tokensList` (optional, defaults to DenyList)
|
|
128
|
-
* @returns
|
|
144
|
+
* @returns Result containing either an array of RelevantTokenBalance arrays or an error string
|
|
129
145
|
*/
|
|
130
|
-
export function
|
|
131
|
-
const responseStr =
|
|
132
|
-
const
|
|
133
|
-
|
|
146
|
+
export function rawRelevantTokensQuery(address: Address, chainIds: ChainId[], usdMinAmount: USD, tokensList: BlockchainToken[], listType: ListType): Result<TokenBalanceQuery[][], string> {
|
|
147
|
+
const responseStr = _relevantTokensQuery(JSON.stringify(RelevantTokensQuery.init(address, chainIds, usdMinAmount, tokensList, listType)))
|
|
148
|
+
const parsed = RelevantTokensQueryResponse.fromJson<RelevantTokensQueryResponse>(responseStr)
|
|
149
|
+
|
|
150
|
+
if (parsed.success !== 'true') return Result.err<TokenBalanceQuery[][], string>(parsed.error.length > 0 ? parsed.error : 'Unknown error getting relevant tokens')
|
|
151
|
+
|
|
152
|
+
const responses = parsed.data
|
|
153
|
+
return Result.ok<TokenBalanceQuery[][], string>(responses.map((response: RelevantTokensQueryResult) => response.balances))
|
|
134
154
|
}
|
|
135
155
|
|
|
136
156
|
/**
|
|
@@ -142,14 +162,18 @@ export namespace environment {
|
|
|
142
162
|
* @param listType - Whether to include (AllowList) or exclude (DenyList) the tokens in `tokensList` (optional, defaults to DenyList)
|
|
143
163
|
* @returns Array of TokenAmount objects representing the relevant tokens
|
|
144
164
|
*/
|
|
145
|
-
export function
|
|
165
|
+
export function relevantTokensQuery(
|
|
146
166
|
address: Address,
|
|
147
167
|
chainIds: ChainId[],
|
|
148
168
|
usdMinAmount: USD = USD.zero(),
|
|
149
169
|
tokensList: BlockchainToken[] = [],
|
|
150
170
|
listType: ListType = ListType.DenyList
|
|
151
|
-
): TokenAmount[] {
|
|
152
|
-
const
|
|
171
|
+
): Result<TokenAmount[], string> {
|
|
172
|
+
const responseResult = rawRelevantTokensQuery(address, chainIds, usdMinAmount, tokensList, listType)
|
|
173
|
+
|
|
174
|
+
if (responseResult.isError) return Result.err<TokenAmount[], string>(responseResult.error)
|
|
175
|
+
|
|
176
|
+
const response = responseResult.value
|
|
153
177
|
const resultMap: Map<string, TokenAmount> = new Map()
|
|
154
178
|
for (let i = 0; i < response.length; i++) {
|
|
155
179
|
for (let j = 0; j < response[i].length; j++) {
|
|
@@ -160,7 +184,8 @@ export namespace environment {
|
|
|
160
184
|
resultMap.set(mapKey, tokenAmount)
|
|
161
185
|
}
|
|
162
186
|
}
|
|
163
|
-
|
|
187
|
+
|
|
188
|
+
return Result.ok<TokenAmount[], string>(resultMap.values())
|
|
164
189
|
}
|
|
165
190
|
|
|
166
191
|
/**
|
|
@@ -171,15 +196,16 @@ export namespace environment {
|
|
|
171
196
|
* @param data - The encoded function call data
|
|
172
197
|
* @returns The raw response from the contract call
|
|
173
198
|
*/
|
|
174
|
-
export function
|
|
199
|
+
export function evmCallQuery(
|
|
175
200
|
to: Address,
|
|
176
201
|
chainId: ChainId,
|
|
177
202
|
data: string,
|
|
178
203
|
timestamp: Date | null = null,
|
|
179
|
-
): string {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
)
|
|
204
|
+
): Result<string, string> {
|
|
205
|
+
const responseStr = _evmCallQuery(JSON.stringify(EvmCallQuery.from(to, chainId, timestamp, data)))
|
|
206
|
+
const parsed = EvmCallQueryResponse.fromJson<EvmCallQueryResponse>(responseStr)
|
|
207
|
+
if (parsed.success !== 'true') return Result.err<string, string>(parsed.error.length > 0 ? parsed.error : 'Unknown error getting evm call')
|
|
208
|
+
return Result.ok<string, string>(parsed.data)
|
|
183
209
|
}
|
|
184
210
|
|
|
185
211
|
/**
|
|
@@ -195,31 +221,30 @@ export namespace environment {
|
|
|
195
221
|
subgraphId: string,
|
|
196
222
|
query: string,
|
|
197
223
|
timestamp: Date | null = null,
|
|
198
|
-
):
|
|
224
|
+
): Result<SubgraphQueryResult, string> {
|
|
199
225
|
const responseStr = _subgraphQuery(JSON.stringify(SubgraphQuery.from(chainId, subgraphId, query, timestamp)))
|
|
200
|
-
|
|
226
|
+
const parsed = SubgraphQueryResponse.fromJson<SubgraphQueryResponse>(responseStr)
|
|
227
|
+
if (parsed.success !== 'true') return Result.err<SubgraphQueryResult, string>(parsed.error.length > 0 ? parsed.error : 'Unknown error getting subgraph query')
|
|
228
|
+
return Result.ok<SubgraphQueryResult, string>(parsed.data)
|
|
201
229
|
}
|
|
202
230
|
|
|
203
231
|
/**
|
|
204
232
|
* SVM - Gets on-chain account info
|
|
205
233
|
* @param publicKeys - Accounts to read from chain
|
|
206
234
|
* @param timestamp - The timestamp for the call context (optional)
|
|
207
|
-
* @returns
|
|
235
|
+
* @returns Result containing either the account info result or an error string
|
|
208
236
|
*/
|
|
209
|
-
|
|
210
|
-
export function getAccountsInfo(
|
|
237
|
+
export function svmAccountsInfoQuery(
|
|
211
238
|
publicKeys: Address[],
|
|
212
239
|
timestamp: Date | null = null,
|
|
213
|
-
):
|
|
214
|
-
|
|
215
|
-
const
|
|
216
|
-
|
|
217
|
-
)
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
const response = JSON.parse<SerializableGetAccountsInfoResponse>(responseStr)
|
|
222
|
-
return GetAccountsInfoResponse.fromSerializable(response)
|
|
240
|
+
): Result<SvmAccountsInfoQueryResult, string> {
|
|
241
|
+
const responseStr = _svmAccountsInfoQuery(JSON.stringify(SvmAccountsInfoQuery.from(publicKeys, timestamp)))
|
|
242
|
+
const parsed = SvmAccountsInfoQueryResponse.fromJson<SvmAccountsInfoQueryResponse>(responseStr)
|
|
243
|
+
|
|
244
|
+
if (parsed.success !== 'true') return Result.err<SvmAccountsInfoQueryResult, string>(parsed.error.length > 0 ? parsed.error : 'Unknown error getting SVM accounts info')
|
|
245
|
+
|
|
246
|
+
const result = SvmAccountsInfoQueryResult.fromSerializable(parsed.data)
|
|
247
|
+
return Result.ok<SvmAccountsInfoQueryResult, string>(result)
|
|
223
248
|
}
|
|
224
249
|
|
|
225
250
|
/**
|
package/src/helpers/strings.ts
CHANGED
|
@@ -26,6 +26,45 @@ export function stringToBool(str: string): bool {
|
|
|
26
26
|
return str === 'true'
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Workaround for json-as boolean bug:
|
|
31
|
+
* Converts JSON boolean values (true/false) into their string equivalents ("true"/"false")
|
|
32
|
+
* without touching occurrences inside JSON strings or keys.
|
|
33
|
+
*
|
|
34
|
+
* This function assumes compact JSON (no newlines between the boolean and the delimiter).
|
|
35
|
+
*/
|
|
36
|
+
export function replaceJsonBooleans(json: string): string {
|
|
37
|
+
return (
|
|
38
|
+
json
|
|
39
|
+
// true after ':' (object property values)
|
|
40
|
+
.replaceAll(':true', ':"true"')
|
|
41
|
+
.replaceAll(':true,', ':"true",')
|
|
42
|
+
.replaceAll(':true}', ':"true"}')
|
|
43
|
+
.replaceAll(':true]', ':"true"]')
|
|
44
|
+
.replaceAll(': true,', ': "true",')
|
|
45
|
+
.replaceAll(': true}', ': "true"}')
|
|
46
|
+
.replaceAll(': true]', ': "true"]')
|
|
47
|
+
// true in arrays
|
|
48
|
+
.replaceAll('[true,', '["true",')
|
|
49
|
+
.replaceAll('[true]', '["true"]')
|
|
50
|
+
.replaceAll(',true,', ',"true",')
|
|
51
|
+
.replaceAll(',true]', ',"true"]')
|
|
52
|
+
// false after ':' (object property values)
|
|
53
|
+
.replaceAll(':false', ':"false"')
|
|
54
|
+
.replaceAll(':false,', ':"false",')
|
|
55
|
+
.replaceAll(':false}', ':"false"}')
|
|
56
|
+
.replaceAll(':false]', ':"false"]')
|
|
57
|
+
.replaceAll(': false,', ': "false",')
|
|
58
|
+
.replaceAll(': false}', ': "false"}')
|
|
59
|
+
.replaceAll(': false]', ': "false"]')
|
|
60
|
+
// false in arrays
|
|
61
|
+
.replaceAll('[false,', '["false",')
|
|
62
|
+
.replaceAll('[false]', '["false"]')
|
|
63
|
+
.replaceAll(',false,', ',"false",')
|
|
64
|
+
.replaceAll(',false]', ',"false"]')
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
|
|
29
68
|
export function areAllZeros(str: string): boolean {
|
|
30
69
|
for (let i = 0; i < str.length; i++) if (str.charCodeAt(i) !== 48) return false
|
|
31
70
|
return true
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Address, ChainId } from '../types'
|
|
2
|
+
|
|
3
|
+
import { QueryResponseBase } from './QueryResponse'
|
|
4
|
+
|
|
5
|
+
@json
|
|
6
|
+
class EvmCallQueryBase {
|
|
7
|
+
constructor(
|
|
8
|
+
public readonly to: string,
|
|
9
|
+
public readonly chainId: ChainId,
|
|
10
|
+
public readonly data: string
|
|
11
|
+
) {}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
@json
|
|
15
|
+
export class EvmCallQuery extends EvmCallQueryBase {
|
|
16
|
+
public readonly timestamp: i64
|
|
17
|
+
|
|
18
|
+
constructor(to: string, chainId: ChainId, timestamp: i64, data: string) {
|
|
19
|
+
super(to, chainId, data)
|
|
20
|
+
this.timestamp = timestamp
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
static from(to: Address, chainId: ChainId, timestamp: Date | null, data: string): EvmCallQueryBase {
|
|
24
|
+
const address = to.toString()
|
|
25
|
+
return timestamp
|
|
26
|
+
? new EvmCallQuery(address, chainId, changetype<Date>(timestamp).getTime(), data)
|
|
27
|
+
: new EvmCallQueryBase(address, chainId, data)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@json
|
|
32
|
+
export class EvmCallQueryResponse extends QueryResponseBase {
|
|
33
|
+
public data: string
|
|
34
|
+
|
|
35
|
+
constructor(success: string, data: string, error: string) {
|
|
36
|
+
super(success, error)
|
|
37
|
+
this.data = data
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { JSON } from 'json-as'
|
|
2
|
+
|
|
3
|
+
import { replaceJsonBooleans } from '../helpers'
|
|
4
|
+
|
|
5
|
+
@json
|
|
6
|
+
export class QueryResponseBase {
|
|
7
|
+
constructor(
|
|
8
|
+
public success: string, // boolean as string due to json-as bug
|
|
9
|
+
public error: string
|
|
10
|
+
) {}
|
|
11
|
+
|
|
12
|
+
static fromJson<T extends QueryResponseBase>(json: string): T {
|
|
13
|
+
return JSON.parse<T>(replaceJsonBooleans(json))
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -2,6 +2,8 @@ import { ListType } from '../helpers'
|
|
|
2
2
|
import { BlockchainToken, TokenAmount, USD } from '../tokens'
|
|
3
3
|
import { Address, BigInt, ChainId } from '../types'
|
|
4
4
|
|
|
5
|
+
import { QueryResponseBase } from './QueryResponse'
|
|
6
|
+
|
|
5
7
|
@json
|
|
6
8
|
class TokenQuery {
|
|
7
9
|
constructor(
|
|
@@ -15,7 +17,7 @@ class TokenQuery {
|
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
@json
|
|
18
|
-
export class
|
|
20
|
+
export class RelevantTokensQuery {
|
|
19
21
|
constructor(
|
|
20
22
|
public readonly owner: string,
|
|
21
23
|
public readonly chainIds: ChainId[],
|
|
@@ -30,16 +32,16 @@ export class GetRelevantTokens {
|
|
|
30
32
|
usdMinAmount: USD,
|
|
31
33
|
tokens: BlockchainToken[],
|
|
32
34
|
tokenFilter: ListType
|
|
33
|
-
):
|
|
35
|
+
): RelevantTokensQuery {
|
|
34
36
|
const ownerStr = owner.toString()
|
|
35
|
-
const usdMinAmountStr = usdMinAmount.toString()
|
|
37
|
+
const usdMinAmountStr = usdMinAmount.value.toString()
|
|
36
38
|
const tokensQueries = tokens.map<TokenQuery>((token) => TokenQuery.fromToken(token))
|
|
37
|
-
return new
|
|
39
|
+
return new RelevantTokensQuery(ownerStr, chainIds, usdMinAmountStr, tokensQueries, tokenFilter)
|
|
38
40
|
}
|
|
39
41
|
}
|
|
40
42
|
|
|
41
43
|
@json
|
|
42
|
-
export class
|
|
44
|
+
export class TokenBalanceQuery {
|
|
43
45
|
constructor(
|
|
44
46
|
public token: TokenQuery,
|
|
45
47
|
public balance: string
|
|
@@ -54,9 +56,19 @@ export class RelevantTokenBalance {
|
|
|
54
56
|
}
|
|
55
57
|
|
|
56
58
|
@json
|
|
57
|
-
export class
|
|
59
|
+
export class RelevantTokensQueryResult {
|
|
58
60
|
constructor(
|
|
59
61
|
public timestamp: i64,
|
|
60
|
-
public balances:
|
|
62
|
+
public balances: TokenBalanceQuery[]
|
|
61
63
|
) {}
|
|
62
64
|
}
|
|
65
|
+
|
|
66
|
+
@json
|
|
67
|
+
export class RelevantTokensQueryResponse extends QueryResponseBase {
|
|
68
|
+
public data: RelevantTokensQueryResult[]
|
|
69
|
+
|
|
70
|
+
constructor(success: string, data: RelevantTokensQueryResult[], error: string) {
|
|
71
|
+
super(success, error)
|
|
72
|
+
this.data = data
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { ChainId } from '../types'
|
|
2
2
|
|
|
3
|
+
import { QueryResponseBase } from './QueryResponse'
|
|
4
|
+
|
|
3
5
|
@json
|
|
4
6
|
class SubgraphQueryBase {
|
|
5
7
|
constructor(
|
|
@@ -26,9 +28,19 @@ export class SubgraphQuery extends SubgraphQueryBase {
|
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
@json
|
|
29
|
-
export class
|
|
31
|
+
export class SubgraphQueryResult {
|
|
30
32
|
constructor(
|
|
31
33
|
public blockNumber: i64,
|
|
32
34
|
public data: string
|
|
33
35
|
) {}
|
|
34
36
|
}
|
|
37
|
+
|
|
38
|
+
@json
|
|
39
|
+
export class SubgraphQueryResponse extends QueryResponseBase {
|
|
40
|
+
public data: SubgraphQueryResult
|
|
41
|
+
|
|
42
|
+
constructor(success: string, data: SubgraphQueryResult, error: string) {
|
|
43
|
+
super(success, error)
|
|
44
|
+
this.data = data
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Address, SerializableSvmAccountInfo, SvmAccountInfo } from '../types'
|
|
2
|
+
|
|
3
|
+
import { QueryResponseBase } from './QueryResponse'
|
|
4
|
+
|
|
5
|
+
@json
|
|
6
|
+
class SvmAccountsInfoQueryBase {
|
|
7
|
+
constructor(public readonly publicKeys: string[]) {}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
@json
|
|
11
|
+
export class SvmAccountsInfoQuery extends SvmAccountsInfoQueryBase {
|
|
12
|
+
public readonly timestamp: i64
|
|
13
|
+
|
|
14
|
+
constructor(publicKeys: string[], timestamp: i64) {
|
|
15
|
+
super(publicKeys)
|
|
16
|
+
this.timestamp = timestamp
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
static from(publicKeys: Address[], timestamp: Date | null): SvmAccountsInfoQueryBase {
|
|
20
|
+
const strPublicKeys = publicKeys.map((pk: Address) => pk.toString())
|
|
21
|
+
return timestamp
|
|
22
|
+
? new SvmAccountsInfoQuery(strPublicKeys, changetype<Date>(timestamp).getTime())
|
|
23
|
+
: new SvmAccountsInfoQueryBase(strPublicKeys)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@json
|
|
28
|
+
export class SerializableSvmAccountsInfoQueryResult {
|
|
29
|
+
constructor(
|
|
30
|
+
public accountsInfo: SerializableSvmAccountInfo[],
|
|
31
|
+
public slot: string
|
|
32
|
+
) {}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export class SvmAccountsInfoQueryResult {
|
|
36
|
+
constructor(
|
|
37
|
+
public accountsInfo: SvmAccountInfo[],
|
|
38
|
+
public slot: string
|
|
39
|
+
) {}
|
|
40
|
+
|
|
41
|
+
static fromSerializable(serializable: SerializableSvmAccountsInfoQueryResult): SvmAccountsInfoQueryResult {
|
|
42
|
+
return new SvmAccountsInfoQueryResult(
|
|
43
|
+
serializable.accountsInfo.map((acc: SerializableSvmAccountInfo) => SvmAccountInfo.fromSerializable(acc)),
|
|
44
|
+
serializable.slot
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@json
|
|
50
|
+
export class SvmAccountsInfoQueryResponse extends QueryResponseBase {
|
|
51
|
+
public data: SerializableSvmAccountsInfoQueryResult
|
|
52
|
+
|
|
53
|
+
constructor(success: string, data: SerializableSvmAccountsInfoQueryResult, error: string) {
|
|
54
|
+
super(success, error)
|
|
55
|
+
this.data = data
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { BlockchainToken } from '../tokens'
|
|
2
|
+
|
|
3
|
+
import { QueryResponseBase } from './QueryResponse'
|
|
4
|
+
|
|
5
|
+
@json
|
|
6
|
+
class TokenPriceQueryBase {
|
|
7
|
+
constructor(
|
|
8
|
+
public readonly address: string,
|
|
9
|
+
public readonly chainId: i32
|
|
10
|
+
) {}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
@json
|
|
14
|
+
export class TokenPriceQuery extends TokenPriceQueryBase {
|
|
15
|
+
public readonly timestamp: i64
|
|
16
|
+
|
|
17
|
+
constructor(address: string, chainId: i32, timestamp: i64) {
|
|
18
|
+
super(address, chainId)
|
|
19
|
+
this.timestamp = timestamp
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
static fromToken(token: BlockchainToken, timestamp: Date | null): TokenPriceQueryBase {
|
|
23
|
+
const address = token.address.toString()
|
|
24
|
+
const chainId = token.chainId
|
|
25
|
+
|
|
26
|
+
return timestamp
|
|
27
|
+
? new TokenPriceQuery(address, chainId, changetype<Date>(timestamp).getTime())
|
|
28
|
+
: new TokenPriceQueryBase(address, chainId)
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@json
|
|
33
|
+
export class TokenPriceQueryResponse extends QueryResponseBase {
|
|
34
|
+
public data: string[]
|
|
35
|
+
|
|
36
|
+
constructor(success: string, data: string[], error: string) {
|
|
37
|
+
super(success, error)
|
|
38
|
+
this.data = data
|
|
39
|
+
}
|
|
40
|
+
}
|
package/src/queries/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
export * from './
|
|
2
|
-
export * from './
|
|
3
|
-
export * from './
|
|
4
|
-
export * from './GetRelevantTokens'
|
|
1
|
+
export * from './EvmCallQuery'
|
|
2
|
+
export * from './QueryResponse'
|
|
3
|
+
export * from './RelevantTokensQuery'
|
|
5
4
|
export * from './SubgraphQuery'
|
|
5
|
+
export * from './SvmAccountsInfoQuery'
|
|
6
|
+
export * from './TokenPriceQuery'
|
package/src/tokens/ERC20Token.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { environment } from '../environment'
|
|
2
2
|
import { evm } from '../evm'
|
|
3
3
|
import { EVM_NATIVE_ADDRESS } from '../helpers'
|
|
4
|
+
import { log } from '../log'
|
|
4
5
|
import { Address, ChainId, EvmDecodeParam } from '../types'
|
|
5
6
|
|
|
6
7
|
import { BlockchainToken } from './BlockchainToken'
|
|
@@ -110,30 +111,24 @@ export class ERC20Token extends BlockchainToken {
|
|
|
110
111
|
/**
|
|
111
112
|
* Gets the token’s symbol (e.g., "ETH", "USDC").
|
|
112
113
|
* If the symbol was not provided during construction, it will be lazily fetched
|
|
113
|
-
* via a `
|
|
114
|
+
* via a `evmCallQuery` to the token’s `symbol()` function (ERC-20 standard, selector `0x95d89b41`).
|
|
114
115
|
* The fetched symbol is cached in the instance for future accesses.
|
|
115
116
|
* @returns A string containing the token symbol.
|
|
116
117
|
*/
|
|
117
118
|
get symbol(): string {
|
|
118
|
-
if (this._symbol === ERC20Token.EMPTY_SYMBOL)
|
|
119
|
-
const response = environment.contractCall(this.address, this.chainId, '0x95d89b41', this._timestamp)
|
|
120
|
-
this._symbol = evm.decode(new EvmDecodeParam('string', response))
|
|
121
|
-
}
|
|
119
|
+
if (this._symbol === ERC20Token.EMPTY_SYMBOL) this._getSymbol()
|
|
122
120
|
return this._symbol
|
|
123
121
|
}
|
|
124
122
|
|
|
125
123
|
/**
|
|
126
124
|
* Gets the token’s decimals (number of decimal places used).
|
|
127
125
|
* If decimals were not provided during construction, they will be lazily fetched
|
|
128
|
-
* via a `
|
|
126
|
+
* via a `evmCallQuery` to the token’s `decimals()` function (ERC-20 standard, selector `0x313ce567`).
|
|
129
127
|
* The fetched value is parsed to `u8` and cached for future accesses.
|
|
130
128
|
* @returns A `u8` representing the number of decimals of the token.
|
|
131
129
|
*/
|
|
132
130
|
get decimals(): u8 {
|
|
133
|
-
if (this._decimals == ERC20Token.EMPTY_DECIMALS)
|
|
134
|
-
const result = environment.contractCall(this.address, this.chainId, '0x313ce567', this._timestamp)
|
|
135
|
-
this._decimals = u8.parse(evm.decode(new EvmDecodeParam('uint8', result)))
|
|
136
|
-
}
|
|
131
|
+
if (this._decimals == ERC20Token.EMPTY_DECIMALS) this._getDecimals()
|
|
137
132
|
return this._decimals
|
|
138
133
|
}
|
|
139
134
|
|
|
@@ -154,4 +149,38 @@ export class ERC20Token extends BlockchainToken {
|
|
|
154
149
|
isNative(): boolean {
|
|
155
150
|
return this.equals(ERC20Token.native(this.chainId))
|
|
156
151
|
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Internal method to fetch and cache the token symbol.
|
|
155
|
+
* Performs an EVM call query to the token's symbol() function.
|
|
156
|
+
* @private
|
|
157
|
+
*/
|
|
158
|
+
private _getSymbol(): void {
|
|
159
|
+
const response = environment.evmCallQuery(this.address, this.chainId, '0x95d89b41', this._timestamp)
|
|
160
|
+
if (response.isError) {
|
|
161
|
+
log.warning(
|
|
162
|
+
`Failed to get symbol for token ${this.address.toString()} on chain ${this.chainId.toString()}: ${response.error}`
|
|
163
|
+
)
|
|
164
|
+
this._symbol = ERC20Token.EMPTY_SYMBOL
|
|
165
|
+
return
|
|
166
|
+
}
|
|
167
|
+
this._symbol = evm.decode(new EvmDecodeParam('string', response.value))
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Internal method to fetch and cache the token decimals.
|
|
172
|
+
* Performs an EVM call query to the token's decimals() function.
|
|
173
|
+
* @private
|
|
174
|
+
*/
|
|
175
|
+
private _getDecimals(): void {
|
|
176
|
+
const result = environment.evmCallQuery(this.address, this.chainId, '0x313ce567', this._timestamp)
|
|
177
|
+
if (result.isError) {
|
|
178
|
+
log.warning(
|
|
179
|
+
`Failed to get decimals for token ${this.address.toString()} on chain ${this.chainId.toString()}: ${result.error}`
|
|
180
|
+
)
|
|
181
|
+
this._decimals = ERC20Token.EMPTY_DECIMALS
|
|
182
|
+
return
|
|
183
|
+
}
|
|
184
|
+
this._decimals = u8.parse(evm.decode(new EvmDecodeParam('uint8', result.value)))
|
|
185
|
+
}
|
|
157
186
|
}
|
package/src/tokens/SPLToken.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { environment } from '../environment'
|
|
2
2
|
import { SVM_NATIVE_ADDRESS } from '../helpers'
|
|
3
|
+
import { log } from '../log'
|
|
3
4
|
import { svm } from '../svm'
|
|
4
5
|
import { Address, ChainId, SvmMint, SvmPdaSeed, SvmTokenMetadataData } from '../types'
|
|
5
6
|
|
|
@@ -71,11 +72,7 @@ export class SPLToken extends BlockchainToken {
|
|
|
71
72
|
* @returns A `u8` representing the number of decimals of the token.
|
|
72
73
|
*/
|
|
73
74
|
get decimals(): u8 {
|
|
74
|
-
if (this._decimals == SPLToken.EMPTY_DECIMALS)
|
|
75
|
-
const result = environment.getAccountsInfo([this.address])
|
|
76
|
-
const decimals = SvmMint.fromHex(result.accountsInfo[0].data).decimals
|
|
77
|
-
this._decimals = decimals
|
|
78
|
-
}
|
|
75
|
+
if (this._decimals == SPLToken.EMPTY_DECIMALS) this._getDecimals()
|
|
79
76
|
return this._decimals
|
|
80
77
|
}
|
|
81
78
|
|
|
@@ -87,18 +84,50 @@ export class SPLToken extends BlockchainToken {
|
|
|
87
84
|
* @returns A string containing the token symbol.
|
|
88
85
|
*/
|
|
89
86
|
get symbol(): string {
|
|
90
|
-
if (this._symbol == SPLToken.EMPTY_SYMBOL)
|
|
91
|
-
const result = environment.getAccountsInfo([this.getMetadataAddress()])
|
|
92
|
-
const data = result.accountsInfo[0].data
|
|
93
|
-
// Return placeholder symbol from address if TokenMetadata standard is not used
|
|
94
|
-
this._symbol =
|
|
95
|
-
data === '0x'
|
|
96
|
-
? `${this.address.toString().slice(0, 5)}...${this.address.toString().slice(-5)}`
|
|
97
|
-
: SvmTokenMetadataData.fromTokenMetadataHex(result.accountsInfo[0].data).symbol
|
|
98
|
-
}
|
|
87
|
+
if (this._symbol == SPLToken.EMPTY_SYMBOL) this._getSymbol()
|
|
99
88
|
return this._symbol
|
|
100
89
|
}
|
|
101
90
|
|
|
91
|
+
/**
|
|
92
|
+
* Internal method to fetch and cache the token decimals.
|
|
93
|
+
* Performs an SVM accounts info query to get the mint data.
|
|
94
|
+
* @private
|
|
95
|
+
*/
|
|
96
|
+
private _getDecimals(): void {
|
|
97
|
+
const result = environment.svmAccountsInfoQuery([this.address])
|
|
98
|
+
if (result.isError) {
|
|
99
|
+
log.warning(
|
|
100
|
+
`Failed to get decimals for token ${this.address.toString()} on chain ${this.chainId.toString()}: ${result.error}`
|
|
101
|
+
)
|
|
102
|
+
this._decimals = SPLToken.EMPTY_DECIMALS
|
|
103
|
+
return
|
|
104
|
+
}
|
|
105
|
+
const decimals = SvmMint.fromHex(result.value.accountsInfo[0].data).decimals
|
|
106
|
+
this._decimals = decimals
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Internal method to fetch and cache the token symbol.
|
|
111
|
+
* Performs an SVM accounts info query to get the token metadata.
|
|
112
|
+
* @private
|
|
113
|
+
*/
|
|
114
|
+
private _getSymbol(): void {
|
|
115
|
+
const result = environment.svmAccountsInfoQuery([this.getMetadataAddress()])
|
|
116
|
+
if (result.isError) {
|
|
117
|
+
log.warning(
|
|
118
|
+
`Failed to get symbol for token ${this.address.toString()} on chain ${this.chainId.toString()}: ${result.error}`
|
|
119
|
+
)
|
|
120
|
+
this._symbol = SPLToken.EMPTY_SYMBOL
|
|
121
|
+
return
|
|
122
|
+
}
|
|
123
|
+
const data = result.value.accountsInfo[0].data
|
|
124
|
+
// Return placeholder symbol from address if TokenMetadata standard is not used
|
|
125
|
+
this._symbol =
|
|
126
|
+
data === '0x'
|
|
127
|
+
? `${this.address.toString().slice(0, 5)}...${this.address.toString().slice(-5)}`
|
|
128
|
+
: SvmTokenMetadataData.fromTokenMetadataHex(result.value.accountsInfo[0].data).symbol
|
|
129
|
+
}
|
|
130
|
+
|
|
102
131
|
/**
|
|
103
132
|
* Derives Metaplex Metadata address for this given token
|
|
104
133
|
*/
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { environment } from '../environment'
|
|
2
|
-
import { BigInt, JSON } from '../types'
|
|
2
|
+
import { BigInt, JSON, Result } from '../types'
|
|
3
3
|
|
|
4
4
|
import { BlockchainToken } from './BlockchainToken'
|
|
5
5
|
import { SerializableToken, Token } from './Token'
|
|
@@ -217,11 +217,14 @@ export class TokenAmount {
|
|
|
217
217
|
* Converts this TokenAmount to its USD equivalent.
|
|
218
218
|
* @returns A USD instance representing the current USD value
|
|
219
219
|
*/
|
|
220
|
-
toUsd(): USD {
|
|
221
|
-
if (this.isZero()) return USD.zero()
|
|
222
|
-
const
|
|
220
|
+
toUsd(): Result<USD, string> {
|
|
221
|
+
if (this.isZero()) return Result.ok<USD, string>(USD.zero())
|
|
222
|
+
const tokenPriceResult = environment.tokenPriceQuery(this.token)
|
|
223
|
+
if (tokenPriceResult.isError) return Result.err<USD, string>(tokenPriceResult.error)
|
|
224
|
+
|
|
225
|
+
const tokenPrice = tokenPriceResult.value
|
|
223
226
|
const amountUsd = this.amount.times(tokenPrice.value).downscale(this.decimals)
|
|
224
|
-
return USD.fromBigInt(amountUsd)
|
|
227
|
+
return Result.ok<USD, string>(USD.fromBigInt(amountUsd))
|
|
225
228
|
}
|
|
226
229
|
|
|
227
230
|
/**
|
|
@@ -229,9 +232,12 @@ export class TokenAmount {
|
|
|
229
232
|
* @param other - The target token to convert to
|
|
230
233
|
* @returns A TokenAmount of the target token with equivalent USD value
|
|
231
234
|
*/
|
|
232
|
-
toTokenAmount(other: Token): TokenAmount {
|
|
233
|
-
if (this.isZero()) return TokenAmount.fromI32(other, 0)
|
|
234
|
-
|
|
235
|
+
toTokenAmount(other: Token): Result<TokenAmount, string> {
|
|
236
|
+
if (this.isZero()) return Result.ok<TokenAmount, string>(TokenAmount.fromI32(other, 0))
|
|
237
|
+
const usdResult = this.toUsd()
|
|
238
|
+
if (usdResult.isError) return Result.err<TokenAmount, string>(usdResult.error)
|
|
239
|
+
|
|
240
|
+
return usdResult.value.toTokenAmount(other)
|
|
235
241
|
}
|
|
236
242
|
|
|
237
243
|
/**
|
package/src/tokens/USD.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { environment } from '../environment'
|
|
2
2
|
import { STANDARD_DECIMALS } from '../helpers'
|
|
3
3
|
import { Token, TokenAmount } from '../tokens'
|
|
4
|
-
import { BigInt } from '../types'
|
|
4
|
+
import { BigInt, Result } from '../types'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Represents a USD amount with fixed decimal precision.
|
|
@@ -192,10 +192,13 @@ export class USD {
|
|
|
192
192
|
* @param token - The target token to convert to
|
|
193
193
|
* @returns A TokenAmount representing the equivalent value in the target token
|
|
194
194
|
*/
|
|
195
|
-
toTokenAmount(token: Token): TokenAmount {
|
|
196
|
-
if (this.isZero()) return TokenAmount.fromI32(token, 0)
|
|
197
|
-
const
|
|
195
|
+
toTokenAmount(token: Token): Result<TokenAmount, string> {
|
|
196
|
+
if (this.isZero()) return Result.ok<TokenAmount, string>(TokenAmount.fromI32(token, 0))
|
|
197
|
+
const tokenPriceResult = environment.tokenPriceQuery(token)
|
|
198
|
+
if (tokenPriceResult.isError) return Result.err<TokenAmount, string>(tokenPriceResult.error)
|
|
199
|
+
|
|
200
|
+
const tokenPrice = tokenPriceResult.value
|
|
198
201
|
const tokenAmount = this.value.upscale(token.decimals).div(tokenPrice.value)
|
|
199
|
-
return TokenAmount.fromBigInt(token, tokenAmount)
|
|
202
|
+
return Result.ok<TokenAmount, string>(TokenAmount.fromBigInt(token, tokenAmount))
|
|
200
203
|
}
|
|
201
204
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// eslint-disable-next-line no-secrets/no-secrets
|
|
2
|
+
// This file is based on code from "The Graph Tooling" (https://github.com/graphprotocol/graph-tooling/tree/7faa3098b2e6c61f09fc81b8b2d333e66b0080d1).
|
|
3
|
+
// Licensed under the MIT License.
|
|
4
|
+
// Copyright (c) 2018 Graph Protocol, Inc. and contributors.
|
|
5
|
+
// Modified by Mimic Protocol, 2025.
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The result of an operation, with a corresponding value and error type.
|
|
9
|
+
*/
|
|
10
|
+
export class Result<V, E> {
|
|
11
|
+
constructor(
|
|
12
|
+
private _value: Wrapped<V> | null,
|
|
13
|
+
private _error: Wrapped<E> | null
|
|
14
|
+
) {}
|
|
15
|
+
|
|
16
|
+
static ok<V, E>(value: V): Result<V, E> {
|
|
17
|
+
return new Result<V, E>(new Wrapped<V>(value), null)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
static err<V, E>(error: E): Result<V, E> {
|
|
21
|
+
return new Result<V, E>(null, new Wrapped<E>(error))
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
get isOk(): boolean {
|
|
25
|
+
return this._value !== null
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
get isError(): boolean {
|
|
29
|
+
return this._error !== null
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
get value(): V {
|
|
33
|
+
if (this.isError) throw new Error('Trying to get a value from an error result')
|
|
34
|
+
return changetype<Wrapped<V>>(this._value).inner
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
get error(): E {
|
|
38
|
+
if (this.isOk) throw new Error('Trying to get an error from a successful result')
|
|
39
|
+
return changetype<Wrapped<E>>(this._error).inner
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// This is used to wrap a generic so that it can be unioned with `null`, working around limitations
|
|
44
|
+
// with primitives.
|
|
45
|
+
export class Wrapped<T> {
|
|
46
|
+
inner: T
|
|
47
|
+
|
|
48
|
+
constructor(inner: T) {
|
|
49
|
+
this.inner = inner
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// This is used to represent a void return type
|
|
54
|
+
export class Void {
|
|
55
|
+
constructor() {}
|
|
56
|
+
}
|
package/src/types/index.ts
CHANGED
package/src/queries/Call.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { Address, ChainId } from '../types'
|
|
2
|
-
|
|
3
|
-
@json
|
|
4
|
-
class CallBase {
|
|
5
|
-
constructor(
|
|
6
|
-
public readonly to: string,
|
|
7
|
-
public readonly chainId: ChainId,
|
|
8
|
-
public readonly data: string
|
|
9
|
-
) {}
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
@json
|
|
13
|
-
export class Call extends CallBase {
|
|
14
|
-
public readonly timestamp: i64
|
|
15
|
-
|
|
16
|
-
constructor(to: string, chainId: ChainId, timestamp: i64, data: string) {
|
|
17
|
-
super(to, chainId, data)
|
|
18
|
-
this.timestamp = timestamp
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
static from(to: Address, chainId: ChainId, timestamp: Date | null, data: string): CallBase {
|
|
22
|
-
const address = to.toString()
|
|
23
|
-
return timestamp
|
|
24
|
-
? new Call(address, chainId, changetype<Date>(timestamp).getTime(), data)
|
|
25
|
-
: new CallBase(address, chainId, data)
|
|
26
|
-
}
|
|
27
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { Address, SerializableSvmAccountInfo, SvmAccountInfo } from '../types'
|
|
2
|
-
|
|
3
|
-
@json
|
|
4
|
-
class GetAccountsInfoBase {
|
|
5
|
-
constructor(public readonly publicKeys: string[]) {}
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
@json
|
|
9
|
-
export class GetAccountsInfo extends GetAccountsInfoBase {
|
|
10
|
-
public readonly timestamp: i64
|
|
11
|
-
|
|
12
|
-
constructor(publicKeys: string[], timestamp: i64) {
|
|
13
|
-
super(publicKeys)
|
|
14
|
-
this.timestamp = timestamp
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
static from(publicKeys: Address[], timestamp: Date | null): GetAccountsInfoBase {
|
|
18
|
-
const strPublicKeys = publicKeys.map((pk: Address) => pk.toString())
|
|
19
|
-
return timestamp
|
|
20
|
-
? new GetAccountsInfo(strPublicKeys, changetype<Date>(timestamp).getTime())
|
|
21
|
-
: new GetAccountsInfoBase(strPublicKeys)
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// There is a bug with json-as, so this can't be parsed directly
|
|
26
|
-
export class GetAccountsInfoResponse {
|
|
27
|
-
constructor(
|
|
28
|
-
public accountsInfo: SvmAccountInfo[],
|
|
29
|
-
public slot: string
|
|
30
|
-
) {}
|
|
31
|
-
|
|
32
|
-
static fromSerializable(serializable: SerializableGetAccountsInfoResponse): GetAccountsInfoResponse {
|
|
33
|
-
return new GetAccountsInfoResponse(
|
|
34
|
-
serializable.accountsInfo.map((acc: SerializableSvmAccountInfo) => SvmAccountInfo.fromSerializable(acc)),
|
|
35
|
-
serializable.slot
|
|
36
|
-
)
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
@json
|
|
41
|
-
export class SerializableGetAccountsInfoResponse {
|
|
42
|
-
constructor(
|
|
43
|
-
public accountsInfo: SerializableSvmAccountInfo[],
|
|
44
|
-
public slot: string
|
|
45
|
-
) {}
|
|
46
|
-
}
|
package/src/queries/GetPrice.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { BlockchainToken } from '../tokens'
|
|
2
|
-
|
|
3
|
-
@json
|
|
4
|
-
class GetPriceBase {
|
|
5
|
-
constructor(
|
|
6
|
-
public readonly address: string,
|
|
7
|
-
public readonly chainId: i32
|
|
8
|
-
) {}
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
@json
|
|
12
|
-
export class GetPrice extends GetPriceBase {
|
|
13
|
-
public readonly timestamp: i64
|
|
14
|
-
|
|
15
|
-
constructor(address: string, chainId: i32, timestamp: i64) {
|
|
16
|
-
super(address, chainId)
|
|
17
|
-
this.timestamp = timestamp
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
static fromToken(token: BlockchainToken, timestamp: Date | null): GetPriceBase {
|
|
21
|
-
const address = token.address.toString()
|
|
22
|
-
const chainId = token.chainId
|
|
23
|
-
|
|
24
|
-
return timestamp
|
|
25
|
-
? new GetPrice(address, chainId, changetype<Date>(timestamp).getTime())
|
|
26
|
-
: new GetPriceBase(address, chainId)
|
|
27
|
-
}
|
|
28
|
-
}
|