@@ -66,3 +66,200 @@ Utf16.lengthInBytes('👨🏼👩🏼👧🏼👧🏼') // 19
6666```
6767
6868** [ Full documentation for the UTF and hex string helpers] ( https://github.com/fend25/utf-helpers#readme ) **
69+
70+ ## Extension tools
71+
72+ ### Ethereum
73+
74+ A tiny (0.5 Kb) and zero-dependency module to detect whether metamask extension presents,
75+ detect whether the access is granted and get account(s) or request access.
76+
77+ Node.js-safe, it will not throw unexpected errors like "cannot find window".
78+ Also, these methods are safe in a common way, they don't throw errors,
79+ but return wrapped result or error with additional info.
80+
81+ The ` ExtensionsTools ` , ` Ethereum ` and ` Polkadot ` modules should be imported directly from
82+ ` @unique-nft/utils/extension ` because they are not available at ` @unique-nft/utils ` .
83+
84+ For Ethereum browser extensions, like metamask:
85+
86+ ``` ts
87+ import {ExtensionTools } from ' @unique-nft/utils/extension'
88+
89+ const Ethereum = ExtensionTools .Ethereum
90+ // or
91+ import {Ethereum } from ' @unique-nft/utils/extension'
92+
93+ const getAccountsResult = await Ethereum .getAccounts ()
94+ /*
95+ {
96+ accounts: ['0xf8cC75F76d46c3b1c5F270Fe06c8FFdeAB8E5eaB'],
97+ info: {extensionFound: true, chainId: '0x22b2', chainIdNumber: 8882},
98+ selectedAddress: 0xf8cC75F76d46c3b1c5F270Fe06c8FFdeAB8E5eaB
99+ }
100+ // or, when there is no granted account:
101+ {accounts: [], selectedAddress: null, info: {extensionFound: true, chainId: '0x22b2', chainIdNumber: 8882}}
102+ // or, when there is no extension:
103+ {accounts: [], selectedAddress: null, info: {extensionFound: false}}
104+ // in Node.js `info.extensionFound is` always false.
105+ */
106+ ```
107+
108+ Simple example which just checks extension and tries to get an address without prompting user:
109+
110+ ``` ts
111+ import {Ethereum } from ' @unique-nft/utils/extension'
112+
113+ let result = await Ethereum .getAccounts ()
114+
115+ if (result .info .extensionFound && result .selectedAddress ) {
116+ // woohoo, let's create a Web3 Provider like that:
117+ const provider = new ethers .providers .Web3Provider (window .ethereum )
118+ console .log (ethers .utils .formatEther (await provider .getBalance (result .selectedAddress )))
119+ }
120+ ```
121+
122+ More complex example, when we want to request user to grant access.
123+ _ Note: If user has already granted access, it will work silently, just like_ ` getAccounts ` .
124+
125+ ``` ts
126+ import {Ethereum } from ' @unique-nft/utils/extension'
127+
128+ const result = await Ethereum .requestAccounts ()
129+
130+ if (result .selectedAddress ) {
131+ // woohoo, let's create a Web3 Provider like that:
132+ const provider = new ethers .providers .Web3Provider (window .ethereum )
133+ console .log (ethers .utils .formatEther (await provider .getBalance (result .selectedAddress )))
134+ } else {
135+ if (result .info .userRejected ) {
136+ console .log (` Oops, user doesn't want us. Let's show them some kawaii popup ` )
137+ } else {
138+ console .error (result .info .error )
139+ }
140+ }
141+ ```
142+
143+ ### Polkadot
144+
145+ A tiny (1.5 Kb) and zero-dependency (no WASM, no anything) module to work with Polkadot extensions family -
146+ Polkadot.js, Subwallet, Talisman and other Polkadot.js-compatible wallets.
147+ Actually it's a neat and really useful replacement for the extension-dapp module.
148+
149+ This module works in browsers with multiple wallets, it can detect whether there is an extension installed
150+ and contains the boilerplate logic around detecting wallets, it's access and so on.
151+
152+ Node.js-safe, it will not throw unexpected errors like "cannot find window".
153+ Also, these methods are safe in a common way, they don't throw errors,
154+ but return wrapped result or error with additional info.
155+
156+ The ` ExtensionsTools ` , ` Ethereum ` and ` Polkadot ` modules should be imported directly
157+ from ` @unique-nft/utils/extension ` because they are not available at ` @unique-nft/utils ` .
158+
159+ ``` ts
160+ import {ExtensionTools } from ' @unique-nft/utils/extension'
161+ // or
162+ import {Polkadot } from ' @unique-nft/utils/extension'
163+
164+ const result = await Polkadot .enableAndLoadAllWallets ()
165+
166+ result .info .extensionFound // boolean, in Node.js it's always false.
167+
168+ result .accounts [0 ].address // string
169+ ```
170+
171+ Also, it contains ready signer object for the [ Unique SDK] ( https://www.npmjs.com/package/@unique-nft/sdk ) :
172+
173+ ``` ts
174+ import {Polkadot } from ' @unique-nft/utils/extension'
175+ import {Sdk } from ' @unique-nft/sdk'
176+
177+ const {accounts} = await Polkadot .enableAndLoadAllWallets () // Some checks are omitted
178+ const account = accounts [0 ] // For the simplicity
179+
180+ const sdk = new Sdk ({
181+ baseUrl: ' https://rest.opal.uniquenetwork.dev/v1' ,
182+ signer: account .uniqueSdkSigner
183+ })
184+
185+ // or provide it (or override default one) on demand with specific request:
186+
187+ const sdkWithoutSigner = new Sdk ({baseUrl: ' https://rest.opal.uniquenetwork.dev/v1' })
188+
189+ const result = await sdkWithoutSigner .balance .transfer .submitWaitResult ({
190+ amount: 1 ,
191+ address: account .address ,
192+ destination: " 5..." // some another address
193+ }, {
194+ signer: account .uniqueSdkSigner
195+ })
196+ ```
197+
198+ ##### Return types
199+
200+ ` enableAndLoadAllWallets ` and ` loadEnabledWallets ` return such result:
201+
202+ ``` ts
203+ export interface IPolkadotExtensionLoadWalletsResult {
204+ info: {
205+ extensionFound: boolean
206+ accountsFound: boolean
207+ userHasWalletsButHasNoAccounts: boolean
208+ userHasBlockedAllWallets: boolean
209+ }
210+
211+ accounts: IPolkadotExtensionAccount []
212+
213+ wallets: IPolkadotExtensionWallet []
214+
215+ rejectedWallets: Array <{
216+ name: string
217+ version: string
218+ isEnabled: boolean | undefined
219+ prettyName: string
220+ logo: {
221+ ipfsCid: string ,
222+ url: string ,
223+ }
224+ error: Error
225+ isBlockedByUser: boolean
226+ }>
227+ }
228+ ```
229+
230+ where ` IPolkadotExtensionAccount ` is:
231+
232+ ``` ts
233+ export interface IPolkadotExtensionAccount extends Omit <Signer , ' signRaw' > {
234+ name: string
235+ id: string
236+ address: string
237+ addressShort: string
238+
239+ wallet: {
240+ name: string
241+ version: string
242+ isEnabled: boolean | undefined
243+ prettyName: string
244+ logo: {
245+ ipfsCid: string ,
246+ url: string ,
247+ }
248+ }
249+
250+ signRaw: (raw : SignerPayloadRawWithAddressAndTypeOptional | string ) => Promise <SignerResult >
251+ signPayload: (payload : SignerPayloadJSON ) => Promise <SignerResult >
252+ update? : (id : number , status : any ) => void
253+
254+ uniqueSdkSigner: {
255+ sign: (unsignedTxPayload : SDK_UnsignedTxPayloadBody ) => Promise <SDK_SignTxResultResponse >
256+ }
257+
258+ meta: {
259+ genesisHash: string | null
260+ name: string
261+ source: string
262+ }
263+ type: KeypairType // 'ed25519' | 'sr25519' | 'ecdsa' | 'ethereum'
264+ }
265+ ```
0 commit comments