@rango-dev/provider-walletconnect-2 0.0.0-experimental-936229e8-20251208
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 +240 -0
- package/dist/chunk-BPSEZJUF.js +2 -0
- package/dist/chunk-BPSEZJUF.js.map +7 -0
- package/dist/chunk-DXVBX5XQ.js +2 -0
- package/dist/chunk-DXVBX5XQ.js.map +7 -0
- package/dist/chunk-RPL2NMJC.js +2 -0
- package/dist/chunk-RPL2NMJC.js.map +7 -0
- package/dist/constants.d.ts +55 -0
- package/dist/cosmos-I3Z34UI3.js +2 -0
- package/dist/cosmos-I3Z34UI3.js.map +7 -0
- package/dist/dist-6GI3ECE5.js +139 -0
- package/dist/dist-6GI3ECE5.js.map +7 -0
- package/dist/evm-MYSQOTV5.js +2 -0
- package/dist/evm-MYSQOTV5.js.map +7 -0
- package/dist/helpers.d.ts +31 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +7 -0
- package/dist/provider-walletconnect-2.build.json +1 -0
- package/dist/session.d.ts +63 -0
- package/dist/signer.d.ts +3 -0
- package/dist/signers/cosmos.d.ts +14 -0
- package/dist/signers/evm.d.ts +15 -0
- package/dist/signers/helper.d.ts +2 -0
- package/dist/signers/mock.d.ts +2 -0
- package/dist/signers/solana.d.ts +14 -0
- package/dist/solana-35I33VLX.js +2 -0
- package/dist/solana-35I33VLX.js.map +7 -0
- package/dist/types.d.ts +24 -0
- package/package.json +52 -0
- package/readme.md +8 -0
- package/src/constants.ts +91 -0
- package/src/helpers.ts +242 -0
- package/src/index.ts +233 -0
- package/src/session.ts +374 -0
- package/src/signer.ts +45 -0
- package/src/signers/cosmos.ts +248 -0
- package/src/signers/evm.ts +163 -0
- package/src/signers/helper.ts +77 -0
- package/src/signers/mock.ts +3798 -0
- package/src/signers/solana.ts +160 -0
- package/src/types.ts +30 -0
- package/src/wc-types.d.ts +31 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { SignClient } from '@walletconnect/sign-client/dist/types/client';
|
|
2
|
+
import type { SessionTypes } from '@walletconnect/types';
|
|
3
|
+
import type { CosmosTransaction, GenericSigner } from 'rango-types';
|
|
4
|
+
declare class COSMOSSigner implements GenericSigner<CosmosTransaction> {
|
|
5
|
+
private client;
|
|
6
|
+
private session;
|
|
7
|
+
constructor(client: SignClient, session: SessionTypes.Struct);
|
|
8
|
+
signMessage(): Promise<string>;
|
|
9
|
+
signAndSendTx(tx: CosmosTransaction, address: string, chainId: string | null): Promise<{
|
|
10
|
+
hash: string;
|
|
11
|
+
}>;
|
|
12
|
+
private isNetworkAndAccountExistInSession;
|
|
13
|
+
}
|
|
14
|
+
export default COSMOSSigner;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { SignClient } from '@walletconnect/sign-client/dist/types/client';
|
|
2
|
+
import type { SessionTypes } from '@walletconnect/types';
|
|
3
|
+
import type { EvmTransaction } from 'rango-types/mainApi';
|
|
4
|
+
import { type GenericSigner } from 'rango-types';
|
|
5
|
+
declare class EVMSigner implements GenericSigner<EvmTransaction> {
|
|
6
|
+
private client;
|
|
7
|
+
private session;
|
|
8
|
+
constructor(client: SignClient, session: SessionTypes.Struct);
|
|
9
|
+
signMessage(msg: string, address: string, chainId: string | null): Promise<string>;
|
|
10
|
+
signAndSendTx(tx: EvmTransaction, address: string, chainId: string | null): Promise<{
|
|
11
|
+
hash: string;
|
|
12
|
+
}>;
|
|
13
|
+
private isNetworkAndAccountExistInSession;
|
|
14
|
+
}
|
|
15
|
+
export default EVMSigner;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { SignClient } from '@walletconnect/sign-client/dist/types/client';
|
|
2
|
+
import type { SessionTypes } from '@walletconnect/types';
|
|
3
|
+
import type { GenericSigner, SolanaTransaction } from 'rango-types';
|
|
4
|
+
declare class SOLANASigner implements GenericSigner<SolanaTransaction> {
|
|
5
|
+
private client;
|
|
6
|
+
private session;
|
|
7
|
+
constructor(client: SignClient, session: SessionTypes.Struct);
|
|
8
|
+
signMessage(msg: string, address: string, chainId: string | null): Promise<string>;
|
|
9
|
+
signAndSendTx(tx: SolanaTransaction, address: string, chainId: string | null): Promise<{
|
|
10
|
+
hash: string;
|
|
11
|
+
}>;
|
|
12
|
+
private isNetworkAndAccountExistInSession;
|
|
13
|
+
}
|
|
14
|
+
export default SOLANASigner;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import"./chunk-RPL2NMJC.js";import{a as l}from"./chunk-DXVBX5XQ.js";import{generalSolanaTransactionExecutor as h}from"@rango-dev/signer-solana";import{PublicKey as u}from"@solana/web3.js";import g from"bs58";import{AccountId as f,ChainId as S}from"caip";import{SignerError as w,SignerErrorCode as y}from"rango-types";var c="solana",p=class{static{l(this,"SOLANASigner")}client;session;constructor(s,e){this.client=s,this.session=e}async signMessage(s,e,o){let n=this.isNetworkAndAccountExistInSession({address:e,chainId:o}),a=new S({namespace:c,reference:n.chainId});try{let t=g.encode(new TextEncoder().encode(s)),i=new u(e),{signature:r}=await this.client.request({topic:this.session.topic,chainId:a.toString(),request:{method:"solana_signMessage",params:{message:t,pubkey:i}}});return r}catch(t){throw new w(y.SIGN_TX_ERROR,void 0,t)}}async signAndSendTx(s,e,o){let n=this.isNetworkAndAccountExistInSession({address:e,chainId:o});return{hash:await h(s,l(async i=>{let r=await this.client.request({topic:this.session.topic,chainId:n.caipChainId,request:{method:"solana_signTransaction",params:i}}),d=new u(s.from),m=g.decode(r.signature);return i.addSignature(d,Buffer.from(m)),i.serialize()},"DefaultSolanaSigner"))}}isNetworkAndAccountExistInSession(s){let{address:e,chainId:o}=s,n=o;if(this.session.namespaces[c]?.accounts.map(r=>{let d=r.split(":");d[2]===e&&(n=d[1])}),!n)throw new Error("You need to set your chain for signing message/transaction.");let a=new f({chainId:{namespace:c,reference:n},address:e}),t=this.session.namespaces[c]?.accounts.map(r=>r);if(!t||!t.includes(a.toString()))throw console.warn("Available adresses and requested address:",t,a.toString()),new Error("Your requested address doesn't exist on your wallect connect session. Please reconnect your wallet.");let i=new S({namespace:c,reference:n});return{chainId:n,address:e,caipChainId:i.toString()}}},P=p;export{P as default};
|
|
2
|
+
//# sourceMappingURL=solana-35I33VLX.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/signers/solana.ts"],
|
|
4
|
+
"sourcesContent": ["import type { SolanaWeb3Signer } from '@rango-dev/signer-solana';\nimport type { Transaction, VersionedTransaction } from '@solana/web3.js';\nimport type { SignClient } from '@walletconnect/sign-client/dist/types/client';\nimport type { SessionTypes } from '@walletconnect/types';\nimport type { GenericSigner, SolanaTransaction } from 'rango-types';\n\nimport { generalSolanaTransactionExecutor } from '@rango-dev/signer-solana';\nimport { PublicKey } from '@solana/web3.js';\nimport base58 from 'bs58';\nimport { AccountId, ChainId } from 'caip';\nimport { SignerError, SignerErrorCode } from 'rango-types';\n\nimport { NAMESPACES, SolanaRPCMethods } from '../constants.js';\n\nconst NAMESPACE_NAME = NAMESPACES.SOLANA;\nclass SOLANASigner implements GenericSigner<SolanaTransaction> {\n private client: SignClient;\n private session: SessionTypes.Struct;\n\n constructor(client: SignClient, session: SessionTypes.Struct) {\n this.client = client;\n this.session = session;\n }\n\n public async signMessage(\n msg: string,\n address: string,\n chainId: string | null\n ): Promise<string> {\n const requestedFor = this.isNetworkAndAccountExistInSession({\n address,\n chainId,\n });\n\n const caipChainId = new ChainId({\n namespace: NAMESPACE_NAME,\n reference: requestedFor.chainId,\n });\n\n try {\n const message = base58.encode(new TextEncoder().encode(msg));\n const pubkey = new PublicKey(address);\n const { signature } = await this.client.request<{\n signature: string;\n }>({\n topic: this.session.topic,\n chainId: caipChainId.toString(),\n request: {\n method: SolanaRPCMethods.SIGN_MESSAGE,\n params: {\n message,\n pubkey,\n },\n },\n });\n\n return signature;\n } catch (error) {\n throw new SignerError(SignerErrorCode.SIGN_TX_ERROR, undefined, error);\n }\n }\n\n async signAndSendTx(\n tx: SolanaTransaction,\n address: string,\n chainId: string | null\n ): Promise<{ hash: string }> {\n const requestedFor = this.isNetworkAndAccountExistInSession({\n address,\n chainId,\n });\n const DefaultSolanaSigner: SolanaWeb3Signer = async (\n solanaWeb3Transaction: Transaction | VersionedTransaction\n ) => {\n const response: { signature: string } = await this.client.request({\n topic: this.session.topic,\n chainId: requestedFor.caipChainId,\n request: {\n method: SolanaRPCMethods.SIGN_TRANSACTION,\n params: solanaWeb3Transaction,\n },\n });\n\n const publicKey = new PublicKey(tx.from);\n const sign = base58.decode(response.signature);\n\n solanaWeb3Transaction.addSignature(publicKey, Buffer.from(sign));\n const raw = solanaWeb3Transaction.serialize();\n return raw;\n };\n\n const hash = await generalSolanaTransactionExecutor(\n tx,\n DefaultSolanaSigner\n );\n return { hash };\n }\n\n private isNetworkAndAccountExistInSession(requestedFor: {\n address: string;\n chainId: string | null;\n }) {\n const { address, chainId } = requestedFor;\n\n /*\n * TODO: solana chain id in supported blockchains(\"mainnet-beta\") is different from solana chain id is here (\"5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp\")\n * # Solana Mainnet\n * solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvd\n * refrence: https://github.com/ChainAgnostic/namespaces/blob/main/solana/caip2.md\n */\n\n let solana_chain_id = chainId;\n this.session.namespaces[NAMESPACE_NAME]?.accounts.map((account) => {\n const sol_account = account.split(':');\n if (sol_account[2] === address) {\n solana_chain_id = sol_account[1];\n }\n });\n\n if (!solana_chain_id) {\n throw new Error(\n 'You need to set your chain for signing message/transaction.'\n );\n }\n const caipAddress = new AccountId({\n chainId: {\n namespace: NAMESPACE_NAME,\n reference: solana_chain_id,\n },\n address,\n });\n\n const addresses = this.session.namespaces[NAMESPACE_NAME]?.accounts.map(\n (address) => address\n );\n if (!addresses || !addresses.includes(caipAddress.toString())) {\n console.warn(\n 'Available adresses and requested address:',\n addresses,\n caipAddress.toString()\n );\n throw new Error(\n `Your requested address doesn't exist on your wallect connect session. Please reconnect your wallet.`\n );\n }\n\n const caipChainId = new ChainId({\n namespace: NAMESPACE_NAME,\n reference: solana_chain_id,\n });\n\n return {\n chainId: solana_chain_id,\n address,\n caipChainId: caipChainId.toString(),\n };\n }\n}\n\nexport default SOLANASigner;\n"],
|
|
5
|
+
"mappings": "oEAMA,OAAS,oCAAAA,MAAwC,2BACjD,OAAS,aAAAC,MAAiB,kBAC1B,OAAOC,MAAY,OACnB,OAAS,aAAAC,EAAW,WAAAC,MAAe,OACnC,OAAS,eAAAC,EAAa,mBAAAC,MAAuB,cAI7C,IAAMC,WACAC,EAAN,KAA+D,CAf/D,MAe+D,CAAAC,EAAA,qBACrD,OACA,QAER,YAAYC,EAAoBC,EAA8B,CAC5D,KAAK,OAASD,EACd,KAAK,QAAUC,CACjB,CAEA,MAAa,YACXC,EACAC,EACAC,EACiB,CACjB,IAAMC,EAAe,KAAK,kCAAkC,CAC1D,QAAAF,EACA,QAAAC,CACF,CAAC,EAEKE,EAAc,IAAIC,EAAQ,CAC9B,UAAWV,EACX,UAAWQ,EAAa,OAC1B,CAAC,EAED,GAAI,CACF,IAAMG,EAAUC,EAAO,OAAO,IAAI,YAAY,EAAE,OAAOP,CAAG,CAAC,EACrDQ,EAAS,IAAIC,EAAUR,CAAO,EAC9B,CAAE,UAAAS,CAAU,EAAI,MAAM,KAAK,OAAO,QAErC,CACD,MAAO,KAAK,QAAQ,MACpB,QAASN,EAAY,SAAS,EAC9B,QAAS,CACP,4BACA,OAAQ,CACN,QAAAE,EACA,OAAAE,CACF,CACF,CACF,CAAC,EAED,OAAOE,CACT,OAASC,EAAO,CACd,MAAM,IAAIC,EAAYC,EAAgB,cAAe,OAAWF,CAAK,CACvE,CACF,CAEA,MAAM,cACJG,EACAb,EACAC,EAC2B,CAC3B,IAAMC,EAAe,KAAK,kCAAkC,CAC1D,QAAAF,EACA,QAAAC,CACF,CAAC,EAyBD,MAAO,CAAE,KAJI,MAAMa,EACjBD,EArB4CjB,EAAA,MAC5CmB,GACG,CACH,IAAMC,EAAkC,MAAM,KAAK,OAAO,QAAQ,CAChE,MAAO,KAAK,QAAQ,MACpB,QAASd,EAAa,YACtB,QAAS,CACP,gCACA,OAAQa,CACV,CACF,CAAC,EAEKE,EAAY,IAAIT,EAAUK,EAAG,IAAI,EACjCK,EAAOZ,EAAO,OAAOU,EAAS,SAAS,EAE7C,OAAAD,EAAsB,aAAaE,EAAW,OAAO,KAAKC,CAAI,CAAC,EACnDH,EAAsB,UAAU,CAE9C,EAlB8C,sBAuB9C,CACc,CAChB,CAEQ,kCAAkCb,EAGvC,CACD,GAAM,CAAE,QAAAF,EAAS,QAAAC,CAAQ,EAAIC,EASzBiB,EAAkBlB,EAQtB,GAPA,KAAK,QAAQ,WAAWP,CAAc,GAAG,SAAS,IAAK0B,GAAY,CACjE,IAAMC,EAAcD,EAAQ,MAAM,GAAG,EACjCC,EAAY,CAAC,IAAMrB,IACrBmB,EAAkBE,EAAY,CAAC,EAEnC,CAAC,EAEG,CAACF,EACH,MAAM,IAAI,MACR,6DACF,EAEF,IAAMG,EAAc,IAAIC,EAAU,CAChC,QAAS,CACP,UAAW7B,EACX,UAAWyB,CACb,EACA,QAAAnB,CACF,CAAC,EAEKwB,EAAY,KAAK,QAAQ,WAAW9B,CAAc,GAAG,SAAS,IACjEM,GAAYA,CACf,EACA,GAAI,CAACwB,GAAa,CAACA,EAAU,SAASF,EAAY,SAAS,CAAC,EAC1D,cAAQ,KACN,4CACAE,EACAF,EAAY,SAAS,CACvB,EACM,IAAI,MACR,qGACF,EAGF,IAAMnB,EAAc,IAAIC,EAAQ,CAC9B,UAAWV,EACX,UAAWyB,CACb,CAAC,EAED,MAAO,CACL,QAASA,EACT,QAAAnB,EACA,YAAaG,EAAY,SAAS,CACpC,CACF,CACF,EAEOsB,EAAQ9B",
|
|
6
|
+
"names": ["generalSolanaTransactionExecutor", "PublicKey", "base58", "AccountId", "ChainId", "SignerError", "SignerErrorCode", "NAMESPACE_NAME", "SOLANASigner", "__name", "client", "session", "msg", "address", "chainId", "requestedFor", "caipChainId", "ChainId", "message", "base58", "pubkey", "PublicKey", "signature", "error", "SignerError", "SignerErrorCode", "tx", "generalSolanaTransactionExecutor", "solanaWeb3Transaction", "response", "publicKey", "sign", "solana_chain_id", "account", "sol_account", "caipAddress", "AccountId", "addresses", "solana_default"]
|
|
7
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { SignClient } from '@walletconnect/sign-client/dist/types/client';
|
|
2
|
+
import type { ProposalTypes, SessionTypes } from '@walletconnect/types';
|
|
3
|
+
import type { BlockchainMeta, CosmosBlockchainMeta } from 'rango-types';
|
|
4
|
+
export interface Environments extends Record<string, string | undefined> {
|
|
5
|
+
WC_PROJECT_ID: string;
|
|
6
|
+
DISABLE_MODAL_AND_OPEN_LINK?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface WCInstance {
|
|
9
|
+
client: SignClient;
|
|
10
|
+
session: SessionTypes.Struct | null;
|
|
11
|
+
request: (params: any) => Promise<string>;
|
|
12
|
+
}
|
|
13
|
+
export interface CreateSessionParams {
|
|
14
|
+
requiredNamespaces: ProposalTypes.RequiredNamespaces;
|
|
15
|
+
optionalNamespaces?: ProposalTypes.OptionalNamespaces;
|
|
16
|
+
pairingTopic?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface ConnectParams {
|
|
19
|
+
meta: BlockchainMeta[];
|
|
20
|
+
envs: Environments;
|
|
21
|
+
}
|
|
22
|
+
export interface CosmosMeta extends CosmosBlockchainMeta {
|
|
23
|
+
chainId: string;
|
|
24
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rango-dev/provider-walletconnect-2",
|
|
3
|
+
"version": "0.0.0-experimental-936229e8-20251208",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"source": "./src/index.ts",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"typings": "dist/index.d.ts",
|
|
12
|
+
"files": [
|
|
13
|
+
"dist",
|
|
14
|
+
"src"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "node ../../scripts/build/command.mjs --path wallets/provider-walletconnect-2 --splitting --external-all-except @walletconnect/modal",
|
|
18
|
+
"ts-check": "tsc --declaration --emitDeclarationOnly -p ./tsconfig.json",
|
|
19
|
+
"clean": "rimraf dist",
|
|
20
|
+
"format": "prettier --write '{.,src}/**/*.{ts,tsx}'",
|
|
21
|
+
"lint": "eslint \"**/*.{ts,tsx}\""
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@cosmjs/launchpad": "^0.27.1",
|
|
25
|
+
"@keplr-wallet/cosmos": "^0.9.12",
|
|
26
|
+
"@keplr-wallet/simple-fetch": "^0.12.14",
|
|
27
|
+
"@rango-dev/logging-core": "^0.12.1",
|
|
28
|
+
"@rango-dev/signer-cosmos": "^0.38.0",
|
|
29
|
+
"@rango-dev/signer-evm": "^0.40.0",
|
|
30
|
+
"@rango-dev/signer-solana": "^0.46.1",
|
|
31
|
+
"@rango-dev/wallets-shared": "^0.0.0-experimental-936229e8-20251208",
|
|
32
|
+
"@solana/web3.js": "^1.91.4",
|
|
33
|
+
"@walletconnect/encoding": "^1.0.2",
|
|
34
|
+
"@walletconnect/sign-client": "^2.11.2",
|
|
35
|
+
"@walletconnect/utils": "^2.11.2",
|
|
36
|
+
"bs58": "^5.0.0",
|
|
37
|
+
"caip": "^1.1.1",
|
|
38
|
+
"cosmos-wallet": "^1.2.0",
|
|
39
|
+
"rango-types": "^0.1.89"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@walletconnect/modal": "^2.6.2",
|
|
43
|
+
"@walletconnect/types": "^2.11.2"
|
|
44
|
+
},
|
|
45
|
+
"resolutions": {
|
|
46
|
+
"protobufjs": "^6.11.4",
|
|
47
|
+
"@keplr-wallet/cosmos/@keplr-wallet/types/secretjs/protobufjs": "^6.14.4"
|
|
48
|
+
},
|
|
49
|
+
"publishConfig": {
|
|
50
|
+
"access": "public"
|
|
51
|
+
}
|
|
52
|
+
}
|
package/readme.md
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# @rango-dev/provider-walletconnect2
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
## Known issues
|
|
5
|
+
|
|
6
|
+
- Using Private key to import wallets other than `Ethereum` will be problematic. Because it imports only a single blockchain and we are by default asking for `Ethereum`.
|
|
7
|
+
- Signing a transaction on Metamask goes through an internal error.
|
|
8
|
+
- We couldn't update exist session during a bug in `@walletconnect/utils`, so we are creating new session for accessing to new chains.
|
package/src/constants.ts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { Networks } from '@rango-dev/wallets-shared';
|
|
2
|
+
|
|
3
|
+
export const DEFAULT_NETWORK = Networks.ETHEREUM;
|
|
4
|
+
export const PING_TIMEOUT = 10_000;
|
|
5
|
+
|
|
6
|
+
export enum NAMESPACES {
|
|
7
|
+
ETHEREUM = 'eip155',
|
|
8
|
+
SOLANA = 'solana',
|
|
9
|
+
COSMOS = 'cosmos',
|
|
10
|
+
POLKADOT = 'polkadot',
|
|
11
|
+
CARDANO = 'cip34',
|
|
12
|
+
ERLOND = 'elrond',
|
|
13
|
+
MULTIVERSX = 'multiversx',
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const CHAIN_ID_STORAGE = 'wc@2:client//namespaces';
|
|
17
|
+
|
|
18
|
+
// Refrence: https://docs.walletconnect.com/2.0/advanced/rpc-reference/solana-rpc
|
|
19
|
+
export enum SolanaRPCMethods {
|
|
20
|
+
GET_ACCOUNTS = 'solana_getAccounts',
|
|
21
|
+
REQUEST_ACCOUNTS = 'solana_requestAccounts',
|
|
22
|
+
SIGN_TRANSACTION = 'solana_signTransaction',
|
|
23
|
+
SIGN_MESSAGE = 'solana_signMessage',
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Refrence: https://docs.walletconnect.com/2.0/advanced/rpc-reference/cosmos-rpc
|
|
27
|
+
export enum CosmosRPCMethods {
|
|
28
|
+
GET_ACCOUNTS = 'cosmos_getAccounts',
|
|
29
|
+
SIGN_DIRECT = 'cosmos_signDirect',
|
|
30
|
+
SIGN_AMINO = 'cosmos_signAmino',
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Refrence: https://docs.walletconnect.com/2.0/advanced/rpc-reference/ethereum-rpc
|
|
34
|
+
export enum EthereumRPCMethods {
|
|
35
|
+
PERSONAL_SIGN = 'personal_sign',
|
|
36
|
+
SIGN = 'eth_sign',
|
|
37
|
+
SIGN_TYPED_DATA = 'eth_signTypedData',
|
|
38
|
+
SIGN_TRANSACTION = 'eth_signTransaction',
|
|
39
|
+
SEND_TRANSACTION = 'eth_sendTransaction',
|
|
40
|
+
SEND_RAW_TRANSACTION = 'eth_sendRawTransaction',
|
|
41
|
+
SWITCH_CHAIN = 'wallet_switchEthereumChain',
|
|
42
|
+
ADD_CHAIN = 'wallet_addEthereumChain',
|
|
43
|
+
GET_CHAIN = 'eth_chainId',
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export enum StarknetRPCMethods {
|
|
47
|
+
REQUEST_ADD_INVOKE_TRANSACTION = 'starknet_requestAddInvokeTransaction',
|
|
48
|
+
SIGN_TYPED_DATA = 'starknet_signTypedData',
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export enum EthereumEvents {
|
|
52
|
+
CHAIN_CHANGED = 'chainChanged',
|
|
53
|
+
ACCOUNTS_CHANGED = 'accountsChanged',
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export const DEFAULT_ETHEREUM_EVENTS: EthereumEvents[] = [
|
|
57
|
+
EthereumEvents.CHAIN_CHANGED,
|
|
58
|
+
EthereumEvents.ACCOUNTS_CHANGED,
|
|
59
|
+
];
|
|
60
|
+
|
|
61
|
+
export const DEFAULT_ETHEREUM_METHODS = [
|
|
62
|
+
EthereumRPCMethods.PERSONAL_SIGN,
|
|
63
|
+
EthereumRPCMethods.SEND_TRANSACTION,
|
|
64
|
+
EthereumRPCMethods.SIGN_TRANSACTION,
|
|
65
|
+
EthereumRPCMethods.SWITCH_CHAIN,
|
|
66
|
+
EthereumRPCMethods.ADD_CHAIN,
|
|
67
|
+
EthereumRPCMethods.GET_CHAIN,
|
|
68
|
+
];
|
|
69
|
+
|
|
70
|
+
export const DEFAULT_SOLANA_METHODS = [
|
|
71
|
+
SolanaRPCMethods.SIGN_TRANSACTION,
|
|
72
|
+
SolanaRPCMethods.SIGN_MESSAGE,
|
|
73
|
+
];
|
|
74
|
+
|
|
75
|
+
export const DEFAULT_COSMOS_METHODS = [
|
|
76
|
+
CosmosRPCMethods.GET_ACCOUNTS,
|
|
77
|
+
CosmosRPCMethods.SIGN_AMINO,
|
|
78
|
+
CosmosRPCMethods.SIGN_DIRECT,
|
|
79
|
+
];
|
|
80
|
+
|
|
81
|
+
// refrence: https://github.com/ChainAgnostic/namespaces/blob/main/solana/caip2.md
|
|
82
|
+
export const DEFAULT_SOLANA_CHAIN_ID = '4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ';
|
|
83
|
+
|
|
84
|
+
export const DEFAULT_APP_METADATA = {
|
|
85
|
+
name: 'Rango Exchange',
|
|
86
|
+
description: 'The Ultimate Cross-Chain Solution',
|
|
87
|
+
url: 'https://app.rango.exchange/',
|
|
88
|
+
icons: ['https://app.rango.exchange/logo-rounded.png'],
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export const RELAY_URL = 'wss://relay.walletconnect.com';
|
package/src/helpers.ts
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import type { WalletConnectModal as WalletConnectModalType } from './wc-types.js';
|
|
2
|
+
import type { WalletState } from '@rango-dev/wallets-shared';
|
|
3
|
+
import type { ProposalTypes } from '@walletconnect/types';
|
|
4
|
+
import type { BlockchainMeta } from 'rango-types';
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
convertEvmBlockchainMetaToEvmChainInfo,
|
|
8
|
+
isEvmAddress,
|
|
9
|
+
Networks,
|
|
10
|
+
} from '@rango-dev/wallets-shared';
|
|
11
|
+
import { WalletConnectModal } from '@walletconnect/modal';
|
|
12
|
+
import { AccountId, ChainId } from 'caip';
|
|
13
|
+
import { evmBlockchains, isEvmBlockchain } from 'rango-types';
|
|
14
|
+
|
|
15
|
+
import {
|
|
16
|
+
DEFAULT_ETHEREUM_EVENTS,
|
|
17
|
+
DEFAULT_ETHEREUM_METHODS,
|
|
18
|
+
DEFAULT_SOLANA_CHAIN_ID,
|
|
19
|
+
EthereumRPCMethods,
|
|
20
|
+
NAMESPACES,
|
|
21
|
+
} from './constants.js';
|
|
22
|
+
import { getLastSession } from './session.js';
|
|
23
|
+
|
|
24
|
+
let web3Modal: WalletConnectModalType;
|
|
25
|
+
export function createModalInstance(projectId: string) {
|
|
26
|
+
if (!web3Modal) {
|
|
27
|
+
web3Modal = new WalletConnectModal({
|
|
28
|
+
projectId,
|
|
29
|
+
themeMode: 'light',
|
|
30
|
+
themeVariables: {
|
|
31
|
+
'--wcm-z-index': '999999999',
|
|
32
|
+
},
|
|
33
|
+
}) as unknown as WalletConnectModalType;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function getModal(): WalletConnectModalType {
|
|
38
|
+
return web3Modal;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
type FinalNamespaces = {
|
|
42
|
+
[key in NAMESPACES]?: ProposalTypes.BaseRequiredNamespace;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/*
|
|
46
|
+
* Some wallets like 1inch (android) has problem when we pass cosmos chains in optional namespace
|
|
47
|
+
* Also some wallets like keplr mobile doesn't work when we don't pass cosmos chains in required namespace
|
|
48
|
+
* It seems to be a bug in their current implementation.
|
|
49
|
+
*/
|
|
50
|
+
export function generateOptionalNamespace(
|
|
51
|
+
meta: BlockchainMeta[]
|
|
52
|
+
): FinalNamespaces | undefined {
|
|
53
|
+
const evm = evmBlockchains(meta);
|
|
54
|
+
const evmChains = evm.map((chain) => {
|
|
55
|
+
return new ChainId({
|
|
56
|
+
namespace: NAMESPACES.ETHEREUM,
|
|
57
|
+
reference: String(parseInt(chain.chainId)),
|
|
58
|
+
}).toString();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const namespaces: FinalNamespaces = {
|
|
62
|
+
[NAMESPACES.ETHEREUM]: {
|
|
63
|
+
methods: DEFAULT_ETHEREUM_METHODS,
|
|
64
|
+
events: DEFAULT_ETHEREUM_EVENTS,
|
|
65
|
+
chains: evmChains,
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
return namespaces;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function solanaChainIdToNetworkName(chainId: string): string {
|
|
72
|
+
return chainId === DEFAULT_SOLANA_CHAIN_ID ? Networks.SOLANA : chainId;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
*
|
|
77
|
+
* In `rango-preset` we are working with `window.ethereum.request()`,
|
|
78
|
+
* this is an interceptor for some RPC methods (e.g. eth_chainId).
|
|
79
|
+
*
|
|
80
|
+
*/
|
|
81
|
+
export async function simulateRequest(
|
|
82
|
+
params: any,
|
|
83
|
+
provider: any,
|
|
84
|
+
meta: BlockchainMeta[],
|
|
85
|
+
getState: () => WalletState
|
|
86
|
+
) {
|
|
87
|
+
if (params.method === 'eth_chainId') {
|
|
88
|
+
const currentSession = getLastSession(provider);
|
|
89
|
+
const standaloneChains = Object.values(currentSession.namespaces)
|
|
90
|
+
.map((namespace) => namespace.chains)
|
|
91
|
+
.flat() as string[];
|
|
92
|
+
|
|
93
|
+
const network = getState().network;
|
|
94
|
+
|
|
95
|
+
if (standaloneChains.length > 0) {
|
|
96
|
+
const chainId = network
|
|
97
|
+
? getChainIdByNetworkName(network, meta)
|
|
98
|
+
: undefined;
|
|
99
|
+
|
|
100
|
+
if (chainId) {
|
|
101
|
+
return chainId;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const firstIndex = 0;
|
|
105
|
+
const firstChain = standaloneChains[firstIndex];
|
|
106
|
+
const firstChainId = new ChainId(firstChain);
|
|
107
|
+
return firstChainId.reference;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
throw new Error(`Couldn't find any chain on namespace`);
|
|
111
|
+
}
|
|
112
|
+
throw new Error('Dissallowed method:', params);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function getChainIdByNetworkName(
|
|
116
|
+
network: string,
|
|
117
|
+
meta: BlockchainMeta[]
|
|
118
|
+
): string | undefined {
|
|
119
|
+
const targetBlockchain = meta.find(
|
|
120
|
+
(blockchain) => blockchain.name === network
|
|
121
|
+
);
|
|
122
|
+
const chainIdInHex = targetBlockchain?.chainId;
|
|
123
|
+
if (!chainIdInHex) {
|
|
124
|
+
return undefined;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const chainId = String(parseInt(chainIdInHex));
|
|
128
|
+
|
|
129
|
+
return chainId;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export async function switchOrAddEvmChain(
|
|
133
|
+
meta: BlockchainMeta[],
|
|
134
|
+
requestedNetwork: string,
|
|
135
|
+
currentNetwork: string,
|
|
136
|
+
instance: any
|
|
137
|
+
) {
|
|
138
|
+
const evmBlockchains = meta.filter(isEvmBlockchain);
|
|
139
|
+
const evmNetworksChainInfo =
|
|
140
|
+
convertEvmBlockchainMetaToEvmChainInfo(evmBlockchains);
|
|
141
|
+
const targetChain = evmNetworksChainInfo[requestedNetwork];
|
|
142
|
+
const targetBlockchain = meta.find(
|
|
143
|
+
(blockchain: BlockchainMeta) => blockchain.name === requestedNetwork
|
|
144
|
+
);
|
|
145
|
+
const chainIdInHex = targetBlockchain?.chainId;
|
|
146
|
+
|
|
147
|
+
const currentChainId = getChainIdByNetworkName(currentNetwork, meta);
|
|
148
|
+
const currentChainEip = ChainId.format({
|
|
149
|
+
namespace: NAMESPACES.ETHEREUM,
|
|
150
|
+
reference: String(currentChainId),
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
const session = instance.session;
|
|
154
|
+
|
|
155
|
+
try {
|
|
156
|
+
await instance.client.request({
|
|
157
|
+
topic: session.topic,
|
|
158
|
+
request: {
|
|
159
|
+
method: EthereumRPCMethods.SWITCH_CHAIN,
|
|
160
|
+
params: [
|
|
161
|
+
{
|
|
162
|
+
chainId: chainIdInHex,
|
|
163
|
+
},
|
|
164
|
+
],
|
|
165
|
+
},
|
|
166
|
+
// It's required to pass current chain, otherwise it won't work
|
|
167
|
+
chainId: currentChainEip,
|
|
168
|
+
});
|
|
169
|
+
} catch (err: any) {
|
|
170
|
+
const addChainError = 4902;
|
|
171
|
+
if (
|
|
172
|
+
err?.code === addChainError ||
|
|
173
|
+
err?.message?.includes(String(addChainError))
|
|
174
|
+
) {
|
|
175
|
+
await instance.client.request({
|
|
176
|
+
topic: session.topic,
|
|
177
|
+
request: {
|
|
178
|
+
method: EthereumRPCMethods.ADD_CHAIN,
|
|
179
|
+
params: [targetChain],
|
|
180
|
+
},
|
|
181
|
+
// It's required to pass current chain, otherwise it won't work
|
|
182
|
+
chainId: currentChainEip,
|
|
183
|
+
});
|
|
184
|
+
} else {
|
|
185
|
+
throw err;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export function getCurrentEvmAccountAddress(instance: any) {
|
|
191
|
+
return instance.session.namespaces.eip155.accounts
|
|
192
|
+
?.map((account: string) => {
|
|
193
|
+
return new AccountId(account).address;
|
|
194
|
+
})
|
|
195
|
+
?.filter((address: string) => isEvmAddress(address))?.[0];
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export function getEvmAccount(
|
|
199
|
+
network: string,
|
|
200
|
+
address: string,
|
|
201
|
+
meta: BlockchainMeta[]
|
|
202
|
+
) {
|
|
203
|
+
const currentChainId = getChainIdByNetworkName(network, meta);
|
|
204
|
+
return AccountId.format({
|
|
205
|
+
chainId: {
|
|
206
|
+
namespace: NAMESPACES.ETHEREUM,
|
|
207
|
+
reference: String(currentChainId),
|
|
208
|
+
},
|
|
209
|
+
address,
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// It's enough to return only connected network for the EVM networks and ignore others
|
|
214
|
+
export function filterEvmAccounts(
|
|
215
|
+
accounts: {
|
|
216
|
+
address: string;
|
|
217
|
+
chainId: string;
|
|
218
|
+
}[],
|
|
219
|
+
currentChainId?: string
|
|
220
|
+
) {
|
|
221
|
+
let firstEvmAddress = false;
|
|
222
|
+
return accounts
|
|
223
|
+
.filter(({ address, chainId }) => {
|
|
224
|
+
const isEvm = isEvmAddress(address);
|
|
225
|
+
if (isEvm) {
|
|
226
|
+
if (currentChainId && chainId !== currentChainId) {
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
if (!currentChainId) {
|
|
230
|
+
if (firstEvmAddress) {
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
firstEvmAddress = true;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return true;
|
|
237
|
+
})
|
|
238
|
+
.map(({ address, chainId }) => ({
|
|
239
|
+
accounts: [address],
|
|
240
|
+
chainId: chainId,
|
|
241
|
+
}));
|
|
242
|
+
}
|