@dynamic-labs/sui-core 4.19.7

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.
Files changed (42) hide show
  1. package/CHANGELOG.md +5555 -0
  2. package/LICENSE +21 -0
  3. package/README.md +1 -0
  4. package/_virtual/_tslib.cjs +36 -0
  5. package/_virtual/_tslib.js +32 -0
  6. package/package.cjs +8 -0
  7. package/package.js +4 -0
  8. package/package.json +34 -0
  9. package/src/SuiWalletConnector.cjs +306 -0
  10. package/src/SuiWalletConnector.d.ts +75 -0
  11. package/src/SuiWalletConnector.js +302 -0
  12. package/src/index.cjs +23 -0
  13. package/src/index.d.ts +7 -0
  14. package/src/index.js +12 -0
  15. package/src/types.d.ts +27 -0
  16. package/src/utils/SuiUiTransaction/SuiUiTransaction.cjs +125 -0
  17. package/src/utils/SuiUiTransaction/SuiUiTransaction.d.ts +47 -0
  18. package/src/utils/SuiUiTransaction/SuiUiTransaction.js +121 -0
  19. package/src/utils/SuiUiTransaction/index.d.ts +1 -0
  20. package/src/utils/constants/constants.cjs +8 -0
  21. package/src/utils/constants/constants.d.ts +1 -0
  22. package/src/utils/constants/constants.js +4 -0
  23. package/src/utils/constants/index.d.ts +1 -0
  24. package/src/utils/network/index.d.ts +1 -0
  25. package/src/utils/network/networkHelpers.cjs +34 -0
  26. package/src/utils/network/networkHelpers.d.ts +19 -0
  27. package/src/utils/network/networkHelpers.js +29 -0
  28. package/src/wallet/SuiWallet.cjs +116 -0
  29. package/src/wallet/SuiWallet.d.ts +40 -0
  30. package/src/wallet/SuiWallet.js +112 -0
  31. package/src/wallet/index.d.ts +1 -0
  32. package/src/wallet/isSuiWallet/index.d.ts +1 -0
  33. package/src/wallet/isSuiWallet/isSuiWallet.cjs +8 -0
  34. package/src/wallet/isSuiWallet/isSuiWallet.d.ts +3 -0
  35. package/src/wallet/isSuiWallet/isSuiWallet.js +4 -0
  36. package/src/wallets/injected/fetchSuiInjectedWalletConnectors.cjs +64 -0
  37. package/src/wallets/injected/fetchSuiInjectedWalletConnectors.d.ts +5 -0
  38. package/src/wallets/injected/fetchSuiInjectedWalletConnectors.js +60 -0
  39. package/src/wallets/injected/index.d.ts +1 -0
  40. package/src/wallets/injected/injected.cjs +19 -0
  41. package/src/wallets/injected/injected.d.ts +13 -0
  42. package/src/wallets/injected/injected.js +15 -0
