@dynamic-labs/solana-core 4.0.0-alpha.5 → 4.0.0-alpha.50
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 +460 -0
- package/package.cjs +8 -0
- package/package.js +4 -0
- package/package.json +9 -16
- package/src/connector/{SolWalletConnector.cjs → SolanaWalletConnector.cjs} +8 -10
- package/src/connector/{SolWalletConnector.d.ts → SolanaWalletConnector.d.ts} +8 -5
- package/src/connector/{SolWalletConnector.js → SolanaWalletConnector.js} +8 -10
- package/src/connector/index.d.ts +1 -1
- package/src/index.cjs +7 -3
- package/src/index.js +6 -1
- package/src/rpc/RpcProviderSolana/RpcProviderSolana.cjs +2 -2
- package/src/rpc/RpcProviderSolana/RpcProviderSolana.d.ts +2 -2
- package/src/rpc/RpcProviderSolana/RpcProviderSolana.js +2 -2
- package/src/utils/SolanaUiTransaction/SolanaUiTransaction.cjs +67 -41
- package/src/utils/SolanaUiTransaction/SolanaUiTransaction.d.ts +8 -8
- package/src/utils/SolanaUiTransaction/SolanaUiTransaction.js +67 -41
- package/src/utils/index.d.ts +1 -0
- package/src/utils/isTransactionSigned/index.d.ts +1 -0
- package/src/utils/isTransactionSigned/isTransactionSigned.cjs +17 -0
- package/src/utils/isTransactionSigned/isTransactionSigned.d.ts +2 -0
- package/src/utils/isTransactionSigned/isTransactionSigned.js +13 -0
- package/src/wallet/SolanaWallet.cjs +28 -0
- package/src/wallet/SolanaWallet.d.ts +12 -2
- package/src/wallet/SolanaWallet.js +29 -1
|
@@ -3,13 +3,12 @@ import { __awaiter } from '../../_virtual/_tslib.js';
|
|
|
3
3
|
import { PublicKey, Connection, Transaction, TransactionInstruction } from '@solana/web3.js';
|
|
4
4
|
import { WalletConnectorBase } from '@dynamic-labs/wallet-connector-core';
|
|
5
5
|
import { DynamicError, isLedgerAddressViaVerifiedCredentials, NotSupportedError } from '@dynamic-labs/utils';
|
|
6
|
-
import { findWalletBookWallet } from '@dynamic-labs/wallet-book';
|
|
7
6
|
import { SolanaWallet } from '../wallet/SolanaWallet.js';
|
|
8
7
|
import { extractNonce } from '../utils/extractNonce/extractNonce.js';
|
|
9
8
|
import { getGenesisHashLSKey } from '../utils/getGenesisHashLSKey/getGenesisHashLSKey.js';
|
|
10
9
|
|
|
11
10
|
const MEMO_PROGRAM_ID = new PublicKey('MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr');
|
|
12
|
-
class
|
|
11
|
+
class SolanaWalletConnector extends WalletConnectorBase {
|
|
13
12
|
constructor(opts) {
|
|
14
13
|
var _a;
|
|
15
14
|
super(opts);
|
|
@@ -20,7 +19,8 @@ class SolWalletConnector extends WalletConnectorBase {
|
|
|
20
19
|
this.connectedChain = 'SOL';
|
|
21
20
|
this.solNetworks = opts.solNetworks;
|
|
22
21
|
this.chainRpcProviders = opts.chainRpcProviders;
|
|
23
|
-
|
|
22
|
+
this.connectionConfig = opts.connectionConfig;
|
|
23
|
+
(_a = this.chainRpcProviders) === null || _a === void 0 ? void 0 : _a.registerSolanaProviders(this.connectionConfig);
|
|
24
24
|
}
|
|
25
25
|
getNetwork() {
|
|
26
26
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -51,13 +51,13 @@ class SolWalletConnector extends WalletConnectorBase {
|
|
|
51
51
|
});
|
|
52
52
|
}
|
|
53
53
|
getWalletClient() {
|
|
54
|
-
var _a;
|
|
54
|
+
var _a, _b;
|
|
55
55
|
const [network] = this.solNetworks;
|
|
56
56
|
if (!network) {
|
|
57
57
|
throw new DynamicError('No enabled networks');
|
|
58
58
|
}
|
|
59
59
|
const rpcUrl = ((_a = network.privateCustomerRpcUrls) === null || _a === void 0 ? void 0 : _a[0]) || network.rpcUrls[0];
|
|
60
|
-
return new Connection(rpcUrl, 'confirmed');
|
|
60
|
+
return new Connection(rpcUrl, (_b = this.connectionConfig) !== null && _b !== void 0 ? _b : 'confirmed');
|
|
61
61
|
}
|
|
62
62
|
getPublicClient() {
|
|
63
63
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -88,10 +88,8 @@ class SolWalletConnector extends WalletConnectorBase {
|
|
|
88
88
|
return lamports / 1000000000;
|
|
89
89
|
}
|
|
90
90
|
canConnectWithHardwareWallet() {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
return false;
|
|
94
|
-
return wallet.hardwareWallets.includes('ledger');
|
|
91
|
+
var _a;
|
|
92
|
+
return Boolean((_a = this.metadata.supportedHardwareWallets) === null || _a === void 0 ? void 0 : _a.includes('ledger'));
|
|
95
93
|
}
|
|
96
94
|
signMessage(messageToSign) {
|
|
97
95
|
const _super = Object.create(null, {
|
|
@@ -168,4 +166,4 @@ class SolWalletConnector extends WalletConnectorBase {
|
|
|
168
166
|
}
|
|
169
167
|
}
|
|
170
168
|
|
|
171
|
-
export {
|
|
169
|
+
export { SolanaWalletConnector };
|
package/src/connector/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export * from './
|
|
1
|
+
export * from './SolanaWalletConnector';
|
package/src/index.cjs
CHANGED
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
|
|
4
4
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
5
5
|
|
|
6
|
-
var
|
|
6
|
+
var assertPackageVersion = require('@dynamic-labs/assert-package-version');
|
|
7
|
+
var _package = require('../package.cjs');
|
|
8
|
+
var SolanaWalletConnector = require('./connector/SolanaWalletConnector.cjs');
|
|
7
9
|
require('./rpc/RpcProviderSolana/RpcProviderSolana.cjs');
|
|
8
10
|
var rpcProviders = require('@dynamic-labs/rpc-providers');
|
|
9
11
|
var solanaProvidersSelector = require('./rpc/solanaProvidersSelector/solanaProvidersSelector.cjs');
|
|
@@ -12,20 +14,22 @@ var decodeTransactionFromBase64 = require('./utils/decodeTransactionFromBase64/d
|
|
|
12
14
|
var isVersionedTransaction = require('./utils/isVersionedTransaction/isVersionedTransaction.cjs');
|
|
13
15
|
var encodeTransactionToBase64 = require('./utils/encodeTransactionToBase64/encodeTransactionToBase64.cjs');
|
|
14
16
|
var getGenesisHashLSKey = require('./utils/getGenesisHashLSKey/getGenesisHashLSKey.cjs');
|
|
17
|
+
var isTransactionSigned = require('./utils/isTransactionSigned/isTransactionSigned.cjs');
|
|
15
18
|
var SolanaWallet = require('./wallet/SolanaWallet.cjs');
|
|
16
19
|
var isSolanaWallet = require('./wallet/isSolanaWallet/isSolanaWallet.cjs');
|
|
17
20
|
var isLedgerSolanaWallet = require('./wallet/isLedgerSolanaWallet/isLedgerSolanaWallet.cjs');
|
|
18
21
|
var constants = require('./constants.cjs');
|
|
19
22
|
|
|
23
|
+
assertPackageVersion.assertPackageVersion('@dynamic-labs/solana-core', _package.version);
|
|
20
24
|
|
|
21
|
-
|
|
22
|
-
exports.SolWalletConnector = SolWalletConnector.SolWalletConnector;
|
|
25
|
+
exports.SolanaWalletConnector = SolanaWalletConnector.SolanaWalletConnector;
|
|
23
26
|
exports.solanaProvidersSelector = solanaProvidersSelector.solanaProvidersSelector;
|
|
24
27
|
exports.SolanaUiTransaction = SolanaUiTransaction.SolanaUiTransaction;
|
|
25
28
|
exports.decodeTransactionFromBase64 = decodeTransactionFromBase64.decodeTransactionFromBase64;
|
|
26
29
|
exports.isVersionedTransaction = isVersionedTransaction.isVersionedTransaction;
|
|
27
30
|
exports.encodeTransactionToBase64 = encodeTransactionToBase64.encodeTransactionToBase64;
|
|
28
31
|
exports.getGenesisHashLSKey = getGenesisHashLSKey.getGenesisHashLSKey;
|
|
32
|
+
exports.isTxAlreadySigned = isTransactionSigned.isTxAlreadySigned;
|
|
29
33
|
exports.SolanaWallet = SolanaWallet.SolanaWallet;
|
|
30
34
|
exports.isSolanaWallet = isSolanaWallet.isSolanaWallet;
|
|
31
35
|
exports.isLedgerSolanaWallet = isLedgerSolanaWallet.isLedgerSolanaWallet;
|
package/src/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use client'
|
|
2
|
-
|
|
2
|
+
import { assertPackageVersion } from '@dynamic-labs/assert-package-version';
|
|
3
|
+
import { version } from '../package.js';
|
|
4
|
+
export { SolanaWalletConnector } from './connector/SolanaWalletConnector.js';
|
|
3
5
|
import './rpc/RpcProviderSolana/RpcProviderSolana.js';
|
|
4
6
|
export * from '@dynamic-labs/rpc-providers';
|
|
5
7
|
export { solanaProvidersSelector } from './rpc/solanaProvidersSelector/solanaProvidersSelector.js';
|
|
@@ -8,7 +10,10 @@ export { decodeTransactionFromBase64 } from './utils/decodeTransactionFromBase64
|
|
|
8
10
|
export { isVersionedTransaction } from './utils/isVersionedTransaction/isVersionedTransaction.js';
|
|
9
11
|
export { encodeTransactionToBase64 } from './utils/encodeTransactionToBase64/encodeTransactionToBase64.js';
|
|
10
12
|
export { getGenesisHashLSKey } from './utils/getGenesisHashLSKey/getGenesisHashLSKey.js';
|
|
13
|
+
export { isTxAlreadySigned } from './utils/isTransactionSigned/isTransactionSigned.js';
|
|
11
14
|
export { SolanaWallet } from './wallet/SolanaWallet.js';
|
|
12
15
|
export { isSolanaWallet } from './wallet/isSolanaWallet/isSolanaWallet.js';
|
|
13
16
|
export { isLedgerSolanaWallet } from './wallet/isLedgerSolanaWallet/isLedgerSolanaWallet.js';
|
|
14
17
|
export { SOLANA_GENESIS_HASH } from './constants.js';
|
|
18
|
+
|
|
19
|
+
assertPackageVersion('@dynamic-labs/solana-core', version);
|
|
@@ -9,14 +9,14 @@ rpcProviders.ChainRpcProviders.getSolanaProviderByChainId = (rpcProviders, chain
|
|
|
9
9
|
const provider = (_a = rpcProviders['solana']) === null || _a === void 0 ? void 0 : _a.find((rpcProvider) => rpcProvider.chainId === chainId);
|
|
10
10
|
return provider;
|
|
11
11
|
};
|
|
12
|
-
rpcProviders.ChainRpcProviders.registerSolanaProviders = () => {
|
|
12
|
+
rpcProviders.ChainRpcProviders.registerSolanaProviders = (connectionConfig) => {
|
|
13
13
|
rpcProviders.ChainRpcProviders.registerChainProviders(rpcProviders.ProviderChain.SOLANA, (config) => {
|
|
14
14
|
const rpcProviders = {};
|
|
15
15
|
if (config === null || config === void 0 ? void 0 : config.solana) {
|
|
16
16
|
rpcProviders.solana = config.solana.map((network) => {
|
|
17
17
|
var _a;
|
|
18
18
|
const rpcUrl = ((_a = network.privateCustomerRpcUrls) === null || _a === void 0 ? void 0 : _a[0]) || network.rpcUrls[0];
|
|
19
|
-
const provider = new web3_js.Connection(rpcUrl);
|
|
19
|
+
const provider = new web3_js.Connection(rpcUrl, connectionConfig);
|
|
20
20
|
return {
|
|
21
21
|
chainId: network.chainId.toString(),
|
|
22
22
|
chainName: network.name,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Connection } from '@solana/web3.js';
|
|
1
|
+
import { Connection, ConnectionConfig } from '@solana/web3.js';
|
|
2
2
|
import { RpcProviders } from '@dynamic-labs/rpc-providers';
|
|
3
3
|
type ISolanaRpcProvider = {
|
|
4
4
|
chainId: string;
|
|
@@ -12,7 +12,7 @@ declare module '@dynamic-labs/rpc-providers' {
|
|
|
12
12
|
}
|
|
13
13
|
interface IChainRpcProviders {
|
|
14
14
|
getSolanaProviderByChainId(rpcProviders: RpcProviders, chainId: string): SolanaRpcProvider | undefined;
|
|
15
|
-
registerSolanaProviders(): void;
|
|
15
|
+
registerSolanaProviders(connectionConfig?: ConnectionConfig): void;
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
export {};
|
|
@@ -7,14 +7,14 @@ ChainRpcProviders.getSolanaProviderByChainId = (rpcProviders, chainId) => {
|
|
|
7
7
|
const provider = (_a = rpcProviders['solana']) === null || _a === void 0 ? void 0 : _a.find((rpcProvider) => rpcProvider.chainId === chainId);
|
|
8
8
|
return provider;
|
|
9
9
|
};
|
|
10
|
-
ChainRpcProviders.registerSolanaProviders = () => {
|
|
10
|
+
ChainRpcProviders.registerSolanaProviders = (connectionConfig) => {
|
|
11
11
|
ChainRpcProviders.registerChainProviders(ProviderChain.SOLANA, (config) => {
|
|
12
12
|
const rpcProviders = {};
|
|
13
13
|
if (config === null || config === void 0 ? void 0 : config.solana) {
|
|
14
14
|
rpcProviders.solana = config.solana.map((network) => {
|
|
15
15
|
var _a;
|
|
16
16
|
const rpcUrl = ((_a = network.privateCustomerRpcUrls) === null || _a === void 0 ? void 0 : _a[0]) || network.rpcUrls[0];
|
|
17
|
-
const provider = new Connection(rpcUrl);
|
|
17
|
+
const provider = new Connection(rpcUrl, connectionConfig);
|
|
18
18
|
return {
|
|
19
19
|
chainId: network.chainId.toString(),
|
|
20
20
|
chainName: network.name,
|
|
@@ -10,16 +10,69 @@ var utils = require('@dynamic-labs/utils');
|
|
|
10
10
|
|
|
11
11
|
const LAMPORTS_PER_SOL = 1000000000;
|
|
12
12
|
class SolanaUiTransaction {
|
|
13
|
-
constructor({ onSubmit, from, connection,
|
|
13
|
+
constructor({ onSubmit, from, connection, multipleTransactions, }) {
|
|
14
14
|
this.chain = 'SOL';
|
|
15
15
|
this.data = undefined;
|
|
16
16
|
this.fee = { gas: undefined };
|
|
17
|
-
this.feeDeducted = false;
|
|
18
17
|
this.formatNonNativeToken = (value, decimals) => (Number(value) / Number(Math.pow(10, decimals))).toString();
|
|
19
18
|
this.from = from;
|
|
20
19
|
this.onSubmit = onSubmit;
|
|
21
20
|
this.connection = connection;
|
|
22
|
-
this.
|
|
21
|
+
this.multipleTransactions = multipleTransactions;
|
|
22
|
+
}
|
|
23
|
+
fetchFee() {
|
|
24
|
+
return _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
25
|
+
if (this.fee.gas)
|
|
26
|
+
return;
|
|
27
|
+
let transactions = this.multipleTransactions;
|
|
28
|
+
// for send balance flow, create the transaction and then estimate it
|
|
29
|
+
if (!transactions) {
|
|
30
|
+
const tx = yield this.createTransactionSafe();
|
|
31
|
+
if (!tx)
|
|
32
|
+
return;
|
|
33
|
+
transactions = tx instanceof Array ? tx : [tx];
|
|
34
|
+
}
|
|
35
|
+
const compiledMessages = yield Promise.all(transactions.map((tx) => _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
36
|
+
if ('version' in tx) {
|
|
37
|
+
return tx.message;
|
|
38
|
+
}
|
|
39
|
+
return tx.compileMessage();
|
|
40
|
+
})));
|
|
41
|
+
if (compiledMessages.some((msg) => !msg)) {
|
|
42
|
+
throw new Error('Invalid transaction');
|
|
43
|
+
}
|
|
44
|
+
const getFeeWithRetry = (message) => _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
45
|
+
let res = yield this.connection.getFeeForMessage(message);
|
|
46
|
+
let retryCount = 0;
|
|
47
|
+
while (res.value === null && retryCount < 5) {
|
|
48
|
+
res = yield this.connection.getFeeForMessage(message);
|
|
49
|
+
retryCount++;
|
|
50
|
+
}
|
|
51
|
+
return res.value ? BigInt(res.value) : BigInt(0);
|
|
52
|
+
});
|
|
53
|
+
const fees = yield Promise.all(compiledMessages.map((message) => getFeeWithRetry(message)));
|
|
54
|
+
this.fee.gas = fees.reduce((acc, fee) => acc + fee, BigInt(0));
|
|
55
|
+
if (this.fee.gas === BigInt(0)) {
|
|
56
|
+
this.fee.gas = undefined;
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
// if one of the transactions is not sponsored,
|
|
61
|
+
// then the simulation will have a solana transfer in it if it was successful
|
|
62
|
+
isGasSponsored() {
|
|
63
|
+
var _a;
|
|
64
|
+
if (!((_a = this.multipleTransactions) === null || _a === void 0 ? void 0 : _a.length))
|
|
65
|
+
return false;
|
|
66
|
+
return this.multipleTransactions.every((tx) => {
|
|
67
|
+
var _a;
|
|
68
|
+
if ('version' in tx) {
|
|
69
|
+
return this.from !== tx.message.staticAccountKeys[0].toBase58();
|
|
70
|
+
}
|
|
71
|
+
if ('feePayer' in tx) {
|
|
72
|
+
return this.from !== ((_a = tx.feePayer) === null || _a === void 0 ? void 0 : _a.toBase58());
|
|
73
|
+
}
|
|
74
|
+
return false;
|
|
75
|
+
});
|
|
23
76
|
}
|
|
24
77
|
parse(input) {
|
|
25
78
|
const floatValue = parseFloat(input);
|
|
@@ -40,7 +93,11 @@ class SolanaUiTransaction {
|
|
|
40
93
|
}
|
|
41
94
|
submit() {
|
|
42
95
|
return _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
43
|
-
|
|
96
|
+
if (this.multipleTransactions) {
|
|
97
|
+
return this.onSubmit();
|
|
98
|
+
}
|
|
99
|
+
// send balance modal transactions
|
|
100
|
+
const sendTransaction = (yield this.createTransaction());
|
|
44
101
|
return this.onSubmit(sendTransaction);
|
|
45
102
|
});
|
|
46
103
|
}
|
|
@@ -57,41 +114,6 @@ class SolanaUiTransaction {
|
|
|
57
114
|
}
|
|
58
115
|
return /^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(address);
|
|
59
116
|
}
|
|
60
|
-
fetchFee() {
|
|
61
|
-
return _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
62
|
-
if (this.fee.gas)
|
|
63
|
-
return;
|
|
64
|
-
const transaction = yield this.createTransactionSafe();
|
|
65
|
-
if (!transaction) {
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
let compiledMessage;
|
|
69
|
-
const { blockhash } = yield this.connection.getLatestBlockhash();
|
|
70
|
-
if ('version' in transaction) {
|
|
71
|
-
transaction.message.recentBlockhash = blockhash;
|
|
72
|
-
compiledMessage = transaction.message;
|
|
73
|
-
}
|
|
74
|
-
else {
|
|
75
|
-
transaction.recentBlockhash = blockhash;
|
|
76
|
-
transaction.feePayer = new web3_js.PublicKey(this.from);
|
|
77
|
-
compiledMessage = transaction.compileMessage();
|
|
78
|
-
}
|
|
79
|
-
if (!compiledMessage) {
|
|
80
|
-
throw new Error('Invalid transaction');
|
|
81
|
-
}
|
|
82
|
-
let res = yield this.connection.getFeeForMessage(compiledMessage);
|
|
83
|
-
let retryCount = 0;
|
|
84
|
-
while (res.value === null && retryCount < 5) {
|
|
85
|
-
res = yield this.connection.getFeeForMessage(compiledMessage);
|
|
86
|
-
retryCount++;
|
|
87
|
-
}
|
|
88
|
-
this.fee.gas = res.value ? BigInt(res.value) : undefined;
|
|
89
|
-
if (!this.feeDeducted && this.fee.gas && this.value) {
|
|
90
|
-
this.value = this.value - this.fee.gas;
|
|
91
|
-
this.feeDeducted = true;
|
|
92
|
-
}
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
117
|
createTransaction() {
|
|
96
118
|
return _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
97
119
|
var _a;
|
|
@@ -99,8 +121,8 @@ class SolanaUiTransaction {
|
|
|
99
121
|
if (!to) {
|
|
100
122
|
throw new Error('Destination is required');
|
|
101
123
|
}
|
|
102
|
-
if (this.
|
|
103
|
-
return this.
|
|
124
|
+
if (this.multipleTransactions) {
|
|
125
|
+
return this.multipleTransactions;
|
|
104
126
|
}
|
|
105
127
|
const sendTransaction = new web3_js.Transaction();
|
|
106
128
|
const fromPubkey = new web3_js.PublicKey(this.from);
|
|
@@ -134,6 +156,10 @@ class SolanaUiTransaction {
|
|
|
134
156
|
toPubkey,
|
|
135
157
|
}));
|
|
136
158
|
}
|
|
159
|
+
// only set blockhash when we are creating the transaction, e.g send balance flow
|
|
160
|
+
const { blockhash } = yield this.connection.getLatestBlockhash();
|
|
161
|
+
sendTransaction.feePayer = new web3_js.PublicKey(this.from);
|
|
162
|
+
sendTransaction.recentBlockhash = blockhash;
|
|
137
163
|
return sendTransaction;
|
|
138
164
|
});
|
|
139
165
|
}
|
|
@@ -4,11 +4,10 @@ export declare const LAMPORTS_PER_SOL = 1000000000;
|
|
|
4
4
|
type SolanaUiTransactionProps = {
|
|
5
5
|
from: string;
|
|
6
6
|
connection: Connection;
|
|
7
|
-
onSubmit: (transaction
|
|
8
|
-
|
|
7
|
+
onSubmit: (transaction?: Transaction | VersionedTransaction) => Promise<any>;
|
|
8
|
+
multipleTransactions?: (Transaction | VersionedTransaction)[];
|
|
9
9
|
};
|
|
10
10
|
export declare class SolanaUiTransaction implements IUITransaction {
|
|
11
|
-
notEnoughFundsError: boolean | undefined;
|
|
12
11
|
to: string | undefined;
|
|
13
12
|
from: string;
|
|
14
13
|
value: bigint | undefined;
|
|
@@ -18,22 +17,23 @@ export declare class SolanaUiTransaction implements IUITransaction {
|
|
|
18
17
|
fee: {
|
|
19
18
|
gas: bigint | undefined;
|
|
20
19
|
};
|
|
21
|
-
|
|
22
|
-
feeDeducted: boolean;
|
|
20
|
+
multipleTransactions?: (Transaction | VersionedTransaction)[];
|
|
23
21
|
nonNativeAddress?: string;
|
|
24
22
|
nonNativeDecimal?: number;
|
|
25
23
|
nonNativeValue?: bigint;
|
|
26
24
|
private onSubmit;
|
|
27
25
|
private connection;
|
|
28
|
-
constructor({ onSubmit, from, connection,
|
|
26
|
+
constructor({ onSubmit, from, connection, multipleTransactions, }: SolanaUiTransactionProps);
|
|
27
|
+
nativePrice?: number | undefined;
|
|
28
|
+
fetchFee(): Promise<void>;
|
|
29
|
+
isGasSponsored(): boolean;
|
|
29
30
|
parse(input: string): bigint;
|
|
30
31
|
parseNonNativeToken(input: string, decimals: number): bigint;
|
|
31
32
|
formatNonNativeToken: (value: bigint, decimals: number) => string;
|
|
32
33
|
format(value: bigint, { precision }?: IUITransactionFormatOptions): string;
|
|
33
|
-
submit(): Promise<
|
|
34
|
+
submit(): Promise<any>;
|
|
34
35
|
getBalance(): Promise<bigint>;
|
|
35
36
|
validateAddressFormat(address: string): boolean;
|
|
36
|
-
fetchFee(): Promise<void>;
|
|
37
37
|
private createTransaction;
|
|
38
38
|
private createTransactionSafe;
|
|
39
39
|
}
|
|
@@ -6,16 +6,69 @@ import { formatNumberText } from '@dynamic-labs/utils';
|
|
|
6
6
|
|
|
7
7
|
const LAMPORTS_PER_SOL = 1000000000;
|
|
8
8
|
class SolanaUiTransaction {
|
|
9
|
-
constructor({ onSubmit, from, connection,
|
|
9
|
+
constructor({ onSubmit, from, connection, multipleTransactions, }) {
|
|
10
10
|
this.chain = 'SOL';
|
|
11
11
|
this.data = undefined;
|
|
12
12
|
this.fee = { gas: undefined };
|
|
13
|
-
this.feeDeducted = false;
|
|
14
13
|
this.formatNonNativeToken = (value, decimals) => (Number(value) / Number(Math.pow(10, decimals))).toString();
|
|
15
14
|
this.from = from;
|
|
16
15
|
this.onSubmit = onSubmit;
|
|
17
16
|
this.connection = connection;
|
|
18
|
-
this.
|
|
17
|
+
this.multipleTransactions = multipleTransactions;
|
|
18
|
+
}
|
|
19
|
+
fetchFee() {
|
|
20
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
21
|
+
if (this.fee.gas)
|
|
22
|
+
return;
|
|
23
|
+
let transactions = this.multipleTransactions;
|
|
24
|
+
// for send balance flow, create the transaction and then estimate it
|
|
25
|
+
if (!transactions) {
|
|
26
|
+
const tx = yield this.createTransactionSafe();
|
|
27
|
+
if (!tx)
|
|
28
|
+
return;
|
|
29
|
+
transactions = tx instanceof Array ? tx : [tx];
|
|
30
|
+
}
|
|
31
|
+
const compiledMessages = yield Promise.all(transactions.map((tx) => __awaiter(this, void 0, void 0, function* () {
|
|
32
|
+
if ('version' in tx) {
|
|
33
|
+
return tx.message;
|
|
34
|
+
}
|
|
35
|
+
return tx.compileMessage();
|
|
36
|
+
})));
|
|
37
|
+
if (compiledMessages.some((msg) => !msg)) {
|
|
38
|
+
throw new Error('Invalid transaction');
|
|
39
|
+
}
|
|
40
|
+
const getFeeWithRetry = (message) => __awaiter(this, void 0, void 0, function* () {
|
|
41
|
+
let res = yield this.connection.getFeeForMessage(message);
|
|
42
|
+
let retryCount = 0;
|
|
43
|
+
while (res.value === null && retryCount < 5) {
|
|
44
|
+
res = yield this.connection.getFeeForMessage(message);
|
|
45
|
+
retryCount++;
|
|
46
|
+
}
|
|
47
|
+
return res.value ? BigInt(res.value) : BigInt(0);
|
|
48
|
+
});
|
|
49
|
+
const fees = yield Promise.all(compiledMessages.map((message) => getFeeWithRetry(message)));
|
|
50
|
+
this.fee.gas = fees.reduce((acc, fee) => acc + fee, BigInt(0));
|
|
51
|
+
if (this.fee.gas === BigInt(0)) {
|
|
52
|
+
this.fee.gas = undefined;
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
// if one of the transactions is not sponsored,
|
|
57
|
+
// then the simulation will have a solana transfer in it if it was successful
|
|
58
|
+
isGasSponsored() {
|
|
59
|
+
var _a;
|
|
60
|
+
if (!((_a = this.multipleTransactions) === null || _a === void 0 ? void 0 : _a.length))
|
|
61
|
+
return false;
|
|
62
|
+
return this.multipleTransactions.every((tx) => {
|
|
63
|
+
var _a;
|
|
64
|
+
if ('version' in tx) {
|
|
65
|
+
return this.from !== tx.message.staticAccountKeys[0].toBase58();
|
|
66
|
+
}
|
|
67
|
+
if ('feePayer' in tx) {
|
|
68
|
+
return this.from !== ((_a = tx.feePayer) === null || _a === void 0 ? void 0 : _a.toBase58());
|
|
69
|
+
}
|
|
70
|
+
return false;
|
|
71
|
+
});
|
|
19
72
|
}
|
|
20
73
|
parse(input) {
|
|
21
74
|
const floatValue = parseFloat(input);
|
|
@@ -36,7 +89,11 @@ class SolanaUiTransaction {
|
|
|
36
89
|
}
|
|
37
90
|
submit() {
|
|
38
91
|
return __awaiter(this, void 0, void 0, function* () {
|
|
39
|
-
|
|
92
|
+
if (this.multipleTransactions) {
|
|
93
|
+
return this.onSubmit();
|
|
94
|
+
}
|
|
95
|
+
// send balance modal transactions
|
|
96
|
+
const sendTransaction = (yield this.createTransaction());
|
|
40
97
|
return this.onSubmit(sendTransaction);
|
|
41
98
|
});
|
|
42
99
|
}
|
|
@@ -53,41 +110,6 @@ class SolanaUiTransaction {
|
|
|
53
110
|
}
|
|
54
111
|
return /^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(address);
|
|
55
112
|
}
|
|
56
|
-
fetchFee() {
|
|
57
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
58
|
-
if (this.fee.gas)
|
|
59
|
-
return;
|
|
60
|
-
const transaction = yield this.createTransactionSafe();
|
|
61
|
-
if (!transaction) {
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
let compiledMessage;
|
|
65
|
-
const { blockhash } = yield this.connection.getLatestBlockhash();
|
|
66
|
-
if ('version' in transaction) {
|
|
67
|
-
transaction.message.recentBlockhash = blockhash;
|
|
68
|
-
compiledMessage = transaction.message;
|
|
69
|
-
}
|
|
70
|
-
else {
|
|
71
|
-
transaction.recentBlockhash = blockhash;
|
|
72
|
-
transaction.feePayer = new PublicKey(this.from);
|
|
73
|
-
compiledMessage = transaction.compileMessage();
|
|
74
|
-
}
|
|
75
|
-
if (!compiledMessage) {
|
|
76
|
-
throw new Error('Invalid transaction');
|
|
77
|
-
}
|
|
78
|
-
let res = yield this.connection.getFeeForMessage(compiledMessage);
|
|
79
|
-
let retryCount = 0;
|
|
80
|
-
while (res.value === null && retryCount < 5) {
|
|
81
|
-
res = yield this.connection.getFeeForMessage(compiledMessage);
|
|
82
|
-
retryCount++;
|
|
83
|
-
}
|
|
84
|
-
this.fee.gas = res.value ? BigInt(res.value) : undefined;
|
|
85
|
-
if (!this.feeDeducted && this.fee.gas && this.value) {
|
|
86
|
-
this.value = this.value - this.fee.gas;
|
|
87
|
-
this.feeDeducted = true;
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
113
|
createTransaction() {
|
|
92
114
|
return __awaiter(this, void 0, void 0, function* () {
|
|
93
115
|
var _a;
|
|
@@ -95,8 +117,8 @@ class SolanaUiTransaction {
|
|
|
95
117
|
if (!to) {
|
|
96
118
|
throw new Error('Destination is required');
|
|
97
119
|
}
|
|
98
|
-
if (this.
|
|
99
|
-
return this.
|
|
120
|
+
if (this.multipleTransactions) {
|
|
121
|
+
return this.multipleTransactions;
|
|
100
122
|
}
|
|
101
123
|
const sendTransaction = new Transaction();
|
|
102
124
|
const fromPubkey = new PublicKey(this.from);
|
|
@@ -130,6 +152,10 @@ class SolanaUiTransaction {
|
|
|
130
152
|
toPubkey,
|
|
131
153
|
}));
|
|
132
154
|
}
|
|
155
|
+
// only set blockhash when we are creating the transaction, e.g send balance flow
|
|
156
|
+
const { blockhash } = yield this.connection.getLatestBlockhash();
|
|
157
|
+
sendTransaction.feePayer = new PublicKey(this.from);
|
|
158
|
+
sendTransaction.recentBlockhash = blockhash;
|
|
133
159
|
return sendTransaction;
|
|
134
160
|
});
|
|
135
161
|
}
|
package/src/utils/index.d.ts
CHANGED
|
@@ -3,3 +3,4 @@ export { decodeTransactionFromBase64 } from './decodeTransactionFromBase64';
|
|
|
3
3
|
export { isVersionedTransaction } from './isVersionedTransaction';
|
|
4
4
|
export { encodeTransactionToBase64, type EncodedTransaction, } from './encodeTransactionToBase64';
|
|
5
5
|
export { getGenesisHashLSKey } from './getGenesisHashLSKey';
|
|
6
|
+
export { isTxAlreadySigned } from './isTransactionSigned';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './isTransactionSigned';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
5
|
+
|
|
6
|
+
const isTxAlreadySigned = (transaction) => {
|
|
7
|
+
let alreadySigned = false;
|
|
8
|
+
if ('version' in transaction) {
|
|
9
|
+
alreadySigned = transaction.signatures.some((sig) => !sig.every((byte) => byte === 0));
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
alreadySigned = transaction.signatures.some((sig) => sig.signature);
|
|
13
|
+
}
|
|
14
|
+
return alreadySigned;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
exports.isTxAlreadySigned = isTxAlreadySigned;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
const isTxAlreadySigned = (transaction) => {
|
|
3
|
+
let alreadySigned = false;
|
|
4
|
+
if ('version' in transaction) {
|
|
5
|
+
alreadySigned = transaction.signatures.some((sig) => !sig.every((byte) => byte === 0));
|
|
6
|
+
}
|
|
7
|
+
else {
|
|
8
|
+
alreadySigned = transaction.signatures.some((sig) => sig.signature);
|
|
9
|
+
}
|
|
10
|
+
return alreadySigned;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export { isTxAlreadySigned };
|
|
@@ -4,10 +4,38 @@
|
|
|
4
4
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
5
5
|
|
|
6
6
|
var _tslib = require('../../_virtual/_tslib.cjs');
|
|
7
|
+
var web3_js = require('@solana/web3.js');
|
|
7
8
|
var walletConnectorCore = require('@dynamic-labs/wallet-connector-core');
|
|
8
9
|
var utils = require('@dynamic-labs/utils');
|
|
9
10
|
|
|
10
11
|
class SolanaWallet extends walletConnectorCore.Wallet {
|
|
12
|
+
/**
|
|
13
|
+
* Sends the native balance of the wallet to the given address.
|
|
14
|
+
* @param amount - The amount of balance to send (in SOL).
|
|
15
|
+
* @param toAddress - The address to send the balance to.
|
|
16
|
+
* @returns The signature of the sent transaction.
|
|
17
|
+
*/
|
|
18
|
+
sendBalance(_a) {
|
|
19
|
+
return _tslib.__awaiter(this, arguments, void 0, function* ({ amount, toAddress, }) {
|
|
20
|
+
const connection = yield this.getConnection();
|
|
21
|
+
const signer = yield this.getSigner();
|
|
22
|
+
const { blockhash } = yield connection.getLatestBlockhash('finalized');
|
|
23
|
+
const message = new web3_js.TransactionMessage({
|
|
24
|
+
instructions: [
|
|
25
|
+
web3_js.SystemProgram.transfer({
|
|
26
|
+
fromPubkey: new web3_js.PublicKey(this.address),
|
|
27
|
+
lamports: utils.solToLamports(Number(amount)),
|
|
28
|
+
toPubkey: new web3_js.PublicKey(toAddress),
|
|
29
|
+
}),
|
|
30
|
+
],
|
|
31
|
+
payerKey: new web3_js.PublicKey(this.address),
|
|
32
|
+
recentBlockhash: blockhash,
|
|
33
|
+
}).compileToV0Message();
|
|
34
|
+
const transaction = new web3_js.VersionedTransaction(message);
|
|
35
|
+
const { signature } = yield signer.signAndSendTransaction(transaction);
|
|
36
|
+
return signature;
|
|
37
|
+
});
|
|
38
|
+
}
|
|
11
39
|
/**
|
|
12
40
|
* Retrieves the RPC connection
|
|
13
41
|
* @returns A promise that resolves to the RPC connection
|
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
import { Connection } from '@solana/web3.js';
|
|
2
2
|
import { Wallet } from '@dynamic-labs/wallet-connector-core';
|
|
3
|
-
import {
|
|
3
|
+
import { SolanaWalletConnector } from '../connector';
|
|
4
4
|
import { ISolana } from '../types';
|
|
5
|
-
export declare class SolanaWallet extends Wallet<
|
|
5
|
+
export declare class SolanaWallet extends Wallet<SolanaWalletConnector> {
|
|
6
|
+
/**
|
|
7
|
+
* Sends the native balance of the wallet to the given address.
|
|
8
|
+
* @param amount - The amount of balance to send (in SOL).
|
|
9
|
+
* @param toAddress - The address to send the balance to.
|
|
10
|
+
* @returns The signature of the sent transaction.
|
|
11
|
+
*/
|
|
12
|
+
sendBalance({ amount, toAddress, }: {
|
|
13
|
+
amount: string;
|
|
14
|
+
toAddress: string;
|
|
15
|
+
}): Promise<string | undefined>;
|
|
6
16
|
/**
|
|
7
17
|
* Retrieves the RPC connection
|
|
8
18
|
* @returns A promise that resolves to the RPC connection
|
|
@@ -1,9 +1,37 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
import { __awaiter } from '../../_virtual/_tslib.js';
|
|
3
|
+
import { TransactionMessage, SystemProgram, PublicKey, VersionedTransaction } from '@solana/web3.js';
|
|
3
4
|
import { Wallet, logger } from '@dynamic-labs/wallet-connector-core';
|
|
4
|
-
import { cloneObjectWithOverrides } from '@dynamic-labs/utils';
|
|
5
|
+
import { solToLamports, cloneObjectWithOverrides } from '@dynamic-labs/utils';
|
|
5
6
|
|
|
6
7
|
class SolanaWallet extends Wallet {
|
|
8
|
+
/**
|
|
9
|
+
* Sends the native balance of the wallet to the given address.
|
|
10
|
+
* @param amount - The amount of balance to send (in SOL).
|
|
11
|
+
* @param toAddress - The address to send the balance to.
|
|
12
|
+
* @returns The signature of the sent transaction.
|
|
13
|
+
*/
|
|
14
|
+
sendBalance(_a) {
|
|
15
|
+
return __awaiter(this, arguments, void 0, function* ({ amount, toAddress, }) {
|
|
16
|
+
const connection = yield this.getConnection();
|
|
17
|
+
const signer = yield this.getSigner();
|
|
18
|
+
const { blockhash } = yield connection.getLatestBlockhash('finalized');
|
|
19
|
+
const message = new TransactionMessage({
|
|
20
|
+
instructions: [
|
|
21
|
+
SystemProgram.transfer({
|
|
22
|
+
fromPubkey: new PublicKey(this.address),
|
|
23
|
+
lamports: solToLamports(Number(amount)),
|
|
24
|
+
toPubkey: new PublicKey(toAddress),
|
|
25
|
+
}),
|
|
26
|
+
],
|
|
27
|
+
payerKey: new PublicKey(this.address),
|
|
28
|
+
recentBlockhash: blockhash,
|
|
29
|
+
}).compileToV0Message();
|
|
30
|
+
const transaction = new VersionedTransaction(message);
|
|
31
|
+
const { signature } = yield signer.signAndSendTransaction(transaction);
|
|
32
|
+
return signature;
|
|
33
|
+
});
|
|
34
|
+
}
|
|
7
35
|
/**
|
|
8
36
|
* Retrieves the RPC connection
|
|
9
37
|
* @returns A promise that resolves to the RPC connection
|