@exodus/sui-api 0.1.0
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/README.md +20 -0
- package/package.json +53 -0
- package/src/api.js +198 -0
- package/src/balances.js +22 -0
- package/src/basic-account-state.js +11 -0
- package/src/create-unsigned-tx.js +60 -0
- package/src/get-fee-async.js +62 -0
- package/src/get-fee.js +10 -0
- package/src/index.js +9 -0
- package/src/sui-no-history-monitor.js +277 -0
- package/src/transform-tx.js +100 -0
- package/src/tx-send.js +249 -0
- package/src/vendors/client/client.js +891 -0
- package/src/vendors/client/errors.js +38 -0
- package/src/vendors/client/http-transport.js +108 -0
- package/src/vendors/client/index.js +1 -0
- package/src/vendors/client/rpc-websocket-client.js +178 -0
- package/src/vendors/experimental/cache.js +89 -0
- package/src/vendors/experimental/client.js +27 -0
- package/src/vendors/experimental/core.js +105 -0
- package/src/vendors/experimental/errors.js +32 -0
- package/src/vendors/experimental/index.js +5 -0
- package/src/vendors/experimental/mvr.js +443 -0
- package/src/vendors/experimental/transports/json-rpc-resolver.js +359 -0
- package/src/vendors/experimental/transports/jsonRPC.js +504 -0
- package/src/vendors/experimental/transports/utils.js +90 -0
- package/src/vendors/transactions/Arguments.js +22 -0
- package/src/vendors/transactions/Commands.js +108 -0
- package/src/vendors/transactions/Inputs.js +59 -0
- package/src/vendors/transactions/ObjectCache.js +272 -0
- package/src/vendors/transactions/Transaction.js +843 -0
- package/src/vendors/transactions/TransactionData.js +293 -0
- package/src/vendors/transactions/data/internal.js +218 -0
- package/src/vendors/transactions/data/v1.js +538 -0
- package/src/vendors/transactions/data/v2.js +119 -0
- package/src/vendors/transactions/hash.js +12 -0
- package/src/vendors/transactions/index.js +1 -0
- package/src/vendors/transactions/object.js +22 -0
- package/src/vendors/transactions/plugins/NamedPackagesPlugin.js +49 -0
- package/src/vendors/transactions/pure.js +40 -0
- package/src/vendors/transactions/resolve.js +95 -0
- package/src/vendors/transactions/serializer.js +203 -0
- package/src/vendors/transactions/utils.js +67 -0
- package/src/vendors/valibot.js +7920 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
const CODE_TO_ERROR_TYPE = {
|
|
2
|
+
'-32700': 'ParseError',
|
|
3
|
+
'-32701': 'OversizedRequest',
|
|
4
|
+
'-32702': 'OversizedResponse',
|
|
5
|
+
'-32600': 'InvalidRequest',
|
|
6
|
+
'-32601': 'MethodNotFound',
|
|
7
|
+
'-32602': 'InvalidParams',
|
|
8
|
+
'-32603': 'InternalError',
|
|
9
|
+
'-32604': 'ServerBusy',
|
|
10
|
+
'-32000': 'CallExecutionFailed',
|
|
11
|
+
'-32001': 'UnknownError',
|
|
12
|
+
'-32003': 'SubscriptionClosed',
|
|
13
|
+
'-32004': 'SubscriptionClosedWithError',
|
|
14
|
+
'-32005': 'BatchesNotSupported',
|
|
15
|
+
'-32006': 'TooManySubscriptions',
|
|
16
|
+
'-32050': 'TransientError',
|
|
17
|
+
'-32002': 'TransactionExecutionClientError',
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
class SuiHTTPTransportError extends Error {}
|
|
21
|
+
|
|
22
|
+
class JsonRpcError extends SuiHTTPTransportError {
|
|
23
|
+
constructor(message, code) {
|
|
24
|
+
super(message)
|
|
25
|
+
this.code = code
|
|
26
|
+
this.type = CODE_TO_ERROR_TYPE[code] ?? 'ServerError'
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
class SuiHTTPStatusError extends SuiHTTPTransportError {
|
|
31
|
+
constructor(message, status, statusText) {
|
|
32
|
+
super(message)
|
|
33
|
+
this.status = status
|
|
34
|
+
this.statusText = statusText
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export { JsonRpcError, SuiHTTPStatusError, SuiHTTPTransportError }
|
|
38
|
+
// # sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// Copyright (c) Mysten Labs, Inc.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import { JsonRpcError, SuiHTTPStatusError } from './errors.js'
|
|
5
|
+
import { WebsocketClient } from './rpc-websocket-client.js'
|
|
6
|
+
|
|
7
|
+
export const PACKAGE_VERSION = '1.36.1'
|
|
8
|
+
export const TARGETED_RPC_VERSION = '1.55.0'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* An object defining headers to be passed to the RPC server
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export class SuiHTTPTransport {
|
|
15
|
+
#requestId = 0
|
|
16
|
+
#options
|
|
17
|
+
#websocketClient
|
|
18
|
+
|
|
19
|
+
constructor(options) {
|
|
20
|
+
this.#options = options
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
fetch(input, init) {
|
|
24
|
+
const fetchFn = this.#options.fetch ?? fetch
|
|
25
|
+
|
|
26
|
+
if (!fetchFn) {
|
|
27
|
+
throw new Error(
|
|
28
|
+
'The current environment does not support fetch, you can provide a fetch implementation in the options for SuiHTTPTransport.'
|
|
29
|
+
)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return fetchFn(input, init)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
#getWebsocketClient() {
|
|
36
|
+
if (!this.#websocketClient) {
|
|
37
|
+
// eslint-disable-next-line no-undef
|
|
38
|
+
const WebSocketConstructor = this.#options.WebSocketConstructor ?? WebSocket
|
|
39
|
+
if (!WebSocketConstructor) {
|
|
40
|
+
throw new Error(
|
|
41
|
+
'The current environment does not support WebSocket, you can provide a WebSocketConstructor in the options for SuiHTTPTransport.'
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
this.#websocketClient = new WebsocketClient(
|
|
46
|
+
this.#options.websocket?.url ?? this.#options.url,
|
|
47
|
+
{
|
|
48
|
+
WebSocketConstructor,
|
|
49
|
+
...this.#options.websocket,
|
|
50
|
+
}
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return this.#websocketClient
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async request(input) {
|
|
58
|
+
this.#requestId += 1
|
|
59
|
+
|
|
60
|
+
const res = await this.fetch(this.#options.rpc?.url ?? this.#options.url, {
|
|
61
|
+
method: 'POST',
|
|
62
|
+
signal: input.signal,
|
|
63
|
+
headers: {
|
|
64
|
+
'Content-Type': 'application/json',
|
|
65
|
+
'Client-Sdk-Type': 'typescript',
|
|
66
|
+
'Client-Sdk-Version': PACKAGE_VERSION,
|
|
67
|
+
'Client-Target-Api-Version': TARGETED_RPC_VERSION,
|
|
68
|
+
'Client-Request-Method': input.method,
|
|
69
|
+
...this.#options.rpc?.headers,
|
|
70
|
+
},
|
|
71
|
+
body: JSON.stringify({
|
|
72
|
+
jsonrpc: '2.0',
|
|
73
|
+
id: this.#requestId,
|
|
74
|
+
method: input.method,
|
|
75
|
+
params: input.params,
|
|
76
|
+
}),
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
if (!res.ok) {
|
|
80
|
+
throw new SuiHTTPStatusError(
|
|
81
|
+
`Unexpected status code: ${res.status}`,
|
|
82
|
+
res.status,
|
|
83
|
+
res.statusText
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const data = await res.json()
|
|
88
|
+
|
|
89
|
+
if ('error' in data && data.error != null) {
|
|
90
|
+
throw new JsonRpcError(data.error.message, data.error.code)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return data.result
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async subscribe(input) {
|
|
97
|
+
const unsubscribe = await this.#getWebsocketClient().subscribe(input)
|
|
98
|
+
|
|
99
|
+
if (input.signal) {
|
|
100
|
+
input.signal.throwIfAborted()
|
|
101
|
+
input.signal.addEventListener('abort', () => {
|
|
102
|
+
unsubscribe()
|
|
103
|
+
})
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return async () => !!(await unsubscribe())
|
|
107
|
+
}
|
|
108
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { SuiClient } from './client.js'
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { JsonRpcError } from './errors.js'
|
|
2
|
+
|
|
3
|
+
function getWebsocketUrl(httpUrl) {
|
|
4
|
+
const url = new URL(httpUrl)
|
|
5
|
+
url.protocol = url.protocol.replace('http', 'ws')
|
|
6
|
+
return url.toString()
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const DEFAULT_CLIENT_OPTIONS = {
|
|
10
|
+
// We fudge the typing because we also check for undefined in the constructor:
|
|
11
|
+
// eslint-disable-next-line no-undef
|
|
12
|
+
WebSocketConstructor: typeof WebSocket === 'undefined' ? undefined : WebSocket, // eslint-disable-line @typescript-eslint/no-unsafe-assignment
|
|
13
|
+
callTimeout: 30_000,
|
|
14
|
+
reconnectTimeout: 3000,
|
|
15
|
+
maxReconnects: 5,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export class WebsocketClient {
|
|
19
|
+
endpoint
|
|
20
|
+
options
|
|
21
|
+
#requestId = 0
|
|
22
|
+
#disconnects = 0
|
|
23
|
+
#webSocket = null
|
|
24
|
+
#connectionPromise = null
|
|
25
|
+
#subscriptions = new Set()
|
|
26
|
+
#pendingRequests = new Map()
|
|
27
|
+
|
|
28
|
+
constructor(endpoint, options = Object.create(null)) {
|
|
29
|
+
this.endpoint = endpoint
|
|
30
|
+
this.options = { ...DEFAULT_CLIENT_OPTIONS, ...options }
|
|
31
|
+
|
|
32
|
+
if (!this.options.WebSocketConstructor) {
|
|
33
|
+
throw new Error('Missing WebSocket constructor')
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (this.endpoint.startsWith('http')) {
|
|
37
|
+
this.endpoint = getWebsocketUrl(this.endpoint)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async makeRequest(method, params, signal) {
|
|
42
|
+
const webSocket = await this.#setupWebSocket()
|
|
43
|
+
|
|
44
|
+
return new Promise((resolve, reject) => {
|
|
45
|
+
this.#requestId += 1
|
|
46
|
+
this.#pendingRequests.set(this.#requestId, {
|
|
47
|
+
resolve,
|
|
48
|
+
reject,
|
|
49
|
+
timeout: setTimeout(() => {
|
|
50
|
+
this.#pendingRequests.delete(this.#requestId)
|
|
51
|
+
reject(new Error(`Request timeout: ${method}`))
|
|
52
|
+
}, this.options.callTimeout),
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
signal?.addEventListener('abort', () => {
|
|
56
|
+
this.#pendingRequests.delete(this.#requestId)
|
|
57
|
+
reject(signal.reason)
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
webSocket.send(JSON.stringify({ jsonrpc: '2.0', id: this.#requestId, method, params }))
|
|
61
|
+
}).then(({ error, result }) => {
|
|
62
|
+
if (error) {
|
|
63
|
+
throw new JsonRpcError(error.message, error.code)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return result
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
#setupWebSocket() {
|
|
71
|
+
if (this.#connectionPromise) {
|
|
72
|
+
return this.#connectionPromise
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
this.#connectionPromise = new Promise((resolve) => {
|
|
76
|
+
this.#webSocket?.close()
|
|
77
|
+
this.#webSocket = new this.options.WebSocketConstructor(this.endpoint)
|
|
78
|
+
|
|
79
|
+
this.#webSocket.addEventListener('open', () => {
|
|
80
|
+
this.#disconnects = 0
|
|
81
|
+
resolve(this.#webSocket)
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
this.#webSocket.addEventListener('close', () => {
|
|
85
|
+
this.#disconnects++
|
|
86
|
+
if (this.#disconnects <= this.options.maxReconnects) {
|
|
87
|
+
setTimeout(() => {
|
|
88
|
+
this.#reconnect()
|
|
89
|
+
}, this.options.reconnectTimeout)
|
|
90
|
+
}
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
this.#webSocket.addEventListener('message', ({ data }) => {
|
|
94
|
+
let json
|
|
95
|
+
try {
|
|
96
|
+
json = JSON.parse(data)
|
|
97
|
+
} catch (error) {
|
|
98
|
+
console.error(new Error(`Failed to parse RPC message: ${data}`, { cause: error }))
|
|
99
|
+
return
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if ('id' in json && json.id != null && this.#pendingRequests.has(json.id)) {
|
|
103
|
+
const { resolve, timeout } = this.#pendingRequests.get(json.id)
|
|
104
|
+
|
|
105
|
+
clearTimeout(timeout)
|
|
106
|
+
resolve(json)
|
|
107
|
+
} else if ('params' in json) {
|
|
108
|
+
const { params } = json
|
|
109
|
+
this.#subscriptions.forEach((subscription) => {
|
|
110
|
+
if (
|
|
111
|
+
subscription.subscriptionId === params.subscription &&
|
|
112
|
+
params.subscription === subscription.subscriptionId
|
|
113
|
+
) {
|
|
114
|
+
subscription.onMessage(params.result)
|
|
115
|
+
}
|
|
116
|
+
})
|
|
117
|
+
}
|
|
118
|
+
})
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
return this.#connectionPromise
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async #reconnect() {
|
|
125
|
+
this.#webSocket?.close()
|
|
126
|
+
this.#connectionPromise = null
|
|
127
|
+
|
|
128
|
+
return Promise.allSettled(
|
|
129
|
+
[...this.#subscriptions].map((subscription) => subscription.subscribe(this))
|
|
130
|
+
)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
async subscribe(input) {
|
|
134
|
+
const subscription = new RpcSubscription(input)
|
|
135
|
+
this.#subscriptions.add(subscription)
|
|
136
|
+
await subscription.subscribe(this)
|
|
137
|
+
return () => subscription.unsubscribe(this)
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
class RpcSubscription {
|
|
142
|
+
subscriptionId = null
|
|
143
|
+
input
|
|
144
|
+
subscribed = false
|
|
145
|
+
|
|
146
|
+
constructor(input) {
|
|
147
|
+
this.input = input
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
onMessage(message) {
|
|
151
|
+
if (this.subscribed) {
|
|
152
|
+
this.input.onMessage(message)
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async unsubscribe(client) {
|
|
157
|
+
const { subscriptionId } = this
|
|
158
|
+
this.subscribed = false
|
|
159
|
+
if (subscriptionId == null) return false
|
|
160
|
+
this.subscriptionId = null
|
|
161
|
+
|
|
162
|
+
return client.makeRequest(this.input.unsubscribe, [subscriptionId])
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
async subscribe(client) {
|
|
166
|
+
this.subscriptionId = null
|
|
167
|
+
this.subscribed = true
|
|
168
|
+
const newSubscriptionId = await client.makeRequest(
|
|
169
|
+
this.input.method,
|
|
170
|
+
this.input.params,
|
|
171
|
+
this.input.signal
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
if (this.subscribed) {
|
|
175
|
+
this.subscriptionId = newSubscriptionId
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/* eslint-disable no-sequences */
|
|
2
|
+
var __typeError = (msg) => {
|
|
3
|
+
throw new TypeError(msg)
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError('Cannot ' + msg)
|
|
7
|
+
var __privateGet = (obj, member, getter) => (
|
|
8
|
+
__accessCheck(obj, member, 'read from private field'), getter ? getter.call(obj) : member.get(obj)
|
|
9
|
+
)
|
|
10
|
+
var __privateAdd = (obj, member, value) =>
|
|
11
|
+
member.has(obj)
|
|
12
|
+
? __typeError('Cannot add the same private member more than once')
|
|
13
|
+
: member instanceof WeakSet
|
|
14
|
+
? member.add(obj)
|
|
15
|
+
: member.set(obj, value)
|
|
16
|
+
var __privateSet = (obj, member, value, setter) => (
|
|
17
|
+
__accessCheck(obj, member, 'write to private field'),
|
|
18
|
+
setter ? setter.call(obj, value) : member.set(obj, value),
|
|
19
|
+
value
|
|
20
|
+
)
|
|
21
|
+
var _prefix, _cache
|
|
22
|
+
const _ClientCache = class _ClientCache {
|
|
23
|
+
constructor({ prefix, cache } = Object.create(null)) {
|
|
24
|
+
__privateAdd(this, _prefix)
|
|
25
|
+
__privateAdd(this, _cache)
|
|
26
|
+
__privateSet(this, _prefix, prefix ?? [])
|
|
27
|
+
__privateSet(this, _cache, cache ?? /* @__PURE__ */ new Map())
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
read(key, load) {
|
|
31
|
+
const cacheKey = [__privateGet(this, _prefix), ...key].join(':')
|
|
32
|
+
if (__privateGet(this, _cache).has(cacheKey)) {
|
|
33
|
+
return __privateGet(this, _cache).get(cacheKey)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const result = load()
|
|
37
|
+
__privateGet(this, _cache).set(cacheKey, result)
|
|
38
|
+
if (typeof result === 'object' && result !== null && result.hasOwnProperty('then')) {
|
|
39
|
+
return Promise.resolve(result)
|
|
40
|
+
.then((v) => {
|
|
41
|
+
__privateGet(this, _cache).set(cacheKey, v)
|
|
42
|
+
return v
|
|
43
|
+
})
|
|
44
|
+
.catch((err) => {
|
|
45
|
+
__privateGet(this, _cache).delete(cacheKey)
|
|
46
|
+
throw err
|
|
47
|
+
})
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return result
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
readSync(key, load) {
|
|
54
|
+
const cacheKey = [__privateGet(this, _prefix), ...key].join(':')
|
|
55
|
+
if (__privateGet(this, _cache).has(cacheKey)) {
|
|
56
|
+
return __privateGet(this, _cache).get(cacheKey)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const result = load()
|
|
60
|
+
__privateGet(this, _cache).set(cacheKey, result)
|
|
61
|
+
return result
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
clear(prefix) {
|
|
65
|
+
const prefixKey = [...__privateGet(this, _prefix), ...(prefix ?? [])].join(':')
|
|
66
|
+
if (!prefixKey) {
|
|
67
|
+
__privateGet(this, _cache).clear()
|
|
68
|
+
return
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
for (const key of __privateGet(this, _cache).keys()) {
|
|
72
|
+
if (key.startsWith(prefixKey)) {
|
|
73
|
+
__privateGet(this, _cache).delete(key)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
scope(prefix) {
|
|
79
|
+
return new _ClientCache({
|
|
80
|
+
prefix: [...__privateGet(this, _prefix), ...(Array.isArray(prefix) ? prefix : [prefix])],
|
|
81
|
+
cache: __privateGet(this, _cache),
|
|
82
|
+
})
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
_prefix = new WeakMap()
|
|
86
|
+
_cache = new WeakMap()
|
|
87
|
+
const ClientCache = _ClientCache
|
|
88
|
+
export { ClientCache }
|
|
89
|
+
// # sourceMappingURL=cache.js.map
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/* eslint-disable camelcase */
|
|
2
|
+
import { ClientCache } from './cache.js'
|
|
3
|
+
|
|
4
|
+
class Experimental_BaseClient {
|
|
5
|
+
constructor({ network, base }) {
|
|
6
|
+
this.network = network
|
|
7
|
+
this.base = base ?? this
|
|
8
|
+
this.cache = base?.cache ?? new ClientCache()
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
$extend(...registrations) {
|
|
12
|
+
return Object.create(
|
|
13
|
+
this,
|
|
14
|
+
Object.fromEntries(
|
|
15
|
+
registrations.map((registration) => {
|
|
16
|
+
if ('experimental_asClientExtension' in registration) {
|
|
17
|
+
const { name, register } = registration.experimental_asClientExtension()
|
|
18
|
+
return [name, { value: register(this) }]
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return [registration.name, { value: registration.register(this) }]
|
|
22
|
+
})
|
|
23
|
+
)
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export { Experimental_BaseClient }
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/* eslint-disable camelcase */
|
|
2
|
+
|
|
3
|
+
import { vendorLib } from '@exodus/sui-lib'
|
|
4
|
+
|
|
5
|
+
import { Experimental_BaseClient } from './client.js'
|
|
6
|
+
import { MvrClient } from './mvr.js'
|
|
7
|
+
|
|
8
|
+
const { TypeTagSerializer } = vendorLib.bcs
|
|
9
|
+
const { deriveDynamicFieldID, normalizeStructTag, parseStructTag, SUI_ADDRESS_LENGTH } =
|
|
10
|
+
vendorLib.utils
|
|
11
|
+
|
|
12
|
+
const DEFAULT_MVR_URLS = {
|
|
13
|
+
mainnet: 'https://mainnet.mvr.mystenlabs.com',
|
|
14
|
+
testnet: 'https://testnet.mvr.mystenlabs.com',
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
class Experimental_CoreClient extends Experimental_BaseClient {
|
|
18
|
+
constructor(options) {
|
|
19
|
+
super(options)
|
|
20
|
+
this.core = this
|
|
21
|
+
this.mvr = new MvrClient({
|
|
22
|
+
cache: this.cache.scope('core.mvr'),
|
|
23
|
+
url: options.mvr?.url ?? DEFAULT_MVR_URLS[this.network],
|
|
24
|
+
pageSize: options.mvr?.pageSize,
|
|
25
|
+
overrides: options.mvr?.overrides,
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async getObject(options) {
|
|
30
|
+
const { objectId } = options
|
|
31
|
+
const {
|
|
32
|
+
objects: [result],
|
|
33
|
+
} = await this.getObjects({ objectIds: [objectId], signal: options.signal })
|
|
34
|
+
if (result instanceof Error) {
|
|
35
|
+
throw result
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return { object: result }
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async getDynamicField(options) {
|
|
42
|
+
const fieldId = deriveDynamicFieldID(
|
|
43
|
+
options.parentId,
|
|
44
|
+
TypeTagSerializer.parseFromStr(options.name.type),
|
|
45
|
+
options.name.bcs
|
|
46
|
+
)
|
|
47
|
+
const {
|
|
48
|
+
objects: [fieldObject],
|
|
49
|
+
} = await this.getObjects({
|
|
50
|
+
objectIds: [fieldId],
|
|
51
|
+
signal: options.signal,
|
|
52
|
+
})
|
|
53
|
+
if (fieldObject instanceof Error) {
|
|
54
|
+
throw fieldObject
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const fieldType = parseStructTag(fieldObject.type)
|
|
58
|
+
const content = await fieldObject.content
|
|
59
|
+
return {
|
|
60
|
+
dynamicField: {
|
|
61
|
+
id: fieldObject.id,
|
|
62
|
+
digest: fieldObject.digest,
|
|
63
|
+
version: fieldObject.version,
|
|
64
|
+
type: fieldObject.type,
|
|
65
|
+
name: {
|
|
66
|
+
type:
|
|
67
|
+
typeof fieldType.typeParams[0] === 'string'
|
|
68
|
+
? fieldType.typeParams[0]
|
|
69
|
+
: normalizeStructTag(fieldType.typeParams[0]),
|
|
70
|
+
bcs: options.name.bcs,
|
|
71
|
+
},
|
|
72
|
+
value: {
|
|
73
|
+
type:
|
|
74
|
+
typeof fieldType.typeParams[1] === 'string'
|
|
75
|
+
? fieldType.typeParams[1]
|
|
76
|
+
: normalizeStructTag(fieldType.typeParams[1]),
|
|
77
|
+
bcs: content.slice(SUI_ADDRESS_LENGTH + options.name.bcs.length),
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async waitForTransaction({ signal, timeout = 60 * 1e3, ...input }) {
|
|
84
|
+
const abortSignal = signal
|
|
85
|
+
? AbortSignal.any([AbortSignal.timeout(timeout), signal])
|
|
86
|
+
: AbortSignal.timeout(timeout)
|
|
87
|
+
// eslint-disable-next-line promise/param-names
|
|
88
|
+
const abortPromise = new Promise((_, reject) => {
|
|
89
|
+
abortSignal.addEventListener('abort', () => reject(abortSignal.reason))
|
|
90
|
+
})
|
|
91
|
+
abortPromise.catch(() => {})
|
|
92
|
+
while (true) {
|
|
93
|
+
abortSignal.throwIfAborted()
|
|
94
|
+
try {
|
|
95
|
+
return await this.getTransaction({
|
|
96
|
+
...input,
|
|
97
|
+
signal: abortSignal,
|
|
98
|
+
})
|
|
99
|
+
} catch {
|
|
100
|
+
await Promise.race([new Promise((resolve) => setTimeout(resolve, 2e3)), abortPromise])
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
export { Experimental_CoreClient }
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/* eslint-disable sonarjs/no-nested-template-literals */
|
|
2
|
+
class SuiClientError extends Error {}
|
|
3
|
+
|
|
4
|
+
class ObjectError extends SuiClientError {
|
|
5
|
+
constructor(code, message) {
|
|
6
|
+
super(message)
|
|
7
|
+
this.code = code
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
static fromResponse(response, objectId) {
|
|
11
|
+
switch (response.code) {
|
|
12
|
+
case 'notExists':
|
|
13
|
+
return new ObjectError(response.code, `Object ${response.object_id} does not exist`)
|
|
14
|
+
case 'dynamicFieldNotFound':
|
|
15
|
+
return new ObjectError(
|
|
16
|
+
response.code,
|
|
17
|
+
`Dynamic field not found for object ${response.parent_object_id}`
|
|
18
|
+
)
|
|
19
|
+
case 'deleted':
|
|
20
|
+
return new ObjectError(response.code, `Object ${response.object_id} has been deleted`)
|
|
21
|
+
case 'displayError':
|
|
22
|
+
return new ObjectError(response.code, `Display error: ${response.error}`)
|
|
23
|
+
default:
|
|
24
|
+
return new ObjectError(
|
|
25
|
+
response.code,
|
|
26
|
+
`Unknown error while loading object${objectId ? ` ${objectId}` : ''}`
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export { ObjectError, SuiClientError }
|
|
32
|
+
// # sourceMappingURL=errors.js.map
|