@@ -0,0 +1,302 @@
1
+ 'use client'
2
+ import { __awaiter } from '../_virtual/_tslib.js';
3
+ import { SuiClient } from '@mysten/sui/client';
4
+ import { WalletConnectorBase } from '@dynamic-labs/wallet-connector-core';
5
+ import { DynamicError } from '@dynamic-labs/utils';
6
+ import { Logger } from '@dynamic-labs/logger';
7
+ import { SuiWallet } from './wallet/SuiWallet.js';
8
+ import { getSuiNetworkIdFromName, getPreferredRpcUrl } from './utils/network/networkHelpers.js';
9
+ import { SuiUiTransaction } from './utils/SuiUiTransaction/SuiUiTransaction.js';
10
+
11
+ class SuiWalletConnector extends WalletConnectorBase {
12
+ constructor(name, opts) {
13
+ super(opts);
14
+ this.name = 'Sui';
15
+ this.ChainWallet = SuiWallet;
16
+ this.connectedChain = 'SUI';
17
+ this.supportedChains = ['SUI'];
18
+ this.switchNetworkOnlyFromWallet = true;
19
+ /** required for metamask snap integration as MM snaps don't have event listeners */
20
+ this.canSetEventListeners = true;
21
+ /** Sui clients */
22
+ this.suiClients = {};
23
+ /** Whether the connector is currently attempting to connect */
24
+ this.isConnecting = false;
25
+ this.name = name;
26
+ this.wallet = opts.wallet;
27
+ this.chainRpcProviders = opts.chainRpcProviders;
28
+ this.suiNetworks = opts.suiNetworks;
29
+ this.logger = new Logger(this.name);
30
+ }
31
+ /** Helper to return the wallet features */
32
+ getFeatures() {
33
+ var _a;
34
+ return (_a = this.wallet) === null || _a === void 0 ? void 0 : _a.features;
35
+ }
36
+ /** Connect to the wallet using the standard:connect feature */
37
+ connect() {
38
+ return __awaiter(this, arguments, void 0, function* ({ silent } = {}) {
39
+ var _a, _b;
40
+ if (this.account || this.isConnecting) {
41
+ // Account is already connected or we're already connecting
42
+ return;
43
+ }
44
+ const connectFeature = (_a = this.getFeatures()) === null || _a === void 0 ? void 0 : _a['standard:connect'];
45
+ if (!connectFeature) {
46
+ if (silent) {
47
+ return;
48
+ }
49
+ throw new DynamicError('Wallet does not support standard:connect');
50
+ }
51
+ // Start connecting
52
+ this.isConnecting = true;
53
+ this.logger.debug('[connect] Creating new connection');
54
+ try {
55
+ const response = yield connectFeature.connect(silent ? { silent } : undefined);
56
+ this.logger.debug(`[connect] Connection returned accounts: ${response === null || response === void 0 ? void 0 : response.accounts.length}`);
57
+ this.account = response === null || response === void 0 ? void 0 : response.accounts[0];
58
+ const primaryChain = (_b = this.account) === null || _b === void 0 ? void 0 : _b.chains[0];
59
+ if (primaryChain) {
60
+ this.activeNetworkId = getSuiNetworkIdFromName(primaryChain, this.suiNetworks);
61
+ }
62
+ }
63
+ catch (error) {
64
+ this.logger.error(error);
65
+ if (silent) {
66
+ return;
67
+ }
68
+ throw new DynamicError('Connection failed');
69
+ }
70
+ finally {
71
+ this.isConnecting = false;
72
+ }
73
+ this.setupEventListeners();
74
+ });
75
+ }
76
+ /** Get the wallet address by connecting to the current account */
77
+ getAddress() {
78
+ return __awaiter(this, void 0, void 0, function* () {
79
+ this.logger.debug('[getAddress] called, attempting to obtain the account address');
80
+ yield this.connect();
81
+ if (!this.account) {
82
+ throw new DynamicError('No account found');
83
+ }
84
+ return this.account.address;
85
+ });
86
+ }
87
+ /** Returns the network id of the account's active chain */
88
+ getNetwork() {
89
+ return __awaiter(this, void 0, void 0, function* () {
90
+ if (!this.account) {
91
+ yield this.connect();
92
+ }
93
+ return this.activeNetworkId;
94
+ });
95
+ }
96
+ getConnectedAccounts() {
97
+ return __awaiter(this, void 0, void 0, function* () {
98
+ var _a;
99
+ if (!this.account) {
100
+ yield this.connect({ silent: true });
101
+ }
102
+ const address = (_a = this.account) === null || _a === void 0 ? void 0 : _a.address;
103
+ if (address) {
104
+ return [address];
105
+ }
106
+ return [];
107
+ });
108
+ }
109
+ /**
110
+ * Helper to get the chain id from a [SuiChangeEvent].
111
+ *
112
+ * Some wallets set the event.chains objects but others use event.accounts.chains,
113
+ * so we need to deal with both cases.
114
+ *
115
+ * @param event - The [SuiChangeEvent] to get the chain id from
116
+ * @returns The dynamic chain id or '-1' if the chain id is not found
117
+ */
118
+ getChainFromEvent(event) {
119
+ var _a, _b, _c, _d, _e;
120
+ let suiChain = (_a = event.chains) === null || _a === void 0 ? void 0 : _a[0];
121
+ if (!suiChain) {
122
+ suiChain = (_d = (_c = (_b = event.accounts) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.chains) === null || _d === void 0 ? void 0 : _d[0];
123
+ }
124
+ if (!suiChain) {
125
+ return '-1';
126
+ }
127
+ return (_e = getSuiNetworkIdFromName(suiChain, this.suiNetworks)) !== null && _e !== void 0 ? _e : '-1';
128
+ }
129
+ setupEventListeners() {
130
+ var _a;
131
+ if (!this.canSetEventListeners || this.eventsHandler)
132
+ return;
133
+ const eventsFeature = (_a = this.getFeatures()) === null || _a === void 0 ? void 0 : _a['standard:events'];
134
+ if (!eventsFeature) {
135
+ this.logger.debug('[setupEventListeners] Wallet not connected or does not support standard:events');
136
+ return;
137
+ }
138
+ this.eventsHandler = (event) => __awaiter(this, void 0, void 0, function* () {
139
+ var _b;
140
+ if (event.accounts) {
141
+ // If the event sets accounts but it's empty, we need to disconnect.
142
+ if (event.accounts.length === 0 && this.account) {
143
+ this.account = undefined;
144
+ this.emit('disconnect');
145
+ return;
146
+ }
147
+ const [primaryAccount] = event.accounts;
148
+ if (primaryAccount.address !== ((_b = this.account) === null || _b === void 0 ? void 0 : _b.address)) {
149
+ this.account = primaryAccount;
150
+ this.emit('accountChange', { accounts: [primaryAccount.address] });
151
+ }
152
+ }
153
+ // Some events will leave out accounts but set the chains object, so we process those
154
+ // with the helper.
155
+ const suiChainId = this.getChainFromEvent(event);
156
+ if (suiChainId !== this.activeNetworkId) {
157
+ this.activeNetworkId = suiChainId;
158
+ this.emit('chainChange', { chain: suiChainId });
159
+ }
160
+ });
161
+ this.logger.debug('[setupEventListeners] Setting up sui wallet connector event listeners');
162
+ this.eventsUnsubscribeHandler = eventsFeature.on('change', this.eventsHandler);
163
+ }
164
+ /**
165
+ * Helper to get the Sui client for the current network
166
+ *
167
+ * The client will prefer the private customer rpc url if available.
168
+ */
169
+ getSuiClient(networkId) {
170
+ return __awaiter(this, void 0, void 0, function* () {
171
+ const clientNetworkId = networkId !== null && networkId !== void 0 ? networkId : (yield this.getNetwork());
172
+ if (!clientNetworkId) {
173
+ this.logger.error('[getSuiClient] Failed to get network id');
174
+ return undefined;
175
+ }
176
+ // Default to an existing client if available
177
+ if (this.suiClients[clientNetworkId]) {
178
+ return this.suiClients[clientNetworkId];
179
+ }
180
+ const network = this.getEnabledNetworks().find((network) => network.networkId === clientNetworkId);
181
+ const url = network ? getPreferredRpcUrl(network) : undefined;
182
+ if (!url) {
183
+ this.logger.error('[getSuiClient] Failed to get network url');
184
+ return undefined;
185
+ }
186
+ this.suiClients[clientNetworkId] = new SuiClient({
187
+ url: url,
188
+ });
189
+ return this.suiClients[clientNetworkId];
190
+ });
191
+ }
192
+ getBalance(address) {
193
+ return __awaiter(this, void 0, void 0, function* () {
194
+ const client = yield this.getSuiClient();
195
+ if (!client) {
196
+ this.logger.error('[getBalance] Failed to get Sui client');
197
+ return undefined;
198
+ }
199
+ const balanceResult = yield client.getBalance({
200
+ owner: address,
201
+ });
202
+ // Balance comes back as MIST, 1 SUI = 1e9 MIST
203
+ const balance = Number(balanceResult === null || balanceResult === void 0 ? void 0 : balanceResult.totalBalance) / 1e9;
204
+ if (Number.isNaN(balance)) {
205
+ this.logger.error(`[getBalance] Failed to get balance for address: ${address}`);
206
+ return undefined;
207
+ }
208
+ return balance.toFixed(6);
209
+ });
210
+ }
211
+ signMessage(messageToSign) {
212
+ return __awaiter(this, void 0, void 0, function* () {
213
+ var _a;
214
+ this.logger.debug('[signMessage] called, attempting to sign a message');
215
+ const signFeature = (_a = this.getFeatures()) === null || _a === void 0 ? void 0 : _a['sui:signPersonalMessage'];
216
+ if (!signFeature) {
217
+ throw new DynamicError('Wallet does not support sui:signPersonalMessage');
218
+ }
219
+ yield this.connect();
220
+ if (!this.account) {
221
+ throw new DynamicError('[signMessage] No account found');
222
+ }
223
+ let output;
224
+ try {
225
+ output = yield signFeature.signPersonalMessage({
226
+ account: this.account,
227
+ message: new TextEncoder().encode(messageToSign),
228
+ });
229
+ }
230
+ catch (error) {
231
+ this.logger.error(error);
232
+ throw new DynamicError('An error occured during signing');
233
+ }
234
+ if (!output || !output.signature) {
235
+ throw new DynamicError('[signMessage] Failed to sign message');
236
+ }
237
+ this.logger.debug(`[signMessage] Signed message: ${output.signature}`);
238
+ return output.signature;
239
+ });
240
+ }
241
+ getWalletAccount() {
242
+ return __awaiter(this, void 0, void 0, function* () {
243
+ return this.account;
244
+ });
245
+ }
246
+ /** Function used to create transactions in the SDK interface */
247
+ createUiTransaction(from) {
248
+ return __awaiter(this, void 0, void 0, function* () {
249
+ yield this.validateActiveWallet(from);
250
+ const suiClient = yield this.getSuiClient();
251
+ if (!suiClient) {
252
+ throw new DynamicError('No Sui client available');
253
+ }
254
+ return new SuiUiTransaction({
255
+ client: suiClient,
256
+ from,
257
+ onSubmit: (transaction) => __awaiter(this, void 0, void 0, function* () {
258
+ var _a, _b;
259
+ if (!this.account || !transaction) {
260
+ throw new DynamicError('No account or transaction found');
261
+ }
262
+ const result = yield ((_b = (_a = this.getFeatures()) === null || _a === void 0 ? void 0 : _a['sui:signAndExecuteTransaction']) === null || _b === void 0 ? void 0 : _b.signAndExecuteTransaction({
263
+ account: this.account,
264
+ chain: this.account.chains[0],
265
+ transaction,
266
+ }));
267
+ return result;
268
+ }),
269
+ });
270
+ });
271
+ }
272
+ teardownEventListeners() {
273
+ return __awaiter(this, void 0, void 0, function* () {
274
+ if (this.eventsUnsubscribeHandler) {
275
+ this.eventsUnsubscribeHandler();
276
+ this.eventsUnsubscribeHandler = undefined;
277
+ }
278
+ });
279
+ }
280
+ endSession() {
281
+ return __awaiter(this, void 0, void 0, function* () {
282
+ var _a;
283
+ this.teardownEventListeners();
284
+ this.account = undefined;
285
+ const disconnectFeature = (_a = this.getFeatures()) === null || _a === void 0 ? void 0 : _a['standard:disconnect'];
286
+ if (disconnectFeature) {
287
+ yield disconnectFeature.disconnect();
288
+ return;
289
+ }
290
+ if (this.wallet.disconnect) {
291
+ yield this.wallet.disconnect();
292
+ return;
293
+ }
294
+ throw new DynamicError('Wallet does not support disconnect');
295
+ });
296
+ }
297
+ getEnabledNetworks() {
298
+ return this.suiNetworks;
299
+ }
300
+ }
301
+
302
+ export { SuiWalletConnector };
package/src/index.cjs ADDED
@@ -0,0 +1,23 @@
1
+ 'use client'
2
+ 'use strict';
3
+
4
+ Object.defineProperty(exports, '__esModule', { value: true });
5
+
6
+ var assertPackageVersion = require('@dynamic-labs/assert-package-version');
7
+ var _package = require('../package.cjs');
8
+ var constants = require('./utils/constants/constants.cjs');
9
+ var SuiWalletConnector = require('./SuiWalletConnector.cjs');
10
+ var SuiWallet = require('./wallet/SuiWallet.cjs');
11
+ var isSuiWallet = require('./wallet/isSuiWallet/isSuiWallet.cjs');
12
+ var SuiUiTransaction = require('./utils/SuiUiTransaction/SuiUiTransaction.cjs');
13
+ var fetchSuiInjectedWalletConnectors = require('./wallets/injected/fetchSuiInjectedWalletConnectors.cjs');
14
+
15
+ /* eslint-disable @typescript-eslint/no-unused-vars */
16
+ assertPackageVersion.assertPackageVersion('@dynamic-labs/sui-core', _package.version);
17
+
18
+ exports.MIST_PER_SUI = constants.MIST_PER_SUI;
19
+ exports.SuiWalletConnector = SuiWalletConnector.SuiWalletConnector;
20
+ exports.SuiWallet = SuiWallet.SuiWallet;
21
+ exports.isSuiWallet = isSuiWallet.isSuiWallet;
22
+ exports.SuiUiTransaction = SuiUiTransaction.SuiUiTransaction;
23
+ exports.fetchSuiInjectedWalletConnectors = fetchSuiInjectedWalletConnectors.fetchSuiInjectedWalletConnectors;
package/src/index.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ export * from './utils/constants';
2
+ export { SuiWalletConnector } from './SuiWalletConnector';
3
+ export { SuiWallet } from './wallet/SuiWallet';
4
+ export { isSuiWallet } from './wallet/isSuiWallet';
5
+ export type { SuiWalletConnectorProps, SuiSendBalanceProps } from './types';
6
+ export { SuiUiTransaction } from './utils/SuiUiTransaction/SuiUiTransaction';
7
+ export { fetchSuiInjectedWalletConnectors } from './wallets/injected/fetchSuiInjectedWalletConnectors';
package/src/index.js ADDED
@@ -0,0 +1,12 @@
1
+ 'use client'
2
+ import { assertPackageVersion } from '@dynamic-labs/assert-package-version';
3
+ import { version } from '../package.js';
4
+ export { MIST_PER_SUI } from './utils/constants/constants.js';
5
+ export { SuiWalletConnector } from './SuiWalletConnector.js';
6
+ export { SuiWallet } from './wallet/SuiWallet.js';
7
+ export { isSuiWallet } from './wallet/isSuiWallet/isSuiWallet.js';
8
+ export { SuiUiTransaction } from './utils/SuiUiTransaction/SuiUiTransaction.js';
9
+ export { fetchSuiInjectedWalletConnectors } from './wallets/injected/fetchSuiInjectedWalletConnectors.js';
10
+
11
+ /* eslint-disable @typescript-eslint/no-unused-vars */
12
+ assertPackageVersion('@dynamic-labs/sui-core', version);
package/src/types.d.ts ADDED
@@ -0,0 +1,27 @@
1
+ import { WalletWithFeatures, SuiWalletFeatures, IdentifierRecord, IdentifierArray, WalletAccount } from '@mysten/wallet-standard';
2
+ import { IChainRpcProviders } from '@dynamic-labs/rpc-providers';
3
+ import { NetworkConfiguration } from '@dynamic-labs/sdk-api-core';
4
+ import { WalletBookSchema } from '@dynamic-labs/wallet-book';
5
+ import { WalletMetadata } from '@dynamic-labs/wallet-connector-core';
6
+ export type SuiWalletConnectorProps = {
7
+ chainRpcProviders: IChainRpcProviders;
8
+ suiNetworks: NetworkConfiguration[];
9
+ walletBook: WalletBookSchema;
10
+ metadata?: WalletMetadata;
11
+ wallet: WalletWithFeatures<SuiWalletFeatures>;
12
+ overrideKey?: string;
13
+ };
14
+ export type SuiChangeEvent = {
15
+ accounts: WalletAccount[];
16
+ chains: IdentifierArray;
17
+ features: IdentifierRecord<unknown>;
18
+ };
19
+ export type SuiWalletStandardEventHandler = (event: SuiChangeEvent) => Promise<void>;
20
+ export type SuiSendBalanceProps = {
21
+ amount: string;
22
+ toAddress: string;
23
+ token?: {
24
+ address: string;
25
+ decimals?: number;
26
+ };
27
+ };
@@ -0,0 +1,125 @@
1
+ 'use client'
2
+ 'use strict';
3
+
4
+ Object.defineProperty(exports, '__esModule', { value: true });
5
+
6
+ var _tslib = require('../../../_virtual/_tslib.cjs');
7
+ var transactions = require('@mysten/sui/transactions');
8
+ var utils$1 = require('@mysten/sui/utils');
9
+ var utils = require('@dynamic-labs/utils');
10
+ var constants = require('../constants/constants.cjs');
11
+
12
+ class SuiUiTransaction {
13
+ constructor({ onSubmit, from, client }) {
14
+ this.chain = 'SUI';
15
+ this.data = undefined;
16
+ this.fee = { gas: undefined };
17
+ this.formatNonNativeToken = (value, decimals) => (Number(value) / Number(Math.pow(10, decimals))).toString();
18
+ this.from = from;
19
+ this.onSubmit = onSubmit;
20
+ this.client = client;
21
+ }
22
+ /**
23
+ * Fetches the gas fee for the transaction by executing a dry run of the
24
+ * transaction and calculating the gas used.
25
+ *
26
+ * @returns The gas fee for the transaction
27
+ */
28
+ fetchFee() {
29
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
30
+ if (this.fee.gas)
31
+ return;
32
+ const transaction = yield this.createTransactionSafe();
33
+ if (!transaction) {
34
+ throw new Error('Could not create a valid SUI transaction, check your address and value');
35
+ }
36
+ const transactionBlock = yield transaction.build({ client: this.client });
37
+ const dryRunResult = yield this.client.dryRunTransactionBlock({
38
+ transactionBlock,
39
+ });
40
+ if (!dryRunResult) {
41
+ this.fee.gas = undefined;
42
+ throw new Error('Error accessing SUI network to calculate gas, please try again later');
43
+ }
44
+ const gasObject = dryRunResult.effects.gasUsed;
45
+ // net_gas_fees = computation_gas_fee + storage_gas_fee - storage_rebate
46
+ // https://docs.sui.io/concepts/tokenomics/gas-in-sui
47
+ const calculatedGas = BigInt(gasObject.computationCost) +
48
+ BigInt(gasObject.storageCost) -
49
+ BigInt(gasObject.storageRebate);
50
+ this.fee.gas = calculatedGas;
51
+ if (this.fee.gas <= BigInt(0)) {
52
+ this.fee.gas = undefined;
53
+ }
54
+ });
55
+ }
56
+ isGasSponsored() {
57
+ return false;
58
+ }
59
+ parse(input) {
60
+ const floatValue = parseFloat(input);
61
+ const mist = Math.round(floatValue * constants.MIST_PER_SUI);
62
+ return BigInt(mist);
63
+ }
64
+ parseNonNativeToken(input, decimals) {
65
+ return BigInt(Math.floor(Number(input) * Math.pow(10, decimals)));
66
+ }
67
+ format(value, { precision } = {}) {
68
+ const suiValue = Number(value) / constants.MIST_PER_SUI;
69
+ const decimalString = suiValue.toLocaleString('fullwide', {
70
+ maximumFractionDigits: 20,
71
+ minimumFractionDigits: 0,
72
+ useGrouping: false,
73
+ });
74
+ return utils.formatNumberText(decimalString, { precision });
75
+ }
76
+ submit() {
77
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
78
+ const sendTransaction = (yield this.createTransaction());
79
+ return this.onSubmit(sendTransaction);
80
+ });
81
+ }
82
+ getBalance() {
83
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
84
+ const balance = yield this.client.getBalance({
85
+ coinType: '0x2::sui::SUI',
86
+ owner: this.from,
87
+ });
88
+ return BigInt(balance.totalBalance);
89
+ });
90
+ }
91
+ validateAddressFormat(address) {
92
+ if (address === 'dyn_send_transaction.multiple_recipients') {
93
+ return true;
94
+ }
95
+ return utils$1.isValidSuiAddress(address);
96
+ }
97
+ createTransaction() {
98
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
99
+ const { value, to } = this;
100
+ if (!to) {
101
+ throw new Error('Destination is required');
102
+ }
103
+ if (!value) {
104
+ return undefined;
105
+ }
106
+ const sendTransaction = new transactions.Transaction();
107
+ sendTransaction.setSender(this.from);
108
+ const [coin] = sendTransaction.splitCoins(sendTransaction.gas, [value]);
109
+ sendTransaction.transferObjects([coin], to);
110
+ return sendTransaction;
111
+ });
112
+ }
113
+ createTransactionSafe() {
114
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
115
+ try {
116
+ return yield this.createTransaction();
117
+ }
118
+ catch (error) {
119
+ return undefined;
120
+ }
121
+ });
122
+ }
123
+ }
124
+
125
+ exports.SuiUiTransaction = SuiUiTransaction;
@@ -0,0 +1,47 @@
1
+ import { Transaction } from '@mysten/sui/transactions';
2
+ import { SuiClient } from '@mysten/sui/client';
3
+ import { IUITransaction, IUITransactionFormatOptions } from '@dynamic-labs/types';
4
+ type SuiUiTransactionProps = {
5
+ /** SUI Address of the sender */
6
+ from: string;
7
+ /** The [SuiClient] instance, needed to estimate gas fees */
8
+ client: SuiClient;
9
+ /** The function to call when the transaction is submitted */
10
+ onSubmit: (transaction?: Transaction) => Promise<any>;
11
+ };
12
+ export declare class SuiUiTransaction implements IUITransaction {
13
+ to: string | undefined;
14
+ from: string;
15
+ value: bigint | undefined;
16
+ chain: string;
17
+ receipt: string | undefined;
18
+ data: undefined;
19
+ fee: {
20
+ gas: bigint | undefined;
21
+ };
22
+ nonNativeAddress?: string;
23
+ nonNativeDecimal?: number;
24
+ nonNativeValue?: bigint;
25
+ nativePrice?: number;
26
+ private onSubmit;
27
+ private client;
28
+ constructor({ onSubmit, from, client }: SuiUiTransactionProps);
29
+ /**
30
+ * Fetches the gas fee for the transaction by executing a dry run of the
31
+ * transaction and calculating the gas used.
32
+ *
33
+ * @returns The gas fee for the transaction
34
+ */
35
+ fetchFee(): Promise<void>;
36
+ isGasSponsored(): boolean;
37
+ parse(input: string): bigint;
38
+ parseNonNativeToken(input: string, decimals: number): bigint;
39
+ formatNonNativeToken: (value: bigint, decimals: number) => string;
40
+ format(value: bigint, { precision }?: IUITransactionFormatOptions): string;
41
+ submit(): Promise<any>;
42
+ getBalance(): Promise<bigint>;
43
+ validateAddressFormat(address: string): boolean;
44
+ private createTransaction;
45
+ private createTransactionSafe;
46
+ }
47
+ export {};
@@ -0,0 +1,121 @@
1
+ 'use client'
2
+ import { __awaiter } from '../../../_virtual/_tslib.js';
3
+ import { Transaction } from '@mysten/sui/transactions';
4
+ import { isValidSuiAddress } from '@mysten/sui/utils';
5
+ import { formatNumberText } from '@dynamic-labs/utils';
6
+ import { MIST_PER_SUI } from '../constants/constants.js';
7
+
8
+ class SuiUiTransaction {
9
+ constructor({ onSubmit, from, client }) {
10
+ this.chain = 'SUI';
11
+ this.data = undefined;
12
+ this.fee = { gas: undefined };
13
+ this.formatNonNativeToken = (value, decimals) => (Number(value) / Number(Math.pow(10, decimals))).toString();
14
+ this.from = from;
15
+ this.onSubmit = onSubmit;
16
+ this.client = client;
17
+ }
18
+ /**
19
+ * Fetches the gas fee for the transaction by executing a dry run of the
20
+ * transaction and calculating the gas used.
21
+ *
22
+ * @returns The gas fee for the transaction
23
+ */
24
+ fetchFee() {
25
+ return __awaiter(this, void 0, void 0, function* () {
26
+ if (this.fee.gas)
27
+ return;
28
+ const transaction = yield this.createTransactionSafe();
29
+ if (!transaction) {
30
+ throw new Error('Could not create a valid SUI transaction, check your address and value');
31
+ }
32
+ const transactionBlock = yield transaction.build({ client: this.client });
33
+ const dryRunResult = yield this.client.dryRunTransactionBlock({
34
+ transactionBlock,
35
+ });
36
+ if (!dryRunResult) {
37
+ this.fee.gas = undefined;
38
+ throw new Error('Error accessing SUI network to calculate gas, please try again later');
39
+ }
40
+ const gasObject = dryRunResult.effects.gasUsed;
41
+ // net_gas_fees = computation_gas_fee + storage_gas_fee - storage_rebate
42
+ // https://docs.sui.io/concepts/tokenomics/gas-in-sui
43
+ const calculatedGas = BigInt(gasObject.computationCost) +
44
+ BigInt(gasObject.storageCost) -
45
+ BigInt(gasObject.storageRebate);
46
+ this.fee.gas = calculatedGas;
47
+ if (this.fee.gas <= BigInt(0)) {
48
+ this.fee.gas = undefined;
49
+ }
50
+ });
51
+ }
52
+ isGasSponsored() {
53
+ return false;
54
+ }
55
+ parse(input) {
56
+ const floatValue = parseFloat(input);
57
+ const mist = Math.round(floatValue * MIST_PER_SUI);
58
+ return BigInt(mist);
59
+ }
60
+ parseNonNativeToken(input, decimals) {
61
+ return BigInt(Math.floor(Number(input) * Math.pow(10, decimals)));
62
+ }
63
+ format(value, { precision } = {}) {
64
+ const suiValue = Number(value) / MIST_PER_SUI;
65
+ const decimalString = suiValue.toLocaleString('fullwide', {
66
+ maximumFractionDigits: 20,
67
+ minimumFractionDigits: 0,
68
+ useGrouping: false,
69
+ });
70
+ return formatNumberText(decimalString, { precision });
71
+ }
72
+ submit() {
73
+ return __awaiter(this, void 0, void 0, function* () {
74
+ const sendTransaction = (yield this.createTransaction());
75
+ return this.onSubmit(sendTransaction);
76
+ });
77
+ }
78
+ getBalance() {
79
+ return __awaiter(this, void 0, void 0, function* () {
80
+ const balance = yield this.client.getBalance({
81
+ coinType: '0x2::sui::SUI',
82
+ owner: this.from,
83
+ });
84
+ return BigInt(balance.totalBalance);
85
+ });
86
+ }
87
+ validateAddressFormat(address) {
88
+ if (address === 'dyn_send_transaction.multiple_recipients') {
89
+ return true;
90
+ }
91
+ return isValidSuiAddress(address);
92
+ }
93
+ createTransaction() {
94
+ return __awaiter(this, void 0, void 0, function* () {
95
+ const { value, to } = this;
96
+ if (!to) {
97
+ throw new Error('Destination is required');
98
+ }
99
+ if (!value) {
100
+ return undefined;
101
+ }
102
+ const sendTransaction = new Transaction();
103
+ sendTransaction.setSender(this.from);
104
+ const [coin] = sendTransaction.splitCoins(sendTransaction.gas, [value]);
105
+ sendTransaction.transferObjects([coin], to);
106
+ return sendTransaction;
107
+ });
108
+ }
109
+ createTransactionSafe() {
110
+ return __awaiter(this, void 0, void 0, function* () {
111
+ try {
112
+ return yield this.createTransaction();
113
+ }
114
+ catch (error) {
115
+ return undefined;
116
+ }
117
+ });
118
+ }
119
+ }
120
+
121
+ export { SuiUiTransaction };
@@ -0,0 +1 @@
1
+ export * from './SuiUiTransaction';
@@ -0,0 +1,8 @@
1
+ 'use client'
2
+ 'use strict';
3
+
4
+ Object.defineProperty(exports, '__esModule', { value: true });
5
+
6
+ const MIST_PER_SUI = 1e9;
7
+
8
+ exports.MIST_PER_SUI = MIST_PER_SUI;
@@ -0,0 +1 @@
1
+ export declare const MIST_PER_SUI = 1000000000;