@rango-dev/provider-okx 0.63.1-next.1 → 0.63.1-next.3
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/dist/actions/ton.d.ts +12 -0
- package/dist/actions/ton.d.ts.map +1 -0
- package/dist/actions/tron.d.ts +5 -0
- package/dist/actions/tron.d.ts.map +1 -0
- package/dist/builders/ton.d.ts +10 -0
- package/dist/builders/ton.d.ts.map +1 -0
- package/dist/builders/tron.d.ts +7 -0
- package/dist/builders/tron.d.ts.map +1 -0
- package/dist/constants.d.ts +4 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/mod.d.ts +1 -1
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +1 -1
- package/dist/mod.js.map +4 -4
- package/dist/namespaces/ton/ton.d.ts +4 -0
- package/dist/namespaces/ton/ton.d.ts.map +1 -0
- package/dist/namespaces/ton/types.d.ts +65 -0
- package/dist/namespaces/ton/types.d.ts.map +1 -0
- package/dist/namespaces/ton/utils.d.ts +9 -0
- package/dist/namespaces/ton/utils.d.ts.map +1 -0
- package/dist/namespaces/tron.d.ts +4 -0
- package/dist/namespaces/tron.d.ts.map +1 -0
- package/dist/provider.d.ts +1 -1
- package/dist/provider.d.ts.map +1 -1
- package/dist/signer.d.ts.map +1 -1
- package/dist/signers/ton.d.ts +11 -0
- package/dist/signers/ton.d.ts.map +1 -0
- package/dist/types.d.ts +13 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/utils.d.ts +6 -1
- package/dist/utils.d.ts.map +1 -1
- package/package.json +4 -2
- package/readme.md +10 -4
- package/src/actions/ton.ts +99 -0
- package/src/actions/tron.ts +37 -0
- package/src/builders/ton.ts +48 -0
- package/src/builders/tron.ts +63 -0
- package/src/constants.ts +22 -0
- package/src/namespaces/ton/ton.ts +50 -0
- package/src/namespaces/ton/types.ts +89 -0
- package/src/namespaces/ton/utils.ts +79 -0
- package/src/namespaces/tron.ts +40 -0
- package/src/provider.ts +9 -1
- package/src/signer.ts +10 -0
- package/src/signers/ton.ts +70 -0
- package/src/types.ts +20 -0
- package/src/utils.ts +53 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rango-dev/provider-okx",
|
|
3
|
-
"version": "0.63.1-next.
|
|
3
|
+
"version": "0.63.1-next.3",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"source": "./src/mod.ts",
|
|
@@ -28,11 +28,13 @@
|
|
|
28
28
|
"@hub3js/std": "^0.2.0",
|
|
29
29
|
"@rango-dev/signer-evm": "^0.44.1-next.0",
|
|
30
30
|
"@rango-dev/signer-solana": "^0.48.1-next.0",
|
|
31
|
+
"@rango-dev/signer-tron": "^0.41.1-next.0",
|
|
31
32
|
"@rango-dev/wallets-core": "^0.60.1-next.3",
|
|
32
33
|
"@rango-dev/wallets-shared": "^0.61.1-next.4",
|
|
34
|
+
"@ton/core": "^0.59.0",
|
|
33
35
|
"rango-types": "^0.5.0"
|
|
34
36
|
},
|
|
35
37
|
"publishConfig": {
|
|
36
38
|
"access": "public"
|
|
37
39
|
}
|
|
38
|
-
}
|
|
40
|
+
}
|
package/readme.md
CHANGED
|
@@ -39,10 +39,6 @@ Supported networks :
|
|
|
39
39
|
The wallet only supports bitcoin.
|
|
40
40
|
|
|
41
41
|
|
|
42
|
-
#### 🚧 TON
|
|
43
|
-
|
|
44
|
-
The wallet supports TON, but it is **not implemented** in the current integration.
|
|
45
|
-
|
|
46
42
|
#### 🚧 Sui
|
|
47
43
|
|
|
48
44
|
The wallet supports Sui, but it is **not implemented** in the current integration.
|
|
@@ -51,6 +47,16 @@ The wallet supports Sui, but it is **not implemented** in the current integratio
|
|
|
51
47
|
|
|
52
48
|
### Feature
|
|
53
49
|
|
|
50
|
+
#### ⚠️ Connect and AutoConnect
|
|
51
|
+
|
|
52
|
+
For Tron, connecting on page load — or disconnecting and reconnecting within the app —
|
|
53
|
+
returns the **first account you connected**, not the account you last switched to. The OKX
|
|
54
|
+
extension resets the Tron address in these cases and gives no way to recover the active
|
|
55
|
+
one; it corrects itself only once you switch accounts in the wallet.
|
|
56
|
+
|
|
57
|
+
If you sign a transaction while that wrong account is selected, the OKX wallet rejects it
|
|
58
|
+
with a **"Transaction Unavailable"** error.
|
|
59
|
+
|
|
54
60
|
#### ⚠️ Disconnect
|
|
55
61
|
|
|
56
62
|
The disconnect function will not work for this wallet, as it attempts to invoke disconnect on the connect method for private key imported wallets.
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
TonConnectEvent,
|
|
3
|
+
TonProviderApi,
|
|
4
|
+
} from '../namespaces/ton/types.js';
|
|
5
|
+
import type { Context, FunctionWithContext } from '@hub3js/core';
|
|
6
|
+
|
|
7
|
+
import { type TonActions } from '@rango-dev/wallets-core/namespaces/ton';
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
TON_CONNECT_PROTOCOL_VERSION,
|
|
11
|
+
TON_CONNECT_USER_REJECTED_CODE,
|
|
12
|
+
} from '../constants.js';
|
|
13
|
+
import {
|
|
14
|
+
connectEventToCAIP,
|
|
15
|
+
getTonConnectManifestUrl,
|
|
16
|
+
isTonConnectEventSuccess,
|
|
17
|
+
nextTonRequestId,
|
|
18
|
+
} from '../namespaces/ton/utils.js';
|
|
19
|
+
|
|
20
|
+
export function connect(
|
|
21
|
+
getInstance: () => TonProviderApi
|
|
22
|
+
): FunctionWithContext<TonActions['connect'], Context> {
|
|
23
|
+
return async () => {
|
|
24
|
+
const instance = getInstance();
|
|
25
|
+
|
|
26
|
+
/*
|
|
27
|
+
* If the dApp was approved before, `restoreConnection` resolves the current
|
|
28
|
+
* session without prompting the user; otherwise fall back to a fresh
|
|
29
|
+
* connect request.
|
|
30
|
+
*/
|
|
31
|
+
let connectEvent: TonConnectEvent | undefined;
|
|
32
|
+
try {
|
|
33
|
+
connectEvent = await instance.restoreConnection();
|
|
34
|
+
} catch {
|
|
35
|
+
// No restorable session; a fresh connect request is made below.
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (!connectEvent || !isTonConnectEventSuccess(connectEvent)) {
|
|
39
|
+
connectEvent = await instance.connect(TON_CONNECT_PROTOCOL_VERSION, {
|
|
40
|
+
manifestUrl: getTonConnectManifestUrl(),
|
|
41
|
+
items: [{ name: 'ton_addr' }],
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (!isTonConnectEventSuccess(connectEvent)) {
|
|
46
|
+
// The bridge reports a user-cancelled prompt as a `connect_error` event.
|
|
47
|
+
if (connectEvent.payload.code === TON_CONNECT_USER_REJECTED_CODE) {
|
|
48
|
+
throw new Error('User rejected the request.');
|
|
49
|
+
}
|
|
50
|
+
throw new Error(
|
|
51
|
+
`Couldn't connect to OKX TON. code: ${connectEvent.payload.code}, message: ${connectEvent.payload.message}`
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const accounts = await connectEventToCAIP(connectEvent);
|
|
56
|
+
if (!accounts.length) {
|
|
57
|
+
throw new Error("Couldn't find any TON address!");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return accounts;
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function canEagerConnect(
|
|
65
|
+
getInstance: () => TonProviderApi
|
|
66
|
+
): FunctionWithContext<TonActions['canEagerConnect'], Context> {
|
|
67
|
+
return async () => {
|
|
68
|
+
/*
|
|
69
|
+
* Auto connect may run this before the wallet is injected; it should never
|
|
70
|
+
* throw.
|
|
71
|
+
*/
|
|
72
|
+
try {
|
|
73
|
+
const connectEvent = await getInstance().restoreConnection();
|
|
74
|
+
return isTonConnectEventSuccess(connectEvent);
|
|
75
|
+
} catch {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function disconnect(getInstance: () => TonProviderApi) {
|
|
82
|
+
return async () => {
|
|
83
|
+
/*
|
|
84
|
+
* Revoking the session on the wallet side is best effort; local state
|
|
85
|
+
* cleanup should proceed even if it fails.
|
|
86
|
+
*/
|
|
87
|
+
try {
|
|
88
|
+
await getInstance().send({
|
|
89
|
+
method: 'disconnect',
|
|
90
|
+
params: [],
|
|
91
|
+
id: nextTonRequestId(),
|
|
92
|
+
});
|
|
93
|
+
} catch {
|
|
94
|
+
// ignore
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export const tonActions = { connect, canEagerConnect, disconnect };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { utils } from '@rango-dev/wallets-core/namespaces/tron';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
TRON_OK_REQUEST_CODE,
|
|
5
|
+
TRON_USER_REJECTION_CODE,
|
|
6
|
+
} from '../constants.js';
|
|
7
|
+
import { tronOKX } from '../utils.js';
|
|
8
|
+
|
|
9
|
+
const connect = async () => {
|
|
10
|
+
const instance = tronOKX();
|
|
11
|
+
const accountsResult = await instance.request({
|
|
12
|
+
method: 'tron_requestAccounts',
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
if (accountsResult?.code && accountsResult.code !== TRON_OK_REQUEST_CODE) {
|
|
16
|
+
if (accountsResult.code === TRON_USER_REJECTION_CODE) {
|
|
17
|
+
throw new Error('User rejected the request.');
|
|
18
|
+
}
|
|
19
|
+
throw new Error(
|
|
20
|
+
accountsResult.message ?? 'Failed to connect to OKX Wallet Tron.'
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
return utils.formatAccountsToCAIP([instance.tronWeb.defaultAddress.base58]);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/*
|
|
27
|
+
* Wrapped in a try-catch in the case of wallet injection delay
|
|
28
|
+
*/
|
|
29
|
+
const canEagerConnect = async () => {
|
|
30
|
+
try {
|
|
31
|
+
const tronInstance = tronOKX();
|
|
32
|
+
return !!tronInstance.ready;
|
|
33
|
+
} catch {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
export const tronActions = { connect, canEagerConnect };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { TonProviderApi } from '../namespaces/ton/types.js';
|
|
2
|
+
|
|
3
|
+
import { ChangeAccountSubscriberBuilder } from '@hub3js/std/hooks';
|
|
4
|
+
import { type TonActions, utils } from '@rango-dev/wallets-core/namespaces/ton';
|
|
5
|
+
|
|
6
|
+
import { connectEventToCAIP } from '../namespaces/ton/utils.js';
|
|
7
|
+
|
|
8
|
+
/*
|
|
9
|
+
* OKX emits its non-standard `accountChanged` event without a documented
|
|
10
|
+
* payload, so the switched address can't be read from the event. Because the
|
|
11
|
+
* bridge is standard TON Connect, `format` re-reads the active account from the
|
|
12
|
+
* instance via `restoreConnection` instead
|
|
13
|
+
*/
|
|
14
|
+
export const changeAccountSubscriber = (getInstance: () => TonProviderApi) =>
|
|
15
|
+
new ChangeAccountSubscriberBuilder<unknown, TonProviderApi, TonActions>()
|
|
16
|
+
.getInstance(getInstance)
|
|
17
|
+
.format(async (instance) => {
|
|
18
|
+
try {
|
|
19
|
+
const connectEvent = await instance.restoreConnection();
|
|
20
|
+
return await connectEventToCAIP(connectEvent);
|
|
21
|
+
} catch {
|
|
22
|
+
// No active session after the switch — treat as disconnected.
|
|
23
|
+
return utils.formatAccountsToCAIP([]);
|
|
24
|
+
}
|
|
25
|
+
})
|
|
26
|
+
.addEventListener((instance, callback) => {
|
|
27
|
+
instance.on('accountChanged', callback);
|
|
28
|
+
})
|
|
29
|
+
.removeEventListener((instance, callback) => {
|
|
30
|
+
instance.off('accountChanged', callback);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
export const disconnectSubscriber = (getInstance: () => TonProviderApi) =>
|
|
34
|
+
new ChangeAccountSubscriberBuilder<unknown, TonProviderApi, TonActions>()
|
|
35
|
+
.getInstance(getInstance)
|
|
36
|
+
.onSwitchAccount((event, context) => {
|
|
37
|
+
event.preventDefault();
|
|
38
|
+
void context.action('disconnect');
|
|
39
|
+
})
|
|
40
|
+
.format(async () => [])
|
|
41
|
+
.addEventListener((instance, callback) => {
|
|
42
|
+
instance.on('disconnect', callback);
|
|
43
|
+
})
|
|
44
|
+
.removeEventListener((instance, callback) => {
|
|
45
|
+
instance.off('disconnect', callback);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
export const tonBuilders = { changeAccountSubscriber, disconnectSubscriber };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { ChangeAccountSubscriberBuilder } from '@hub3js/std/hooks';
|
|
2
|
+
import {
|
|
3
|
+
type ProviderAPI,
|
|
4
|
+
type TronActions,
|
|
5
|
+
utils,
|
|
6
|
+
} from '@rango-dev/wallets-core/namespaces/tron';
|
|
7
|
+
|
|
8
|
+
import { isOkxTronMessageEvent } from '../utils.js';
|
|
9
|
+
|
|
10
|
+
export const changeAccountSubscriber = (getInstance: () => ProviderAPI) =>
|
|
11
|
+
new ChangeAccountSubscriberBuilder<
|
|
12
|
+
MessageEvent<unknown>,
|
|
13
|
+
ProviderAPI,
|
|
14
|
+
TronActions
|
|
15
|
+
>()
|
|
16
|
+
.getInstance(getInstance)
|
|
17
|
+
.onSwitchAccount((event, context) => {
|
|
18
|
+
const data = event.payload?.data;
|
|
19
|
+
|
|
20
|
+
if (!isOkxTronMessageEvent(data)) {
|
|
21
|
+
event.preventDefault();
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const { action } = data.message;
|
|
26
|
+
|
|
27
|
+
if (action === 'disconnect') {
|
|
28
|
+
event.preventDefault();
|
|
29
|
+
context.action('disconnect');
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/*
|
|
34
|
+
* Change account only on `accountsChanged` with a string address (`format`
|
|
35
|
+
* reads it). Everything else — including `accountsChanged` with address
|
|
36
|
+
* `false` (its disconnect is handled above) — is ignored.
|
|
37
|
+
*/
|
|
38
|
+
if (
|
|
39
|
+
action !== 'accountsChanged' ||
|
|
40
|
+
typeof data.message.data?.address !== 'string'
|
|
41
|
+
) {
|
|
42
|
+
event.preventDefault();
|
|
43
|
+
}
|
|
44
|
+
})
|
|
45
|
+
.format(async (_, event) => {
|
|
46
|
+
const data = event.data;
|
|
47
|
+
const address =
|
|
48
|
+
isOkxTronMessageEvent(data) && data.message.action === 'accountsChanged'
|
|
49
|
+
? data.message.data?.address
|
|
50
|
+
: undefined;
|
|
51
|
+
if (typeof address !== 'string') {
|
|
52
|
+
throw new Error('No Tron address received from OKX Wallet.');
|
|
53
|
+
}
|
|
54
|
+
return utils.formatAccountsToCAIP([address]);
|
|
55
|
+
})
|
|
56
|
+
.addEventListener((_, callback) => {
|
|
57
|
+
window.addEventListener('message', callback);
|
|
58
|
+
})
|
|
59
|
+
.removeEventListener((_, callback) => {
|
|
60
|
+
window.removeEventListener('message', callback);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
export const tronBuilders = { changeAccountSubscriber };
|
package/src/constants.ts
CHANGED
|
@@ -5,13 +5,21 @@ import { Networks } from '@rango-dev/wallets-shared';
|
|
|
5
5
|
import {
|
|
6
6
|
type BlockchainMeta,
|
|
7
7
|
solanaBlockchain,
|
|
8
|
+
tonBlockchain,
|
|
8
9
|
type TransferBlockchainMeta,
|
|
10
|
+
tronBlockchain,
|
|
9
11
|
} from 'rango-types';
|
|
10
12
|
|
|
11
13
|
import getSigners from './signer.js';
|
|
12
14
|
import { getInstanceOrThrow } from './utils.js';
|
|
13
15
|
|
|
14
16
|
export const WALLET_ID = 'okx';
|
|
17
|
+
export const TON_CONNECT_PROTOCOL_VERSION = 2;
|
|
18
|
+
export const TON_CONNECT_USER_REJECTED_CODE = 300;
|
|
19
|
+
export const TRON_OK_REQUEST_CODE = 200;
|
|
20
|
+
// EIP-1193 user-rejected-request code returned by `tron_requestAccounts`.
|
|
21
|
+
export const TRON_USER_REJECTION_CODE = 4001;
|
|
22
|
+
|
|
15
23
|
export const OKX_WALLET_SUPPORTED_CHAINS = [
|
|
16
24
|
LegacyNetworks.ETHEREUM,
|
|
17
25
|
LegacyNetworks.BSC,
|
|
@@ -73,6 +81,20 @@ export const metadata: ProviderMetadata = {
|
|
|
73
81
|
chain.name === Networks.BTC
|
|
74
82
|
),
|
|
75
83
|
},
|
|
84
|
+
{
|
|
85
|
+
label: 'Ton',
|
|
86
|
+
value: 'Ton',
|
|
87
|
+
id: 'TON',
|
|
88
|
+
getSupportedChains: (allBlockchains: BlockchainMeta[]) =>
|
|
89
|
+
tonBlockchain(allBlockchains),
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
label: 'Tron',
|
|
93
|
+
value: 'Tron',
|
|
94
|
+
id: 'TRON',
|
|
95
|
+
getSupportedChains: (allBlockchains: BlockchainMeta[]) =>
|
|
96
|
+
tronBlockchain(allBlockchains),
|
|
97
|
+
},
|
|
76
98
|
],
|
|
77
99
|
},
|
|
78
100
|
},
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { NamespaceBuilder } from '@hub3js/core';
|
|
2
|
+
import * as commonBuilders from '@hub3js/std/builders';
|
|
3
|
+
import { standardizeAndThrowError } from '@hub3js/std/operators';
|
|
4
|
+
import {
|
|
5
|
+
builders,
|
|
6
|
+
type TonActions,
|
|
7
|
+
} from '@rango-dev/wallets-core/namespaces/ton';
|
|
8
|
+
|
|
9
|
+
import { tonActions } from '../../actions/ton.js';
|
|
10
|
+
import { tonBuilders } from '../../builders/ton.js';
|
|
11
|
+
import { WALLET_ID } from '../../constants.js';
|
|
12
|
+
import { tonOKX } from '../../utils.js';
|
|
13
|
+
|
|
14
|
+
const [changeAccountSubscriber, changeAccountCleanup] = tonBuilders
|
|
15
|
+
.changeAccountSubscriber(tonOKX)
|
|
16
|
+
.build();
|
|
17
|
+
|
|
18
|
+
const [walletDisconnectSubscriber, walletDisconnectCleanup] = tonBuilders
|
|
19
|
+
.disconnectSubscriber(tonOKX)
|
|
20
|
+
.build();
|
|
21
|
+
|
|
22
|
+
const connect = builders
|
|
23
|
+
.connect()
|
|
24
|
+
.action(tonActions.connect(tonOKX))
|
|
25
|
+
.before(changeAccountSubscriber)
|
|
26
|
+
.before(walletDisconnectSubscriber)
|
|
27
|
+
.or(walletDisconnectCleanup)
|
|
28
|
+
.or(changeAccountCleanup)
|
|
29
|
+
.or(standardizeAndThrowError)
|
|
30
|
+
.build();
|
|
31
|
+
|
|
32
|
+
const disconnect = commonBuilders
|
|
33
|
+
.disconnect<TonActions>()
|
|
34
|
+
.before(tonActions.disconnect(tonOKX))
|
|
35
|
+
.after(changeAccountCleanup)
|
|
36
|
+
.after(walletDisconnectCleanup)
|
|
37
|
+
.build();
|
|
38
|
+
|
|
39
|
+
const canEagerConnect = builders
|
|
40
|
+
.canEagerConnect()
|
|
41
|
+
.action(tonActions.canEagerConnect(tonOKX))
|
|
42
|
+
.build();
|
|
43
|
+
|
|
44
|
+
const ton = new NamespaceBuilder<TonActions>('Ton', WALLET_ID)
|
|
45
|
+
.action(connect)
|
|
46
|
+
.action(disconnect)
|
|
47
|
+
.action(canEagerConnect)
|
|
48
|
+
.build();
|
|
49
|
+
|
|
50
|
+
export { ton };
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
export type Environments = {
|
|
2
|
+
tonConnectManifestUrl?: string;
|
|
3
|
+
};
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
* OKX injects a standard TonConnect JS bridge at `window.okxTonWallet.tonconnect`.
|
|
7
|
+
* The types below describe the subset of the TonConnect protocol we rely on,
|
|
8
|
+
* plus OKX's non-standard `on`/`off` event API.
|
|
9
|
+
*/
|
|
10
|
+
export type TonAddressItemReply = {
|
|
11
|
+
name: 'ton_addr';
|
|
12
|
+
// Raw format: `<workchain>:<hex>`
|
|
13
|
+
address: string;
|
|
14
|
+
// '-239' for mainnet, '-3' for testnet
|
|
15
|
+
network: string;
|
|
16
|
+
walletStateInit: string;
|
|
17
|
+
publicKey: string;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type TonConnectEventSuccess = {
|
|
21
|
+
event: 'connect';
|
|
22
|
+
id: number;
|
|
23
|
+
payload: {
|
|
24
|
+
items: Array<TonAddressItemReply | { name: string }>;
|
|
25
|
+
device: unknown;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export type TonConnectEventError = {
|
|
30
|
+
event: 'connect_error';
|
|
31
|
+
id: number;
|
|
32
|
+
payload: {
|
|
33
|
+
code: number;
|
|
34
|
+
message: string;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export type TonConnectEvent = TonConnectEventSuccess | TonConnectEventError;
|
|
39
|
+
|
|
40
|
+
export type TonConnectRequest = {
|
|
41
|
+
manifestUrl: string;
|
|
42
|
+
items: Array<{ name: 'ton_addr' }>;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export type TonConnectAppRequest = {
|
|
46
|
+
method: 'sendTransaction' | 'disconnect';
|
|
47
|
+
params: string[];
|
|
48
|
+
id: string;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export type TonConnectWalletResponseSuccess = {
|
|
52
|
+
result: string;
|
|
53
|
+
id: string;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export type TonConnectWalletResponseError = {
|
|
57
|
+
error: { code: number; message: string; data?: unknown };
|
|
58
|
+
id: string;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export type TonConnectWalletResponse =
|
|
62
|
+
| TonConnectWalletResponseSuccess
|
|
63
|
+
| TonConnectWalletResponseError;
|
|
64
|
+
|
|
65
|
+
export interface TonProviderApi {
|
|
66
|
+
deviceInfo: unknown;
|
|
67
|
+
walletInfo?: unknown;
|
|
68
|
+
protocolVersion: number;
|
|
69
|
+
connect(
|
|
70
|
+
protocolVersion: number,
|
|
71
|
+
message: TonConnectRequest
|
|
72
|
+
): Promise<TonConnectEvent>;
|
|
73
|
+
restoreConnection(): Promise<TonConnectEvent>;
|
|
74
|
+
send(message: TonConnectAppRequest): Promise<TonConnectWalletResponse>;
|
|
75
|
+
listen(callback: (event: unknown) => void): () => void;
|
|
76
|
+
/*
|
|
77
|
+
* Non-standard OKX-specific event API. `accountChanged` fires when the user
|
|
78
|
+
* switches the active account inside the wallet; its payload is undocumented
|
|
79
|
+
* and must not be relied on.
|
|
80
|
+
*/
|
|
81
|
+
on(
|
|
82
|
+
event: 'accountChanged' | 'connect' | 'disconnect',
|
|
83
|
+
callback: (payload?: unknown) => void
|
|
84
|
+
): void;
|
|
85
|
+
off(
|
|
86
|
+
event: 'accountChanged' | 'connect' | 'disconnect',
|
|
87
|
+
callback: (payload?: unknown) => void
|
|
88
|
+
): void;
|
|
89
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Environments,
|
|
3
|
+
TonAddressItemReply,
|
|
4
|
+
TonConnectEvent,
|
|
5
|
+
TonConnectEventSuccess,
|
|
6
|
+
} from './types.js';
|
|
7
|
+
import type { CaipAccount } from '@rango-dev/wallets-core/namespaces/common';
|
|
8
|
+
|
|
9
|
+
import { utils as tonCoreUtils } from '@rango-dev/wallets-core/namespaces/ton';
|
|
10
|
+
import { dynamicImportWithRefinedError } from '@rango-dev/wallets-shared';
|
|
11
|
+
|
|
12
|
+
export function isTonConnectEventSuccess(
|
|
13
|
+
event: TonConnectEvent
|
|
14
|
+
): event is TonConnectEventSuccess {
|
|
15
|
+
return (
|
|
16
|
+
!!event && event.event === 'connect' && Array.isArray(event.payload?.items)
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function isTonAddressItemReply(
|
|
21
|
+
item: unknown
|
|
22
|
+
): item is TonAddressItemReply {
|
|
23
|
+
return (
|
|
24
|
+
typeof item === 'object' &&
|
|
25
|
+
item !== null &&
|
|
26
|
+
'name' in item &&
|
|
27
|
+
item.name === 'ton_addr' &&
|
|
28
|
+
'address' in item &&
|
|
29
|
+
typeof item.address === 'string'
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
let environments: Environments | undefined;
|
|
34
|
+
|
|
35
|
+
export function setEnvironments(env?: Environments) {
|
|
36
|
+
environments = env;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function getTonConnectManifestUrl(): string {
|
|
40
|
+
const manifestUrl = environments?.tonConnectManifestUrl;
|
|
41
|
+
if (!manifestUrl) {
|
|
42
|
+
throw new Error(
|
|
43
|
+
'OKX TON requires a TonConnect manifest URL. Please provide it through the provider environments.'
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
return manifestUrl;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
let tonRequestId = 0;
|
|
50
|
+
|
|
51
|
+
// TonConnect requires a unique string `id` on every request sent to the bridge.
|
|
52
|
+
export function nextTonRequestId(): string {
|
|
53
|
+
tonRequestId += 1;
|
|
54
|
+
return tonRequestId.toString();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Convert a `ConnectEvent`'s raw `<workchain>:<hex>` address to user-friendly CAIP.
|
|
58
|
+
export async function connectEventToCAIP(
|
|
59
|
+
connectEvent: TonConnectEvent
|
|
60
|
+
): Promise<CaipAccount[]> {
|
|
61
|
+
if (!isTonConnectEventSuccess(connectEvent)) {
|
|
62
|
+
return tonCoreUtils.formatAccountsToCAIP([]);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const addressItem = connectEvent.payload.items.find(isTonAddressItemReply);
|
|
66
|
+
if (!addressItem) {
|
|
67
|
+
return tonCoreUtils.formatAccountsToCAIP([]);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const { Address } = await dynamicImportWithRefinedError(
|
|
71
|
+
async () => await import('@ton/core')
|
|
72
|
+
);
|
|
73
|
+
const userFriendlyAddress = Address.parseRaw(addressItem.address).toString({
|
|
74
|
+
bounceable: false,
|
|
75
|
+
urlSafe: true,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
return tonCoreUtils.formatAccountsToCAIP([userFriendlyAddress]);
|
|
79
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { NamespaceBuilder } from '@hub3js/core';
|
|
2
|
+
import * as commonBuilders from '@hub3js/std/builders';
|
|
3
|
+
import { standardizeAndThrowError } from '@hub3js/std/operators';
|
|
4
|
+
import { type TronActions } from '@rango-dev/wallets-core/namespaces/tron';
|
|
5
|
+
import { builders } from '@rango-dev/wallets-core/namespaces/tron';
|
|
6
|
+
|
|
7
|
+
import { tronActions } from '../actions/tron.js';
|
|
8
|
+
import { tronBuilders } from '../builders/tron.js';
|
|
9
|
+
import { WALLET_ID } from '../constants.js';
|
|
10
|
+
import { tronOKX } from '../utils.js';
|
|
11
|
+
|
|
12
|
+
const [changeAccountSubscriber, changeAccountCleanup] = tronBuilders
|
|
13
|
+
.changeAccountSubscriber(tronOKX)
|
|
14
|
+
.build();
|
|
15
|
+
|
|
16
|
+
const connect = builders
|
|
17
|
+
.connect()
|
|
18
|
+
.action(tronActions.connect)
|
|
19
|
+
.before(changeAccountSubscriber)
|
|
20
|
+
.or(changeAccountCleanup)
|
|
21
|
+
.or(standardizeAndThrowError)
|
|
22
|
+
.build();
|
|
23
|
+
|
|
24
|
+
const canEagerConnect = builders
|
|
25
|
+
.canEagerConnect()
|
|
26
|
+
.action(tronActions.canEagerConnect)
|
|
27
|
+
.build();
|
|
28
|
+
|
|
29
|
+
const disconnect = commonBuilders
|
|
30
|
+
.disconnect<TronActions>()
|
|
31
|
+
.after(changeAccountCleanup)
|
|
32
|
+
.build();
|
|
33
|
+
|
|
34
|
+
const tron = new NamespaceBuilder<TronActions>('Tron', WALLET_ID)
|
|
35
|
+
.action(connect)
|
|
36
|
+
.action(disconnect)
|
|
37
|
+
.action(canEagerConnect)
|
|
38
|
+
.build();
|
|
39
|
+
|
|
40
|
+
export { tron };
|
package/src/provider.ts
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
|
+
import type { Environments } from './namespaces/ton/types.js';
|
|
2
|
+
|
|
1
3
|
import { ProviderBuilder } from '@hub3js/core';
|
|
2
4
|
|
|
3
5
|
import { metadata, WALLET_ID } from './constants.js';
|
|
4
6
|
import { evm } from './namespaces/evm.js';
|
|
5
7
|
import { solana } from './namespaces/solana.js';
|
|
8
|
+
import { ton } from './namespaces/ton/ton.js';
|
|
9
|
+
import { setEnvironments } from './namespaces/ton/utils.js';
|
|
10
|
+
import { tron } from './namespaces/tron.js';
|
|
6
11
|
import { utxo } from './namespaces/utxo.js';
|
|
7
12
|
import { okx as okxInstance } from './utils.js';
|
|
8
13
|
|
|
9
14
|
const buildProvider = () =>
|
|
10
15
|
new ProviderBuilder(WALLET_ID)
|
|
11
|
-
.init(function (context) {
|
|
16
|
+
.init(function (context, environments?: Environments) {
|
|
17
|
+
setEnvironments(environments);
|
|
12
18
|
const [, setState] = context.state();
|
|
13
19
|
|
|
14
20
|
if (okxInstance()) {
|
|
@@ -20,6 +26,8 @@ const buildProvider = () =>
|
|
|
20
26
|
.add('solana', solana)
|
|
21
27
|
.add('evm', evm)
|
|
22
28
|
.add('utxo', utxo)
|
|
29
|
+
.add('ton', ton)
|
|
30
|
+
.add('tron', tron)
|
|
23
31
|
|
|
24
32
|
.build();
|
|
25
33
|
|
package/src/signer.ts
CHANGED
|
@@ -5,6 +5,8 @@ import {
|
|
|
5
5
|
EVM_NAMESPACE,
|
|
6
6
|
SOLANA_NAMESPACE,
|
|
7
7
|
UTXO_NAMESPACE,
|
|
8
|
+
TON_NAMESPACE,
|
|
9
|
+
TRON_NAMESPACE,
|
|
8
10
|
} from '@hub3js/namespaces';
|
|
9
11
|
import {
|
|
10
12
|
dynamicImportWithRefinedError,
|
|
@@ -13,6 +15,7 @@ import {
|
|
|
13
15
|
import { DefaultSignerFactory, TransactionType as TxType } from 'rango-types';
|
|
14
16
|
|
|
15
17
|
import { OKXSolanaSigner } from './signers/solana.js';
|
|
18
|
+
import { OKXTonSigner } from './signers/ton.js';
|
|
16
19
|
import { OKXUTXOSigner } from './signers/utxo.js';
|
|
17
20
|
|
|
18
21
|
export default async function getSigners(
|
|
@@ -21,14 +24,21 @@ export default async function getSigners(
|
|
|
21
24
|
const ethProvider = getNetworkInstance(provider, EVM_NAMESPACE);
|
|
22
25
|
const solProvider = getNetworkInstance(provider, SOLANA_NAMESPACE);
|
|
23
26
|
const utxoProvider = getNetworkInstance(provider, UTXO_NAMESPACE);
|
|
27
|
+
const tonProvider = getNetworkInstance(provider, TON_NAMESPACE);
|
|
28
|
+
const tronProvider = getNetworkInstance(provider, TRON_NAMESPACE);
|
|
24
29
|
|
|
25
30
|
const signers = new DefaultSignerFactory();
|
|
26
31
|
const { DefaultEvmSigner } = await dynamicImportWithRefinedError(
|
|
27
32
|
async () => await import('@rango-dev/signer-evm')
|
|
28
33
|
);
|
|
34
|
+
const { DefaultTronSigner } = await dynamicImportWithRefinedError(
|
|
35
|
+
async () => await import('@rango-dev/signer-tron')
|
|
36
|
+
);
|
|
29
37
|
signers.registerSigner(TxType.EVM, new DefaultEvmSigner(ethProvider));
|
|
30
38
|
signers.registerSigner(TxType.SOLANA, new OKXSolanaSigner(solProvider));
|
|
31
39
|
signers.registerSigner(TxType.TRANSFER, new OKXUTXOSigner(utxoProvider));
|
|
40
|
+
signers.registerSigner(TxType.TON, new OKXTonSigner(tonProvider));
|
|
41
|
+
signers.registerSigner(TxType.TRON, new DefaultTronSigner(tronProvider));
|
|
32
42
|
|
|
33
43
|
return signers;
|
|
34
44
|
}
|