@concordium/browser-wallet-api-helpers 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -51,25 +51,49 @@ declare global {
|
|
|
51
51
|
|
|
52
52
|
### connect
|
|
53
53
|
|
|
54
|
-
To request a connection to the wallet from the user, the `connect` method has to be invoked. The method returns a `Promise` resolving with information related to the
|
|
54
|
+
To request a connection to the wallet from the user, the `connect` method has to be invoked. The method returns a `Promise` resolving with information related to the most recently selected account, which has whitelisted the dApp, or rejecting if the request is rejected in the wallet.
|
|
55
55
|
|
|
56
56
|
```typescript
|
|
57
57
|
const provider = await detectConcordiumProvider();
|
|
58
58
|
const accountAddress = await provider.connect();
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
+
N.B. In the current version, if the dApp is already whitelisted, but not by the currently selected account, the returned account will not actually be the most recently selected account, but instead the oldest account that has whitelasted the dApp.
|
|
62
|
+
|
|
63
|
+
### getMostRecentlySelectedAccount
|
|
64
|
+
|
|
65
|
+
To get the most recently selected account, or to check whether the wallet is connected without using connect, the `getMostRecentlySelectedAccount` can be invoked. The method returns a `Promise` resolving with the address of the most recently selected account in the wallet, or with undefined if there are no connected accounts in the wallet.
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
const provider = await detectConcordiumProvider();
|
|
69
|
+
const accountAddress = await provider.getMostRecentlySelectedAccount();
|
|
70
|
+
if (accountAddress) {
|
|
71
|
+
// We are connected to the wallet
|
|
72
|
+
} else {
|
|
73
|
+
// We are not connected to the wallet
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
N.B. In the current version, if the currently selected account has not whitelisted the dApp, the returned account will not actually be the most recently selected account, but instead the oldest account that has whitelasted the dApp.
|
|
78
|
+
|
|
61
79
|
### sendTransaction
|
|
62
80
|
|
|
63
|
-
To send a transaction,
|
|
81
|
+
To send a transaction, three arguments need to be provided: The account address for the account in the wallet that should sign the transaction, a transaction type and a corresponding payload. Invoking `sendTransaction` returns a `Promise`, which resolves with the transaction hash for the submitted transaction.
|
|
64
82
|
|
|
65
|
-
|
|
83
|
+
If you have not connected with the wallet (or previously been whitelisted) or if the user rejects signing the transaction, the `Promise` will reject.
|
|
84
|
+
|
|
85
|
+
The following exemplifies how to create a simple transfer of funds from one account to another. Please note that [@concordium/web-sdk](https://github.com/Concordium/concordium-node-sdk-js/tree/main/packages/web) is used to provide the correct formats and types for the transaction payload.
|
|
66
86
|
|
|
67
87
|
```typescript
|
|
68
88
|
const provider = await detectConcordiumProvider();
|
|
69
|
-
const txHash = await provider.sendTransaction(
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
89
|
+
const txHash = await provider.sendTransaction(
|
|
90
|
+
'4MyVHYbRkAU6fqQsoSDzni6mrVz1KEvhDJoMVmDmrCgPBD8b7S',
|
|
91
|
+
concordiumSDK.AccountTransactionType.SimpleTransfer,
|
|
92
|
+
{
|
|
93
|
+
amount: new concordiumSDK.GtuAmount(1n),
|
|
94
|
+
toAddress: new concordiumSDK.AccountAddress('39bKAuC7sXCZQfo7DmVQTMbiUuBMQJ5bCfsS7sva1HvDnUXp13'),
|
|
95
|
+
}
|
|
96
|
+
);
|
|
73
97
|
```
|
|
74
98
|
|
|
75
99
|
In the case of a smart contract init/update, parameters for the specific function, a corresponding schema for serializing the parameters and the version of the schema can be defined.
|
|
@@ -77,6 +101,7 @@ In the case of a smart contract init/update, parameters for the specific functio
|
|
|
77
101
|
```typescript
|
|
78
102
|
const provider = await detectConcordiumProvider();
|
|
79
103
|
const txHash = await provider.sendTransaction(
|
|
104
|
+
'4MyVHYbRkAU6fqQsoSDzni6mrVz1KEvhDJoMVmDmrCgPBD8b7S',
|
|
80
105
|
concordiumSDK.AccountTransactionType.UpdateSmartContractInstance,
|
|
81
106
|
{
|
|
82
107
|
amount: new concordiumSDK.GtuAmount(1n),
|
|
@@ -97,21 +122,65 @@ const txHash = await provider.sendTransaction(
|
|
|
97
122
|
|
|
98
123
|
### signMessage
|
|
99
124
|
|
|
100
|
-
It is possible to sign arbitrary messages using the keys for an account stored in the wallet, by invoking the `signMessage` method. This method returns a `Promise` resolving with a signature of the message.
|
|
125
|
+
It is possible to sign arbitrary messages using the keys for an account stored in the wallet, by invoking the `signMessage` method. The first parameter is the account to be used for signing the message. This method returns a `Promise` resolving with a signature of the message.
|
|
126
|
+
|
|
127
|
+
If you have not connected with the wallet (or previously been whitelisted) or if the user rejects signing the meesage, the `Promise` will reject.
|
|
101
128
|
|
|
102
129
|
The following exemplifies requesting a signature of a message:
|
|
103
130
|
|
|
104
131
|
```typescript
|
|
105
132
|
const provider = await detectConcordiumProvider();
|
|
106
|
-
const signature = await provider.signMessage(
|
|
133
|
+
const signature = await provider.signMessage(
|
|
134
|
+
'4MyVHYbRkAU6fqQsoSDzni6mrVz1KEvhDJoMVmDmrCgPBD8b7S',
|
|
135
|
+
'This is a message to be signed'
|
|
136
|
+
);
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Events
|
|
140
|
+
|
|
141
|
+
### Account changed
|
|
142
|
+
|
|
143
|
+
An event is emitted when the selected account in the wallet is changed. An event is not emitted by the wallet when initially opening, only when the user
|
|
144
|
+
explicitly switches between accounts. The `connect` method should be used to obtain the currently selected account when starting an interaction with the wallet.
|
|
145
|
+
Note that the event will not be received if the user changes to an account in the wallet that is not connected to your dApp.
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
const provider = await detectConcordiumProvider();
|
|
149
|
+
let selectedAccountAddress: string | undefined = undefined;
|
|
150
|
+
provider.on('accountChanged', (accountAddress) => (selectedAccountAddress = accountAddress);
|
|
107
151
|
```
|
|
108
152
|
|
|
109
|
-
###
|
|
153
|
+
### Account disconnected
|
|
110
154
|
|
|
111
|
-
|
|
155
|
+
An event is emitted when dApp connection is disconnected by the user in the wallet. The disconnect
|
|
156
|
+
event is only emitted to the relevant dApp being disconnected. To either reconnect or get another
|
|
157
|
+
connected account a dApp should use the `connect` method. This can be done either by having the user of the dApp manually press a connect button, or it can be done automatically based on the received disconnect event.
|
|
112
158
|
|
|
113
159
|
```typescript
|
|
114
160
|
const provider = await detectConcordiumProvider();
|
|
115
161
|
let selectedAccountAddress: string | undefined = undefined;
|
|
116
|
-
provider.
|
|
162
|
+
provider.on('accountDisconnected', (accountAddress) => {
|
|
163
|
+
selectedAccountAddress = undefined;
|
|
164
|
+
|
|
165
|
+
// To immediately connect to an account in the wallet again.
|
|
166
|
+
// provider.connect().then((accountAddress) => (selectedAccountAddress = accountAddress));
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// Connect to an account in the wallet again triggered elsewhere in the dApp.
|
|
170
|
+
provider.connect().then((accountAddress) => (selectedAccountAddress = accountAddress));
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Accessing node through JSON-RPC
|
|
174
|
+
|
|
175
|
+
The wallet API exposes access to a JSON-RPC client. This allows a dApp to communicate with the same node as the wallet is connected to, and enables dApps to access the JSON-RPC interface without being connected to a separate server itself. The client is accessed as shown in the example below.
|
|
176
|
+
The dApp does not need to recreate the client again when the wallet changes node or network, the client will always use the wallet's current connected JSON-RPC server.
|
|
177
|
+
|
|
178
|
+
If you have not connected with the wallet (or previously been whitelisted), the commands will not be executed and the method will throw an error.
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
const provider = await detectConcordiumProvider();
|
|
182
|
+
const client: JsonRpcClient = await provider.getJsonRpcClient();
|
|
183
|
+
...
|
|
184
|
+
// The client can then be used to acccess node through JSON-RPC
|
|
185
|
+
const accountInfo = await client.getAccountInfo(accountAddress);
|
|
117
186
|
```
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
!function(e,o){"object"==typeof exports&&"object"==typeof module?module.exports=o():"function"==typeof define&&define.amd?define([],o):"object"==typeof exports?exports.concordiumHelpers=o():e.concordiumHelpers=o()}(self,(()=>(()=>{"use strict";var e={611:(e,o)=>{Object.defineProperty(o,"__esModule",{value:!0}),o.detectConcordiumProvider=async function(e=5e3){return new Promise(((o,n)=>{if(window.concordium)o(window.concordium);else{const
|
|
1
|
+
!function(e,o){"object"==typeof exports&&"object"==typeof module?module.exports=o():"function"==typeof define&&define.amd?define([],o):"object"==typeof exports?exports.concordiumHelpers=o():e.concordiumHelpers=o()}(self,(()=>(()=>{"use strict";var e={611:(e,o)=>{Object.defineProperty(o,"__esModule",{value:!0}),o.detectConcordiumProvider=async function(e=5e3){return new Promise(((o,n)=>{if(window.concordium)o(window.concordium);else{const t=setTimeout((()=>{window.concordium?o(window.concordium):n()}),e);window.addEventListener("concordium#initialized",(()=>{window.concordium&&(clearTimeout(t),o(window.concordium))}),{once:!0})}}))}},685:(e,o,n)=>{Object.defineProperty(o,"__esModule",{value:!0});var t={detectConcordiumProvider:!0};Object.defineProperty(o,"detectConcordiumProvider",{enumerable:!0,get:function(){return c.detectConcordiumProvider}});var r=n(740);Object.keys(r).forEach((function(e){"default"!==e&&"__esModule"!==e&&(Object.prototype.hasOwnProperty.call(t,e)||e in o&&o[e]===r[e]||Object.defineProperty(o,e,{enumerable:!0,get:function(){return r[e]}}))}));var c=n(611)},740:(e,o)=>{var n;Object.defineProperty(o,"__esModule",{value:!0}),o.EventType=void 0,o.EventType=n,function(e){e.AccountChanged="accountChanged",e.AccountDisconnected="accountDisconnected",e.ChainChanged="chainChanged"}(n||(o.EventType=n={}))}},o={};return function n(t){var r=o[t];if(void 0!==r)return r.exports;var c=o[t]={exports:{}};return e[t](c,c.exports,n),c.exports}(685)})()));
|
|
2
2
|
//# sourceMappingURL=concordiumHelpers.min.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"concordiumHelpers.min.js","mappings":"CAAA,SAA2CA,EAAMC,GAC1B,iBAAZC,SAA0C,iBAAXC,OACxCA,OAAOD,QAAUD,IACQ,mBAAXG,QAAyBA,OAAOC,IAC9CD,OAAO,GAAIH,GACe,iBAAZC,QACdA,QAA2B,kBAAID,IAE/BD,EAAwB,kBAAIC,IAR9B,CASGK,MAAM,I,kHCHFC,eAAwCC,EAAU,KACrD,OAAO,IAAIC,SAAQ,CAACC,EAASC,KACzB,GAAIC,OAAOC,WACPH,EAAQE,OAAOC,gBAEd,CACD,MAAMC,EAAIC,YAAW,KACbH,OAAOC,WACPH,EAAQE,OAAOC,YAGfF,MAELH,GACHI,OAAOI,iBAAiB,0BAA0B,KAC1CJ,OAAOC,aACPI,aAAaH,GACbJ,EAAQE,OAAOC,eAEpB,CAAEK,MAAM,U,yNCzBvB,8NACA,c,YCEO,IAAIC,E,kFACX,SAAWA,GACPA,EAAS,eAAqB,iBAC9BA,EAAS,aAAmB,
|
|
1
|
+
{"version":3,"file":"concordiumHelpers.min.js","mappings":"CAAA,SAA2CA,EAAMC,GAC1B,iBAAZC,SAA0C,iBAAXC,OACxCA,OAAOD,QAAUD,IACQ,mBAAXG,QAAyBA,OAAOC,IAC9CD,OAAO,GAAIH,GACe,iBAAZC,QACdA,QAA2B,kBAAID,IAE/BD,EAAwB,kBAAIC,IAR9B,CASGK,MAAM,I,kHCHFC,eAAwCC,EAAU,KACrD,OAAO,IAAIC,SAAQ,CAACC,EAASC,KACzB,GAAIC,OAAOC,WACPH,EAAQE,OAAOC,gBAEd,CACD,MAAMC,EAAIC,YAAW,KACbH,OAAOC,WACPH,EAAQE,OAAOC,YAGfF,MAELH,GACHI,OAAOI,iBAAiB,0BAA0B,KAC1CJ,OAAOC,aACPI,aAAaH,GACbJ,EAAQE,OAAOC,eAEpB,CAAEK,MAAM,U,yNCzBvB,8NACA,c,YCEO,IAAIC,E,kFACX,SAAWA,GACPA,EAAS,eAAqB,iBAC9BA,EAAS,oBAA0B,sBACnCA,EAAS,aAAmB,eAHhC,CAIGA,IAAc,EAAAA,UAAAA,EAAY,OCPzBC,EAA2B,G,OAG/B,SAASC,EAAoBC,GAE5B,IAAIC,EAAeH,EAAyBE,GAC5C,QAAqBE,IAAjBD,EACH,OAAOA,EAAarB,QAGrB,IAAIC,EAASiB,EAAyBE,GAAY,CAGjDpB,QAAS,IAOV,OAHAuB,EAAoBH,GAAUnB,EAAQA,EAAOD,QAASmB,GAG/ClB,EAAOD,QClBWmB,CAAoB,M","sources":["webpack:///webpack/universalModuleDefinition","webpack:///./lib/detector.js","webpack:///./lib/index.js","webpack:///./lib/wallet-api-types.js","webpack:///webpack/bootstrap","webpack:///webpack/startup"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"concordiumHelpers\"] = factory();\n\telse\n\t\troot[\"concordiumHelpers\"] = factory();\n})(self, () => {\nreturn ","/**\n * Detect the Concordium browser wallet API by waiting for it to have been successfully injected\n * into the window so that it is ready for use.\n * @param timeout determines how long to wait before rejecting if the Concordium provider is not available, in milliseconds.\n * @returns a promise containing the Concordium Wallet provider API.\n */\nexport async function detectConcordiumProvider(timeout = 5000) {\n return new Promise((resolve, reject) => {\n if (window.concordium) {\n resolve(window.concordium);\n }\n else {\n const t = setTimeout(() => {\n if (window.concordium) {\n resolve(window.concordium);\n }\n else {\n reject();\n }\n }, timeout);\n window.addEventListener('concordium#initialized', () => {\n if (window.concordium) {\n clearTimeout(t);\n resolve(window.concordium);\n }\n }, { once: true });\n }\n });\n}\n","export * from './wallet-api-types';\nexport { detectConcordiumProvider } from './detector';\n","/**\n * An enumeration of the events that can be emitted by the WalletApi.\n */\nexport var EventType;\n(function (EventType) {\n EventType[\"AccountChanged\"] = \"accountChanged\";\n EventType[\"AccountDisconnected\"] = \"accountDisconnected\";\n EventType[\"ChainChanged\"] = \"chainChanged\";\n})(EventType || (EventType = {}));\n","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// startup\n// Load entry module and return exports\n// This entry module is referenced by other modules so it can't be inlined\nvar __webpack_exports__ = __webpack_require__(685);\n"],"names":["root","factory","exports","module","define","amd","self","async","timeout","Promise","resolve","reject","window","concordium","t","setTimeout","addEventListener","clearTimeout","once","EventType","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","undefined","__webpack_modules__"],"sourceRoot":""}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import type { AccountTransactionPayload, AccountTransactionSignature, AccountTransactionType, SchemaVersion } from '@concordium/web-sdk';
|
|
1
|
+
import type { AccountTransactionPayload, AccountTransactionSignature, AccountTransactionType, JsonRpcClient, SchemaVersion } from '@concordium/web-sdk';
|
|
2
2
|
/**
|
|
3
3
|
* An enumeration of the events that can be emitted by the WalletApi.
|
|
4
4
|
*/
|
|
5
5
|
export declare enum EventType {
|
|
6
6
|
AccountChanged = "accountChanged",
|
|
7
|
+
AccountDisconnected = "accountDisconnected",
|
|
7
8
|
ChainChanged = "chainChanged"
|
|
8
9
|
}
|
|
9
10
|
declare type EventListener<Args extends any[]> = (...args: Args) => void;
|
|
@@ -13,37 +14,45 @@ interface Listeners<T extends EventType, Args extends any[]> {
|
|
|
13
14
|
addListener(eventName: T | `${T}`, listener: EventListener<Args>): this;
|
|
14
15
|
removeListener(eventName: T | `${T}`, listener: EventListener<Args>): this;
|
|
15
16
|
}
|
|
16
|
-
declare type EventListeners = Listeners<EventType.AccountChanged, [accountAddress: string]> & Listeners<EventType.ChainChanged, [chain: string]>;
|
|
17
|
+
declare type EventListeners = Listeners<EventType.AccountChanged, [accountAddress: string]> & Listeners<EventType.ChainChanged, [chain: string]> & Listeners<EventType.AccountDisconnected, [accountAddress: string]>;
|
|
17
18
|
interface MainWalletApi {
|
|
18
19
|
/**
|
|
19
20
|
* Sends a transaction to the Concordium Wallet and awaits the users action. Note that a header is not sent, and will be constructed by the wallet itself.
|
|
20
21
|
* Note that if the user rejects signing the transaction, this will throw an error.
|
|
22
|
+
* @param accountAddress the address of the account that should sign the transaction
|
|
21
23
|
* @param type the type of transaction that is to be signed and sent.
|
|
22
24
|
* @param payload the payload of the transaction to be signed and sent.
|
|
23
25
|
* @param parameters parameters for the initContract and updateContract transactions in JSON-like format.
|
|
24
26
|
* @param schema schema used for the initContract and updateContract transactions to serialize the parameters. Should be base64 encoded.
|
|
25
27
|
* @param schemaVersion version of the schema provided. Must be supplied for schemas that use version 0 or 1, as they don't have the version embedded.
|
|
26
28
|
*/
|
|
27
|
-
sendTransaction(type: AccountTransactionType.UpdateSmartContractInstance | AccountTransactionType.InitializeSmartContractInstance, payload: AccountTransactionPayload, parameters: Record<string, unknown>, schema: string, schemaVersion?: SchemaVersion): Promise<string>;
|
|
29
|
+
sendTransaction(accountAddress: string, type: AccountTransactionType.UpdateSmartContractInstance | AccountTransactionType.InitializeSmartContractInstance, payload: AccountTransactionPayload, parameters: Record<string, unknown>, schema: string, schemaVersion?: SchemaVersion): Promise<string>;
|
|
28
30
|
/**
|
|
29
31
|
* Sends a transaction to the Concordium Wallet and awaits the users action. Note that a header is not sent, and will be constructed by the wallet itself.
|
|
30
32
|
* Note that if the user rejects signing the transaction, this will throw an error.
|
|
33
|
+
* @param accountAddress the address of the account that should sign the transaction
|
|
31
34
|
* @param type the type of transaction that is to be signed and sent.
|
|
32
35
|
* @param payload the payload of the transaction to be signed and sent.
|
|
33
36
|
*/
|
|
34
|
-
sendTransaction(type: AccountTransactionType, payload: AccountTransactionPayload): Promise<string>;
|
|
37
|
+
sendTransaction(accountAddress: string, type: AccountTransactionType, payload: AccountTransactionPayload): Promise<string>;
|
|
35
38
|
/**
|
|
36
39
|
* Sends a message to the Concordium Wallet and awaits the users action. If the user signs the message, this will resolve to the signature.
|
|
37
40
|
* Note that if the user rejects signing the message, this will throw an error.
|
|
41
|
+
* @param accountAddress the address of the account that should sign the message
|
|
38
42
|
* @param message message to be signed. Note that the wallet will prepend some bytes to ensure the message cannot be a transaction
|
|
39
43
|
*/
|
|
40
|
-
signMessage(message: string): Promise<AccountTransactionSignature>;
|
|
44
|
+
signMessage(accountAddress: string, message: string): Promise<AccountTransactionSignature>;
|
|
41
45
|
/**
|
|
42
46
|
* Requests a connection to the Concordium wallet, prompting the user to either accept or reject the request.
|
|
43
47
|
* If a connection has already been accepted for the url once the returned promise will resolve without prompting the user.
|
|
44
48
|
*/
|
|
45
49
|
connect(): Promise<string | undefined>;
|
|
50
|
+
/**
|
|
51
|
+
* Returns some connected account, prioritizing the most recently selected. Resolves with account address or undefined if there are no connected account.
|
|
52
|
+
*/
|
|
53
|
+
getMostRecentlySelectedAccount(): Promise<string | undefined>;
|
|
46
54
|
removeAllListeners(event?: EventType | string | undefined): this;
|
|
55
|
+
getJsonRpcClient(): JsonRpcClient;
|
|
47
56
|
}
|
|
48
57
|
export declare type WalletApi = MainWalletApi & EventListeners;
|
|
49
58
|
export {};
|
package/lib/wallet-api-types.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@concordium/browser-wallet-api-helpers",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"packageManager": "yarn@3.2.0",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"url": "https://concordium.com"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@concordium/web-sdk": "^0.
|
|
22
|
+
"@concordium/web-sdk": "^0.4.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@babel/core": "^7.17.10",
|