@mimicprotocol/lib-ts 0.0.1-rc.18 → 0.0.1-rc.19
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/index.ts +1 -0
- package/package.json +2 -2
- package/src/context/Context.ts +42 -3
- package/src/environment.ts +65 -10
- package/src/helpers/BorshDeserializer.ts +133 -0
- package/src/helpers/index.ts +1 -0
- package/src/helpers/serialize.ts +5 -6
- package/src/helpers/strings.ts +7 -2
- package/src/intents/Call.ts +1 -2
- package/src/queries/GetAccountsInfo.ts +46 -0
- package/src/queries/GetRelevantTokens.ts +14 -34
- package/src/queries/SubgraphQuery.ts +34 -0
- package/src/queries/index.ts +2 -0
- package/src/svm.ts +27 -0
- package/src/tokens/SPLToken.ts +57 -6
- package/src/types/Address.ts +17 -0
- package/src/types/ByteArray.ts +23 -0
- package/src/types/Option.ts +35 -0
- package/src/types/TriggerType.ts +2 -2
- package/src/types/{EvmEncodeParam.ts → evm/EvmEncodeParam.ts} +1 -1
- package/src/types/evm/index.ts +2 -0
- package/src/types/index.ts +3 -2
- package/src/types/svm/SvmAccountInfo.ts +32 -0
- package/src/types/svm/SvmFindProgramAddress.ts +32 -0
- package/src/types/svm/SvmMint.ts +44 -0
- package/src/types/svm/SvmPdaSeed.ts +19 -0
- package/src/types/svm/SvmTokenMetadataData.ts +29 -0
- package/src/types/svm/index.ts +5 -0
- /package/src/types/{EvmDecodeParam.ts → evm/EvmDecodeParam.ts} +0 -0
package/index.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mimicprotocol/lib-ts",
|
|
3
|
-
"version": "0.0.1-rc.
|
|
3
|
+
"version": "0.0.1-rc.19",
|
|
4
4
|
"license": "GPL-3.0",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"build": "asc index.ts -b build/lib.wasm --disableWarning 235 --noEmit --transform json-as/transform",
|
|
9
9
|
"test": "asp",
|
|
10
|
-
"lint": "eslint . --ignore-pattern 'src/environment.ts' --ignore-pattern 'src/evm.ts' --ignore-pattern 'src/log.ts'"
|
|
10
|
+
"lint": "eslint . --ignore-pattern 'src/environment.ts' --ignore-pattern 'src/evm.ts' --ignore-pattern 'src/svm.ts' --ignore-pattern 'src/log.ts'"
|
|
11
11
|
},
|
|
12
12
|
"files": [
|
|
13
13
|
"src",
|
package/src/context/Context.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { evm } from '../evm'
|
|
2
|
+
import { Address, BigInt, ChainId, EvmDecodeParam, JSON } from '../types'
|
|
2
3
|
import { TriggerType } from '../types/TriggerType'
|
|
3
4
|
|
|
4
5
|
@json
|
|
@@ -20,12 +21,50 @@ export class Settler {
|
|
|
20
21
|
}
|
|
21
22
|
}
|
|
22
23
|
|
|
24
|
+
@json
|
|
25
|
+
export class SerializableTrigger {
|
|
26
|
+
constructor(
|
|
27
|
+
public type: u8,
|
|
28
|
+
public data: string
|
|
29
|
+
) {}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export class EventTriggerData {
|
|
33
|
+
constructor(
|
|
34
|
+
public blockHash: string,
|
|
35
|
+
public index: BigInt,
|
|
36
|
+
public topics: string[],
|
|
37
|
+
public eventData: string
|
|
38
|
+
) {}
|
|
39
|
+
}
|
|
40
|
+
|
|
23
41
|
@json
|
|
24
42
|
export class Trigger {
|
|
25
43
|
constructor(
|
|
26
44
|
public type: TriggerType,
|
|
27
45
|
public data: string
|
|
28
46
|
) {}
|
|
47
|
+
|
|
48
|
+
static fromSerializable(serializable: SerializableTrigger): Trigger {
|
|
49
|
+
return new Trigger(serializable.type, serializable.data)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
getCronData(): BigInt {
|
|
53
|
+
return Trigger.deserializeCronTriggerData(this.data)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
getEventData(): EventTriggerData {
|
|
57
|
+
return Trigger.deserializeEventTriggerData(this.data)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
static deserializeCronTriggerData(data: string): BigInt {
|
|
61
|
+
return BigInt.fromString(evm.decode(new EvmDecodeParam('uint256', data)))
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
static deserializeEventTriggerData(data: string): EventTriggerData {
|
|
65
|
+
const fields = JSON.parse<string[]>(evm.decode(new EvmDecodeParam('(bytes32,uint256,bytes32[],bytes)', data)))
|
|
66
|
+
return new EventTriggerData(fields[0], BigInt.fromString(fields[1]), JSON.parse<string[]>(fields[2]), fields[3])
|
|
67
|
+
}
|
|
29
68
|
}
|
|
30
69
|
|
|
31
70
|
@json
|
|
@@ -36,7 +75,7 @@ export class SerializableContext {
|
|
|
36
75
|
public user: string,
|
|
37
76
|
public settlers: SerializableSettler[],
|
|
38
77
|
public configSig: string,
|
|
39
|
-
public trigger:
|
|
78
|
+
public trigger: SerializableTrigger
|
|
40
79
|
) {}
|
|
41
80
|
}
|
|
42
81
|
|
|
@@ -57,7 +96,7 @@ export class Context {
|
|
|
57
96
|
Address.fromString(serializable.user),
|
|
58
97
|
serializable.settlers.map<Settler>((s) => Settler.fromSerializable(s)),
|
|
59
98
|
serializable.configSig,
|
|
60
|
-
serializable.trigger
|
|
99
|
+
Trigger.fromSerializable(serializable.trigger)
|
|
61
100
|
)
|
|
62
101
|
}
|
|
63
102
|
|
package/src/environment.ts
CHANGED
|
@@ -3,7 +3,18 @@ import { JSON } from 'json-as/assembly'
|
|
|
3
3
|
import { Context, SerializableContext } from './context'
|
|
4
4
|
import { ListType } from './helpers'
|
|
5
5
|
import { Swap, Transfer, Call } from './intents'
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
Call as CallQuery,
|
|
8
|
+
GetAccountsInfo,
|
|
9
|
+
GetAccountsInfoResponse,
|
|
10
|
+
GetPrice,
|
|
11
|
+
GetRelevantTokens,
|
|
12
|
+
GetRelevantTokensResponse,
|
|
13
|
+
RelevantTokenBalance,
|
|
14
|
+
SerializableGetAccountsInfoResponse,
|
|
15
|
+
SubgraphQuery,
|
|
16
|
+
SubgraphQueryResponse,
|
|
17
|
+
} from './queries'
|
|
7
18
|
import { BlockchainToken, Token, TokenAmount, USD } from './tokens'
|
|
8
19
|
import { Address, BigInt, ChainId } from './types'
|
|
9
20
|
|
|
@@ -26,6 +37,12 @@ export namespace environment {
|
|
|
26
37
|
@external('environment', '_contractCall')
|
|
27
38
|
declare function _contractCall(params: string): string
|
|
28
39
|
|
|
40
|
+
@external('environment', '_subgraphQuery')
|
|
41
|
+
declare function _subgraphQuery(params: string): string
|
|
42
|
+
|
|
43
|
+
@external('environment', '_getAccountsInfo')
|
|
44
|
+
declare function _getAccountsInfo(params: string): string
|
|
45
|
+
|
|
29
46
|
@external('environment', '_getContext')
|
|
30
47
|
declare function _getContext(): string
|
|
31
48
|
|
|
@@ -96,12 +113,12 @@ export namespace environment {
|
|
|
96
113
|
* @param usdMinAmount - Minimum USD value threshold for tokens (optional, defaults to zero)
|
|
97
114
|
* @param tokensList - List of blockchain tokens to include/exclude (optional, defaults to empty array)
|
|
98
115
|
* @param listType - Whether to include (AllowList) or exclude (DenyList) the tokens in `tokensList` (optional, defaults to DenyList)
|
|
99
|
-
* @
|
|
100
|
-
* @returns Array of TokenAmount objects representing the relevant tokens
|
|
116
|
+
* @returns Array of RelevantTokenBalance objects representing the relevant tokens
|
|
101
117
|
*/
|
|
102
|
-
export function getRawRelevantTokens(address: Address, chainIds: ChainId[], usdMinAmount: USD, tokensList: BlockchainToken[], listType: ListType
|
|
103
|
-
const responseStr = _getRelevantTokens(JSON.stringify(GetRelevantTokens.init(address, chainIds, usdMinAmount, tokensList, listType
|
|
104
|
-
|
|
118
|
+
export function getRawRelevantTokens(address: Address, chainIds: ChainId[], usdMinAmount: USD, tokensList: BlockchainToken[], listType: ListType): RelevantTokenBalance[][] {
|
|
119
|
+
const responseStr = _getRelevantTokens(JSON.stringify(GetRelevantTokens.init(address, chainIds, usdMinAmount, tokensList, listType)))
|
|
120
|
+
const responses = JSON.parse<GetRelevantTokensResponse[]>(responseStr)
|
|
121
|
+
return responses.map((response: GetRelevantTokensResponse) => response.balances)
|
|
105
122
|
}
|
|
106
123
|
|
|
107
124
|
/**
|
|
@@ -111,7 +128,6 @@ export namespace environment {
|
|
|
111
128
|
* @param usdMinAmount - Minimum USD value threshold for tokens (optional, defaults to zero)
|
|
112
129
|
* @param tokensList - List of blockchain tokens to include/exclude (optional, defaults to empty array)
|
|
113
130
|
* @param listType - Whether to include (AllowList) or exclude (DenyList) the tokens in `tokensList` (optional, defaults to DenyList)
|
|
114
|
-
* @param timestamp - The timestamp for relevant tokens qery (optional, defaults to current time)
|
|
115
131
|
* @returns Array of TokenAmount objects representing the relevant tokens
|
|
116
132
|
*/
|
|
117
133
|
export function getRelevantTokens(
|
|
@@ -119,10 +135,9 @@ export namespace environment {
|
|
|
119
135
|
chainIds: ChainId[],
|
|
120
136
|
usdMinAmount: USD = USD.zero(),
|
|
121
137
|
tokensList: BlockchainToken[] = [],
|
|
122
|
-
listType: ListType = ListType.DenyList
|
|
123
|
-
timestamp: Date | null = null
|
|
138
|
+
listType: ListType = ListType.DenyList
|
|
124
139
|
): TokenAmount[] {
|
|
125
|
-
const response = getRawRelevantTokens(address, chainIds, usdMinAmount, tokensList, listType
|
|
140
|
+
const response = getRawRelevantTokens(address, chainIds, usdMinAmount, tokensList, listType)
|
|
126
141
|
const resultMap: Map<string, TokenAmount> = new Map()
|
|
127
142
|
for (let i = 0; i < response.length; i++) {
|
|
128
143
|
for (let j = 0; j < response[i].length; j++) {
|
|
@@ -155,6 +170,46 @@ export namespace environment {
|
|
|
155
170
|
)
|
|
156
171
|
}
|
|
157
172
|
|
|
173
|
+
/**
|
|
174
|
+
* Generates a subgraph query and returns the result.
|
|
175
|
+
* @param chainId - The blockchain network identifier
|
|
176
|
+
* @param subgraphId - The ID of the subgraph to be called
|
|
177
|
+
* @param query - The string representing the subgraph query to be executed
|
|
178
|
+
* @param timestamp - The timestamp for the query context (optional)
|
|
179
|
+
* @returns The subgraph query response
|
|
180
|
+
*/
|
|
181
|
+
export function subgraphQuery(
|
|
182
|
+
chainId: ChainId,
|
|
183
|
+
subgraphId: string,
|
|
184
|
+
query: string,
|
|
185
|
+
timestamp: Date | null,
|
|
186
|
+
): SubgraphQueryResponse {
|
|
187
|
+
const responseStr = _subgraphQuery(JSON.stringify(SubgraphQuery.from(chainId, subgraphId, query, timestamp)))
|
|
188
|
+
return JSON.parse<SubgraphQueryResponse>(responseStr)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* SVM - Gets on-chain account info
|
|
193
|
+
* @param publicKeys - Accounts to read from chain
|
|
194
|
+
* @param timestamp - The timestamp for the call context (optional)
|
|
195
|
+
* @returns The raw response from the underlying getMultipleAccountsInfo call
|
|
196
|
+
*/
|
|
197
|
+
|
|
198
|
+
export function getAccountsInfo(
|
|
199
|
+
publicKeys: Address[],
|
|
200
|
+
timestamp: Date | null
|
|
201
|
+
): GetAccountsInfoResponse {
|
|
202
|
+
// There is a bug with json-as, so we have to do this with JSON booleans
|
|
203
|
+
const responseStr = _getAccountsInfo(
|
|
204
|
+
JSON.stringify(GetAccountsInfo.from(publicKeys, timestamp))
|
|
205
|
+
)
|
|
206
|
+
.replaceAll("true",`"true"`)
|
|
207
|
+
.replaceAll("false",`"false"`)
|
|
208
|
+
|
|
209
|
+
const response = JSON.parse<SerializableGetAccountsInfoResponse>(responseStr)
|
|
210
|
+
return GetAccountsInfoResponse.fromSerializable(response)
|
|
211
|
+
}
|
|
212
|
+
|
|
158
213
|
/**
|
|
159
214
|
* Tells the current execution context containing environment information.
|
|
160
215
|
* @returns The Context object containing: user, settler, timestamp, and config ID
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { Address, ByteArray, Bytes } from '../types'
|
|
2
|
+
import { Option } from '../types/Option'
|
|
3
|
+
|
|
4
|
+
import { bytesToString } from './strings'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Unsafe class to deserialize bytes into Rust-like types
|
|
8
|
+
* Should be used with caution! This will only throw if there are insufficient bytes for the type
|
|
9
|
+
*/
|
|
10
|
+
export class BorshDeserializer {
|
|
11
|
+
private _bytes: Uint8Array
|
|
12
|
+
private _offset: u32 = 0
|
|
13
|
+
|
|
14
|
+
constructor(bytes: Uint8Array) {
|
|
15
|
+
this._bytes = bytes
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
static fromHex(hex: string): BorshDeserializer {
|
|
19
|
+
return new BorshDeserializer(Bytes.fromHexString(hex))
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
static fromBytes(bytes: Uint8Array): BorshDeserializer {
|
|
23
|
+
return new BorshDeserializer(bytes)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
tryBool(): bool {
|
|
27
|
+
if (this._offset >= this.getBytesLength()) throw new Error('Insufficient bytes for bool')
|
|
28
|
+
const value = this._bytes.at(this._offset)
|
|
29
|
+
this._offset += 1
|
|
30
|
+
return value === 1
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
tryU8(): u8 {
|
|
34
|
+
if (this._offset >= this.getBytesLength()) throw new Error('Insufficient bytes for u8')
|
|
35
|
+
const value = this._bytes.at(this._offset)
|
|
36
|
+
this._offset += 1
|
|
37
|
+
return value
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
tryU16(): u16 {
|
|
41
|
+
if (this._offset + 1 >= this.getBytesLength()) throw new Error('Insufficient bytes for u16')
|
|
42
|
+
const subarray = changetype<ByteArray>(this._bytes.subarray(this._offset, this._offset + 2))
|
|
43
|
+
this._offset += 2
|
|
44
|
+
return subarray.toU16()
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
tryU32(): u32 {
|
|
48
|
+
if (this._offset + 3 >= this.getBytesLength()) throw new Error('Insufficient bytes for u32')
|
|
49
|
+
const subarray = changetype<ByteArray>(this._bytes.subarray(this._offset, this._offset + 4))
|
|
50
|
+
this._offset += 4
|
|
51
|
+
return subarray.toU32()
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
tryU64(): u64 {
|
|
55
|
+
if (this._offset + 7 >= this.getBytesLength()) throw new Error('Insufficient bytes for u64')
|
|
56
|
+
const subarray = changetype<ByteArray>(this._bytes.subarray(this._offset, this._offset + 8))
|
|
57
|
+
this._offset += 8
|
|
58
|
+
return subarray.toU64()
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
tryPubkey(): Address {
|
|
62
|
+
if (this._offset + 31 >= this.getBytesLength()) throw new Error('Insufficient bytes for pubkey')
|
|
63
|
+
const pubkey = Address.fromBytes(Bytes.fromUint8Array(this._bytes.subarray(this._offset, this._offset + 32)))
|
|
64
|
+
this._offset += 32
|
|
65
|
+
return pubkey
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
tryString(): string {
|
|
69
|
+
const length = this.tryU32()
|
|
70
|
+
if (this._offset + length - 1 >= this.getBytesLength())
|
|
71
|
+
throw new Error(`Insufficient bytes for string of size ${length}`)
|
|
72
|
+
const str = bytesToString(this._bytes.subarray(this._offset, this._offset + length), true)
|
|
73
|
+
this._offset += length
|
|
74
|
+
return str
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
tryOptionBool(): Option<bool> {
|
|
78
|
+
const tag = this.tryU32()
|
|
79
|
+
if (tag === 0) return Option.none<bool>()
|
|
80
|
+
return Option.some<bool>(this.tryBool())
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
tryOptionU8(): Option<u8> {
|
|
84
|
+
const tag = this.tryU32()
|
|
85
|
+
if (tag === 0) return Option.none<u8>()
|
|
86
|
+
return Option.some<u8>(this.tryU8())
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
tryOptionU16(): Option<u16> {
|
|
90
|
+
const tag = this.tryU32()
|
|
91
|
+
if (tag === 0) return Option.none<u16>()
|
|
92
|
+
return Option.some<u16>(this.tryU16())
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
tryOptionU32(): Option<u32> {
|
|
96
|
+
const tag = this.tryU32()
|
|
97
|
+
if (tag === 0) return Option.none<u32>()
|
|
98
|
+
return Option.some<u32>(this.tryU32())
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
tryOptionU64(): Option<u64> {
|
|
102
|
+
const tag = this.tryU32()
|
|
103
|
+
if (tag === 0) return Option.none<u64>()
|
|
104
|
+
return Option.some<u64>(this.tryU64())
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
tryOptionPubkey(): Option<Address> {
|
|
108
|
+
const tag = this.tryU32()
|
|
109
|
+
if (tag === 0) return Option.none<Address>(Address.fromBytes(new Bytes(32)))
|
|
110
|
+
return Option.some<Address>(this.tryPubkey())
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
private getBytesLength(): u32 {
|
|
114
|
+
return this._bytes.length as u32
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
getOffset(): u32 {
|
|
118
|
+
return this._offset
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
setOffset(offset: u32): void {
|
|
122
|
+
if (offset > this.getBytesLength()) throw new Error('Offset overruns buffer length')
|
|
123
|
+
this._offset = offset
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
isEmpty(): bool {
|
|
127
|
+
return this._offset >= this.getBytesLength()
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
getLength(): u32 {
|
|
131
|
+
return this._bytes.length
|
|
132
|
+
}
|
|
133
|
+
}
|
package/src/helpers/index.ts
CHANGED
package/src/helpers/serialize.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { BigInt, EvmDecodeParam } from '../types'
|
|
1
|
+
import { Bytes } from '../types'
|
|
3
2
|
|
|
4
3
|
export interface Stringable {
|
|
5
4
|
toString(): string
|
|
@@ -9,13 +8,13 @@ export interface Serializable {
|
|
|
9
8
|
serialize(): string
|
|
10
9
|
}
|
|
11
10
|
|
|
11
|
+
export interface Byteable {
|
|
12
|
+
toBytes(): Bytes
|
|
13
|
+
}
|
|
14
|
+
|
|
12
15
|
export function serialize<T extends Stringable>(elem: T): string {
|
|
13
16
|
// eslint-disable-next-line
|
|
14
17
|
// @ts-ignore
|
|
15
18
|
if (elem instanceof Serializable) return elem.serialize()
|
|
16
19
|
return elem.toString()
|
|
17
20
|
}
|
|
18
|
-
|
|
19
|
-
export function deserializeCronTriggerData(data: string): BigInt {
|
|
20
|
-
return BigInt.fromString(evm.decode(new EvmDecodeParam('uint256', data)))
|
|
21
|
-
}
|
package/src/helpers/strings.ts
CHANGED
|
@@ -2,8 +2,8 @@ import { decode, encode } from 'as-base58/assembly/index'
|
|
|
2
2
|
|
|
3
3
|
import { ByteArray } from '../types'
|
|
4
4
|
|
|
5
|
-
export function bytesToString(bytes: Uint8Array): string {
|
|
6
|
-
return String.UTF8.decodeUnsafe(bytes.dataStart, bytes.length)
|
|
5
|
+
export function bytesToString(bytes: Uint8Array, nullTerminated: bool = false): string {
|
|
6
|
+
return String.UTF8.decodeUnsafe(bytes.dataStart, bytes.length, nullTerminated)
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
export function bytesToHexString(bytes: Uint8Array): string {
|
|
@@ -21,6 +21,11 @@ export function bytesFromBase58String(base58: string): ByteArray {
|
|
|
21
21
|
return changetype<ByteArray>(decode(base58))
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
export function stringToBool(str: string): bool {
|
|
25
|
+
if (str !== 'true' && str !== 'false') throw new Error(`Invalid boolean: ${str}`)
|
|
26
|
+
return str === 'true'
|
|
27
|
+
}
|
|
28
|
+
|
|
24
29
|
export function areAllZeros(str: string): boolean {
|
|
25
30
|
for (let i = 0; i < str.length; i++) if (str.charCodeAt(i) !== 48) return false
|
|
26
31
|
return true
|
package/src/intents/Call.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { environment } from '../environment'
|
|
2
2
|
import { TokenAmount } from '../tokens'
|
|
3
|
-
import { ChainId } from '../types'
|
|
4
|
-
import { Address, BigInt, Bytes } from '../types'
|
|
3
|
+
import { Address, BigInt, Bytes, ChainId } from '../types'
|
|
5
4
|
|
|
6
5
|
import { Intent, IntentBuilder, IntentEvent, MaxFee, OperationType } from './Intent'
|
|
7
6
|
|
|
@@ -0,0 +1,46 @@
|
|
|
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
|
+
}
|
|
@@ -6,7 +6,7 @@ import { Address, BigInt, ChainId } from '../types'
|
|
|
6
6
|
class TokenQuery {
|
|
7
7
|
constructor(
|
|
8
8
|
public address: string,
|
|
9
|
-
public chainId:
|
|
9
|
+
public chainId: ChainId
|
|
10
10
|
) {}
|
|
11
11
|
|
|
12
12
|
static fromToken(token: BlockchainToken): TokenQuery {
|
|
@@ -15,7 +15,7 @@ class TokenQuery {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
@json
|
|
18
|
-
class
|
|
18
|
+
export class GetRelevantTokens {
|
|
19
19
|
constructor(
|
|
20
20
|
public readonly owner: string,
|
|
21
21
|
public readonly chainIds: ChainId[],
|
|
@@ -23,51 +23,23 @@ class GetRelevantTokensBase {
|
|
|
23
23
|
public readonly tokens: TokenQuery[],
|
|
24
24
|
public readonly tokenFilter: ListType
|
|
25
25
|
) {}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
@json
|
|
29
|
-
export class GetRelevantTokens extends GetRelevantTokensBase {
|
|
30
|
-
public readonly timestamp: i64
|
|
31
|
-
|
|
32
|
-
constructor(
|
|
33
|
-
owner: string,
|
|
34
|
-
chainIds: ChainId[],
|
|
35
|
-
usdMinAmount: string,
|
|
36
|
-
tokens: TokenQuery[],
|
|
37
|
-
tokenFilter: ListType,
|
|
38
|
-
timestamp: i64
|
|
39
|
-
) {
|
|
40
|
-
super(owner, chainIds, usdMinAmount, tokens, tokenFilter)
|
|
41
|
-
this.timestamp = timestamp
|
|
42
|
-
}
|
|
43
26
|
|
|
44
27
|
static init(
|
|
45
28
|
owner: Address,
|
|
46
29
|
chainIds: ChainId[],
|
|
47
30
|
usdMinAmount: USD,
|
|
48
31
|
tokens: BlockchainToken[],
|
|
49
|
-
tokenFilter: ListType
|
|
50
|
-
|
|
51
|
-
): GetRelevantTokensBase {
|
|
32
|
+
tokenFilter: ListType
|
|
33
|
+
): GetRelevantTokens {
|
|
52
34
|
const ownerStr = owner.toString()
|
|
53
35
|
const usdMinAmountStr = usdMinAmount.toString()
|
|
54
36
|
const tokensQueries = tokens.map<TokenQuery>((token) => TokenQuery.fromToken(token))
|
|
55
|
-
|
|
56
|
-
return timestamp
|
|
57
|
-
? new GetRelevantTokens(
|
|
58
|
-
ownerStr,
|
|
59
|
-
chainIds,
|
|
60
|
-
usdMinAmountStr,
|
|
61
|
-
tokensQueries,
|
|
62
|
-
tokenFilter,
|
|
63
|
-
changetype<Date>(timestamp).getTime()
|
|
64
|
-
)
|
|
65
|
-
: new GetRelevantTokensBase(ownerStr, chainIds, usdMinAmountStr, tokensQueries, tokenFilter)
|
|
37
|
+
return new GetRelevantTokens(ownerStr, chainIds, usdMinAmountStr, tokensQueries, tokenFilter)
|
|
66
38
|
}
|
|
67
39
|
}
|
|
68
40
|
|
|
69
41
|
@json
|
|
70
|
-
export class
|
|
42
|
+
export class RelevantTokenBalance {
|
|
71
43
|
constructor(
|
|
72
44
|
public token: TokenQuery,
|
|
73
45
|
public amount: string
|
|
@@ -80,3 +52,11 @@ export class GetRelevantTokensResponse {
|
|
|
80
52
|
)
|
|
81
53
|
}
|
|
82
54
|
}
|
|
55
|
+
|
|
56
|
+
@json
|
|
57
|
+
export class GetRelevantTokensResponse {
|
|
58
|
+
constructor(
|
|
59
|
+
public timestamp: i64,
|
|
60
|
+
public balances: RelevantTokenBalance[]
|
|
61
|
+
) {}
|
|
62
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { ChainId } from '../types'
|
|
2
|
+
|
|
3
|
+
@json
|
|
4
|
+
class SubgraphQueryBase {
|
|
5
|
+
constructor(
|
|
6
|
+
public readonly chainId: ChainId,
|
|
7
|
+
public readonly subgraphId: string,
|
|
8
|
+
public readonly query: string
|
|
9
|
+
) {}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
@json
|
|
13
|
+
export class SubgraphQuery extends SubgraphQueryBase {
|
|
14
|
+
public readonly timestamp: i64
|
|
15
|
+
|
|
16
|
+
constructor(chainId: ChainId, timestamp: i64, subgraphId: string, query: string) {
|
|
17
|
+
super(chainId, subgraphId, query)
|
|
18
|
+
this.timestamp = timestamp
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
static from(chainId: ChainId, subgraphId: string, query: string, timestamp: Date | null): SubgraphQueryBase {
|
|
22
|
+
return timestamp
|
|
23
|
+
? new SubgraphQuery(chainId, changetype<Date>(timestamp).getTime(), subgraphId, query)
|
|
24
|
+
: new SubgraphQueryBase(chainId, subgraphId, query)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@json
|
|
29
|
+
export class SubgraphQueryResponse {
|
|
30
|
+
constructor(
|
|
31
|
+
public blockNumber: i64,
|
|
32
|
+
public data: string
|
|
33
|
+
) {}
|
|
34
|
+
}
|
package/src/queries/index.ts
CHANGED
package/src/svm.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { JSON } from 'json-as'
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
Address,
|
|
5
|
+
SerializableSvmFindProgramAddressResult,
|
|
6
|
+
SvmFindProgramAddressParams,
|
|
7
|
+
SvmFindProgramAddressResult,
|
|
8
|
+
SvmPdaSeed,
|
|
9
|
+
} from './types'
|
|
10
|
+
|
|
11
|
+
export namespace svm {
|
|
12
|
+
@external('svm', '_findProgramAddress')
|
|
13
|
+
declare function _findProgramAddress(params: string): string
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Calculates PDA address
|
|
17
|
+
* @param seeds - SvmPdaSeed array of seeds
|
|
18
|
+
* @param programId - Base programId to be derived of
|
|
19
|
+
* @returns The PDA address and bump
|
|
20
|
+
*/
|
|
21
|
+
export function findProgramAddress(seeds: SvmPdaSeed[], programId: Address): SvmFindProgramAddressResult {
|
|
22
|
+
const params = new SvmFindProgramAddressParams(seeds, programId.toBase58String())
|
|
23
|
+
const result = _findProgramAddress(JSON.stringify(params))
|
|
24
|
+
const parsed = JSON.parse<SerializableSvmFindProgramAddressResult>(result)
|
|
25
|
+
return SvmFindProgramAddressResult.fromSerializable(parsed)
|
|
26
|
+
}
|
|
27
|
+
}
|
package/src/tokens/SPLToken.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { environment } from '../environment'
|
|
1
2
|
import { SVM_NATIVE_ADDRESS } from '../helpers'
|
|
2
|
-
import {
|
|
3
|
+
import { svm } from '../svm'
|
|
4
|
+
import { Address, ChainId, SvmMint, SvmPdaSeed, SvmTokenMetadataData } from '../types'
|
|
3
5
|
|
|
4
6
|
import { BlockchainToken } from './BlockchainToken'
|
|
5
7
|
import { Token } from './Token'
|
|
@@ -27,8 +29,8 @@ export class SPLToken extends BlockchainToken {
|
|
|
27
29
|
static fromAddress(
|
|
28
30
|
address: Address,
|
|
29
31
|
chainId: ChainId = ChainId.SOLANA_MAINNET,
|
|
30
|
-
decimals: u8 =
|
|
31
|
-
symbol: string =
|
|
32
|
+
decimals: u8 = SPLToken.EMPTY_DECIMALS,
|
|
33
|
+
symbol: string = SPLToken.EMPTY_SYMBOL
|
|
32
34
|
): SPLToken {
|
|
33
35
|
if (chainId != ChainId.SOLANA_MAINNET) throw new Error(`SPL tokens are only supported for Solana mainnet.`)
|
|
34
36
|
return new SPLToken(address, decimals, symbol)
|
|
@@ -45,8 +47,8 @@ export class SPLToken extends BlockchainToken {
|
|
|
45
47
|
static fromString(
|
|
46
48
|
address: string,
|
|
47
49
|
chainId: ChainId = ChainId.SOLANA_MAINNET,
|
|
48
|
-
decimals: u8 =
|
|
49
|
-
symbol: string =
|
|
50
|
+
decimals: u8 = SPLToken.EMPTY_DECIMALS,
|
|
51
|
+
symbol: string = SPLToken.EMPTY_SYMBOL
|
|
50
52
|
): SPLToken {
|
|
51
53
|
return SPLToken.fromAddress(Address.fromString(address), chainId, decimals, symbol)
|
|
52
54
|
}
|
|
@@ -57,11 +59,60 @@ export class SPLToken extends BlockchainToken {
|
|
|
57
59
|
* @param decimals - Number of decimal places
|
|
58
60
|
* @param symbol - Token symbol
|
|
59
61
|
*/
|
|
60
|
-
constructor(address: Address, decimals: u8, symbol: string) {
|
|
62
|
+
constructor(address: Address, decimals: u8 = SPLToken.EMPTY_DECIMALS, symbol: string = SPLToken.EMPTY_SYMBOL) {
|
|
61
63
|
if (!address.isSVM()) throw new Error(`Address ${address} must be an SVM address.`)
|
|
62
64
|
super(address, decimals, symbol, ChainId.SOLANA_MAINNET)
|
|
63
65
|
}
|
|
64
66
|
|
|
67
|
+
/**
|
|
68
|
+
* Gets the token’s decimals (number of decimal places used).
|
|
69
|
+
* If decimals were not provided during construction, they will be lazily fetched
|
|
70
|
+
* The fetched value is parsed to `u8` and cached for future accesses.
|
|
71
|
+
* @returns A `u8` representing the number of decimals of the token.
|
|
72
|
+
*/
|
|
73
|
+
get decimals(): u8 {
|
|
74
|
+
if (this._decimals == SPLToken.EMPTY_DECIMALS) {
|
|
75
|
+
const result = environment.getAccountsInfo([this.address], null)
|
|
76
|
+
const decimals = SvmMint.fromHex(result.accountsInfo[0].data).decimals
|
|
77
|
+
this._decimals = decimals
|
|
78
|
+
}
|
|
79
|
+
return this._decimals
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Gets the token’s symbol (e.g., "SOL", "USDC").
|
|
84
|
+
* If the symbol was not provided during construction, it will be lazily fetched
|
|
85
|
+
* If the token doesn't have a symbol (TokenMetadata standard), an abbreviated address is returned
|
|
86
|
+
* The symbol is cached in the instance for future accesses.
|
|
87
|
+
* @returns A string containing the token symbol.
|
|
88
|
+
*/
|
|
89
|
+
get symbol(): string {
|
|
90
|
+
if (this._symbol == SPLToken.EMPTY_SYMBOL) {
|
|
91
|
+
const result = environment.getAccountsInfo([this.getMetadataAddress()], null)
|
|
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
|
+
}
|
|
99
|
+
return this._symbol
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Derives Metaplex Metadata address for this given token
|
|
104
|
+
*/
|
|
105
|
+
private getMetadataAddress(): Address {
|
|
106
|
+
return svm.findProgramAddress(
|
|
107
|
+
[
|
|
108
|
+
SvmPdaSeed.fromString('metadata'),
|
|
109
|
+
SvmPdaSeed.from(Address.fromString(SvmTokenMetadataData.METADATA_PROGRAM_ID)),
|
|
110
|
+
SvmPdaSeed.from(this._address),
|
|
111
|
+
],
|
|
112
|
+
Address.fromBase58String(SvmTokenMetadataData.METADATA_PROGRAM_ID)
|
|
113
|
+
).address
|
|
114
|
+
}
|
|
115
|
+
|
|
65
116
|
/**
|
|
66
117
|
* Checks if this token is equal to another token.
|
|
67
118
|
* SPL Tokens are considered equal if they have the same address.
|
package/src/types/Address.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { EVM_NATIVE_ADDRESS, isHex, USD_ADDRESS } from '../helpers'
|
|
|
8
8
|
|
|
9
9
|
import { ByteArray } from './ByteArray'
|
|
10
10
|
import { Bytes } from './Bytes'
|
|
11
|
+
import { Option } from './Option'
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* Represents an EVM or SVM address, a fixed-length 20 or 32-byte value.
|
|
@@ -21,6 +22,15 @@ export class Address extends Bytes {
|
|
|
21
22
|
return changetype<Address>(self)
|
|
22
23
|
}
|
|
23
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Returns a None variant for the Option type, representing no address
|
|
27
|
+
* @param length 32 by default (SVM)
|
|
28
|
+
* @returns Option.none with empty bytes
|
|
29
|
+
*/
|
|
30
|
+
static none(length: u32 = 32): Option<Address> {
|
|
31
|
+
return Option.none<Address>(Address.fromBytes(new Bytes(length)))
|
|
32
|
+
}
|
|
33
|
+
|
|
24
34
|
/**
|
|
25
35
|
* Returns the USD denomination address.
|
|
26
36
|
*/
|
|
@@ -111,4 +121,11 @@ export class Address extends Bytes {
|
|
|
111
121
|
toString(): string {
|
|
112
122
|
return this.isEVM() ? super.toHexString() : super.toBase58String()
|
|
113
123
|
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Returns the address as its underlying bytes
|
|
127
|
+
*/
|
|
128
|
+
toBytes(): Bytes {
|
|
129
|
+
return changetype<Bytes>(this.slice(0))
|
|
130
|
+
}
|
|
114
131
|
}
|
package/src/types/ByteArray.ts
CHANGED
|
@@ -176,6 +176,29 @@ export class ByteArray extends Uint8Array implements Serializable {
|
|
|
176
176
|
return !(this == other)
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
+
/**
|
|
180
|
+
* Interprets the byte array as a little-endian U16.
|
|
181
|
+
* Throws in case of overflow.
|
|
182
|
+
*/
|
|
183
|
+
toU16(): u16 {
|
|
184
|
+
for (let i = 2; i < this.length; i++) {
|
|
185
|
+
if (this[i] != 0) {
|
|
186
|
+
assert(false, 'overflow converting ' + this.toHexString() + ' to u16')
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
const paddedBytes = new Bytes(2)
|
|
190
|
+
paddedBytes[0] = 0
|
|
191
|
+
paddedBytes[1] = 0
|
|
192
|
+
const minLen = paddedBytes.length < this.length ? paddedBytes.length : this.length
|
|
193
|
+
for (let i = 0; i < minLen; i++) {
|
|
194
|
+
paddedBytes[i] = this[i]
|
|
195
|
+
}
|
|
196
|
+
let x: u16 = 0
|
|
197
|
+
x = (x | paddedBytes[1]) << 8
|
|
198
|
+
x = x | paddedBytes[0]
|
|
199
|
+
return x
|
|
200
|
+
}
|
|
201
|
+
|
|
179
202
|
/**
|
|
180
203
|
* Interprets the byte array as a little-endian U32.
|
|
181
204
|
* Throws in case of overflow.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple wrapper for Option<T> Rust types
|
|
3
|
+
* To be used in tandem with BorshDeserializer
|
|
4
|
+
*/
|
|
5
|
+
export class Option<T> {
|
|
6
|
+
constructor(
|
|
7
|
+
private _value: T,
|
|
8
|
+
public readonly isSome: bool
|
|
9
|
+
) {}
|
|
10
|
+
|
|
11
|
+
static some<T>(value: T): Option<T> {
|
|
12
|
+
return new Option<T>(value, true)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
static none<T>(defaultValue: T = 0 as T): Option<T> {
|
|
16
|
+
return new Option<T>(defaultValue, false)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
unwrap(): T {
|
|
20
|
+
if (this.isSome) return this._value
|
|
21
|
+
throw new Error("Can't unwrap None variant")
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
eq(other: Option<T>): bool {
|
|
25
|
+
if (this.isSome != other.isSome) return false
|
|
26
|
+
if (!this.isSome && !other.isSome) return true
|
|
27
|
+
return this._value == other._value
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
toString(): string {
|
|
31
|
+
if (!this.isSome) return 'None'
|
|
32
|
+
// @ts-expect-error: AssemblyScript lacks runtime reflection, so we assume toString exists
|
|
33
|
+
return `Some(${this._value.toString ? this._value.toString() : '[Object]'})`
|
|
34
|
+
}
|
|
35
|
+
}
|
package/src/types/TriggerType.ts
CHANGED
package/src/types/index.ts
CHANGED
|
@@ -5,6 +5,7 @@ export * from './BigInt'
|
|
|
5
5
|
export * from './ByteArray'
|
|
6
6
|
export * from './Bytes'
|
|
7
7
|
export * from './ChainId'
|
|
8
|
-
export * from './
|
|
9
|
-
export * from './
|
|
8
|
+
export * from './evm'
|
|
9
|
+
export * from './Option'
|
|
10
|
+
export * from './svm'
|
|
10
11
|
export { JSON }
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { stringToBool } from '../../helpers'
|
|
2
|
+
|
|
3
|
+
export class SvmAccountInfo {
|
|
4
|
+
constructor(
|
|
5
|
+
public owner: string,
|
|
6
|
+
public lamports: string,
|
|
7
|
+
public data: string,
|
|
8
|
+
public rentEpoch: string,
|
|
9
|
+
public executable: bool
|
|
10
|
+
) {}
|
|
11
|
+
|
|
12
|
+
static fromSerializable(serializable: SerializableSvmAccountInfo): SvmAccountInfo {
|
|
13
|
+
return new SvmAccountInfo(
|
|
14
|
+
serializable.owner,
|
|
15
|
+
serializable.lamports,
|
|
16
|
+
serializable.data,
|
|
17
|
+
serializable.rentEpoch,
|
|
18
|
+
stringToBool(serializable.executable)
|
|
19
|
+
)
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@json
|
|
24
|
+
export class SerializableSvmAccountInfo {
|
|
25
|
+
constructor(
|
|
26
|
+
public owner: string,
|
|
27
|
+
public lamports: string,
|
|
28
|
+
public data: string,
|
|
29
|
+
public rentEpoch: string,
|
|
30
|
+
public executable: string
|
|
31
|
+
) {}
|
|
32
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Address } from './../Address'
|
|
2
|
+
import { SvmPdaSeed } from './SvmPdaSeed'
|
|
3
|
+
|
|
4
|
+
@json
|
|
5
|
+
export class SvmFindProgramAddressParams {
|
|
6
|
+
public readonly seeds: SvmPdaSeed[]
|
|
7
|
+
public readonly programId: string
|
|
8
|
+
|
|
9
|
+
constructor(seeds: SvmPdaSeed[], programId: string) {
|
|
10
|
+
this.seeds = seeds.slice()
|
|
11
|
+
this.programId = programId
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export class SvmFindProgramAddressResult {
|
|
16
|
+
constructor(
|
|
17
|
+
public address: Address,
|
|
18
|
+
public bump: u8
|
|
19
|
+
) {}
|
|
20
|
+
|
|
21
|
+
static fromSerializable(serializable: SerializableSvmFindProgramAddressResult): SvmFindProgramAddressResult {
|
|
22
|
+
return new SvmFindProgramAddressResult(Address.fromString(serializable.address), serializable.bump)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@json
|
|
27
|
+
export class SerializableSvmFindProgramAddressResult {
|
|
28
|
+
constructor(
|
|
29
|
+
public address: string,
|
|
30
|
+
public bump: u8
|
|
31
|
+
) {}
|
|
32
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { BorshDeserializer } from '../../helpers'
|
|
2
|
+
|
|
3
|
+
import { Address } from './../Address'
|
|
4
|
+
import { Bytes } from './../Bytes'
|
|
5
|
+
import { Option } from './../Option'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* State layout for Mint TokenProgram PDAs
|
|
9
|
+
*/
|
|
10
|
+
export class SvmMint {
|
|
11
|
+
static DECIMALS_OFFSET: u32 = 44
|
|
12
|
+
|
|
13
|
+
constructor(
|
|
14
|
+
public mintAuthority: Option<Address>,
|
|
15
|
+
public supply: u64,
|
|
16
|
+
public decimals: u8,
|
|
17
|
+
public isInitialized: bool,
|
|
18
|
+
public freezeAuthority: Option<Address>
|
|
19
|
+
) {}
|
|
20
|
+
|
|
21
|
+
static fromHex(hex: string): SvmMint {
|
|
22
|
+
return this.fromBytes(Bytes.fromHexString(hex))
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static fromBytes(bytes: Bytes): SvmMint {
|
|
26
|
+
const deserializer = BorshDeserializer.fromBytes(bytes)
|
|
27
|
+
|
|
28
|
+
const mintAuthorityFlag = deserializer.tryU32() === 1
|
|
29
|
+
const mintAuthority = deserializer.tryPubkey()
|
|
30
|
+
const supply = deserializer.tryU64()
|
|
31
|
+
const decimals = deserializer.tryU8()
|
|
32
|
+
const isInitialized = deserializer.tryBool()
|
|
33
|
+
const freezeAuthorityFlag = deserializer.tryU32() === 1
|
|
34
|
+
const freezeAuthority = deserializer.tryPubkey()
|
|
35
|
+
|
|
36
|
+
return new SvmMint(
|
|
37
|
+
mintAuthorityFlag ? Option.some(mintAuthority) : Address.none(),
|
|
38
|
+
supply,
|
|
39
|
+
decimals,
|
|
40
|
+
isInitialized,
|
|
41
|
+
freezeAuthorityFlag ? Option.some(freezeAuthority) : Address.none()
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Byteable, bytesToHexString } from '../../helpers'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Type for findProgramAddress seeds
|
|
5
|
+
* As we need all seeds to be decoded as bytes in the same way as in Rust,
|
|
6
|
+
* this class provides a simple interface for end-users to abstract all this
|
|
7
|
+
*/
|
|
8
|
+
@json
|
|
9
|
+
export class SvmPdaSeed {
|
|
10
|
+
constructor(public readonly hex: string) {}
|
|
11
|
+
|
|
12
|
+
static fromString(str: string): SvmPdaSeed {
|
|
13
|
+
return new SvmPdaSeed(bytesToHexString(Uint8Array.wrap(String.UTF8.encode(str))))
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
static from<T extends Byteable>(t: T): SvmPdaSeed {
|
|
17
|
+
return new SvmPdaSeed(bytesToHexString(t.toBytes()))
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { BorshDeserializer } from '../../helpers'
|
|
2
|
+
|
|
3
|
+
import { Bytes } from './../Bytes'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Partial state layout for Data Metaplex PDA (Metadata PDA "data" field)
|
|
7
|
+
*/
|
|
8
|
+
export class SvmTokenMetadataData {
|
|
9
|
+
static DATA_OFFSET: u32 = 65
|
|
10
|
+
// eslint-disable-next-line no-secrets/no-secrets
|
|
11
|
+
static METADATA_PROGRAM_ID: string = 'metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s'
|
|
12
|
+
|
|
13
|
+
constructor(
|
|
14
|
+
public name: string,
|
|
15
|
+
public symbol: string,
|
|
16
|
+
public uri: string
|
|
17
|
+
) {}
|
|
18
|
+
|
|
19
|
+
static fromTokenMetadataHex(hex: string): SvmTokenMetadataData {
|
|
20
|
+
return this.fromTokenMetadataBytes(Bytes.fromHexString(hex))
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
static fromTokenMetadataBytes(bytes: Bytes): SvmTokenMetadataData {
|
|
24
|
+
const deserializer = BorshDeserializer.fromBytes(bytes)
|
|
25
|
+
deserializer.setOffset(this.DATA_OFFSET)
|
|
26
|
+
|
|
27
|
+
return new SvmTokenMetadataData(deserializer.tryString(), deserializer.tryString(), deserializer.tryString())
|
|
28
|
+
}
|
|
29
|
+
}
|
|
File without changes
|