@rango-dev/provider-walletconnect-2 0.16.0 → 0.17.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/CHANGELOG.md +0 -4
- package/dist/constants.d.ts +5 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/helpers.d.ts +3 -0
- package/dist/helpers.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +3 -3
- package/dist/session.d.ts +10 -2
- package/dist/session.d.ts.map +1 -1
- package/dist/signers/evm.d.ts +1 -0
- package/dist/signers/evm.d.ts.map +1 -1
- package/package.json +15 -14
- package/src/constants.ts +12 -3
- package/src/helpers.ts +93 -3
- package/src/index.ts +58 -22
- package/src/session.ts +103 -5
- package/src/signers/evm.ts +38 -1
package/dist/session.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ConnectParams, CreateSessionParams, WCInstance } from './types';
|
|
2
2
|
import type { SignClient } from '@walletconnect/sign-client/dist/types/client';
|
|
3
3
|
import type { PairingTypes, SessionTypes, SignClientTypes } from '@walletconnect/types';
|
|
4
|
+
import type { BlockchainMeta } from 'rango-types/lib';
|
|
4
5
|
export declare function getLastSession(client: SignClient): SessionTypes.Struct;
|
|
5
6
|
/**
|
|
6
7
|
*
|
|
@@ -31,7 +32,10 @@ export declare function tryGetPairing(client: SignClient): PairingTypes.Struct |
|
|
|
31
32
|
* Try to restore the session first, if couldn't, create a new session by showing a modal.
|
|
32
33
|
*
|
|
33
34
|
*/
|
|
34
|
-
export declare function tryConnect(client: SignClient, params: ConnectParams): Promise<
|
|
35
|
+
export declare function tryConnect(client: SignClient, params: ConnectParams): Promise<{
|
|
36
|
+
session: SessionTypes.Struct;
|
|
37
|
+
isNew: boolean;
|
|
38
|
+
}>;
|
|
35
39
|
/**
|
|
36
40
|
* Wallet connect is a multichain protocol and we can not determine the connected wallet
|
|
37
41
|
* supports which wallet, `extend`ing session doesn't work during a bug in their utils packages.
|
|
@@ -50,7 +54,7 @@ export declare function cleanupSingleSession(client: SignClient, topic: string):
|
|
|
50
54
|
*
|
|
51
55
|
*/
|
|
52
56
|
export declare function disconnectSessions(client: SignClient): Promise<void[]>;
|
|
53
|
-
export declare function getAccountsFromSession(session: SessionTypes.Struct): {
|
|
57
|
+
export declare function getAccountsFromSession(session: SessionTypes.Struct, chainId?: string): {
|
|
54
58
|
accounts: string[];
|
|
55
59
|
chainId: string;
|
|
56
60
|
}[];
|
|
@@ -60,4 +64,8 @@ export declare function getAccountsFromEvent(event: SignClientTypes.BaseEventArg
|
|
|
60
64
|
accounts: string[];
|
|
61
65
|
chainId: string;
|
|
62
66
|
}[];
|
|
67
|
+
export declare function updateSessionAccounts(instance: any, requestedNetwork: string, currentNetwork: string, meta: BlockchainMeta[]): Promise<void>;
|
|
68
|
+
export declare function needSessionRecreateOnSwitchNetwork(instance: any): boolean;
|
|
69
|
+
export declare function persistCurrentChainId(instance: any, chainId: string): any;
|
|
70
|
+
export declare function getPersistedChainId(instance: any): Promise<any>;
|
|
63
71
|
//# sourceMappingURL=session.d.ts.map
|
package/dist/session.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC9E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8CAA8C,CAAC;AAC/E,OAAO,KAAK,EACV,YAAY,EACZ,YAAY,EACZ,eAAe,EAChB,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC9E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8CAA8C,CAAC;AAC/E,OAAO,KAAK,EACV,YAAY,EACZ,YAAY,EACZ,eAAe,EAChB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAiBtD,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,uBAEhD;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,YAAY,CAAC,MAAM,GAC3B,OAAO,CAAC,YAAY,CAAC,MAAM,GAAG,SAAS,CAAC,CAW1C;AAED;;;;;;;GAOG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,CA+C9B;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,UAAU,GACjB,YAAY,CAAC,MAAM,GAAG,SAAS,CAMjC;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,UAAU,EAClB,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC;IAAE,OAAO,EAAE,YAAY,CAAC,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC,CAoC3D;AAED;;;;GAIG;AACH,wBAAsB,6BAA6B,CACjD,QAAQ,EAAE,UAAU,EACpB,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,CA0B9B;AAoBD;;;;GAIG;AACH,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,iBAiB3E;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,UAAU,mBAwB1D;AAED,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,YAAY,CAAC,MAAM,EAC5B,OAAO,CAAC,EAAE,MAAM;;;IAgCjB;AAED,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,eAAe,CAAC,aAAa,CAAC;IACnC,UAAU,EAAE,YAAY,CAAC,UAAU,CAAC;CACrC,CAAC;;;IAeH;AAMD,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,GAAG,EACb,gBAAgB,EAAE,MAAM,EACxB,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,cAAc,EAAE,iBA8CvB;AAMD,wBAAgB,kCAAkC,CAAC,QAAQ,EAAE,GAAG,GAAG,OAAO,CAIzE;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,OAInE;AAED,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,GAAG,gBAGtD"}
|
package/dist/signers/evm.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ declare class EVMSigner implements GenericSigner<EvmTransaction> {
|
|
|
6
6
|
private client;
|
|
7
7
|
private session;
|
|
8
8
|
constructor(client: SignClient, session: SessionTypes.Struct);
|
|
9
|
+
static buildTx(evmTx: EvmTransaction, disableV2?: boolean): {};
|
|
9
10
|
signMessage(msg: string, address: string, chainId: string | null): Promise<string>;
|
|
10
11
|
signAndSendTx(tx: EvmTransaction, address: string, chainId: string | null): Promise<{
|
|
11
12
|
hash: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"evm.d.ts","sourceRoot":"","sources":["../../src/signers/evm.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8CAA8C,CAAC;AAC/E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAK/D,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAMjD,cAAM,SAAU,YAAW,aAAa,CAAC,cAAc,CAAC;IACtD,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,OAAO,CAAsB;gBAEzB,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,CAAC,MAAM;
|
|
1
|
+
{"version":3,"file":"evm.d.ts","sourceRoot":"","sources":["../../src/signers/evm.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8CAA8C,CAAC;AAC/E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAK/D,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAMjD,cAAM,SAAU,YAAW,aAAa,CAAC,cAAc,CAAC;IACtD,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,OAAO,CAAsB;gBAEzB,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,CAAC,MAAM;IAK5D,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,cAAc,EAAE,SAAS,UAAQ;IAoC1C,WAAW,CACtB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GAAG,IAAI,GACrB,OAAO,CAAC,MAAM,CAAC;IAqCZ,aAAa,CACjB,EAAE,EAAE,cAAc,EAClB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GAAG,IAAI,GACrB,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAuB5B,OAAO,CAAC,iCAAiC;CAwD1C;AAED,eAAe,SAAS,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rango-dev/provider-walletconnect-2",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"
|
|
6
|
+
"source": "./src/index.ts",
|
|
7
7
|
"main": "./dist/index.js",
|
|
8
8
|
"exports": {
|
|
9
9
|
".": "./dist/index.js"
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
],
|
|
16
16
|
"scripts": {
|
|
17
17
|
"build": "node ../../scripts/build/command.mjs --path wallets/provider-walletconnect-2",
|
|
18
|
+
"ts-check": "tsc --declaration --emitDeclarationOnly -p ./tsconfig.json",
|
|
18
19
|
"clean": "rimraf dist",
|
|
19
20
|
"format": "prettier --write '{.,src}/**/*.{ts,tsx}'",
|
|
20
21
|
"lint": "eslint \"**/*.{ts,tsx}\" --ignore-path ../../.eslintignore"
|
|
@@ -23,24 +24,24 @@
|
|
|
23
24
|
"@cosmjs/launchpad": "^0.27.1",
|
|
24
25
|
"@keplr-wallet/cosmos": "^0.9.12",
|
|
25
26
|
"@keplr-wallet/simple-fetch": "^0.12.14",
|
|
26
|
-
"@rango-dev/signer-cosmos": "^0.
|
|
27
|
-
"@rango-dev/signer-evm": "^0.
|
|
28
|
-
"@rango-dev/signer-solana": "^0.
|
|
29
|
-
"@rango-dev/wallets-shared": "^0.
|
|
30
|
-
"@solana/web3.js": "
|
|
31
|
-
"@walletconnect/encoding": "
|
|
32
|
-
"@walletconnect/modal": "
|
|
33
|
-
"@walletconnect/sign-client": "
|
|
34
|
-
"@walletconnect/utils": "
|
|
27
|
+
"@rango-dev/signer-cosmos": "^0.24.0",
|
|
28
|
+
"@rango-dev/signer-evm": "^0.24.0",
|
|
29
|
+
"@rango-dev/signer-solana": "^0.24.0",
|
|
30
|
+
"@rango-dev/wallets-shared": "^0.24.0",
|
|
31
|
+
"@solana/web3.js": "1.67.2",
|
|
32
|
+
"@walletconnect/encoding": "1.0.2",
|
|
33
|
+
"@walletconnect/modal": "2.6.1",
|
|
34
|
+
"@walletconnect/sign-client": "2.9.1",
|
|
35
|
+
"@walletconnect/utils": "2.9.1",
|
|
35
36
|
"bs58": "^5.0.0",
|
|
36
37
|
"caip": "^1.1.0",
|
|
37
38
|
"cosmos-wallet": "^1.2.0",
|
|
38
|
-
"rango-types": "^0.1.
|
|
39
|
+
"rango-types": "^0.1.57"
|
|
39
40
|
},
|
|
40
41
|
"devDependencies": {
|
|
41
|
-
"@walletconnect/types": "
|
|
42
|
+
"@walletconnect/types": "2.9.1"
|
|
42
43
|
},
|
|
43
44
|
"publishConfig": {
|
|
44
45
|
"access": "public"
|
|
45
46
|
}
|
|
46
|
-
}
|
|
47
|
+
}
|
package/src/constants.ts
CHANGED
|
@@ -13,6 +13,8 @@ export enum NAMESPACES {
|
|
|
13
13
|
MULTIVERSX = 'multiversx',
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
export const CHAIN_ID_STORAGE = 'wc@2:client//namespaces';
|
|
17
|
+
|
|
16
18
|
// Refrence: https://docs.walletconnect.com/2.0/advanced/rpc-reference/solana-rpc
|
|
17
19
|
export enum SolanaRPCMethods {
|
|
18
20
|
GET_ACCOUNTS = 'solana_getAccounts',
|
|
@@ -36,6 +38,9 @@ export enum EthereumRPCMethods {
|
|
|
36
38
|
SIGN_TRANSACTION = 'eth_signTransaction',
|
|
37
39
|
SEND_TRANSACTION = 'eth_sendTransaction',
|
|
38
40
|
SEND_RAW_TRANSACTION = 'eth_sendRawTransaction',
|
|
41
|
+
SWITCH_CHAIN = 'wallet_switchEthereumChain',
|
|
42
|
+
ADD_CHAIN = 'wallet_addEthereumChain',
|
|
43
|
+
GET_CHAIN = 'eth_chainId',
|
|
39
44
|
}
|
|
40
45
|
|
|
41
46
|
export enum StarknetRPCMethods {
|
|
@@ -57,11 +62,16 @@ export const DEFAULT_ETHEREUM_METHODS = [
|
|
|
57
62
|
EthereumRPCMethods.PERSONAL_SIGN,
|
|
58
63
|
EthereumRPCMethods.SEND_TRANSACTION,
|
|
59
64
|
EthereumRPCMethods.SIGN_TRANSACTION,
|
|
65
|
+
EthereumRPCMethods.SWITCH_CHAIN,
|
|
66
|
+
EthereumRPCMethods.ADD_CHAIN,
|
|
67
|
+
EthereumRPCMethods.GET_CHAIN,
|
|
60
68
|
];
|
|
69
|
+
|
|
61
70
|
export const DEFAULT_SOLANA_METHODS = [
|
|
62
71
|
SolanaRPCMethods.SIGN_TRANSACTION,
|
|
63
72
|
SolanaRPCMethods.SIGN_MESSAGE,
|
|
64
73
|
];
|
|
74
|
+
|
|
65
75
|
export const DEFAULT_COSMOS_METHODS = [
|
|
66
76
|
CosmosRPCMethods.GET_ACCOUNTS,
|
|
67
77
|
CosmosRPCMethods.SIGN_AMINO,
|
|
@@ -73,10 +83,9 @@ export const DEFAULT_SOLANA_CHAIN_ID = '4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ';
|
|
|
73
83
|
|
|
74
84
|
export const DEFAULT_APP_METADATA = {
|
|
75
85
|
name: 'Rango Exchange',
|
|
76
|
-
description:
|
|
77
|
-
'Easiest DEX UX with best price to exchange all coins on all blockchains.',
|
|
86
|
+
description: 'The Ultimate Cross-Chain Solution',
|
|
78
87
|
url: 'https://app.rango.exchange/',
|
|
79
|
-
icons: ['https://
|
|
88
|
+
icons: ['https://app.rango.exchange/logo-rounded.png'],
|
|
80
89
|
};
|
|
81
90
|
|
|
82
91
|
export const RELAY_URL = 'wss://relay.walletconnect.com';
|
package/src/helpers.ts
CHANGED
|
@@ -3,10 +3,18 @@ import type { WalletState } from '@rango-dev/wallets-shared';
|
|
|
3
3
|
import type { ProposalTypes } from '@walletconnect/types';
|
|
4
4
|
import type { BlockchainMeta } from 'rango-types';
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
convertEvmBlockchainMetaToEvmChainInfo,
|
|
8
|
+
isEvmAddress,
|
|
9
|
+
Networks,
|
|
10
|
+
} from '@rango-dev/wallets-shared';
|
|
7
11
|
import { WalletConnectModal } from '@walletconnect/modal';
|
|
8
|
-
import { ChainId } from 'caip';
|
|
9
|
-
import {
|
|
12
|
+
import { AccountId, ChainId } from 'caip';
|
|
13
|
+
import {
|
|
14
|
+
cosmosBlockchains,
|
|
15
|
+
evmBlockchains,
|
|
16
|
+
isEvmBlockchain,
|
|
17
|
+
} from 'rango-types';
|
|
10
18
|
|
|
11
19
|
import {
|
|
12
20
|
DEFAULT_COSMOS_METHODS,
|
|
@@ -14,6 +22,7 @@ import {
|
|
|
14
22
|
DEFAULT_ETHEREUM_METHODS,
|
|
15
23
|
DEFAULT_SOLANA_CHAIN_ID,
|
|
16
24
|
DEFAULT_SOLANA_METHODS,
|
|
25
|
+
EthereumRPCMethods,
|
|
17
26
|
NAMESPACES,
|
|
18
27
|
} from './constants';
|
|
19
28
|
import { getLastSession } from './session';
|
|
@@ -192,3 +201,84 @@ export function getChainIdByNetworkName(
|
|
|
192
201
|
|
|
193
202
|
return chainId;
|
|
194
203
|
}
|
|
204
|
+
|
|
205
|
+
export async function switchOrAddEvmChain(
|
|
206
|
+
meta: BlockchainMeta[],
|
|
207
|
+
requestedNetwork: string,
|
|
208
|
+
currentNetwork: string,
|
|
209
|
+
instance: any
|
|
210
|
+
) {
|
|
211
|
+
const evmBlockchains = meta.filter(isEvmBlockchain);
|
|
212
|
+
const evmNetworksChainInfo =
|
|
213
|
+
convertEvmBlockchainMetaToEvmChainInfo(evmBlockchains);
|
|
214
|
+
const targetChain = evmNetworksChainInfo[requestedNetwork];
|
|
215
|
+
const targetBlockchain = meta.find(
|
|
216
|
+
(blockchain: BlockchainMeta) => blockchain.name === requestedNetwork
|
|
217
|
+
);
|
|
218
|
+
const chainIdInHex = targetBlockchain?.chainId;
|
|
219
|
+
|
|
220
|
+
const currentChainId = getChainIdByNetworkName(currentNetwork, meta);
|
|
221
|
+
const currentChainEip = ChainId.format({
|
|
222
|
+
namespace: NAMESPACES.ETHEREUM,
|
|
223
|
+
reference: String(currentChainId),
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
const session = instance.session;
|
|
227
|
+
|
|
228
|
+
try {
|
|
229
|
+
await instance.client.request({
|
|
230
|
+
topic: session.topic,
|
|
231
|
+
request: {
|
|
232
|
+
method: EthereumRPCMethods.SWITCH_CHAIN,
|
|
233
|
+
params: [
|
|
234
|
+
{
|
|
235
|
+
chainId: chainIdInHex,
|
|
236
|
+
},
|
|
237
|
+
],
|
|
238
|
+
},
|
|
239
|
+
// It's required to pass current chain, otherwise it won't work
|
|
240
|
+
chainId: currentChainEip,
|
|
241
|
+
});
|
|
242
|
+
} catch (err: any) {
|
|
243
|
+
const addChainError = 4902;
|
|
244
|
+
if (
|
|
245
|
+
err?.code === addChainError ||
|
|
246
|
+
err?.message?.includes(String(addChainError))
|
|
247
|
+
) {
|
|
248
|
+
await instance.client.request({
|
|
249
|
+
topic: session.topic,
|
|
250
|
+
request: {
|
|
251
|
+
method: EthereumRPCMethods.ADD_CHAIN,
|
|
252
|
+
params: [targetChain],
|
|
253
|
+
},
|
|
254
|
+
// It's required to pass current chain, otherwise it won't work
|
|
255
|
+
chainId: currentChainEip,
|
|
256
|
+
});
|
|
257
|
+
} else {
|
|
258
|
+
throw err;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export function getCurrentEvmAccountAddress(instance: any) {
|
|
264
|
+
return instance.session.namespaces.eip155.accounts
|
|
265
|
+
?.map((account: string) => {
|
|
266
|
+
return new AccountId(account).address;
|
|
267
|
+
})
|
|
268
|
+
?.filter((address: string) => isEvmAddress(address))?.[0];
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
export function getEvmAccount(
|
|
272
|
+
network: string,
|
|
273
|
+
address: string,
|
|
274
|
+
meta: BlockchainMeta[]
|
|
275
|
+
) {
|
|
276
|
+
const currentChainId = getChainIdByNetworkName(network, meta);
|
|
277
|
+
return AccountId.format({
|
|
278
|
+
chainId: {
|
|
279
|
+
namespace: NAMESPACES.ETHEREUM,
|
|
280
|
+
reference: String(currentChainId),
|
|
281
|
+
},
|
|
282
|
+
address,
|
|
283
|
+
});
|
|
284
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -12,8 +12,9 @@ import type {
|
|
|
12
12
|
import type { ISignClient } from '@walletconnect/types';
|
|
13
13
|
import type { BlockchainMeta, SignerFactory } from 'rango-types';
|
|
14
14
|
|
|
15
|
-
import { WalletTypes } from '@rango-dev/wallets-shared';
|
|
15
|
+
import { Networks, WalletTypes } from '@rango-dev/wallets-shared';
|
|
16
16
|
import Client from '@walletconnect/sign-client';
|
|
17
|
+
import { AccountId, ChainId } from 'caip';
|
|
17
18
|
import { evmBlockchains } from 'rango-types';
|
|
18
19
|
|
|
19
20
|
import {
|
|
@@ -22,14 +23,22 @@ import {
|
|
|
22
23
|
EthereumEvents,
|
|
23
24
|
RELAY_URL,
|
|
24
25
|
} from './constants';
|
|
25
|
-
import {
|
|
26
|
+
import {
|
|
27
|
+
createModalInstance,
|
|
28
|
+
simulateRequest,
|
|
29
|
+
switchOrAddEvmChain,
|
|
30
|
+
} from './helpers';
|
|
26
31
|
import {
|
|
27
32
|
cleanupSingleSession,
|
|
28
33
|
disconnectSessions,
|
|
29
34
|
getAccountsFromEvent,
|
|
30
35
|
getAccountsFromSession,
|
|
36
|
+
getPersistedChainId,
|
|
37
|
+
needSessionRecreateOnSwitchNetwork,
|
|
38
|
+
persistCurrentChainId,
|
|
31
39
|
tryConnect,
|
|
32
40
|
trySwitchByCreatingNewSession,
|
|
41
|
+
updateSessionAccounts,
|
|
33
42
|
} from './session';
|
|
34
43
|
import signer from './signer';
|
|
35
44
|
|
|
@@ -51,14 +60,15 @@ export const config: WalletConfig = {
|
|
|
51
60
|
checkInstallation: false,
|
|
52
61
|
isAsyncInstance: true,
|
|
53
62
|
defaultNetwork: DEFAULT_NETWORK,
|
|
63
|
+
isAsyncSwitchNetwork: true,
|
|
54
64
|
};
|
|
55
65
|
|
|
56
66
|
export const getInstance: GetInstance = async (options) => {
|
|
57
67
|
const { currentProvider, getState, meta } = options;
|
|
58
68
|
|
|
59
69
|
/*
|
|
60
|
-
*Create a new pair, if exists use the pair,
|
|
61
|
-
*Or use the already created one.
|
|
70
|
+
* Create a new pair, if exists use the pair,
|
|
71
|
+
* Or use the already created one.
|
|
62
72
|
*/
|
|
63
73
|
let provider: ISignClient;
|
|
64
74
|
if (!currentProvider) {
|
|
@@ -67,7 +77,6 @@ export const getInstance: GetInstance = async (options) => {
|
|
|
67
77
|
'You need to set `WC_PROJECT_ID` in Wallet Connect provider.'
|
|
68
78
|
);
|
|
69
79
|
}
|
|
70
|
-
|
|
71
80
|
provider = await Client.init({
|
|
72
81
|
relayUrl: RELAY_URL,
|
|
73
82
|
projectId: envs.WC_PROJECT_ID,
|
|
@@ -91,15 +100,29 @@ export const connect: Connect = async ({ instance, network, meta }) => {
|
|
|
91
100
|
const requestedNetwork = network || DEFAULT_NETWORK;
|
|
92
101
|
|
|
93
102
|
// Try to restore the session first, if couldn't, create a new session by showing a modal.
|
|
94
|
-
const session = await tryConnect(client, {
|
|
103
|
+
const { session, isNew } = await tryConnect(client, {
|
|
95
104
|
network: requestedNetwork,
|
|
96
105
|
meta,
|
|
97
106
|
});
|
|
98
107
|
// Override the value (session).
|
|
99
108
|
instance.session = session;
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
109
|
+
const currentChainId = !isNew
|
|
110
|
+
? String(await getPersistedChainId(instance))
|
|
111
|
+
: undefined;
|
|
112
|
+
const accounts = getAccountsFromSession(session, currentChainId);
|
|
113
|
+
/*
|
|
114
|
+
* TODO: we need to fix next lines to support multiple accounts
|
|
115
|
+
* for now, it will return the current evm account on the current chain
|
|
116
|
+
*/
|
|
117
|
+
if (!isNew) {
|
|
118
|
+
return {
|
|
119
|
+
chainId: String(currentChainId),
|
|
120
|
+
accounts: accounts?.[0].accounts,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
const newChainId = accounts?.[accounts.length - 1].chainId;
|
|
124
|
+
void persistCurrentChainId(instance, newChainId);
|
|
125
|
+
return accounts?.[accounts.length - 1];
|
|
103
126
|
};
|
|
104
127
|
|
|
105
128
|
export const subscribe: Subscribe = ({
|
|
@@ -126,13 +149,16 @@ export const subscribe: Subscribe = ({
|
|
|
126
149
|
// Listen to events triggred by wallet. (e.g. accountsChanged and chainChanged)
|
|
127
150
|
client.on('session_event', (args) => {
|
|
128
151
|
if (args.params.event.name === EthereumEvents.ACCOUNTS_CHANGED) {
|
|
129
|
-
const accounts = args.params.event.data
|
|
130
|
-
|
|
152
|
+
const accounts = args.params.event.data.map((account: string) => {
|
|
153
|
+
return new AccountId(account).address;
|
|
154
|
+
});
|
|
155
|
+
const chainId = ChainId.parse(args.params.chainId).reference;
|
|
131
156
|
updateAccounts(accounts);
|
|
132
157
|
updateChainId(chainId);
|
|
133
158
|
} else if (args.params.event.name === EthereumEvents.CHAIN_CHANGED) {
|
|
134
|
-
const chainId = args.params.
|
|
159
|
+
const chainId = args.params.event.data;
|
|
135
160
|
updateChainId(chainId);
|
|
161
|
+
void persistCurrentChainId(instance, chainId);
|
|
136
162
|
} else {
|
|
137
163
|
console.log('[WC2] session_event not supported', args.params.event);
|
|
138
164
|
}
|
|
@@ -149,17 +175,27 @@ export const switchNetwork: SwitchNetwork = async ({
|
|
|
149
175
|
network,
|
|
150
176
|
instance,
|
|
151
177
|
meta,
|
|
178
|
+
getState,
|
|
152
179
|
}) => {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
180
|
+
const needRecreateSession = needSessionRecreateOnSwitchNetwork(instance);
|
|
181
|
+
config.isAsyncSwitchNetwork = true;
|
|
182
|
+
if (needRecreateSession) {
|
|
183
|
+
config.isAsyncSwitchNetwork = false;
|
|
184
|
+
/**
|
|
185
|
+
* In case of trust wallet that doesn't support switch chain method,
|
|
186
|
+
* we need to handle it manually by deleting last session and create a new one
|
|
187
|
+
* with correct chain id.
|
|
188
|
+
*/
|
|
189
|
+
const session = await trySwitchByCreatingNewSession(instance, {
|
|
190
|
+
network,
|
|
191
|
+
meta,
|
|
192
|
+
});
|
|
193
|
+
instance.session = session;
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
const currentNetwork = getState?.().network || Networks.ETHEREUM;
|
|
197
|
+
await updateSessionAccounts(instance, network, currentNetwork, meta);
|
|
198
|
+
await switchOrAddEvmChain(meta, network, currentNetwork, instance);
|
|
163
199
|
};
|
|
164
200
|
|
|
165
201
|
/**
|
package/src/session.ts
CHANGED
|
@@ -5,16 +5,19 @@ import type {
|
|
|
5
5
|
SessionTypes,
|
|
6
6
|
SignClientTypes,
|
|
7
7
|
} from '@walletconnect/types';
|
|
8
|
+
import type { BlockchainMeta } from 'rango-types/lib';
|
|
8
9
|
|
|
9
10
|
import { Networks, timeout } from '@rango-dev/wallets-shared';
|
|
10
11
|
import { getSdkError } from '@walletconnect/utils';
|
|
11
12
|
import { AccountId } from 'caip';
|
|
12
13
|
|
|
13
|
-
import { PING_TIMEOUT } from './constants';
|
|
14
|
+
import { CHAIN_ID_STORAGE, PING_TIMEOUT } from './constants';
|
|
14
15
|
import {
|
|
15
16
|
generateOptionalNamespace,
|
|
16
17
|
generateRequiredNamespace,
|
|
17
18
|
getChainIdByNetworkName,
|
|
19
|
+
getCurrentEvmAccountAddress,
|
|
20
|
+
getEvmAccount,
|
|
18
21
|
getModal,
|
|
19
22
|
solanaChainIdToNetworkName,
|
|
20
23
|
} from './helpers';
|
|
@@ -130,7 +133,7 @@ export function tryGetPairing(
|
|
|
130
133
|
export async function tryConnect(
|
|
131
134
|
client: SignClient,
|
|
132
135
|
params: ConnectParams
|
|
133
|
-
): Promise<SessionTypes.Struct> {
|
|
136
|
+
): Promise<{ session: SessionTypes.Struct; isNew: boolean }> {
|
|
134
137
|
const { network, meta } = params;
|
|
135
138
|
|
|
136
139
|
const requiredNamespaces = generateRequiredNamespace(meta, network);
|
|
@@ -145,6 +148,7 @@ export async function tryConnect(
|
|
|
145
148
|
}
|
|
146
149
|
|
|
147
150
|
// Check if the user has a session, if yes, restore the session and use it.
|
|
151
|
+
let isNew = false;
|
|
148
152
|
let session: SessionTypes.Struct | undefined;
|
|
149
153
|
const pairing = tryGetPairing(client);
|
|
150
154
|
if (pairing) {
|
|
@@ -161,9 +165,10 @@ export async function tryConnect(
|
|
|
161
165
|
requiredNamespaces,
|
|
162
166
|
optionalNamespaces,
|
|
163
167
|
});
|
|
168
|
+
isNew = true;
|
|
164
169
|
}
|
|
165
170
|
|
|
166
|
-
return session;
|
|
171
|
+
return { session, isNew };
|
|
167
172
|
}
|
|
168
173
|
|
|
169
174
|
/**
|
|
@@ -275,7 +280,10 @@ export async function disconnectSessions(client: SignClient) {
|
|
|
275
280
|
return await Promise.all(allPromises);
|
|
276
281
|
}
|
|
277
282
|
|
|
278
|
-
export function getAccountsFromSession(
|
|
283
|
+
export function getAccountsFromSession(
|
|
284
|
+
session: SessionTypes.Struct,
|
|
285
|
+
chainId?: string
|
|
286
|
+
) {
|
|
279
287
|
const accounts = Object.values(session.namespaces)
|
|
280
288
|
.map((namespace) => namespace.accounts)
|
|
281
289
|
.flat()
|
|
@@ -290,8 +298,21 @@ export function getAccountsFromSession(session: SessionTypes.Struct) {
|
|
|
290
298
|
accounts: [address],
|
|
291
299
|
chainId: chain,
|
|
292
300
|
};
|
|
301
|
+
})
|
|
302
|
+
// TODO: fix, ignore solana and cosmos for now
|
|
303
|
+
.filter((account) => account.chainId !== Networks.SOLANA);
|
|
304
|
+
// sort accounts, so connected chain is first item in array
|
|
305
|
+
if (!!chainId) {
|
|
306
|
+
accounts.sort((a, b) => {
|
|
307
|
+
if (a.chainId === chainId) {
|
|
308
|
+
return 1;
|
|
309
|
+
}
|
|
310
|
+
if (b.chainId === chainId) {
|
|
311
|
+
return -1;
|
|
312
|
+
}
|
|
313
|
+
return 0;
|
|
293
314
|
});
|
|
294
|
-
|
|
315
|
+
}
|
|
295
316
|
return accounts;
|
|
296
317
|
}
|
|
297
318
|
|
|
@@ -314,3 +335,80 @@ export function getAccountsFromEvent(
|
|
|
314
335
|
|
|
315
336
|
return accounts;
|
|
316
337
|
}
|
|
338
|
+
|
|
339
|
+
/*
|
|
340
|
+
* Before switch network, we need to update session namespace accounts
|
|
341
|
+
* to contain both current chain and target chain accoutns.
|
|
342
|
+
*/
|
|
343
|
+
export async function updateSessionAccounts(
|
|
344
|
+
instance: any,
|
|
345
|
+
requestedNetwork: string,
|
|
346
|
+
currentNetwork: string,
|
|
347
|
+
meta: BlockchainMeta[]
|
|
348
|
+
) {
|
|
349
|
+
const session = instance.session;
|
|
350
|
+
|
|
351
|
+
const namespaces = session.namespaces;
|
|
352
|
+
let needUpdateNamepspace = false;
|
|
353
|
+
const accounts = namespaces.eip155.accounts;
|
|
354
|
+
|
|
355
|
+
const currentAccountAddress = getCurrentEvmAccountAddress(instance);
|
|
356
|
+
const requestedAccount = getEvmAccount(
|
|
357
|
+
requestedNetwork,
|
|
358
|
+
currentAccountAddress,
|
|
359
|
+
meta
|
|
360
|
+
);
|
|
361
|
+
if (!accounts.includes(requestedAccount)) {
|
|
362
|
+
accounts.push(requestedAccount);
|
|
363
|
+
needUpdateNamepspace = true;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
const currentAccount = getEvmAccount(
|
|
367
|
+
currentNetwork,
|
|
368
|
+
currentAccountAddress,
|
|
369
|
+
meta
|
|
370
|
+
);
|
|
371
|
+
if (!accounts.includes(currentAccount)) {
|
|
372
|
+
accounts.push(currentAccount);
|
|
373
|
+
needUpdateNamepspace = true;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
if (needUpdateNamepspace) {
|
|
377
|
+
const updatedNamespaces = {
|
|
378
|
+
...namespaces,
|
|
379
|
+
eip155: {
|
|
380
|
+
...namespaces.eip155,
|
|
381
|
+
accounts,
|
|
382
|
+
},
|
|
383
|
+
};
|
|
384
|
+
await instance.client.session
|
|
385
|
+
.update({
|
|
386
|
+
topic: session.topic,
|
|
387
|
+
namespaces: updatedNamespaces,
|
|
388
|
+
})
|
|
389
|
+
.catch((err: unknown) => {
|
|
390
|
+
console.log(err);
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/*
|
|
396
|
+
* For some wallet e.g. Trust Wallet Mobile which doesn't support
|
|
397
|
+
* RPC method for switch network, we need to recreate session
|
|
398
|
+
*/
|
|
399
|
+
export function needSessionRecreateOnSwitchNetwork(instance: any): boolean {
|
|
400
|
+
const TRUST_WALLET_KEYWORD = 'trust';
|
|
401
|
+
const peerName = instance?.session?.peer?.metadata?.name;
|
|
402
|
+
return peerName?.toLowerCase()?.includes(TRUST_WALLET_KEYWORD);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
export function persistCurrentChainId(instance: any, chainId: string) {
|
|
406
|
+
return instance.client.core.storage.setItem(CHAIN_ID_STORAGE, {
|
|
407
|
+
defaultChainId: parseInt(chainId),
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
export async function getPersistedChainId(instance: any) {
|
|
412
|
+
return (await instance.client.core.storage.getItem(CHAIN_ID_STORAGE))
|
|
413
|
+
?.defaultChainId;
|
|
414
|
+
}
|
package/src/signers/evm.ts
CHANGED
|
@@ -20,6 +20,42 @@ class EVMSigner implements GenericSigner<EvmTransaction> {
|
|
|
20
20
|
this.session = session;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
static buildTx(evmTx: EvmTransaction, disableV2 = false) {
|
|
24
|
+
let tx = {};
|
|
25
|
+
if (evmTx.from) {
|
|
26
|
+
tx = { ...tx, from: evmTx.from };
|
|
27
|
+
}
|
|
28
|
+
if (evmTx.to) {
|
|
29
|
+
tx = { ...tx, to: evmTx.to };
|
|
30
|
+
}
|
|
31
|
+
if (evmTx.data) {
|
|
32
|
+
tx = { ...tx, data: evmTx.data };
|
|
33
|
+
}
|
|
34
|
+
if (evmTx.value) {
|
|
35
|
+
tx = { ...tx, value: evmTx.value };
|
|
36
|
+
}
|
|
37
|
+
if (evmTx.nonce) {
|
|
38
|
+
tx = { ...tx, nonce: evmTx.nonce };
|
|
39
|
+
}
|
|
40
|
+
if (evmTx.gasLimit) {
|
|
41
|
+
tx = { ...tx, gasLimit: evmTx.gasLimit };
|
|
42
|
+
}
|
|
43
|
+
if (evmTx.gasPrice) {
|
|
44
|
+
const shift = 16;
|
|
45
|
+
tx = {
|
|
46
|
+
...tx,
|
|
47
|
+
gasPrice: '0x' + parseInt(evmTx.gasPrice).toString(shift),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
if (evmTx.maxFeePerGas && !disableV2) {
|
|
51
|
+
tx = { ...tx, maxFeePerGas: evmTx.maxFeePerGas };
|
|
52
|
+
}
|
|
53
|
+
if (evmTx.maxPriorityFeePerGas && !disableV2) {
|
|
54
|
+
tx = { ...tx, maxPriorityFeePerGas: evmTx.maxPriorityFeePerGas };
|
|
55
|
+
}
|
|
56
|
+
return tx;
|
|
57
|
+
}
|
|
58
|
+
|
|
23
59
|
public async signMessage(
|
|
24
60
|
msg: string,
|
|
25
61
|
address: string,
|
|
@@ -71,12 +107,13 @@ class EVMSigner implements GenericSigner<EvmTransaction> {
|
|
|
71
107
|
chainId,
|
|
72
108
|
});
|
|
73
109
|
try {
|
|
110
|
+
const transaction = EVMSigner.buildTx(tx);
|
|
74
111
|
const hash: string = await this.client.request({
|
|
75
112
|
topic: this.session.topic,
|
|
76
113
|
chainId: requestedFor.caipChainId,
|
|
77
114
|
request: {
|
|
78
115
|
method: EthereumRPCMethods.SEND_TRANSACTION,
|
|
79
|
-
params: [
|
|
116
|
+
params: [transaction],
|
|
80
117
|
},
|
|
81
118
|
});
|
|
82
119
|
return {
|