@rango-dev/provider-ledger 0.2.1-next.1 → 0.2.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/helpers.d.ts +8 -4
- package/dist/helpers.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +4 -4
- package/dist/signer.d.ts.map +1 -1
- package/dist/signers/solana.d.ts +10 -0
- package/dist/signers/solana.d.ts.map +1 -0
- package/package.json +10 -5
- package/src/helpers.ts +64 -12
- package/src/index.ts +26 -11
- package/src/signer.ts +2 -0
- package/src/signers/solana.ts +74 -0
package/dist/helpers.d.ts
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import type Transport from '@ledgerhq/hw-transport';
|
|
2
2
|
export declare const ETH_BIP32_PATH = "44'/60'/0'/0/0";
|
|
3
|
-
export declare
|
|
3
|
+
export declare const SOLANA_BIP32_PATH = "44'/501'/0'";
|
|
4
|
+
export declare const HEXADECIMAL_BASE = 16;
|
|
5
|
+
export declare function getLedgerError(error: any): any;
|
|
6
|
+
export declare function getLedgerInstance(): Map<any, any>;
|
|
7
|
+
export declare function getEthereumAccounts(): Promise<{
|
|
8
|
+
accounts: string[];
|
|
4
9
|
chainId: string;
|
|
5
|
-
}
|
|
6
|
-
export declare function
|
|
10
|
+
}>;
|
|
11
|
+
export declare function getSolanaAccounts(): Promise<{
|
|
7
12
|
accounts: string[];
|
|
8
13
|
chainId: string;
|
|
9
14
|
}>;
|
|
10
|
-
export declare function getLedgerError(error: any): any;
|
|
11
15
|
export declare function transportConnect(): Promise<Transport>;
|
|
12
16
|
export declare function transportDisconnect(): Promise<void>;
|
|
13
17
|
//# sourceMappingURL=helpers.d.ts.map
|
package/dist/helpers.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,wBAAwB,CAAC;AAQpD,eAAO,MAAM,cAAc,mBAAmB,CAAC;AAC/C,eAAO,MAAM,iBAAiB,gBAAgB,CAAC;AAE/C,eAAO,MAAM,gBAAgB,KAAK,CAAC;AAoBnC,wBAAgB,cAAc,CAAC,KAAK,EAAE,GAAG,OASxC;AAED,wBAAgB,iBAAiB,kBAWhC;AAED,wBAAsB,mBAAmB,IAAI,OAAO,CAAC;IACnD,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC,CAoBD;AAED,wBAAsB,iBAAiB,IAAI,OAAO,CAAC;IACjD,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC,CAsBD;AAID,wBAAsB,gBAAgB,uBAMrC;AAED,wBAAsB,mBAAmB,kBAKxC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Connect, Disconnect, WalletInfo } from '@rango-dev/wallets-shared';
|
|
2
|
-
import type { BlockchainMeta, SignerFactory } from 'rango-types';
|
|
3
2
|
import { WalletTypes } from '@rango-dev/wallets-shared';
|
|
3
|
+
import { type BlockchainMeta, type SignerFactory } from 'rango-types';
|
|
4
4
|
import { getLedgerInstance } from './helpers';
|
|
5
5
|
export declare const config: {
|
|
6
6
|
type: WalletTypes;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EACP,UAAU,EACV,UAAU,EACX,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EACP,UAAU,EACV,UAAU,EACX,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAAuB,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAC7E,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAEtE,OAAO,EAEL,iBAAiB,EAGlB,MAAM,WAAW,CAAC;AAGnB,eAAO,MAAM,MAAM;;CAElB,CAAC;AAEF,eAAO,MAAM,WAAW,0BAAoB,CAAC;AAC7C,eAAO,MAAM,OAAO,EAAE,OAKrB,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,UAExB,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,aAAsB,CAAC;AAEnE,eAAO,MAAM,aAAa,EAAE,CAAC,cAAc,EAAE,cAAc,EAAE,KAAK,UA+BjE,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var
|
|
1
|
+
var _=Object.defineProperty;var n=(t,r)=>_(t,"name",{value:r,configurable:!0});import{Namespace as x,Networks as k,WalletTypes as W}from"@rango-dev/wallets-shared";import{getAltStatusMessage as A}from"@ledgerhq/errors";import{Networks as u}from"@rango-dev/wallets-shared";import b from"bs58";var L="0x1",T="44'/60'/0'/0/0",m="44'/501'/0'",B=16,I={21781:"The device is locked",25871:"Related application is not ready on your device",27013:"Action denied by user"};function C(t){return I[t]?I[t]:A(t)?A(t):`Ledger device unknown error 0x${t.toString(B)}`}n(C,"getLedgerErrorMessage");function g(t){return t?.statusCode?new Error(C(t.statusCode)):t?.code==="INSUFFICIENT_FUNDS"?new Error("Insufficient funds for transaction"):t}n(g,"getLedgerError");function P(){let t=new Map;return t.set(u.ETHEREUM,{chainId:L}),t.set(u.SOLANA,{chainId:u.SOLANA}),t}n(P,"getLedgerInstance");async function v(){try{let t=await p(),r=new(await import("@ledgerhq/hw-app-eth")).default(t),a=[],o=await r.getAddress(T,!1,!0);return a.push(o.address),{accounts:a,chainId:L}}catch(t){throw g(t)}finally{await s()}}n(v,"getEthereumAccounts");async function D(){try{let t=await p(),r=new(await import("@ledgerhq/hw-app-solana")).default(t),a=[],o=await r.getAddress(m);return a.push(b.encode(o.address)),{accounts:a,chainId:u.SOLANA}}catch(t){throw g(t)}finally{await s()}}n(D,"getSolanaAccounts");var l=null;async function p(){return l=await(await import("@ledgerhq/hw-transport-webhid")).default.create(),l}n(p,"transportConnect");async function s(){l&&(await l.close(),l=null)}n(s,"transportDisconnect");import{DefaultSignerFactory as K,TransactionType as N}from"rango-types";import{JsonRpcProvider as H,Transaction as M}from"ethers";import{SignerError as G}from"rango-types";var U="https://rpc.ankr.com/eth",d=class{static{n(this,"EthereumSigner")}async signMessage(){throw G.UnimplementedError("signMessage")}async signAndSendTx(r,a,o){try{let e=new H(U),h=await e.getTransactionCount(a),i={to:r.to,gasPrice:r.gasPrice,gasLimit:r.gasLimit,nonce:h,chainId:o,data:r.data,value:r.value,maxPriorityFeePerGas:r.maxPriorityFeePerGas,maxFeePerGas:r.maxFeePerGas},c=M.from(i).unsignedSerialized.substring(2),w=await(await import("@ledgerhq/hw-app-eth")).ledgerService.resolveTransaction(c,{},{}),y=await p(),S=await new(await import("@ledgerhq/hw-app-eth")).default(y).signTransaction(T,c,w),R=M.from({...i,signature:{r:"0x"+S.r,s:"0x"+S.s,v:parseInt(S.v)}}).serialized;return{hash:(await e.broadcastTransaction(R)).hash}}catch(e){throw g(e)}finally{await s()}}};import{generalSolanaTransactionExecutor as O}from"@rango-dev/signer-solana";import{PublicKey as z}from"@solana/web3.js";import{SignerError as V}from"rango-types";function q(t){return"version"in t}n(q,"isVersionedTransaction");var f=class{static{n(this,"SolanaSigner")}async signMessage(){throw V.UnimplementedError("signMessage")}async signAndSendTx(r){try{return{hash:await O(r,n(async e=>{let h=await p(),i=new(await import("@ledgerhq/hw-app-solana")).default(h),c;q(e)?c=await i.signTransaction(m,e.message.serialize()):c=await i.signTransaction(m,e.serialize());let w=await i.getAddress(m),y=new z(w.address);return e.addSignature(y,Buffer.from(c.signature)),e.serialize()},"DefaultSolanaSigner"))}}catch(a){throw g(a)}finally{await s()}}};function E(){let t=new K;return t.registerSigner(N.EVM,new d),t.registerSigner(N.SOLANA,new f),t}n(E,"getSigners");var St={type:W.LEDGER},Tt=P,Et=n(async({namespaces:t})=>t?.includes(x.Solana)?await D():await v(),"connect"),xt=n(async()=>{s()},"disconnect"),At=E,It=n(t=>{let r=[],a=t.find(e=>e.name===k.ETHEREUM);a&&r.push(a);let o=t.find(e=>e.name===k.SOLANA);return o&&r.push(o),{name:"Ledger",img:"https://raw.githubusercontent.com/rango-exchange/assets/main/wallets/ledger/icon.svg",installLink:{DEFAULT:"https://support.ledger.com/hc/en-us/articles/4404389606417-Download-and-install-Ledger-Live?docs=true"},color:"black",supportedChains:r,namespaces:[x.Evm,x.Solana],singleNamespace:!0}},"getWalletInfo");export{St as config,Et as connect,xt as disconnect,Tt as getInstance,At as getSigners,It as getWalletInfo};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/index.ts", "../src/helpers.ts", "../src/signer.ts", "../src/signers/ethereum.ts"],
|
|
4
|
-
"sourcesContent": ["import type {\n Connect,\n Disconnect,\n WalletInfo,\n} from '@rango-dev/wallets-shared';\nimport type { BlockchainMeta, SignerFactory } from 'rango-types';\n\nimport { Networks, WalletTypes } from '@rango-dev/wallets-shared';\n\nimport {\n getLedgerAccounts,\n getLedgerInstance,\n transportDisconnect,\n} from './helpers';\nimport signer from './signer';\n\nconst WALLET = WalletTypes.LEDGER;\n\nexport const config = {\n type: WALLET,\n};\n\nexport const getInstance = getLedgerInstance;\nexport const connect: Connect = async () => {\n const ledgerAccounts = await getLedgerAccounts();\n\n return ledgerAccounts;\n};\n\nexport const disconnect: Disconnect = async () => {\n void transportDisconnect();\n};\n\nexport const getSigners: (provider: any) => SignerFactory = signer;\n\nexport const getWalletInfo: (allBlockChains: BlockchainMeta[]) => WalletInfo = (\n allBlockChains\n) => {\n const ethereumBlockchain = allBlockChains.find(\n (chain) => chain.name === Networks.ETHEREUM\n );\n return {\n name: 'Ledger',\n img: 'https://raw.githubusercontent.com/rango-exchange/assets/main/wallets/ledger/icon.svg',\n installLink: {\n DEFAULT:\n 'https://support.ledger.com/hc/en-us/articles/4404389606417-Download-and-install-Ledger-Live?docs=true',\n },\n color: 'black',\n supportedChains: ethereumBlockchain ? [ethereumBlockchain] : [],\n };\n};\n", "import type Transport from '@ledgerhq/hw-transport';\n\nconst ETHEREUM_CHAIN_ID = '0x1';\n\nexport const ETH_BIP32_PATH = \"44'/60'/0'/0/0\";\n\nconst ledgerErrorMessages: { [statusCode: number | string]: string } = {\n 21781: 'The device is locked',\n 25871: 'Related application is not ready on your device',\n 27013: 'Action denied by user',\n INSUFFICIENT_FUNDS: 'Insufficient funds for transaction',\n};\n\nexport function getLedgerInstance() {\n /*\n * Instances have a required property which is `chainId` and is using in swap execution.\n * Here we are setting it as Ethereum always since we are supporting only eth for now.\n */\n return { chainId: ETHEREUM_CHAIN_ID };\n}\n\nexport async function getLedgerAccounts(): Promise<{\n accounts: string[];\n chainId: string;\n}> {\n try {\n const transport = await transportConnect();\n\n const eth = new (await import('@ledgerhq/hw-app-eth')).default(transport);\n\n const accounts: string[] = [];\n\n const result = await eth.getAddress(ETH_BIP32_PATH, false, true);\n accounts.push(result.address);\n\n return {\n accounts: accounts,\n chainId: ETHEREUM_CHAIN_ID,\n };\n } catch (error: any) {\n throw getLedgerError(error);\n } finally {\n await transportDisconnect();\n }\n}\n\nexport function getLedgerError(error: any) {\n const errorCode = error?.statusCode || error?.code; // ledger error || broadcast error\n\n if (errorCode && !!ledgerErrorMessages[errorCode]) {\n return new Error(ledgerErrorMessages[errorCode]);\n }\n return error;\n}\n\nlet transportConnection: Transport | null = null;\n\nexport async function transportConnect() {\n transportConnection = await (\n await import('@ledgerhq/hw-transport-webhid')\n ).default.create();\n\n return transportConnection;\n}\n\nexport async function transportDisconnect() {\n if (transportConnection) {\n await transportConnection.close();\n transportConnection = null;\n }\n}\n", "import type { SignerFactory } from 'rango-types';\n\nimport { DefaultSignerFactory, TransactionType as TxType } from 'rango-types';\n\nimport { EthereumSigner } from './signers/ethereum';\n\nexport default function getSigners(): SignerFactory {\n const signers = new DefaultSignerFactory();\n signers.registerSigner(TxType.EVM, new EthereumSigner());\n return signers;\n}\n", "import type { TransactionLike } from 'ethers';\nimport type { GenericSigner } from 'rango-types';\nimport type { EvmTransaction } from 'rango-types/lib/api/main';\n\nimport { JsonRpcProvider, Transaction } from 'ethers';\nimport { SignerError } from 'rango-types';\n\nimport {\n ETH_BIP32_PATH,\n getLedgerError,\n transportConnect,\n transportDisconnect,\n} from '../helpers';\n\nexport const RPC_PROVIDER_URL = 'https://rpc.ankr.com/eth';\n\nexport class EthereumSigner implements GenericSigner<EvmTransaction> {\n async signMessage(): Promise<string> {\n // TODO: Should be implemented using eth.signPersonalMessage\n throw SignerError.UnimplementedError('signMessage');\n }\n\n async signAndSendTx(\n tx: EvmTransaction,\n fromAddress: string,\n chainId: string | null\n ): Promise<{ hash: string }> {\n try {\n const provider = new JsonRpcProvider(RPC_PROVIDER_URL); // Provider to broadcast transaction\n\n const transactionCount = await provider.getTransactionCount(fromAddress); // Get nonce\n\n const transaction: TransactionLike<string> = {\n to: tx.to,\n gasPrice: tx.gasPrice,\n gasLimit: tx.gasLimit,\n nonce: transactionCount,\n chainId: chainId,\n data: tx.data,\n value: tx.value,\n maxPriorityFeePerGas: tx.maxPriorityFeePerGas,\n maxFeePerGas: tx.maxFeePerGas,\n };\n\n const unsignedTx =\n Transaction.from(transaction).unsignedSerialized.substring(2); // Create unsigned transaction\n\n const resolution = await (\n await import('@ledgerhq/hw-app-eth')\n ).ledgerService.resolveTransaction(unsignedTx, {}, {}); // metadata necessary to allow the device to clear sign information\n\n const transport = await transportConnect();\n\n const eth = new (await import('@ledgerhq/hw-app-eth')).default(transport);\n\n const signature = await eth.signTransaction(\n ETH_BIP32_PATH,\n unsignedTx,\n resolution\n );\n\n const signedTx = Transaction.from({\n ...transaction,\n signature: {\n r: '0x' + signature.r,\n s: '0x' + signature.s,\n v: parseInt(signature.v),\n },\n }).serialized;\n\n const broadcastResult = await provider.broadcastTransaction(signedTx);\n\n return { hash: broadcastResult.hash };\n } catch (error) {\n throw getLedgerError(error);\n } finally {\n await transportDisconnect();\n }\n }\n}\n"],
|
|
5
|
-
"mappings": "+
|
|
6
|
-
"names": ["Networks", "WalletTypes", "ETHEREUM_CHAIN_ID", "ETH_BIP32_PATH", "
|
|
3
|
+
"sources": ["../src/index.ts", "../src/helpers.ts", "../src/signer.ts", "../src/signers/ethereum.ts", "../src/signers/solana.ts"],
|
|
4
|
+
"sourcesContent": ["import type {\n Connect,\n Disconnect,\n WalletInfo,\n} from '@rango-dev/wallets-shared';\n\nimport { Namespace, Networks, WalletTypes } from '@rango-dev/wallets-shared';\nimport { type BlockchainMeta, type SignerFactory } from 'rango-types';\n\nimport {\n getEthereumAccounts,\n getLedgerInstance,\n getSolanaAccounts,\n transportDisconnect,\n} from './helpers';\nimport signer from './signer';\n\nexport const config = {\n type: WalletTypes.LEDGER,\n};\n\nexport const getInstance = getLedgerInstance;\nexport const connect: Connect = async ({ namespaces }) => {\n if (namespaces?.includes(Namespace.Solana)) {\n return await getSolanaAccounts();\n }\n return await getEthereumAccounts();\n};\n\nexport const disconnect: Disconnect = async () => {\n void transportDisconnect();\n};\n\nexport const getSigners: (provider: any) => SignerFactory = signer;\n\nexport const getWalletInfo: (allBlockChains: BlockchainMeta[]) => WalletInfo = (\n allBlockChains\n) => {\n const supportedChains: BlockchainMeta[] = [];\n\n const ethereumBlockchain = allBlockChains.find(\n (chain) => chain.name === Networks.ETHEREUM\n );\n if (ethereumBlockchain) {\n supportedChains.push(ethereumBlockchain);\n }\n\n const solanaBlockchain = allBlockChains.find(\n (chain) => chain.name === Networks.SOLANA\n );\n if (solanaBlockchain) {\n supportedChains.push(solanaBlockchain);\n }\n\n return {\n name: 'Ledger',\n img: 'https://raw.githubusercontent.com/rango-exchange/assets/main/wallets/ledger/icon.svg',\n installLink: {\n DEFAULT:\n 'https://support.ledger.com/hc/en-us/articles/4404389606417-Download-and-install-Ledger-Live?docs=true',\n },\n color: 'black',\n supportedChains,\n namespaces: [Namespace.Evm, Namespace.Solana],\n singleNamespace: true,\n };\n};\n", "import type Transport from '@ledgerhq/hw-transport';\n\nimport { getAltStatusMessage } from '@ledgerhq/errors';\nimport { Networks } from '@rango-dev/wallets-shared';\nimport bs58 from 'bs58';\n\nconst ETHEREUM_CHAIN_ID = '0x1';\n\nexport const ETH_BIP32_PATH = \"44'/60'/0'/0/0\";\nexport const SOLANA_BIP32_PATH = \"44'/501'/0'\";\n\nexport const HEXADECIMAL_BASE = 16;\n\nconst ledgerFrequentErrorMessages: { [statusCode: number]: string } = {\n 0x5515: 'The device is locked',\n 0x650f: 'Related application is not ready on your device',\n 0x6985: 'Action denied by user',\n};\n\nfunction getLedgerErrorMessage(statusCode: number): string {\n if (ledgerFrequentErrorMessages[statusCode]) {\n return ledgerFrequentErrorMessages[statusCode];\n } else if (getAltStatusMessage(statusCode)) {\n return getAltStatusMessage(statusCode) as string;\n }\n\n return `Ledger device unknown error 0x${statusCode.toString(\n HEXADECIMAL_BASE\n )}`; // Hexadecimal numbers are more commonly recognized and utilized for representing ledger error codes\n}\n\nexport function getLedgerError(error: any) {\n if (error?.statusCode) {\n return new Error(getLedgerErrorMessage(error.statusCode));\n }\n\n if (error?.code === 'INSUFFICIENT_FUNDS') {\n return new Error('Insufficient funds for transaction');\n }\n return error;\n}\n\nexport function getLedgerInstance() {\n /*\n * Instances have a required property which is `chainId` and is using in swap execution.\n * Here we are setting it as Ethereum always since we are supporting only eth for now.\n */\n const instances = new Map();\n\n instances.set(Networks.ETHEREUM, { chainId: ETHEREUM_CHAIN_ID });\n instances.set(Networks.SOLANA, { chainId: Networks.SOLANA });\n\n return instances;\n}\n\nexport async function getEthereumAccounts(): Promise<{\n accounts: string[];\n chainId: string;\n}> {\n try {\n const transport = await transportConnect();\n\n const eth = new (await import('@ledgerhq/hw-app-eth')).default(transport);\n\n const accounts: string[] = [];\n\n const result = await eth.getAddress(ETH_BIP32_PATH, false, true);\n accounts.push(result.address);\n\n return {\n accounts: accounts,\n chainId: ETHEREUM_CHAIN_ID,\n };\n } catch (error: any) {\n throw getLedgerError(error);\n } finally {\n await transportDisconnect();\n }\n}\n\nexport async function getSolanaAccounts(): Promise<{\n accounts: string[];\n chainId: string;\n}> {\n try {\n const transport = await transportConnect();\n\n const solana = new (await import('@ledgerhq/hw-app-solana')).default(\n transport\n );\n\n const accounts: string[] = [];\n\n const result = await solana.getAddress(SOLANA_BIP32_PATH);\n accounts.push(bs58.encode(result.address));\n\n return {\n accounts: accounts,\n chainId: Networks.SOLANA,\n };\n } catch (error: any) {\n throw getLedgerError(error);\n } finally {\n await transportDisconnect();\n }\n}\n\nlet transportConnection: Transport | null = null;\n\nexport async function transportConnect() {\n transportConnection = await (\n await import('@ledgerhq/hw-transport-webhid')\n ).default.create();\n\n return transportConnection;\n}\n\nexport async function transportDisconnect() {\n if (transportConnection) {\n await transportConnection.close();\n transportConnection = null;\n }\n}\n", "import type { SignerFactory } from 'rango-types';\n\nimport { DefaultSignerFactory, TransactionType as TxType } from 'rango-types';\n\nimport { EthereumSigner } from './signers/ethereum';\nimport { SolanaSigner } from './signers/solana';\n\nexport default function getSigners(): SignerFactory {\n const signers = new DefaultSignerFactory();\n signers.registerSigner(TxType.EVM, new EthereumSigner());\n signers.registerSigner(TxType.SOLANA, new SolanaSigner());\n return signers;\n}\n", "import type { TransactionLike } from 'ethers';\nimport type { GenericSigner } from 'rango-types';\nimport type { EvmTransaction } from 'rango-types/lib/api/main';\n\nimport { JsonRpcProvider, Transaction } from 'ethers';\nimport { SignerError } from 'rango-types';\n\nimport {\n ETH_BIP32_PATH,\n getLedgerError,\n transportConnect,\n transportDisconnect,\n} from '../helpers';\n\nexport const RPC_PROVIDER_URL = 'https://rpc.ankr.com/eth';\n\nexport class EthereumSigner implements GenericSigner<EvmTransaction> {\n async signMessage(): Promise<string> {\n // TODO: Should be implemented using eth.signPersonalMessage\n throw SignerError.UnimplementedError('signMessage');\n }\n\n async signAndSendTx(\n tx: EvmTransaction,\n fromAddress: string,\n chainId: string | null\n ): Promise<{ hash: string }> {\n try {\n const provider = new JsonRpcProvider(RPC_PROVIDER_URL); // Provider to broadcast transaction\n\n const transactionCount = await provider.getTransactionCount(fromAddress); // Get nonce\n\n const transaction: TransactionLike<string> = {\n to: tx.to,\n gasPrice: tx.gasPrice,\n gasLimit: tx.gasLimit,\n nonce: transactionCount,\n chainId: chainId,\n data: tx.data,\n value: tx.value,\n maxPriorityFeePerGas: tx.maxPriorityFeePerGas,\n maxFeePerGas: tx.maxFeePerGas,\n };\n\n const unsignedTx =\n Transaction.from(transaction).unsignedSerialized.substring(2); // Create unsigned transaction\n\n const resolution = await (\n await import('@ledgerhq/hw-app-eth')\n ).ledgerService.resolveTransaction(unsignedTx, {}, {}); // metadata necessary to allow the device to clear sign information\n\n const transport = await transportConnect();\n\n const eth = new (await import('@ledgerhq/hw-app-eth')).default(transport);\n\n const signature = await eth.signTransaction(\n ETH_BIP32_PATH,\n unsignedTx,\n resolution\n );\n\n const signedTx = Transaction.from({\n ...transaction,\n signature: {\n r: '0x' + signature.r,\n s: '0x' + signature.s,\n v: parseInt(signature.v),\n },\n }).serialized;\n\n const broadcastResult = await provider.broadcastTransaction(signedTx);\n\n return { hash: broadcastResult.hash };\n } catch (error) {\n throw getLedgerError(error);\n } finally {\n await transportDisconnect();\n }\n }\n}\n", "import type { SolanaWeb3Signer } from '@rango-dev/signer-solana';\nimport type { Transaction, VersionedTransaction } from '@solana/web3.js';\nimport type { GenericSigner, SolanaTransaction } from 'rango-types';\n\nimport { generalSolanaTransactionExecutor } from '@rango-dev/signer-solana';\nimport { PublicKey } from '@solana/web3.js';\nimport { SignerError } from 'rango-types';\n\nimport {\n getLedgerError,\n SOLANA_BIP32_PATH,\n transportConnect,\n transportDisconnect,\n} from '../helpers';\n\nexport function isVersionedTransaction(\n transaction: Transaction | VersionedTransaction\n): transaction is VersionedTransaction {\n return 'version' in transaction;\n}\n\nexport class SolanaSigner implements GenericSigner<SolanaTransaction> {\n async signMessage(): Promise<string> {\n throw SignerError.UnimplementedError('signMessage');\n }\n\n async signAndSendTx(tx: SolanaTransaction): Promise<{ hash: string }> {\n try {\n const DefaultSolanaSigner: SolanaWeb3Signer = async (\n solanaWeb3Transaction: Transaction | VersionedTransaction\n ) => {\n const transport = await transportConnect();\n const solana = new (await import('@ledgerhq/hw-app-solana')).default(\n transport\n );\n\n let signResult;\n if (isVersionedTransaction(solanaWeb3Transaction)) {\n signResult = await solana.signTransaction(\n SOLANA_BIP32_PATH,\n solanaWeb3Transaction.message.serialize() as Buffer\n );\n } else {\n signResult = await solana.signTransaction(\n SOLANA_BIP32_PATH,\n solanaWeb3Transaction.serialize()\n );\n }\n\n const addressResult = await solana.getAddress(SOLANA_BIP32_PATH);\n\n const publicKey = new PublicKey(addressResult.address);\n\n solanaWeb3Transaction.addSignature(\n publicKey,\n Buffer.from(signResult.signature)\n );\n\n const serializedTx = solanaWeb3Transaction.serialize();\n\n return serializedTx;\n };\n const hash = await generalSolanaTransactionExecutor(\n tx,\n DefaultSolanaSigner\n );\n return { hash };\n } catch (error) {\n throw getLedgerError(error);\n } finally {\n await transportDisconnect();\n }\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["Namespace", "Networks", "WalletTypes", "getAltStatusMessage", "Networks", "bs58", "ETHEREUM_CHAIN_ID", "ETH_BIP32_PATH", "SOLANA_BIP32_PATH", "HEXADECIMAL_BASE", "ledgerFrequentErrorMessages", "getLedgerErrorMessage", "statusCode", "getAltStatusMessage", "__name", "getLedgerError", "error", "getLedgerInstance", "instances", "Networks", "getEthereumAccounts", "transport", "transportConnect", "eth", "accounts", "result", "transportDisconnect", "getSolanaAccounts", "solana", "bs58", "transportConnection", "DefaultSignerFactory", "TxType", "JsonRpcProvider", "Transaction", "SignerError", "RPC_PROVIDER_URL", "EthereumSigner", "__name", "SignerError", "tx", "fromAddress", "chainId", "provider", "JsonRpcProvider", "transactionCount", "transaction", "unsignedTx", "Transaction", "resolution", "transport", "transportConnect", "signature", "ETH_BIP32_PATH", "signedTx", "error", "getLedgerError", "transportDisconnect", "generalSolanaTransactionExecutor", "PublicKey", "SignerError", "isVersionedTransaction", "transaction", "__name", "SolanaSigner", "SignerError", "tx", "generalSolanaTransactionExecutor", "solanaWeb3Transaction", "transport", "transportConnect", "solana", "signResult", "SOLANA_BIP32_PATH", "addressResult", "publicKey", "PublicKey", "error", "getLedgerError", "transportDisconnect", "getSigners", "signers", "DefaultSignerFactory", "TxType", "EthereumSigner", "SolanaSigner", "__name", "config", "WalletTypes", "getInstance", "getLedgerInstance", "connect", "__name", "namespaces", "Namespace", "getSolanaAccounts", "getEthereumAccounts", "disconnect", "transportDisconnect", "getSigners", "getWalletInfo", "allBlockChains", "supportedChains", "ethereumBlockchain", "chain", "Networks", "solanaBlockchain"]
|
|
7
7
|
}
|
package/dist/signer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signer.d.ts","sourceRoot":"","sources":["../src/signer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"signer.d.ts","sourceRoot":"","sources":["../src/signer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAOjD,MAAM,CAAC,OAAO,UAAU,UAAU,IAAI,aAAa,CAKlD"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Transaction, VersionedTransaction } from '@solana/web3.js';
|
|
2
|
+
import type { GenericSigner, SolanaTransaction } from 'rango-types';
|
|
3
|
+
export declare function isVersionedTransaction(transaction: Transaction | VersionedTransaction): transaction is VersionedTransaction;
|
|
4
|
+
export declare class SolanaSigner implements GenericSigner<SolanaTransaction> {
|
|
5
|
+
signMessage(): Promise<string>;
|
|
6
|
+
signAndSendTx(tx: SolanaTransaction): Promise<{
|
|
7
|
+
hash: string;
|
|
8
|
+
}>;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=solana.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"solana.d.ts","sourceRoot":"","sources":["../../src/signers/solana.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAapE,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,WAAW,GAAG,oBAAoB,GAC9C,WAAW,IAAI,oBAAoB,CAErC;AAED,qBAAa,YAAa,YAAW,aAAa,CAAC,iBAAiB,CAAC;IAC7D,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC;IAI9B,aAAa,CAAC,EAAE,EAAE,iBAAiB,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CA+CtE"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rango-dev/provider-ledger",
|
|
3
|
-
"version": "0.2.1-next.
|
|
3
|
+
"version": "0.2.1-next.3",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"source": "./src/index.ts",
|
|
@@ -21,13 +21,18 @@
|
|
|
21
21
|
"lint": "eslint \"**/*.{ts,tsx}\" --ignore-path ../../.eslintignore"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@ledgerhq/
|
|
25
|
-
"@ledgerhq/hw-
|
|
26
|
-
"@
|
|
24
|
+
"@ledgerhq/errors": "^6.16.4",
|
|
25
|
+
"@ledgerhq/hw-app-eth": "^6.36.0",
|
|
26
|
+
"@ledgerhq/hw-app-solana": "^7.1.6",
|
|
27
|
+
"@ledgerhq/hw-transport-webhid": "^6.28.6",
|
|
28
|
+
"@rango-dev/signer-solana": "^0.27.1-next.0",
|
|
29
|
+
"@rango-dev/wallets-shared": "^0.32.1-next.2",
|
|
30
|
+
"@solana/web3.js": "^1.91.4",
|
|
31
|
+
"bs58": "^5.0.0",
|
|
27
32
|
"ethers": "^6.11.1",
|
|
28
33
|
"rango-types": "^0.1.59"
|
|
29
34
|
},
|
|
30
35
|
"publishConfig": {
|
|
31
36
|
"access": "public"
|
|
32
37
|
}
|
|
33
|
-
}
|
|
38
|
+
}
|
package/src/helpers.ts
CHANGED
|
@@ -1,25 +1,59 @@
|
|
|
1
1
|
import type Transport from '@ledgerhq/hw-transport';
|
|
2
2
|
|
|
3
|
+
import { getAltStatusMessage } from '@ledgerhq/errors';
|
|
4
|
+
import { Networks } from '@rango-dev/wallets-shared';
|
|
5
|
+
import bs58 from 'bs58';
|
|
6
|
+
|
|
3
7
|
const ETHEREUM_CHAIN_ID = '0x1';
|
|
4
8
|
|
|
5
9
|
export const ETH_BIP32_PATH = "44'/60'/0'/0/0";
|
|
10
|
+
export const SOLANA_BIP32_PATH = "44'/501'/0'";
|
|
11
|
+
|
|
12
|
+
export const HEXADECIMAL_BASE = 16;
|
|
6
13
|
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
INSUFFICIENT_FUNDS: 'Insufficient funds for transaction',
|
|
14
|
+
const ledgerFrequentErrorMessages: { [statusCode: number]: string } = {
|
|
15
|
+
0x5515: 'The device is locked',
|
|
16
|
+
0x650f: 'Related application is not ready on your device',
|
|
17
|
+
0x6985: 'Action denied by user',
|
|
12
18
|
};
|
|
13
19
|
|
|
20
|
+
function getLedgerErrorMessage(statusCode: number): string {
|
|
21
|
+
if (ledgerFrequentErrorMessages[statusCode]) {
|
|
22
|
+
return ledgerFrequentErrorMessages[statusCode];
|
|
23
|
+
} else if (getAltStatusMessage(statusCode)) {
|
|
24
|
+
return getAltStatusMessage(statusCode) as string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return `Ledger device unknown error 0x${statusCode.toString(
|
|
28
|
+
HEXADECIMAL_BASE
|
|
29
|
+
)}`; // Hexadecimal numbers are more commonly recognized and utilized for representing ledger error codes
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function getLedgerError(error: any) {
|
|
33
|
+
if (error?.statusCode) {
|
|
34
|
+
return new Error(getLedgerErrorMessage(error.statusCode));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (error?.code === 'INSUFFICIENT_FUNDS') {
|
|
38
|
+
return new Error('Insufficient funds for transaction');
|
|
39
|
+
}
|
|
40
|
+
return error;
|
|
41
|
+
}
|
|
42
|
+
|
|
14
43
|
export function getLedgerInstance() {
|
|
15
44
|
/*
|
|
16
45
|
* Instances have a required property which is `chainId` and is using in swap execution.
|
|
17
46
|
* Here we are setting it as Ethereum always since we are supporting only eth for now.
|
|
18
47
|
*/
|
|
19
|
-
|
|
48
|
+
const instances = new Map();
|
|
49
|
+
|
|
50
|
+
instances.set(Networks.ETHEREUM, { chainId: ETHEREUM_CHAIN_ID });
|
|
51
|
+
instances.set(Networks.SOLANA, { chainId: Networks.SOLANA });
|
|
52
|
+
|
|
53
|
+
return instances;
|
|
20
54
|
}
|
|
21
55
|
|
|
22
|
-
export async function
|
|
56
|
+
export async function getEthereumAccounts(): Promise<{
|
|
23
57
|
accounts: string[];
|
|
24
58
|
chainId: string;
|
|
25
59
|
}> {
|
|
@@ -44,13 +78,31 @@ export async function getLedgerAccounts(): Promise<{
|
|
|
44
78
|
}
|
|
45
79
|
}
|
|
46
80
|
|
|
47
|
-
export function
|
|
48
|
-
|
|
81
|
+
export async function getSolanaAccounts(): Promise<{
|
|
82
|
+
accounts: string[];
|
|
83
|
+
chainId: string;
|
|
84
|
+
}> {
|
|
85
|
+
try {
|
|
86
|
+
const transport = await transportConnect();
|
|
87
|
+
|
|
88
|
+
const solana = new (await import('@ledgerhq/hw-app-solana')).default(
|
|
89
|
+
transport
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
const accounts: string[] = [];
|
|
93
|
+
|
|
94
|
+
const result = await solana.getAddress(SOLANA_BIP32_PATH);
|
|
95
|
+
accounts.push(bs58.encode(result.address));
|
|
49
96
|
|
|
50
|
-
|
|
51
|
-
|
|
97
|
+
return {
|
|
98
|
+
accounts: accounts,
|
|
99
|
+
chainId: Networks.SOLANA,
|
|
100
|
+
};
|
|
101
|
+
} catch (error: any) {
|
|
102
|
+
throw getLedgerError(error);
|
|
103
|
+
} finally {
|
|
104
|
+
await transportDisconnect();
|
|
52
105
|
}
|
|
53
|
-
return error;
|
|
54
106
|
}
|
|
55
107
|
|
|
56
108
|
let transportConnection: Transport | null = null;
|
package/src/index.ts
CHANGED
|
@@ -3,28 +3,28 @@ import type {
|
|
|
3
3
|
Disconnect,
|
|
4
4
|
WalletInfo,
|
|
5
5
|
} from '@rango-dev/wallets-shared';
|
|
6
|
-
import type { BlockchainMeta, SignerFactory } from 'rango-types';
|
|
7
6
|
|
|
8
|
-
import { Networks, WalletTypes } from '@rango-dev/wallets-shared';
|
|
7
|
+
import { Namespace, Networks, WalletTypes } from '@rango-dev/wallets-shared';
|
|
8
|
+
import { type BlockchainMeta, type SignerFactory } from 'rango-types';
|
|
9
9
|
|
|
10
10
|
import {
|
|
11
|
-
|
|
11
|
+
getEthereumAccounts,
|
|
12
12
|
getLedgerInstance,
|
|
13
|
+
getSolanaAccounts,
|
|
13
14
|
transportDisconnect,
|
|
14
15
|
} from './helpers';
|
|
15
16
|
import signer from './signer';
|
|
16
17
|
|
|
17
|
-
const WALLET = WalletTypes.LEDGER;
|
|
18
|
-
|
|
19
18
|
export const config = {
|
|
20
|
-
type:
|
|
19
|
+
type: WalletTypes.LEDGER,
|
|
21
20
|
};
|
|
22
21
|
|
|
23
22
|
export const getInstance = getLedgerInstance;
|
|
24
|
-
export const connect: Connect = async () => {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
export const connect: Connect = async ({ namespaces }) => {
|
|
24
|
+
if (namespaces?.includes(Namespace.Solana)) {
|
|
25
|
+
return await getSolanaAccounts();
|
|
26
|
+
}
|
|
27
|
+
return await getEthereumAccounts();
|
|
28
28
|
};
|
|
29
29
|
|
|
30
30
|
export const disconnect: Disconnect = async () => {
|
|
@@ -36,9 +36,22 @@ export const getSigners: (provider: any) => SignerFactory = signer;
|
|
|
36
36
|
export const getWalletInfo: (allBlockChains: BlockchainMeta[]) => WalletInfo = (
|
|
37
37
|
allBlockChains
|
|
38
38
|
) => {
|
|
39
|
+
const supportedChains: BlockchainMeta[] = [];
|
|
40
|
+
|
|
39
41
|
const ethereumBlockchain = allBlockChains.find(
|
|
40
42
|
(chain) => chain.name === Networks.ETHEREUM
|
|
41
43
|
);
|
|
44
|
+
if (ethereumBlockchain) {
|
|
45
|
+
supportedChains.push(ethereumBlockchain);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const solanaBlockchain = allBlockChains.find(
|
|
49
|
+
(chain) => chain.name === Networks.SOLANA
|
|
50
|
+
);
|
|
51
|
+
if (solanaBlockchain) {
|
|
52
|
+
supportedChains.push(solanaBlockchain);
|
|
53
|
+
}
|
|
54
|
+
|
|
42
55
|
return {
|
|
43
56
|
name: 'Ledger',
|
|
44
57
|
img: 'https://raw.githubusercontent.com/rango-exchange/assets/main/wallets/ledger/icon.svg',
|
|
@@ -47,6 +60,8 @@ export const getWalletInfo: (allBlockChains: BlockchainMeta[]) => WalletInfo = (
|
|
|
47
60
|
'https://support.ledger.com/hc/en-us/articles/4404389606417-Download-and-install-Ledger-Live?docs=true',
|
|
48
61
|
},
|
|
49
62
|
color: 'black',
|
|
50
|
-
supportedChains
|
|
63
|
+
supportedChains,
|
|
64
|
+
namespaces: [Namespace.Evm, Namespace.Solana],
|
|
65
|
+
singleNamespace: true,
|
|
51
66
|
};
|
|
52
67
|
};
|
package/src/signer.ts
CHANGED
|
@@ -3,9 +3,11 @@ import type { SignerFactory } from 'rango-types';
|
|
|
3
3
|
import { DefaultSignerFactory, TransactionType as TxType } from 'rango-types';
|
|
4
4
|
|
|
5
5
|
import { EthereumSigner } from './signers/ethereum';
|
|
6
|
+
import { SolanaSigner } from './signers/solana';
|
|
6
7
|
|
|
7
8
|
export default function getSigners(): SignerFactory {
|
|
8
9
|
const signers = new DefaultSignerFactory();
|
|
9
10
|
signers.registerSigner(TxType.EVM, new EthereumSigner());
|
|
11
|
+
signers.registerSigner(TxType.SOLANA, new SolanaSigner());
|
|
10
12
|
return signers;
|
|
11
13
|
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { SolanaWeb3Signer } from '@rango-dev/signer-solana';
|
|
2
|
+
import type { Transaction, VersionedTransaction } from '@solana/web3.js';
|
|
3
|
+
import type { GenericSigner, SolanaTransaction } from 'rango-types';
|
|
4
|
+
|
|
5
|
+
import { generalSolanaTransactionExecutor } from '@rango-dev/signer-solana';
|
|
6
|
+
import { PublicKey } from '@solana/web3.js';
|
|
7
|
+
import { SignerError } from 'rango-types';
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
getLedgerError,
|
|
11
|
+
SOLANA_BIP32_PATH,
|
|
12
|
+
transportConnect,
|
|
13
|
+
transportDisconnect,
|
|
14
|
+
} from '../helpers';
|
|
15
|
+
|
|
16
|
+
export function isVersionedTransaction(
|
|
17
|
+
transaction: Transaction | VersionedTransaction
|
|
18
|
+
): transaction is VersionedTransaction {
|
|
19
|
+
return 'version' in transaction;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class SolanaSigner implements GenericSigner<SolanaTransaction> {
|
|
23
|
+
async signMessage(): Promise<string> {
|
|
24
|
+
throw SignerError.UnimplementedError('signMessage');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async signAndSendTx(tx: SolanaTransaction): Promise<{ hash: string }> {
|
|
28
|
+
try {
|
|
29
|
+
const DefaultSolanaSigner: SolanaWeb3Signer = async (
|
|
30
|
+
solanaWeb3Transaction: Transaction | VersionedTransaction
|
|
31
|
+
) => {
|
|
32
|
+
const transport = await transportConnect();
|
|
33
|
+
const solana = new (await import('@ledgerhq/hw-app-solana')).default(
|
|
34
|
+
transport
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
let signResult;
|
|
38
|
+
if (isVersionedTransaction(solanaWeb3Transaction)) {
|
|
39
|
+
signResult = await solana.signTransaction(
|
|
40
|
+
SOLANA_BIP32_PATH,
|
|
41
|
+
solanaWeb3Transaction.message.serialize() as Buffer
|
|
42
|
+
);
|
|
43
|
+
} else {
|
|
44
|
+
signResult = await solana.signTransaction(
|
|
45
|
+
SOLANA_BIP32_PATH,
|
|
46
|
+
solanaWeb3Transaction.serialize()
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const addressResult = await solana.getAddress(SOLANA_BIP32_PATH);
|
|
51
|
+
|
|
52
|
+
const publicKey = new PublicKey(addressResult.address);
|
|
53
|
+
|
|
54
|
+
solanaWeb3Transaction.addSignature(
|
|
55
|
+
publicKey,
|
|
56
|
+
Buffer.from(signResult.signature)
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
const serializedTx = solanaWeb3Transaction.serialize();
|
|
60
|
+
|
|
61
|
+
return serializedTx;
|
|
62
|
+
};
|
|
63
|
+
const hash = await generalSolanaTransactionExecutor(
|
|
64
|
+
tx,
|
|
65
|
+
DefaultSolanaSigner
|
|
66
|
+
);
|
|
67
|
+
return { hash };
|
|
68
|
+
} catch (error) {
|
|
69
|
+
throw getLedgerError(error);
|
|
70
|
+
} finally {
|
|
71
|
+
await transportDisconnect();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|