@rango-dev/signer-evm 0.0.0-experimental-d44b759f-20260701

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 ADDED
@@ -0,0 +1,169 @@
1
+ # [0.42.0](https://github.com/rango-exchange/rango-client/compare/signer-evm@0.41.1...signer-evm@0.42.0) (2026-05-31)
2
+
3
+
4
+
5
+ ## [0.41.1](https://github.com/rango-exchange/rango-client/compare/signer-evm@0.41.0...signer-evm@0.41.1) (2026-05-02)
6
+
7
+
8
+
9
+ # [0.41.0](https://github.com/rango-exchange/rango-client/compare/signer-evm@0.40.0...signer-evm@0.41.0) (2026-04-29)
10
+
11
+
12
+
13
+ # [0.40.0](https://github.com/rango-exchange/rango-client/compare/signer-evm@0.39.0...signer-evm@0.40.0) (2025-08-19)
14
+
15
+
16
+
17
+ # [0.39.0](https://github.com/rango-exchange/rango-client/compare/signer-evm@0.38.0...signer-evm@0.39.0) (2025-08-05)
18
+
19
+
20
+
21
+ # [0.38.0](https://github.com/rango-exchange/rango-client/compare/signer-evm@0.37.0...signer-evm@0.38.0) (2025-07-22)
22
+
23
+
24
+ ### Reverts
25
+
26
+ * Revert "chore(release): publish" ([064ce15](https://github.com/rango-exchange/rango-client/commit/064ce157a2f819856f647f83aeb1c0410542e8d7))
27
+
28
+
29
+
30
+ # [0.36.0](https://github.com/rango-exchange/rango-client/compare/signer-evm@0.35.0...signer-evm@0.36.0) (2025-06-09)
31
+
32
+
33
+
34
+ # [0.35.0](https://github.com/rango-exchange/rango-client/compare/signer-evm@0.34.0...signer-evm@0.35.0) (2025-04-30)
35
+
36
+
37
+ ### Bug Fixes
38
+
39
+ * rename pbt to ptb for sui ([3d6d89f](https://github.com/rango-exchange/rango-client/commit/3d6d89f2265766607a15d61e0df92643fb33072b))
40
+
41
+
42
+ ### Features
43
+
44
+ * update sui to consider recent api changes ([d764b25](https://github.com/rango-exchange/rango-client/commit/d764b2501df9bb295f63cdbc0b05acd4a3abb4b9))
45
+
46
+
47
+
48
+ # [0.34.0](https://github.com/rango-exchange/rango-client/compare/signer-evm@0.33.0...signer-evm@0.34.0) (2025-03-11)
49
+
50
+
51
+
52
+ # [0.33.0](https://github.com/rango-exchange/rango-client/compare/signer-evm@0.32.0...signer-evm@0.33.0) (2025-02-23)
53
+
54
+
55
+
56
+ # [0.32.0](https://github.com/rango-exchange/rango-client/compare/signer-evm@0.31.0...signer-evm@0.32.0) (2024-11-12)
57
+
58
+
59
+
60
+ # [0.31.0](https://github.com/rango-exchange/rango-client/compare/signer-evm@0.30.0...signer-evm@0.31.0) (2024-10-12)
61
+
62
+
63
+ ### Bug Fixes
64
+
65
+ * bump sdk and fix type issues ([d442208](https://github.com/rango-exchange/rango-client/commit/d4422083bf5dd27d5f509ce1db7f9560d05428c8))
66
+
67
+
68
+
69
+ # [0.30.0](https://github.com/rango-exchange/rango-client/compare/signer-evm@0.29.0...signer-evm@0.30.0) (2024-09-10)
70
+
71
+
72
+
73
+ # [0.29.0](https://github.com/rango-exchange/rango-client/compare/signer-evm@0.28.0...signer-evm@0.29.0) (2024-08-11)
74
+
75
+
76
+
77
+ # [0.28.0](https://github.com/rango-exchange/rango-client/compare/signer-evm@0.27.1...signer-evm@0.28.0) (2024-07-09)
78
+
79
+
80
+ ### Bug Fixes
81
+
82
+ * fix tx data for evm signers when transfering native tokens ([a5d9f6e](https://github.com/rango-exchange/rango-client/commit/a5d9f6e3f5bada210a05c0d1f5c57d7917bf869c))
83
+
84
+
85
+
86
+ ## [0.27.1](https://github.com/rango-exchange/rango-client/compare/signer-evm@0.27.0...signer-evm@0.27.1) (2024-05-26)
87
+
88
+
89
+
90
+ # [0.27.0](https://github.com/rango-exchange/rango-client/compare/signer-evm@0.26.0...signer-evm@0.27.0) (2024-05-25)
91
+
92
+
93
+ ### Bug Fixes
94
+
95
+ * exclude the gas price from evm transaction specifications in version 2 ([49c5005](https://github.com/rango-exchange/rango-client/commit/49c50058f717f439833fe4cff216e5a45fbe252d))
96
+
97
+
98
+
99
+ # [0.26.0](https://github.com/rango-exchange/rango-client/compare/signer-evm@0.25.0...signer-evm@0.26.0) (2024-02-20)
100
+
101
+
102
+
103
+ # [0.25.0](https://github.com/rango-exchange/rango-client/compare/signer-evm@0.23.0...signer-evm@0.25.0) (2023-12-24)
104
+
105
+
106
+ ### Bug Fixes
107
+
108
+ * fix HMR for widget and playground ([8524820](https://github.com/rango-exchange/rango-client/commit/8524820f10cf0b8921f3db0c4f620ff98daa4103))
109
+
110
+
111
+
112
+ # [0.14.0](https://github.com/rango-exchange/rango-client/compare/signer-evm@0.13.0...signer-evm@0.14.0) (2023-08-03)
113
+
114
+
115
+
116
+ # [0.13.0](https://github.com/rango-exchange/rango-client/compare/signer-evm@0.12.0...signer-evm@0.13.0) (2023-08-01)
117
+
118
+
119
+
120
+ # [0.9.0](https://github.com/rango-exchange/rango-client/compare/signer-evm@0.8.0...signer-evm@0.9.0) (2023-07-31)
121
+
122
+
123
+ ### Features
124
+
125
+ * Support for WalletConnect 2 ([faedef0](https://github.com/rango-exchange/rango-client/commit/faedef0b5e6fc3c5ef881cbbe4ec05334cc1c910))
126
+ * support safe wallet ([d04cbcd](https://github.com/rango-exchange/rango-client/commit/d04cbcd2a612755563512d9dff6f2312088d8b4d))
127
+
128
+
129
+
130
+ # [0.7.0](https://github.com/rango-exchange/rango-client/compare/signer-evm@0.6.0...signer-evm@0.7.0) (2023-07-11)
131
+
132
+
133
+
134
+ # [0.6.0](https://github.com/rango-exchange/rango-client/compare/signer-evm@0.5.0...signer-evm@0.6.0) (2023-07-11)
135
+
136
+
137
+ ### Bug Fixes
138
+
139
+ * better parsing of evm rpc errors ([f23031a](https://github.com/rango-exchange/rango-client/commit/f23031ae14e6e841ee488591bd1bf58cfa7ca15b))
140
+ * fix signer wait change network issues ([e453db6](https://github.com/rango-exchange/rango-client/commit/e453db6ccf7736e36e5ada0c29502be32254fe9c))
141
+ * show tenderly error on call exception ([c218f49](https://github.com/rango-exchange/rango-client/commit/c218f49f3330706d9262b0cf3ec8e293e91e3729))
142
+
143
+
144
+
145
+ # [0.5.0](https://github.com/rango-exchange/rango-client/compare/signer-evm@0.4.0...signer-evm@0.5.0) (2023-05-31)
146
+
147
+
148
+
149
+ # [0.4.0](https://github.com/rango-exchange/rango-client/compare/signer-evm@0.3.0...signer-evm@0.4.0) (2023-05-31)
150
+
151
+
152
+
153
+ # [0.3.0](https://github.com/rango-exchange/rango-client/compare/signer-evm@0.2.0...signer-evm@0.3.0) (2023-05-30)
154
+
155
+
156
+
157
+ # [0.2.0](https://github.com/rango-exchange/rango-client/compare/signer-evm@0.1.14...signer-evm@0.2.0) (2023-05-30)
158
+
159
+
160
+
161
+ ## [0.1.13](https://github.com/rango-exchange/rango-client/compare/signer-evm@0.1.12...signer-evm@0.1.13) (2023-05-15)
162
+
163
+
164
+ ### Bug Fixes
165
+
166
+ * update rango-types and fix notification bugs ([993f185](https://github.com/rango-exchange/rango-client/commit/993f185e0b8c5e5e15a2c65ba2d85d1f9c8daa90))
167
+
168
+
169
+
@@ -0,0 +1,5 @@
1
+ import type { SignerError as SignerErrorType } from 'rango-types';
2
+ export declare const cleanEvmError: (error: any) => SignerErrorType;
3
+ export declare function getTenderlyError(chainId: string | undefined, txHash: string): Promise<string | undefined>;
4
+ export declare const waitMs: (ms: number) => Promise<unknown>;
5
+ //# sourceMappingURL=helper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helper.d.ts","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,IAAI,eAAe,EAAE,MAAM,aAAa,CAAC;AASlE,eAAO,MAAM,aAAa,UAAW,GAAG,KAAG,eAgD1C,CAAC;AAMF,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAkB7B;AAED,eAAO,MAAM,MAAM,OAAc,MAAM,qBACY,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { DefaultEvmSigner } from './signer.js';
2
+ export { waitMs, cleanEvmError } from './helper.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ var P=Object.defineProperty;var c=(e,r)=>P(e,"name",{value:r,configurable:!0});import{BrowserProvider as S,isError as y}from"ethers";import{RPCErrorCode as _,SignerError as d,SignerErrorCode as u}from"rango-types";import{isError as l}from"ethers";import{RPCErrorCode as p,SignerError as g,SignerErrorCode as E}from"rango-types";var h=c(e=>{if(!e)return new g(E.SEND_TX_ERROR);if(g.isSignerError(e))return e;if(e.code){if(l(e,"UNKNOWN_ERROR")){let t=e.error?.message||e.message;return new g(E.SEND_TX_ERROR,void 0,t,p.UNKNOWN_ERROR,e)}if(l(e,"ACTION_REJECTED")){let t=e.shortMessage.replace("action",`'${e.action}'`);return new g(E.SEND_TX_ERROR,void 0,t,p.REJECTION,e)}let r=e.shortMessage||e.message;return new g(E.SEND_TX_ERROR,void 0,r,p.UNKNOWN_ERROR,e)}return new g(E.SEND_TX_ERROR,void 0,e,p.UNKNOWN_ERROR,e)},"cleanEvmError");async function T(e,r){if(!e||!r)return;let t=parseInt(e);try{let s=`https://api.tenderly.co/api/v1/public-contract/${t}/tx/${r}`,n=await fetch(s,{method:"GET"});return n.ok?(await n.json())?.error_message:void 0}catch{return}}c(T,"getTenderlyError");var m=c(async e=>new Promise(r=>setTimeout(r,e)),"waitMs");var C=c(async(e,r,t,s)=>{let i=!1;return await Promise.race([(async()=>{await r.wait(s),i=!0})(),(async()=>{for(;!i;){if(await m(3e3),i)return null;try{if(!await e.getTransaction(t))return null}catch(o){return console.log({error:o}),null}}return null})()])},"waitWithMempoolCheck"),w=class e{static{c(this,"DefaultEvmSigner")}provider;constructor(r){this.provider=new S(r)}static buildTx(r,t=!1){let n={};return n={data:r.data||"0x"},r.from&&(n={...n,from:r.from}),r.to&&(n={...n,to:r.to}),r.value&&(n={...n,value:r.value}),r.nonce&&(n={...n,nonce:parseInt(r.nonce)}),r.gasLimit&&(n={...n,gasLimit:r.gasLimit}),!t&&r.maxFeePerGas&&r.maxPriorityFeePerGas?n={...n,maxFeePerGas:r.maxFeePerGas,maxPriorityFeePerGas:r.maxPriorityFeePerGas}:r.gasPrice&&(n={...n,gasPrice:"0x"+parseInt(r.gasPrice).toString(16)}),n}async signTypedData(r){try{return await(await this.provider.getSigner()).signTypedData(r.domain,r.types,r.value)}catch(t){throw new d(u.SIGN_TX_ERROR,void 0,t)}}async signMessage(r){try{return await(await this.provider.getSigner()).signMessage(r)}catch(t){throw new d(u.SIGN_TX_ERROR,void 0,t)}}async signAndSendTx(r,t,s){try{let n=await this.provider.getSigner(r.from??void 0),i=e.buildTx(r),o=(await this.provider.getNetwork()).chainId,f=await n.getAddress();if(s&&o&&o.toString()!==Number(s).toString())throw new d(u.UNEXPECTED_BEHAVIOUR,void 0,`Signer chainId: '${o}' doesn't match with required chainId: '${s}' for tx.`);if(f&&t&&f.toLowerCase()!==t.toLowerCase())throw new d(u.UNEXPECTED_BEHAVIOUR,void 0,`Signer address: '${f.toLowerCase()}' doesn't match with required address: '${t.toLowerCase()}' for tx.`);try{let a=await n.sendTransaction(i);return{hash:a.hash,response:a}}catch(a){if(a?.message&&typeof a.message=="string"&&a.message.indexOf("EIP-1559")!==-1){console.log("retrying EIP-1559 error without v2 fields ...");let N=e.buildTx(r,!0),R=await n.sendTransaction(N);return{hash:R.hash,response:R}}throw a}}catch(n){throw h(n)}}async wait(r,t,s,n){try{if(s)return await s?.wait(n),{hash:r};if(!this.provider)return{hash:r};if(!t)return{hash:r};let i=(await this.provider.getNetwork()).chainId;if(!i||Number(t).toString()!==i.toString())return{hash:r};let o=await this.provider.getTransaction(r);if(!o)throw Error(`Transaction hash '${r}' not found in blockchain.`);return await C(this.provider,o,r,n),{hash:r}}catch(i){if(y(i,"TRANSACTION_REPLACED")){if(i.reason==="cancelled")throw new d(u.SEND_TX_ERROR,void 0,"Transaction replaced and canceled by user",void 0,i);return{hash:i.replacement.hash,response:i.replacement}}else if(y(i,"CALL_EXCEPTION")){let o=await T(t,r);if(o)throw new d(u.TX_FAILED_IN_BLOCKCHAIN,"Trannsaction failed in blockchain",o,_.CALL_EXCEPTION,i);return{hash:r}}return{hash:r}}}};export{w as DefaultEvmSigner,h as cleanEvmError,m as waitMs};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/signer.ts", "../src/helper.ts"],
4
+ "sourcesContent": ["import type { TypedData } from './types.js';\nimport type {\n AbstractProvider,\n Eip1193Provider,\n TransactionRequest,\n TransactionResponse,\n} from 'ethers';\nimport type { GenericSigner } from 'rango-types';\nimport type { EvmTransaction } from 'rango-types/mainApi';\n\nimport { BrowserProvider, isError } from 'ethers';\nimport {\n RPCErrorCode as RangoRPCErrorCode,\n SignerError,\n SignerErrorCode,\n} from 'rango-types';\n\nimport { cleanEvmError, getTenderlyError, waitMs } from './helper.js';\n\nconst waitWithMempoolCheck = async (\n provider: AbstractProvider,\n tx: TransactionResponse,\n txHash: string,\n confirmations?: number\n) => {\n const TIMEOUT = 3_000;\n let finished = false;\n return await Promise.race([\n (async () => {\n await tx.wait(confirmations);\n finished = true;\n })(),\n (async () => {\n while (!finished) {\n await waitMs(TIMEOUT);\n if (finished) {\n return null;\n }\n try {\n const mempoolTx = await provider.getTransaction(txHash);\n if (!mempoolTx) {\n return null;\n }\n } catch (error) {\n console.log({ error });\n return null;\n }\n }\n return null;\n })(),\n ]);\n};\n\nexport class DefaultEvmSigner implements GenericSigner<EvmTransaction> {\n private provider: BrowserProvider;\n\n constructor(provider: Eip1193Provider) {\n this.provider = new BrowserProvider(provider); // provides read-only access to the provider\n }\n\n static buildTx(evmTx: EvmTransaction, disableV2 = false): TransactionRequest {\n const TO_STRING_BASE = 16;\n let tx: TransactionRequest = {};\n /*\n * it's better to pass 0x instead of undefined, otherwise some wallets could face issue\n * https://github.com/WalletConnect/web3modal/issues/1082#issuecomment-1637793242\n */\n tx = {\n data: evmTx.data || '0x',\n };\n if (evmTx.from) {\n tx = { ...tx, from: evmTx.from };\n }\n if (evmTx.to) {\n tx = { ...tx, to: evmTx.to };\n }\n if (evmTx.value) {\n tx = { ...tx, value: evmTx.value };\n }\n if (evmTx.nonce) {\n tx = { ...tx, nonce: parseInt(evmTx.nonce) };\n }\n if (evmTx.gasLimit) {\n tx = { ...tx, gasLimit: evmTx.gasLimit };\n }\n if (!disableV2 && evmTx.maxFeePerGas && evmTx.maxPriorityFeePerGas) {\n tx = {\n ...tx,\n maxFeePerGas: evmTx.maxFeePerGas,\n maxPriorityFeePerGas: evmTx.maxPriorityFeePerGas,\n };\n } else if (evmTx.gasPrice) {\n tx = {\n ...tx,\n gasPrice: '0x' + parseInt(evmTx.gasPrice).toString(TO_STRING_BASE),\n };\n }\n return tx;\n }\n\n async signTypedData(typedData: TypedData): Promise<string> {\n try {\n const signer = await this.provider.getSigner();\n const signature = await signer.signTypedData(\n typedData.domain,\n typedData.types,\n typedData.value\n );\n\n return signature;\n } catch (error) {\n throw new SignerError(SignerErrorCode.SIGN_TX_ERROR, undefined, error);\n }\n }\n\n async signMessage(msg: string): Promise<string> {\n try {\n const signer = await this.provider.getSigner(); // provides access to write operations\n return await signer.signMessage(msg);\n } catch (error) {\n throw new SignerError(SignerErrorCode.SIGN_TX_ERROR, undefined, error);\n }\n }\n\n async signAndSendTx(\n tx: EvmTransaction,\n address: string,\n chainId: string | null\n ): Promise<{ hash: string; response: TransactionResponse }> {\n try {\n const signer = await this.provider.getSigner(tx.from ?? undefined);\n\n const transaction = DefaultEvmSigner.buildTx(tx);\n\n const signerChainId = (await this.provider.getNetwork()).chainId;\n const signerAddress = await signer.getAddress();\n\n if (\n !!chainId &&\n !!signerChainId &&\n signerChainId.toString() !== Number(chainId).toString()\n ) {\n throw new SignerError(\n SignerErrorCode.UNEXPECTED_BEHAVIOUR,\n undefined,\n `Signer chainId: '${signerChainId}' doesn't match with required chainId: '${chainId}' for tx.`\n );\n }\n if (\n !!signerAddress &&\n !!address &&\n signerAddress.toLowerCase() !== address.toLowerCase()\n ) {\n throw new SignerError(\n SignerErrorCode.UNEXPECTED_BEHAVIOUR,\n undefined,\n `Signer address: '${signerAddress.toLowerCase()}' doesn't match with required address: '${address.toLowerCase()}' for tx.`\n );\n }\n try {\n const response = await signer.sendTransaction(transaction);\n return { hash: response.hash, response };\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (error: any) {\n // retrying EIP-1559 without v2 related fields\n if (\n !!error?.message &&\n typeof error.message === 'string' &&\n error.message.indexOf('EIP-1559') !== -1\n ) {\n console.log('retrying EIP-1559 error without v2 fields ...');\n const transaction = DefaultEvmSigner.buildTx(tx, true);\n const response = await signer.sendTransaction(transaction);\n return { hash: response.hash, response };\n }\n throw error;\n }\n } catch (error) {\n throw cleanEvmError(error);\n }\n }\n\n async wait(\n txHash: string,\n chainId?: string,\n txResponse?: TransactionResponse,\n confirmations?: number\n ): Promise<{ hash: string; response?: TransactionResponse }> {\n try {\n /*\n * if we have transaction response, use that to wait\n * otherwise, try to get tx response from the wallet provider\n */\n if (txResponse) {\n // if we use waitWithMempoolCheck here, we can't detect replaced tx anymore\n await txResponse?.wait(confirmations);\n return { hash: txHash };\n }\n\n // ignore wait if wallet not connected yet\n if (!this.provider) {\n return { hash: txHash };\n }\n\n /*\n * don't proceed if signer chain changed or chain id is not specified\n * because if user change the wallet network, we receive null on getTransaction\n */\n if (!chainId) {\n return { hash: txHash };\n }\n const signerChainId = (await this.provider.getNetwork()).chainId;\n if (\n !signerChainId ||\n Number(chainId).toString() !== signerChainId.toString()\n ) {\n return { hash: txHash };\n }\n\n const tx = await this.provider.getTransaction(txHash);\n if (!tx) {\n throw Error(`Transaction hash '${txHash}' not found in blockchain.`);\n }\n\n await waitWithMempoolCheck(this.provider, tx, txHash, confirmations);\n return { hash: txHash };\n } catch (error) {\n if (isError(error, 'TRANSACTION_REPLACED')) {\n const reason = error.reason;\n if (reason === 'cancelled') {\n throw new SignerError(\n SignerErrorCode.SEND_TX_ERROR,\n undefined,\n 'Transaction replaced and canceled by user',\n undefined,\n error\n );\n }\n return { hash: error.replacement.hash, response: error.replacement };\n } else if (isError(error, 'CALL_EXCEPTION')) {\n const tError = await getTenderlyError(chainId, txHash);\n if (!!tError) {\n throw new SignerError(\n SignerErrorCode.TX_FAILED_IN_BLOCKCHAIN,\n 'Trannsaction failed in blockchain',\n tError,\n RangoRPCErrorCode.CALL_EXCEPTION,\n error\n );\n } else {\n /**\n * In cases where the is no error returen from tenderly, we could ignore\n * the error and proceed with check status flow.\n */\n return { hash: txHash };\n }\n }\n /**\n * Ignore other errors in confirming transaction and proceed with check status flow,\n * Some times rpc gives internal error or other type of errors even if the transaction succeeded\n */\n return { hash: txHash };\n }\n }\n}\n", "import type { SignerError as SignerErrorType } from 'rango-types';\n\nimport { isError } from 'ethers';\nimport {\n RPCErrorCode as RangoRPCErrorCode,\n SignerError,\n SignerErrorCode,\n} from 'rango-types';\n\nexport const cleanEvmError = (error: any): SignerErrorType => {\n if (!error) {\n return new SignerError(SignerErrorCode.SEND_TX_ERROR);\n }\n\n if (SignerError.isSignerError(error)) {\n return error;\n }\n\n if (error.code) {\n if (isError(error, 'UNKNOWN_ERROR')) {\n const msg = error.error?.message || error.message;\n return new SignerError(\n SignerErrorCode.SEND_TX_ERROR,\n undefined,\n msg,\n RangoRPCErrorCode.UNKNOWN_ERROR,\n error\n );\n }\n\n if (isError(error, 'ACTION_REJECTED')) {\n const msg = error.shortMessage.replace('action', `'${error.action}'`);\n return new SignerError(\n SignerErrorCode.SEND_TX_ERROR,\n undefined,\n msg,\n RangoRPCErrorCode.REJECTION,\n error\n );\n }\n\n const msg = error.shortMessage || error.message;\n return new SignerError(\n SignerErrorCode.SEND_TX_ERROR,\n undefined,\n msg,\n RangoRPCErrorCode.UNKNOWN_ERROR,\n error\n );\n }\n return new SignerError(\n SignerErrorCode.SEND_TX_ERROR,\n undefined,\n error,\n RangoRPCErrorCode.UNKNOWN_ERROR,\n error\n );\n};\n\ninterface TenderlyResponse {\n error_message: string;\n}\n\nexport async function getTenderlyError(\n chainId: string | undefined,\n txHash: string\n): Promise<string | undefined> {\n if (!chainId || !txHash) {\n return;\n }\n const chainIdInt = parseInt(chainId);\n try {\n const url = `https://api.tenderly.co/api/v1/public-contract/${chainIdInt}/tx/${txHash}`;\n const response = await fetch(url, {\n method: 'GET',\n });\n if (!response.ok) {\n return;\n }\n const data: TenderlyResponse = await response.json();\n return data?.error_message;\n } catch (error) {\n return;\n }\n}\n\nexport const waitMs = async (ms: number) =>\n new Promise((resolve) => setTimeout(resolve, ms));\n"],
5
+ "mappings": "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",
6
+ "names": ["BrowserProvider", "isError", "RangoRPCErrorCode", "SignerError", "SignerErrorCode", "isError", "RangoRPCErrorCode", "SignerError", "SignerErrorCode", "cleanEvmError", "__name", "error", "SignerError", "SignerErrorCode", "isError", "msg", "RangoRPCErrorCode", "getTenderlyError", "chainId", "txHash", "chainIdInt", "url", "response", "waitMs", "ms", "resolve", "waitWithMempoolCheck", "__name", "provider", "tx", "txHash", "confirmations", "finished", "waitMs", "error", "DefaultEvmSigner", "_DefaultEvmSigner", "BrowserProvider", "evmTx", "disableV2", "typedData", "SignerError", "SignerErrorCode", "msg", "address", "chainId", "signer", "transaction", "signerChainId", "signerAddress", "response", "cleanEvmError", "txResponse", "isError", "tError", "getTenderlyError", "RangoRPCErrorCode"]
7
+ }
@@ -0,0 +1 @@
1
+ {"inputs":{"src/helper.ts":{"bytes":2050,"imports":[{"path":"ethers","kind":"import-statement","external":true},{"path":"rango-types","kind":"import-statement","external":true},{"path":"<runtime>","kind":"import-statement","external":true}],"format":"esm"},"src/signer.ts":{"bytes":8016,"imports":[{"path":"ethers","kind":"import-statement","external":true},{"path":"rango-types","kind":"import-statement","external":true},{"path":"src/helper.ts","kind":"import-statement","original":"./helper.js"},{"path":"<runtime>","kind":"import-statement","external":true}],"format":"esm"},"src/index.ts":{"bytes":101,"imports":[{"path":"src/signer.ts","kind":"import-statement","original":"./signer.js"},{"path":"src/helper.ts","kind":"import-statement","original":"./helper.js"}],"format":"esm"}},"outputs":{"dist/index.js.map":{"imports":[],"exports":[],"inputs":{},"bytes":15716},"dist/index.js":{"imports":[{"path":"ethers","kind":"import-statement","external":true},{"path":"rango-types","kind":"import-statement","external":true},{"path":"ethers","kind":"import-statement","external":true},{"path":"rango-types","kind":"import-statement","external":true}],"exports":["DefaultEvmSigner","cleanEvmError","waitMs"],"entryPoint":"src/index.ts","inputs":{"src/signer.ts":{"bytesInOutput":2866},"src/helper.ts":{"bytesInOutput":928},"src/index.ts":{"bytesInOutput":0}},"bytes":3969}}}
@@ -0,0 +1,20 @@
1
+ import type { TypedData } from './types.js';
2
+ import type { Eip1193Provider, TransactionRequest, TransactionResponse } from 'ethers';
3
+ import type { GenericSigner } from 'rango-types';
4
+ import type { EvmTransaction } from 'rango-types/mainApi';
5
+ export declare class DefaultEvmSigner implements GenericSigner<EvmTransaction> {
6
+ private provider;
7
+ constructor(provider: Eip1193Provider);
8
+ static buildTx(evmTx: EvmTransaction, disableV2?: boolean): TransactionRequest;
9
+ signTypedData(typedData: TypedData): Promise<string>;
10
+ signMessage(msg: string): Promise<string>;
11
+ signAndSendTx(tx: EvmTransaction, address: string, chainId: string | null): Promise<{
12
+ hash: string;
13
+ response: TransactionResponse;
14
+ }>;
15
+ wait(txHash: string, chainId?: string, txResponse?: TransactionResponse, confirmations?: number): Promise<{
16
+ hash: string;
17
+ response?: TransactionResponse;
18
+ }>;
19
+ }
20
+ //# sourceMappingURL=signer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signer.d.ts","sourceRoot":"","sources":["../src/signer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,KAAK,EAEV,eAAe,EACf,kBAAkB,EAClB,mBAAmB,EACpB,MAAM,QAAQ,CAAC;AAChB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AA6C1D,qBAAa,gBAAiB,YAAW,aAAa,CAAC,cAAc,CAAC;IACpE,OAAO,CAAC,QAAQ,CAAkB;gBAEtB,QAAQ,EAAE,eAAe;IAIrC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,cAAc,EAAE,SAAS,UAAQ,GAAG,kBAAkB;IAwCtE,aAAa,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC;IAepD,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IASzC,aAAa,CACjB,EAAE,EAAE,cAAc,EAClB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GAAG,IAAI,GACrB,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,mBAAmB,CAAA;KAAE,CAAC;IAsDrD,IAAI,CACR,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,mBAAmB,EAChC,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,mBAAmB,CAAA;KAAE,CAAC;CA6E7D"}
@@ -0,0 +1,7 @@
1
+ import type { TypedDataDomain, TypedDataField } from 'ethers';
2
+ export type TypedData = {
3
+ domain: TypedDataDomain;
4
+ types: Record<string, Array<TypedDataField>>;
5
+ value: Record<string, unknown>;
6
+ };
7
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAE9D,MAAM,MAAM,SAAS,GAAG;IACtB,MAAM,EAAE,eAAe,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC;IAC7C,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "@rango-dev/signer-evm",
3
+ "version": "0.0.0-experimental-d44b759f-20260701",
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 signers/signer-evm",
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
+ "test": "vitest",
23
+ "test:watch": "vitest --watch",
24
+ "test:coverage": "vitest run --coverage"
25
+ },
26
+ "dependencies": {
27
+ "ethers": "^6.13.2",
28
+ "rango-types": "^0.5.0"
29
+ },
30
+ "publishConfig": {
31
+ "access": "public"
32
+ }
33
+ }
package/readme.md ADDED
@@ -0,0 +1,3 @@
1
+ # @rango-dev/signer-evm
2
+
3
+ Signer for EVM Transacations generated by Rango API
package/src/helper.ts ADDED
@@ -0,0 +1,88 @@
1
+ import type { SignerError as SignerErrorType } from 'rango-types';
2
+
3
+ import { isError } from 'ethers';
4
+ import {
5
+ RPCErrorCode as RangoRPCErrorCode,
6
+ SignerError,
7
+ SignerErrorCode,
8
+ } from 'rango-types';
9
+
10
+ export const cleanEvmError = (error: any): SignerErrorType => {
11
+ if (!error) {
12
+ return new SignerError(SignerErrorCode.SEND_TX_ERROR);
13
+ }
14
+
15
+ if (SignerError.isSignerError(error)) {
16
+ return error;
17
+ }
18
+
19
+ if (error.code) {
20
+ if (isError(error, 'UNKNOWN_ERROR')) {
21
+ const msg = error.error?.message || error.message;
22
+ return new SignerError(
23
+ SignerErrorCode.SEND_TX_ERROR,
24
+ undefined,
25
+ msg,
26
+ RangoRPCErrorCode.UNKNOWN_ERROR,
27
+ error
28
+ );
29
+ }
30
+
31
+ if (isError(error, 'ACTION_REJECTED')) {
32
+ const msg = error.shortMessage.replace('action', `'${error.action}'`);
33
+ return new SignerError(
34
+ SignerErrorCode.SEND_TX_ERROR,
35
+ undefined,
36
+ msg,
37
+ RangoRPCErrorCode.REJECTION,
38
+ error
39
+ );
40
+ }
41
+
42
+ const msg = error.shortMessage || error.message;
43
+ return new SignerError(
44
+ SignerErrorCode.SEND_TX_ERROR,
45
+ undefined,
46
+ msg,
47
+ RangoRPCErrorCode.UNKNOWN_ERROR,
48
+ error
49
+ );
50
+ }
51
+ return new SignerError(
52
+ SignerErrorCode.SEND_TX_ERROR,
53
+ undefined,
54
+ error,
55
+ RangoRPCErrorCode.UNKNOWN_ERROR,
56
+ error
57
+ );
58
+ };
59
+
60
+ interface TenderlyResponse {
61
+ error_message: string;
62
+ }
63
+
64
+ export async function getTenderlyError(
65
+ chainId: string | undefined,
66
+ txHash: string
67
+ ): Promise<string | undefined> {
68
+ if (!chainId || !txHash) {
69
+ return;
70
+ }
71
+ const chainIdInt = parseInt(chainId);
72
+ try {
73
+ const url = `https://api.tenderly.co/api/v1/public-contract/${chainIdInt}/tx/${txHash}`;
74
+ const response = await fetch(url, {
75
+ method: 'GET',
76
+ });
77
+ if (!response.ok) {
78
+ return;
79
+ }
80
+ const data: TenderlyResponse = await response.json();
81
+ return data?.error_message;
82
+ } catch (error) {
83
+ return;
84
+ }
85
+ }
86
+
87
+ export const waitMs = async (ms: number) =>
88
+ new Promise((resolve) => setTimeout(resolve, ms));
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export { DefaultEvmSigner } from './signer.js';
2
+ export { waitMs, cleanEvmError } from './helper.js';
package/src/signer.ts ADDED
@@ -0,0 +1,265 @@
1
+ import type { TypedData } from './types.js';
2
+ import type {
3
+ AbstractProvider,
4
+ Eip1193Provider,
5
+ TransactionRequest,
6
+ TransactionResponse,
7
+ } from 'ethers';
8
+ import type { GenericSigner } from 'rango-types';
9
+ import type { EvmTransaction } from 'rango-types/mainApi';
10
+
11
+ import { BrowserProvider, isError } from 'ethers';
12
+ import {
13
+ RPCErrorCode as RangoRPCErrorCode,
14
+ SignerError,
15
+ SignerErrorCode,
16
+ } from 'rango-types';
17
+
18
+ import { cleanEvmError, getTenderlyError, waitMs } from './helper.js';
19
+
20
+ const waitWithMempoolCheck = async (
21
+ provider: AbstractProvider,
22
+ tx: TransactionResponse,
23
+ txHash: string,
24
+ confirmations?: number
25
+ ) => {
26
+ const TIMEOUT = 3_000;
27
+ let finished = false;
28
+ return await Promise.race([
29
+ (async () => {
30
+ await tx.wait(confirmations);
31
+ finished = true;
32
+ })(),
33
+ (async () => {
34
+ while (!finished) {
35
+ await waitMs(TIMEOUT);
36
+ if (finished) {
37
+ return null;
38
+ }
39
+ try {
40
+ const mempoolTx = await provider.getTransaction(txHash);
41
+ if (!mempoolTx) {
42
+ return null;
43
+ }
44
+ } catch (error) {
45
+ console.log({ error });
46
+ return null;
47
+ }
48
+ }
49
+ return null;
50
+ })(),
51
+ ]);
52
+ };
53
+
54
+ export class DefaultEvmSigner implements GenericSigner<EvmTransaction> {
55
+ private provider: BrowserProvider;
56
+
57
+ constructor(provider: Eip1193Provider) {
58
+ this.provider = new BrowserProvider(provider); // provides read-only access to the provider
59
+ }
60
+
61
+ static buildTx(evmTx: EvmTransaction, disableV2 = false): TransactionRequest {
62
+ const TO_STRING_BASE = 16;
63
+ let tx: TransactionRequest = {};
64
+ /*
65
+ * it's better to pass 0x instead of undefined, otherwise some wallets could face issue
66
+ * https://github.com/WalletConnect/web3modal/issues/1082#issuecomment-1637793242
67
+ */
68
+ tx = {
69
+ data: evmTx.data || '0x',
70
+ };
71
+ if (evmTx.from) {
72
+ tx = { ...tx, from: evmTx.from };
73
+ }
74
+ if (evmTx.to) {
75
+ tx = { ...tx, to: evmTx.to };
76
+ }
77
+ if (evmTx.value) {
78
+ tx = { ...tx, value: evmTx.value };
79
+ }
80
+ if (evmTx.nonce) {
81
+ tx = { ...tx, nonce: parseInt(evmTx.nonce) };
82
+ }
83
+ if (evmTx.gasLimit) {
84
+ tx = { ...tx, gasLimit: evmTx.gasLimit };
85
+ }
86
+ if (!disableV2 && evmTx.maxFeePerGas && evmTx.maxPriorityFeePerGas) {
87
+ tx = {
88
+ ...tx,
89
+ maxFeePerGas: evmTx.maxFeePerGas,
90
+ maxPriorityFeePerGas: evmTx.maxPriorityFeePerGas,
91
+ };
92
+ } else if (evmTx.gasPrice) {
93
+ tx = {
94
+ ...tx,
95
+ gasPrice: '0x' + parseInt(evmTx.gasPrice).toString(TO_STRING_BASE),
96
+ };
97
+ }
98
+ return tx;
99
+ }
100
+
101
+ async signTypedData(typedData: TypedData): Promise<string> {
102
+ try {
103
+ const signer = await this.provider.getSigner();
104
+ const signature = await signer.signTypedData(
105
+ typedData.domain,
106
+ typedData.types,
107
+ typedData.value
108
+ );
109
+
110
+ return signature;
111
+ } catch (error) {
112
+ throw new SignerError(SignerErrorCode.SIGN_TX_ERROR, undefined, error);
113
+ }
114
+ }
115
+
116
+ async signMessage(msg: string): Promise<string> {
117
+ try {
118
+ const signer = await this.provider.getSigner(); // provides access to write operations
119
+ return await signer.signMessage(msg);
120
+ } catch (error) {
121
+ throw new SignerError(SignerErrorCode.SIGN_TX_ERROR, undefined, error);
122
+ }
123
+ }
124
+
125
+ async signAndSendTx(
126
+ tx: EvmTransaction,
127
+ address: string,
128
+ chainId: string | null
129
+ ): Promise<{ hash: string; response: TransactionResponse }> {
130
+ try {
131
+ const signer = await this.provider.getSigner(tx.from ?? undefined);
132
+
133
+ const transaction = DefaultEvmSigner.buildTx(tx);
134
+
135
+ const signerChainId = (await this.provider.getNetwork()).chainId;
136
+ const signerAddress = await signer.getAddress();
137
+
138
+ if (
139
+ !!chainId &&
140
+ !!signerChainId &&
141
+ signerChainId.toString() !== Number(chainId).toString()
142
+ ) {
143
+ throw new SignerError(
144
+ SignerErrorCode.UNEXPECTED_BEHAVIOUR,
145
+ undefined,
146
+ `Signer chainId: '${signerChainId}' doesn't match with required chainId: '${chainId}' for tx.`
147
+ );
148
+ }
149
+ if (
150
+ !!signerAddress &&
151
+ !!address &&
152
+ signerAddress.toLowerCase() !== address.toLowerCase()
153
+ ) {
154
+ throw new SignerError(
155
+ SignerErrorCode.UNEXPECTED_BEHAVIOUR,
156
+ undefined,
157
+ `Signer address: '${signerAddress.toLowerCase()}' doesn't match with required address: '${address.toLowerCase()}' for tx.`
158
+ );
159
+ }
160
+ try {
161
+ const response = await signer.sendTransaction(transaction);
162
+ return { hash: response.hash, response };
163
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
164
+ } catch (error: any) {
165
+ // retrying EIP-1559 without v2 related fields
166
+ if (
167
+ !!error?.message &&
168
+ typeof error.message === 'string' &&
169
+ error.message.indexOf('EIP-1559') !== -1
170
+ ) {
171
+ console.log('retrying EIP-1559 error without v2 fields ...');
172
+ const transaction = DefaultEvmSigner.buildTx(tx, true);
173
+ const response = await signer.sendTransaction(transaction);
174
+ return { hash: response.hash, response };
175
+ }
176
+ throw error;
177
+ }
178
+ } catch (error) {
179
+ throw cleanEvmError(error);
180
+ }
181
+ }
182
+
183
+ async wait(
184
+ txHash: string,
185
+ chainId?: string,
186
+ txResponse?: TransactionResponse,
187
+ confirmations?: number
188
+ ): Promise<{ hash: string; response?: TransactionResponse }> {
189
+ try {
190
+ /*
191
+ * if we have transaction response, use that to wait
192
+ * otherwise, try to get tx response from the wallet provider
193
+ */
194
+ if (txResponse) {
195
+ // if we use waitWithMempoolCheck here, we can't detect replaced tx anymore
196
+ await txResponse?.wait(confirmations);
197
+ return { hash: txHash };
198
+ }
199
+
200
+ // ignore wait if wallet not connected yet
201
+ if (!this.provider) {
202
+ return { hash: txHash };
203
+ }
204
+
205
+ /*
206
+ * don't proceed if signer chain changed or chain id is not specified
207
+ * because if user change the wallet network, we receive null on getTransaction
208
+ */
209
+ if (!chainId) {
210
+ return { hash: txHash };
211
+ }
212
+ const signerChainId = (await this.provider.getNetwork()).chainId;
213
+ if (
214
+ !signerChainId ||
215
+ Number(chainId).toString() !== signerChainId.toString()
216
+ ) {
217
+ return { hash: txHash };
218
+ }
219
+
220
+ const tx = await this.provider.getTransaction(txHash);
221
+ if (!tx) {
222
+ throw Error(`Transaction hash '${txHash}' not found in blockchain.`);
223
+ }
224
+
225
+ await waitWithMempoolCheck(this.provider, tx, txHash, confirmations);
226
+ return { hash: txHash };
227
+ } catch (error) {
228
+ if (isError(error, 'TRANSACTION_REPLACED')) {
229
+ const reason = error.reason;
230
+ if (reason === 'cancelled') {
231
+ throw new SignerError(
232
+ SignerErrorCode.SEND_TX_ERROR,
233
+ undefined,
234
+ 'Transaction replaced and canceled by user',
235
+ undefined,
236
+ error
237
+ );
238
+ }
239
+ return { hash: error.replacement.hash, response: error.replacement };
240
+ } else if (isError(error, 'CALL_EXCEPTION')) {
241
+ const tError = await getTenderlyError(chainId, txHash);
242
+ if (!!tError) {
243
+ throw new SignerError(
244
+ SignerErrorCode.TX_FAILED_IN_BLOCKCHAIN,
245
+ 'Trannsaction failed in blockchain',
246
+ tError,
247
+ RangoRPCErrorCode.CALL_EXCEPTION,
248
+ error
249
+ );
250
+ } else {
251
+ /**
252
+ * In cases where the is no error returen from tenderly, we could ignore
253
+ * the error and proceed with check status flow.
254
+ */
255
+ return { hash: txHash };
256
+ }
257
+ }
258
+ /**
259
+ * Ignore other errors in confirming transaction and proceed with check status flow,
260
+ * Some times rpc gives internal error or other type of errors even if the transaction succeeded
261
+ */
262
+ return { hash: txHash };
263
+ }
264
+ }
265
+ }
package/src/types.ts ADDED
@@ -0,0 +1,7 @@
1
+ import type { TypedDataDomain, TypedDataField } from 'ethers';
2
+
3
+ export type TypedData = {
4
+ domain: TypedDataDomain;
5
+ types: Record<string, Array<TypedDataField>>;
6
+ value: Record<string, unknown>;
7
+ };