From 0be15040200f094d5123de69d80048b6775ab492 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6ren?= Date: Wed, 15 Jan 2025 16:55:48 +0100 Subject: [PATCH] Update SignMultisigTransaction flow to Albatross PoS SDK And latest multisig Keyguard client. --- client/PublicRequestTypes.ts | 18 +++-- client/dist/HubApi.es.js | 8 +++ client/dist/HubApi.umd.js | 8 +++ client/dist/src/HubApi.d.ts | 4 +- client/dist/src/PublicRequestTypes.d.ts | 66 +++++++++++++++++-- .../dist/standalone/HubApi.standalone.es.js | 2 +- .../dist/standalone/HubApi.standalone.umd.js | 2 +- package.json | 2 +- src/i18n/en.po | 9 +++ src/lib/RequestParser.ts | 28 ++++---- src/lib/RequestTypes.ts | 18 +++-- src/views/ConnectAccountSuccess.vue | 5 -- src/views/SignMultisigTransaction.vue | 2 +- yarn.lock | 4 +- 14 files changed, 124 insertions(+), 52 deletions(-) diff --git a/client/PublicRequestTypes.ts b/client/PublicRequestTypes.ts index 7c318988..67b1910b 100644 --- a/client/PublicRequestTypes.ts +++ b/client/PublicRequestTypes.ts @@ -260,16 +260,14 @@ export interface EncryptionKeyParams { export interface MultisigInfo { publicKeys: Bytes[]; - numberOfSigners: number; - signerPublicKeys?: Bytes[]; // Can be omitted when all publicKeys need to sign - secret: { - aggregatedSecret: Bytes; - } | { - encryptedSecrets: Bytes[]; - bScalar: Bytes; + signers: Array<{ + publicKey: Bytes; + commitments: Bytes[]; + }>; + secrets: Bytes[] | { + encrypted: Bytes[]; keyParams: EncryptionKeyParams; }; - aggregatedCommitment: Bytes; userName?: string; } @@ -277,10 +275,10 @@ export interface SignMultisigTransactionRequest extends BasicRequest { signer: string; // Address sender: string; - senderType?: Nimiq.Account.Type; + senderType?: Nimiq.AccountType; senderLabel: string; recipient: string; - recipientType?: Nimiq.Account.Type; + recipientType?: Nimiq.AccountType; recipientLabel?: string; value: number; fee?: number; diff --git a/client/dist/HubApi.es.js b/client/dist/HubApi.es.js index 9070a56e..a07b5f41 100644 --- a/client/dist/HubApi.es.js +++ b/client/dist/HubApi.es.js @@ -293,6 +293,7 @@ var RequestType; RequestType["CHECKOUT"] = "checkout"; RequestType["SIGN_MESSAGE"] = "sign-message"; RequestType["SIGN_TRANSACTION"] = "sign-transaction"; + RequestType["SIGN_MULTISIG_TRANSACTION"] = "sign-multisig-transaction"; RequestType["SIGN_STAKING"] = "sign-staking"; RequestType["ONBOARD"] = "onboard"; RequestType["SIGNUP"] = "signup"; @@ -313,6 +314,7 @@ var RequestType; RequestType["ACTIVATE_POLYGON"] = "activate-polygon"; RequestType["SETUP_SWAP"] = "setup-swap"; RequestType["REFUND_SWAP"] = "refund-swap"; + RequestType["CONNECT_ACCOUNT"] = "connect-account"; })(RequestType || (RequestType = {})); var AccountType; (function (AccountType) { @@ -438,6 +440,12 @@ class HubApi { refundSwap(request, requestBehavior = this._defaultBehavior) { return this._request(requestBehavior, RequestType.REFUND_SWAP, [request]); } + signMultisigTransaction(request, requestBehavior = this._defaultBehavior) { + return this._request(requestBehavior, RequestType.SIGN_MULTISIG_TRANSACTION, [request]); + } + connectAccount(request, requestBehavior = this._defaultBehavior) { + return this._request(requestBehavior, RequestType.CONNECT_ACCOUNT, [request]); + } /** * Account Management * diff --git a/client/dist/HubApi.umd.js b/client/dist/HubApi.umd.js index bb8c7ede..2397d31b 100644 --- a/client/dist/HubApi.umd.js +++ b/client/dist/HubApi.umd.js @@ -296,6 +296,7 @@ RequestType["CHECKOUT"] = "checkout"; RequestType["SIGN_MESSAGE"] = "sign-message"; RequestType["SIGN_TRANSACTION"] = "sign-transaction"; + RequestType["SIGN_MULTISIG_TRANSACTION"] = "sign-multisig-transaction"; RequestType["SIGN_STAKING"] = "sign-staking"; RequestType["ONBOARD"] = "onboard"; RequestType["SIGNUP"] = "signup"; @@ -316,6 +317,7 @@ RequestType["ACTIVATE_POLYGON"] = "activate-polygon"; RequestType["SETUP_SWAP"] = "setup-swap"; RequestType["REFUND_SWAP"] = "refund-swap"; + RequestType["CONNECT_ACCOUNT"] = "connect-account"; })(RequestType || (RequestType = {})); var AccountType; (function (AccountType) { @@ -441,6 +443,12 @@ refundSwap(request, requestBehavior = this._defaultBehavior) { return this._request(requestBehavior, RequestType.REFUND_SWAP, [request]); } + signMultisigTransaction(request, requestBehavior = this._defaultBehavior) { + return this._request(requestBehavior, RequestType.SIGN_MULTISIG_TRANSACTION, [request]); + } + connectAccount(request, requestBehavior = this._defaultBehavior) { + return this._request(requestBehavior, RequestType.CONNECT_ACCOUNT, [request]); + } /** * Account Management * diff --git a/client/dist/src/HubApi.d.ts b/client/dist/src/HubApi.d.ts index 4cb84bb8..968ed420 100644 --- a/client/dist/src/HubApi.d.ts +++ b/client/dist/src/HubApi.d.ts @@ -1,5 +1,5 @@ import { PopupRequestBehavior, RequestBehavior, RedirectRequestBehavior, BehaviorType } from './RequestBehavior'; -import { AccountType, RequestType, BasicRequest, SimpleRequest, OnboardRequest, ChooseAddressRequest, ChooseAddressResult, CheckoutRequest, SignTransactionRequest, RenameRequest, SignMessageRequest, ExportRequest, ResultByRequestType, Account, Address, SignedTransaction, SimpleResult, ExportResult, SignedMessage, CreateCashlinkRequest, ManageCashlinkRequest, SignBtcTransactionRequest, SignedBtcTransaction, AddBtcAddressesRequest, AddBtcAddressesResult, SignPolygonTransactionRequest, SignedPolygonTransaction, Cashlink, CashlinkState, CashlinkTheme, Currency, PaymentType, PaymentState, SetupSwapRequest, SetupSwapResult, RefundSwapRequest, SignStakingRequest } from './PublicRequestTypes'; +import { AccountType, RequestType, BasicRequest, SimpleRequest, OnboardRequest, ChooseAddressRequest, ChooseAddressResult, CheckoutRequest, SignTransactionRequest, RenameRequest, SignMessageRequest, ExportRequest, ResultByRequestType, Account, Address, SignedTransaction, SimpleResult, ExportResult, SignedMessage, CreateCashlinkRequest, ManageCashlinkRequest, SignBtcTransactionRequest, SignedBtcTransaction, AddBtcAddressesRequest, AddBtcAddressesResult, SignPolygonTransactionRequest, SignedPolygonTransaction, Cashlink, CashlinkState, CashlinkTheme, Currency, PaymentType, PaymentState, SetupSwapRequest, SetupSwapResult, RefundSwapRequest, SignMultisigTransactionRequest, PartialSignature, SignStakingRequest, ConnectAccountRequest, ConnectedAccount } from './PublicRequestTypes'; export default class HubApi { static readonly BehaviorType: typeof BehaviorType; static readonly RequestType: typeof RequestType; @@ -39,6 +39,8 @@ export default class HubApi(request: Promise | SignPolygonTransactionRequest, requestBehavior?: RequestBehavior): Promise; setupSwap(request: Promise | SetupSwapRequest, requestBehavior?: RequestBehavior): Promise; refundSwap(request: Promise | RefundSwapRequest, requestBehavior?: RequestBehavior): Promise; + signMultisigTransaction(request: Promise | SignMultisigTransactionRequest, requestBehavior?: RequestBehavior): Promise; + connectAccount(request: Promise | ConnectAccountRequest, requestBehavior?: RequestBehavior): Promise; /** * Account Management * diff --git a/client/dist/src/PublicRequestTypes.d.ts b/client/dist/src/PublicRequestTypes.d.ts index bd0e76ce..9ef9fc2f 100644 --- a/client/dist/src/PublicRequestTypes.d.ts +++ b/client/dist/src/PublicRequestTypes.d.ts @@ -8,6 +8,7 @@ export declare enum RequestType { CHECKOUT = "checkout", SIGN_MESSAGE = "sign-message", SIGN_TRANSACTION = "sign-transaction", + SIGN_MULTISIG_TRANSACTION = "sign-multisig-transaction", SIGN_STAKING = "sign-staking", ONBOARD = "onboard", SIGNUP = "signup", @@ -27,7 +28,8 @@ export declare enum RequestType { ACTIVATE_BITCOIN = "activate-bitcoin", ACTIVATE_POLYGON = "activate-polygon", SETUP_SWAP = "setup-swap", - REFUND_SWAP = "refund-swap" + REFUND_SWAP = "refund-swap", + CONNECT_ACCOUNT = "connect-account" } export declare type Bytes = Uint8Array | string; export declare enum AccountType { @@ -203,6 +205,38 @@ export interface SignedTransaction { proof: Uint8Array; }; } +export interface EncryptionKeyParams { + kdf: string; + iterations: number; + keySize: number; +} +export interface MultisigInfo { + publicKeys: Bytes[]; + signers: Array<{ + publicKey: Bytes; + commitments: Bytes[]; + }>; + secrets: Bytes[] | { + encrypted: Bytes[]; + keyParams: EncryptionKeyParams; + }; + userName?: string; +} +export interface SignMultisigTransactionRequest extends BasicRequest { + signer: string; + sender: string; + senderType?: Nimiq.AccountType; + senderLabel: string; + recipient: string; + recipientType?: Nimiq.AccountType; + recipientLabel?: string; + value: number; + fee?: number; + extraData?: Bytes; + flags?: number; + validityStartHeight: number; + multisigConfig: MultisigInfo; +} export interface NimiqHtlcCreationInstructions { type: 'NIM'; sender: string; @@ -384,6 +418,7 @@ export interface SignedMessage { signerPublicKey: Uint8Array; signature: Uint8Array; } +export declare type PartialSignature = SignedMessage; export interface Address { address: string; label: string; @@ -481,6 +516,29 @@ export declare type CreateCashlinkRequest = BasicRequest & { export interface ManageCashlinkRequest extends BasicRequest { cashlinkAddress: string; } +export interface ConnectAccountRequest extends BasicRequest { + appLogoUrl: string; + permissions: RequestType[]; + requestedKeyPaths: string[]; + challenge: string; +} +export interface ConnectedAccount { + signatures: SignedMessage[]; + encryptionKey: { + format: 'spki'; + keyData: Uint8Array; + algorithm: { + name: string; + hash: string; + }; + keyUsages: ['encrypt']; + keyParams: EncryptionKeyParams; + }; + account: { + label: string; + type: string; + }; +} /** * Bitcoin */ @@ -554,6 +612,6 @@ export interface SignedPolygonTransaction { message: Record; signature: string; } -export declare type RpcRequest = SignTransactionRequest | SignStakingRequest | CreateCashlinkRequest | ManageCashlinkRequest | CheckoutRequest | BasicRequest | SimpleRequest | ChooseAddressRequest | OnboardRequest | RenameRequest | SignMessageRequest | ExportRequest | SignBtcTransactionRequest | AddBtcAddressesRequest | SignPolygonTransactionRequest | SetupSwapRequest | RefundSwapRequest; -export declare type RpcResult = SignedTransaction | SignedTransaction[] | Account | Account[] | SimpleResult | ChooseAddressResult | Address | Cashlink | Cashlink[] | SignedMessage | ExportResult | SignedBtcTransaction | AddBtcAddressesResult | SignedPolygonTransaction | SetupSwapResult; -export declare type ResultByRequestType = T extends RequestType.RENAME ? Account : T extends RequestType.ONBOARD | RequestType.SIGNUP | RequestType.LOGIN | RequestType.MIGRATE | RequestType.LIST ? Account[] : T extends RequestType.LIST_CASHLINKS ? Cashlink[] : T extends RequestType.CHOOSE_ADDRESS ? ChooseAddressResult : T extends RequestType.ADD_ADDRESS ? Address : T extends RequestType.SIGN_TRANSACTION ? SignedTransaction : T extends RequestType.SIGN_STAKING ? SignedTransaction[] : T extends RequestType.CHECKOUT ? SignedTransaction | SimpleResult : T extends RequestType.SIGN_MESSAGE ? SignedMessage : T extends RequestType.LOGOUT | RequestType.CHANGE_PASSWORD ? SimpleResult : T extends RequestType.EXPORT ? ExportResult : T extends RequestType.CREATE_CASHLINK | RequestType.MANAGE_CASHLINK ? Cashlink : T extends RequestType.SIGN_BTC_TRANSACTION ? SignedBtcTransaction : T extends RequestType.SIGN_POLYGON_TRANSACTION ? SignedPolygonTransaction : T extends RequestType.ACTIVATE_BITCOIN ? Account : T extends RequestType.ACTIVATE_POLYGON ? Account : T extends RequestType.ADD_BTC_ADDRESSES ? AddBtcAddressesResult : T extends RequestType.SETUP_SWAP ? SetupSwapResult : never; +export declare type RpcRequest = SignTransactionRequest | SignMultisigTransactionRequest | SignStakingRequest | CreateCashlinkRequest | ManageCashlinkRequest | CheckoutRequest | BasicRequest | SimpleRequest | ChooseAddressRequest | OnboardRequest | RenameRequest | SignMessageRequest | ExportRequest | SignBtcTransactionRequest | AddBtcAddressesRequest | SignPolygonTransactionRequest | SetupSwapRequest | RefundSwapRequest | ConnectAccountRequest; +export declare type RpcResult = SignedTransaction | SignedTransaction[] | PartialSignature | Account | Account[] | SimpleResult | ChooseAddressResult | Address | Cashlink | Cashlink[] | SignedMessage | ExportResult | SignedBtcTransaction | AddBtcAddressesResult | SignedPolygonTransaction | SetupSwapResult | ConnectedAccount; +export declare type ResultByRequestType = T extends RequestType.RENAME ? Account : T extends RequestType.ONBOARD | RequestType.SIGNUP | RequestType.LOGIN | RequestType.MIGRATE | RequestType.LIST ? Account[] : T extends RequestType.LIST_CASHLINKS ? Cashlink[] : T extends RequestType.CHOOSE_ADDRESS ? ChooseAddressResult : T extends RequestType.ADD_ADDRESS ? Address : T extends RequestType.SIGN_TRANSACTION ? SignedTransaction : T extends RequestType.SIGN_MULTISIG_TRANSACTION ? PartialSignature : T extends RequestType.SIGN_STAKING ? SignedTransaction[] : T extends RequestType.CHECKOUT ? SignedTransaction | SimpleResult : T extends RequestType.SIGN_MESSAGE ? SignedMessage : T extends RequestType.LOGOUT | RequestType.CHANGE_PASSWORD ? SimpleResult : T extends RequestType.EXPORT ? ExportResult : T extends RequestType.CREATE_CASHLINK | RequestType.MANAGE_CASHLINK ? Cashlink : T extends RequestType.SIGN_BTC_TRANSACTION ? SignedBtcTransaction : T extends RequestType.SIGN_POLYGON_TRANSACTION ? SignedPolygonTransaction : T extends RequestType.ACTIVATE_BITCOIN ? Account : T extends RequestType.ACTIVATE_POLYGON ? Account : T extends RequestType.ADD_BTC_ADDRESSES ? AddBtcAddressesResult : T extends RequestType.SETUP_SWAP ? SetupSwapResult : T extends RequestType.CONNECT_ACCOUNT ? ConnectedAccount : never; diff --git a/client/dist/standalone/HubApi.standalone.es.js b/client/dist/standalone/HubApi.standalone.es.js index 49904330..8f5eef21 100644 --- a/client/dist/standalone/HubApi.standalone.es.js +++ b/client/dist/standalone/HubApi.standalone.es.js @@ -1 +1 @@ -class e{static byteLength(t){const[r,s]=e._getLengths(t);return e._byteLength(r,s)}static decode(t){e._initRevLookup();const[r,s]=e._getLengths(t),i=new Uint8Array(e._byteLength(r,s));let n=0;const o=s>0?r-4:r;let a=0;for(;a>16&255,i[n++]=r>>8&255,i[n++]=255&r}if(2===s){const r=e._revLookup[t.charCodeAt(a)]<<2|e._revLookup[t.charCodeAt(a+1)]>>4;i[n++]=255&r}if(1===s){const r=e._revLookup[t.charCodeAt(a)]<<10|e._revLookup[t.charCodeAt(a+1)]<<4|e._revLookup[t.charCodeAt(a+2)]>>2;i[n++]=r>>8&255,i[n]=255&r}return i}static encode(t){const r=t.length,s=r%3,i=[];for(let n=0,o=r-s;no?o:n+16383));if(1===s){const s=t[r-1];i.push(e._lookup[s>>2]+e._lookup[s<<4&63]+"==")}else if(2===s){const s=(t[r-2]<<8)+t[r-1];i.push(e._lookup[s>>10]+e._lookup[s>>4&63]+e._lookup[s<<2&63]+"=")}return i.join("")}static encodeUrl(t){return e.encode(t).replace(/\//g,"_").replace(/\+/g,"-").replace(/=/g,".")}static decodeUrl(t){return e.decode(t.replace(/_/g,"/").replace(/-/g,"+").replace(/\./g,"="))}static _initRevLookup(){if(0===e._revLookup.length){e._revLookup=[];for(let t=0,r=e._lookup.length;t0)throw new Error("Invalid string. Length must be a multiple of 4");let r=e.indexOf("=");return-1===r&&(r=t),[r,r===t?0:4-r%4]}static _byteLength(e,t){return 3*(e+t)/4-t}static _tripletToBase64(t){return e._lookup[t>>18&63]+e._lookup[t>>12&63]+e._lookup[t>>6&63]+e._lookup[63&t]}static _encodeChunk(t,r,s){const i=[];for(let n=r;nthis._checkIfServerClosed(),300)))}async call(e,...t){return this._call({command:e,args:t,id:n.generateRandomId()})}close(){this._connectionState=0,window.removeEventListener("message",this._receiveListener),window.clearInterval(this._serverCloseCheckInterval),this._serverCloseCheckInterval=-1;for(const[e,{reject:t}]of this._responseHandlers){const r=this._waitingRequests.getState(e);t("Connection was closed","number"==typeof e?e:void 0,r)}this._waitingRequests.clear(),this._responseHandlers.clear(),this._target&&this._target.closed&&(this._target=null)}_receive(e){return e.source===this._target&&super._receive(e)}async _call(e){if(!this._target||this._target.closed)throw new Error("Connection was closed.");if(2!==this._connectionState)throw new Error("Client is not connected, call init first");return new Promise((t,r)=>{this._responseHandlers.set(e.id,{resolve:t,reject:r}),this._waitingRequests.add(e.id,e.command),console.debug("RpcClient REQUEST",e.command,e.args),this._target.postMessage(e,this._allowedOrigin)})}_connect(){if(2!==this._connectionState)return this._connectionState=1,new Promise((e,t)=>{const r=t=>{const{source:i,origin:n,data:o}=t;if(i===this._target&&o.status===s.OK&&"pong"===o.result&&1===o.id&&("*"===this._allowedOrigin||n===this._allowedOrigin)){if(o.result.stack){const e=new Error(o.result.message);e.stack=o.result.stack,o.result.name&&(e.name=o.result.name),console.error(e)}window.removeEventListener("message",r),this._connectionState=2,console.log("RpcClient: Connection established"),e(!0)}};window.addEventListener("message",r);const i=()=>{if(2!==this._connectionState){if(0===this._connectionState||this._checkIfServerClosed())return window.removeEventListener("message",r),void t(new Error("Connection was closed"));try{this._target.postMessage({command:"ping",id:1},this._allowedOrigin)}catch(e){console.error(`postMessage failed: ${e}`)}window.setTimeout(i,100)}};window.setTimeout(i,100)})}_checkIfServerClosed(){return!(this._target&&!this._target.closed)&&(this.close(),!0)}}class h extends c{constructor(e,t,r=!0){super(t,!0),this._target=e,this._preserveRequests=r}async init(){const e=a.receiveRedirectResponse(window.location);if(e)return void this._receive(e);if(this._rejectOnBack())return;const t=new URLSearchParams(window.location.search);if(t.has(a.URL_SEARCHPARAM_NAME)){const e=window.sessionStorage.getItem(`response-${t.get(a.URL_SEARCHPARAM_NAME)}`);if(e)return void this._receive(i.parse(e),!1)}}close(){}call(e,t,s,...i){if(s&&"boolean"!=typeof s){if("object"==typeof s){if(s.responseMethod===r.POST_MESSAGE){if(!window.opener&&!window.parent)throw new Error("Window has no opener or parent, responseMethod: ResponseMethod.POST_MESSAGE would fail.");console.warn("Response will skip at least one rpc call, which will result in an unknown response.")}this._call(e,t,s,...i)}}else"boolean"==typeof s&&console.warn("RedirectRpcClient.call(string, string, boolean, any[]) is deprecated. Use RedirectRpcClient.call(string, string, CallOptions, any[]) with an appropriate CallOptions object instead."),this._call(e,t,{responseMethod:r.HTTP_GET,handleHistoryBack:!!s},...i)}callAndSaveLocalState(e,t,s,i=!1,...n){console.warn("RedirectRpcClient.callAndSaveLocalState() is deprecated. Use RedirectRpcClient.call() with an apropriate CallOptions object instead."),this._call(e,s,{responseMethod:r.HTTP_GET,state:t||void 0,handleHistoryBack:i},...n)}_receive(e,t=!0){const r=super._receive(e);return r&&t&&window.sessionStorage.setItem(`response-${e.data.id}`,i.stringify(e)),r}_call(e,t,s,...i){const o=n.generateRandomId(),c=s.responseMethod||r.HTTP_GET,l=a.prepareRedirectInvocation(this._target,o,e,t,i,c);this._waitingRequests.add(o,t,s.state||null),s.handleHistoryBack&&history.replaceState(Object.assign({},history.state,{rpcBackRejectionId:o}),""),console.debug("RpcClient REQUEST",t,i),window.location.href=l}_rejectOnBack(){if(!history.state||!history.state.rpcBackRejectionId)return!1;const e=history.state.rpcBackRejectionId;history.replaceState(Object.assign({},history.state,{rpcBackRejectionId:null}),"");const t=this._getCallback(e),r=this._waitingRequests.getState(e);if(t){this._preserveRequests||(this._waitingRequests.remove(e),this._responseHandlers.delete(e)),console.debug("RpcClient BACK");const s=new Error("Request aborted");return t.reject(s,e,r),!0}return!1}}class d{static getBrowserInfo(){return{browser:d.detectBrowser(),version:d.detectVersion(),isMobile:d.isMobile()}}static isMobile(){return/i?Phone|iP(ad|od)|Android|BlackBerry|Opera Mini|WPDesktop|Mobi(le)?|Silk/i.test(navigator.userAgent)}static detectBrowser(){if(d._detectedBrowser)return d._detectedBrowser;const e=navigator.userAgent;return/Edge\//i.test(e)?d._detectedBrowser=d.Browser.EDGE:/(Opera|OPR)\//i.test(e)?d._detectedBrowser=d.Browser.OPERA:/Firefox\//i.test(e)?d._detectedBrowser=d.Browser.FIREFOX:/Chrome\//i.test(e)?d._detectedBrowser=0!==navigator.plugins.length||0!==navigator.mimeTypes.length||d.isMobile()?d.Browser.CHROME:d.Browser.BRAVE:/^((?!chrome|android).)*safari/i.test(e)?d._detectedBrowser=d.Browser.SAFARI:d._detectedBrowser=d.Browser.UNKNOWN,d._detectedBrowser}static detectVersion(){if(void 0!==d._detectedVersion)return d._detectedVersion;let e;switch(d.detectBrowser()){case d.Browser.EDGE:e=/Edge\/(\S+)/i;break;case d.Browser.OPERA:e=/(Opera|OPR)\/(\S+)/i;break;case d.Browser.FIREFOX:e=/Firefox\/(\S+)/i;break;case d.Browser.CHROME:e=/Chrome\/(\S+)/i;break;case d.Browser.SAFARI:e=/(iP(hone|ad|od).*?OS |Version\/)(\S+)/i;break;case d.Browser.BRAVE:default:return d._detectedVersion=null,null}const t=navigator.userAgent.match(e);if(!t)return d._detectedVersion=null,null;const r=t[t.length-1].replace(/_/g,"."),s=r.split("."),i=[];for(let e=0;e<4;++e)i.push(parseInt(s[e],10)||0);const[n,o,a,c]=i;return d._detectedVersion={versionString:r,major:n,minor:o,build:a,patch:c},d._detectedVersion}static isChrome(){return d.detectBrowser()===d.Browser.CHROME}static isFirefox(){return d.detectBrowser()===d.Browser.FIREFOX}static isOpera(){return d.detectBrowser()===d.Browser.OPERA}static isEdge(){return d.detectBrowser()===d.Browser.EDGE}static isSafari(){return d.detectBrowser()===d.Browser.SAFARI}static isBrave(){return d.detectBrowser()===d.Browser.BRAVE}static isIOS(){return/iPad|iPhone|iPod/.test(navigator.userAgent)&&!window.MSStream}static isBadIOS(){const e=d.getBrowserInfo();return e.browser===d.Browser.SAFARI&&e.isMobile&&e.version&&(e.version.major<11||11===e.version.major&&2===e.version.minor)}static isPrivateMode(){return new Promise(e=>{const t=()=>e(!0),r=()=>e(!1);if(window.webkitRequestFileSystem)window.webkitRequestFileSystem(0,0,r,t);else{if(document.documentElement&&"MozAppearance"in document.documentElement.style){const e=indexedDB.open(null);return e.onerror=t,void(e.onsuccess=r)}if((()=>/Constructor/.test(window.HTMLElement)||window.safari&&window.safari.pushNotification&&"[object SafariRemoteNotification]"===window.safari.pushNotification.toString())())try{window.openDatabase(null,null,null,null)}catch(e){return void t()}window.indexedDB||!window.PointerEvent&&!window.MSPointerEvent?r():t()}})}}!function(e){let t;!function(e){e.CHROME="chrome",e.FIREFOX="firefox",e.OPERA="opera",e.EDGE="edge",e.SAFARI="safari",e.BRAVE="brave",e.UNKNOWN="unknown"}(t=e.Browser||(e.Browser={}))}(d||(d={}));var u=d,p={"popup-overlay":"A popup has been opened,\nclick anywhere to bring it back to the front."};const _={de:{"popup-overlay":"Ein Popup hat sich geöffnet,\nklicke hier, um zurück zum Popup zu kommen."},en:p,es:{"popup-overlay":"Se ha abierto una ventana emergente.\nHaga click en cualquier lugar para traer la ventana al primer plano."},fil:{"popup-overlay":"Nag-bukas ang isang pop-up.\nMaaring pindutin kahit saan para ibalik ito sa harap."},fr:{"popup-overlay":"Une popup a été ouverte,\ncliquez n'importe où pour la ramener au premier plan."},nl:{"popup-overlay":"Er is een pop-up geopend,\nklik op het scherm om het weer naar voren te brengen."},pl:{"popup-overlay":"Pojawiło się wyskakujące okno.\nAby je zobaczyć, kliknij w dowolnym miejscu."},pt:{"popup-overlay":"Um popup foi aberto,\nclique em qualquer lado para o trazer para a frente."},ru:{"popup-overlay":"Открыто всплывающее окно.\nНажмите где-нибудь, чтобы вернуть его на передний план."},tr:{"popup-overlay":"Bir popup penceresi açıldı,\nöne çekmek için herhangi bir yere tıkla. "},uk:{"popup-overlay":"Відкрито випадаюче вікно.\nклацніть будь-де щоб перейти до ньго."},zh:{"popup-overlay":"弹出窗口已打开,\n单击任意位置即可回到上一页"}};class w{constructor(e){this._type=e}static getAllowedOrigin(e){return new URL(e).origin}async request(e,t,r){throw new Error("Not implemented")}}var g,R,A,m,E,S,v,f;!function(e){e[e.REDIRECT=0]="REDIRECT",e[e.POPUP=1]="POPUP",e[e.IFRAME=2]="IFRAME"}(g||(g={}));class I extends w{constructor(e,t){super(g.REDIRECT);const r=window.location;if(this._returnUrl=e||`${r.origin}${r.pathname}`,this._localState=t||{},void 0!==this._localState.__command)throw new Error("Invalid localState: Property '__command' is reserved")}static withLocalState(e){return new I(void 0,e)}async request(e,t,r){const s=w.getAllowedOrigin(e),i=new h(e,s);await i.init();const n=Object.assign({},this._localState,{__command:t});i.callAndSaveLocalState(this._returnUrl,n,t,!0,...await Promise.all(r))}}class y extends w{constructor(e=y.DEFAULT_FEATURES,t){super(g.POPUP),this.shouldRetryRequest=!1,this._popupFeatures=e,this._options={...y.DEFAULT_OPTIONS,...t}}async request(e,t,r){const s=w.getAllowedOrigin(e),i=this.appendOverlay();do{this.shouldRetryRequest=!1;try{return this.popup=this.createPopup(e),this.client=new l(this.popup,s),await this.client.init(),await this.client.call(t,...await Promise.all(r))}catch(e){if(!this.shouldRetryRequest)throw e}finally{this.shouldRetryRequest||(this.removeOverlay(i),this.client&&this.client.close(),this.popup&&this.popup.close())}}while(this.shouldRetryRequest);throw this.popup&&this.popup.close(),this.client&&this.client.close(),i&&this.removeOverlay(i),new Error("Unexpected error occurred")}createPopup(e){const t=window.open(e,"NimiqAccounts",this._popupFeatures);if(!t)throw new Error("Failed to open popup");return t}appendOverlay(){if(!this._options.overlay)return null;const e=document.createElement.bind(document),t=(e,t)=>e.appendChild(t),r=e("div");r.id="nimiq-hub-overlay";const s=r.style;s.position="fixed",s.top="0",s.right="0",s.bottom="0",s.left="0",s.background="rgba(31, 35, 72, 0.8)",s.display="flex",s.flexDirection="column",s.alignItems="center",s.justifyContent="space-between",s.cursor="pointer",s.color="white",s.textAlign="center",s.opacity="0",s.transition="opacity 0.6s ease",s.zIndex="99999",r.addEventListener("click",()=>{u.isIOS()?(this.shouldRetryRequest=!0,this.popup&&this.popup.close(),this.client&&this.client.close()):this.popup&&this.popup.focus()}),t(r,e("div"));const i=e("div");i.textContent=function(e,t){if(!t){const e=document.cookie.match(/(^| )lang=([^;]+)/);t=e&&e[2]||navigator.language.split("-")[0]}return(_[t]||p)[e]||p[e]}("popup-overlay");const n=i.style;n.padding="20px",n.fontFamily='Muli, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif',n.fontSize="24px",n.fontWeight="600",n.lineHeight="40px",n.whiteSpace="pre-line",t(r,i);const o=e("img");o.src='data:image/svg+xml,',o.style.marginBottom="56px",t(r,o);const a=e("div"),c=a.style;return a.innerHTML="×",c.position="absolute",c.top="8px",c.right="8px",c.fontSize="24px",c.lineHeight="32px",c.fontWeight="600",c.width="32px",c.height="32px",c.opacity="0.8",a.addEventListener("click",e=>{this.popup&&this.popup.close(),e.stopPropagation()}),t(r,a),setTimeout(()=>r.style.opacity="1",100),t(document.body,r)}removeOverlay(e){e&&(e.style.opacity="0",setTimeout(()=>document.body.removeChild(e),400))}}y.DEFAULT_FEATURES="",y.DEFAULT_OPTIONS={overlay:!0};class C extends w{constructor(){super(g.IFRAME),this._iframe=null,this._client=null}async request(e,t,r){if(this._iframe&&this._iframe.src!==`${e}${C.IFRAME_PATH_SUFFIX}`)throw new Error("Hub iframe is already opened with another endpoint");const s=w.getAllowedOrigin(e);if(this._iframe||(this._iframe=await this.createIFrame(e)),!this._iframe.contentWindow)throw new Error(`IFrame contentWindow is ${typeof this._iframe.contentWindow}`);return this._client||(this._client=new l(this._iframe.contentWindow,s),await this._client.init()),await this._client.call(t,...await Promise.all(r))}async createIFrame(e){return new Promise((t,r)=>{const s=document.createElement("iframe");s.name="NimiqAccountsIFrame",s.style.display="none",document.body.appendChild(s),s.src=`${e}${C.IFRAME_PATH_SUFFIX}`,s.onload=(()=>t(s)),s.onerror=r})}}C.IFRAME_PATH_SUFFIX="/iframe.html",function(e){e.LIST="list",e.LIST_CASHLINKS="list-cashlinks",e.MIGRATE="migrate",e.CHECKOUT="checkout",e.SIGN_MESSAGE="sign-message",e.SIGN_TRANSACTION="sign-transaction",e.SIGN_STAKING="sign-staking",e.ONBOARD="onboard",e.SIGNUP="signup",e.LOGIN="login",e.EXPORT="export",e.CHANGE_PASSWORD="change-password",e.LOGOUT="logout",e.ADD_ADDRESS="add-address",e.RENAME="rename",e.ADD_VESTING_CONTRACT="add-vesting-contract",e.CHOOSE_ADDRESS="choose-address",e.CREATE_CASHLINK="create-cashlink",e.MANAGE_CASHLINK="manage-cashlink",e.SIGN_BTC_TRANSACTION="sign-btc-transaction",e.ADD_BTC_ADDRESSES="add-btc-addresses",e.SIGN_POLYGON_TRANSACTION="sign-polygon-transaction",e.ACTIVATE_BITCOIN="activate-bitcoin",e.ACTIVATE_POLYGON="activate-polygon",e.SETUP_SWAP="setup-swap",e.REFUND_SWAP="refund-swap"}(R||(R={})),function(e){e[e.LEGACY=1]="LEGACY",e[e.BIP39=2]="BIP39",e[e.LEDGER=3]="LEDGER"}(A||(A={})),function(e){e[e.DIRECT=0]="DIRECT",e[e.OASIS=1]="OASIS"}(m||(m={})),function(e){e.NIM="nim",e.BTC="btc",e.ETH="eth"}(E||(E={})),function(e){e.NOT_FOUND="NOT_FOUND",e.PAID="PAID",e.UNDERPAID="UNDERPAID",e.OVERPAID="OVERPAID"}(S||(S={})),function(e){e[e.UNKNOWN=-1]="UNKNOWN",e[e.UNCHARGED=0]="UNCHARGED",e[e.CHARGING=1]="CHARGING",e[e.UNCLAIMED=2]="UNCLAIMED",e[e.CLAIMING=3]="CLAIMING",e[e.CLAIMED=4]="CLAIMED"}(v||(v={})),function(e){e[e.UNSPECIFIED=0]="UNSPECIFIED",e[e.STANDARD=1]="STANDARD",e[e.CHRISTMAS=2]="CHRISTMAS",e[e.LUNAR_NEW_YEAR=3]="LUNAR_NEW_YEAR",e[e.EASTER=4]="EASTER",e[e.GENERIC=5]="GENERIC",e[e.BIRTHDAY=6]="BIRTHDAY"}(f||(f={}));class O{constructor(e=O.DEFAULT_ENDPOINT,t){this._endpoint=e,this._defaultBehavior=t||new y(`left=${window.innerWidth/2-400},top=75,width=800,height=850,location=yes,dependent=yes`),this._checkoutDefaultBehavior=t||new y(`left=${window.innerWidth/2-400},top=50,width=800,height=895,location=yes,dependent=yes`),this._iframeBehavior=new C,this._redirectClient=new h("",w.getAllowedOrigin(this._endpoint))}static get PaymentMethod(){return console.warn("PaymentMethod has been renamed to PaymentType. Access via HubApi.PaymentMethod will soon get disabled. Use HubApi.PaymentType instead."),m}static get DEFAULT_ENDPOINT(){const e=location.hostname.match(/(?:[^.]+\.[^.]+|localhost)$/),t=e?e[0]:location.hostname;switch(t){case"nimiq.com":case"nimiq-testnet.com":return`https://hub.${t}`;case"bs-local.com":return`${window.location.protocol}//bs-local.com:8080`;default:return"http://localhost:8080"}}checkRedirectResponse(){return this._redirectClient.init()}on(e,t,r){this._redirectClient.onResponse(e,(e,r,s)=>t(e,s),(e,t,s)=>{r&&r(e,s)})}createCashlink(e,t=this._defaultBehavior){return this._request(t,R.CREATE_CASHLINK,[e])}manageCashlink(e,t=this._defaultBehavior){return this._request(t,R.MANAGE_CASHLINK,[e])}checkout(e,t=this._checkoutDefaultBehavior){return this._request(t,R.CHECKOUT,[e])}chooseAddress(e,t=this._defaultBehavior){return this._request(t,R.CHOOSE_ADDRESS,[e])}signTransaction(e,t=this._defaultBehavior){return this._request(t,R.SIGN_TRANSACTION,[e])}signStaking(e,t=this._defaultBehavior){return this._request(t,R.SIGN_STAKING,[e])}signMessage(e,t=this._defaultBehavior){return this._request(t,R.SIGN_MESSAGE,[e])}signBtcTransaction(e,t=this._defaultBehavior){return this._request(t,R.SIGN_BTC_TRANSACTION,[e])}signPolygonTransaction(e,t=this._defaultBehavior){return this._request(t,R.SIGN_POLYGON_TRANSACTION,[e])}setupSwap(e,t=this._defaultBehavior){return this._request(t,R.SETUP_SWAP,[e])}refundSwap(e,t=this._defaultBehavior){return this._request(t,R.REFUND_SWAP,[e])}onboard(e,t=this._defaultBehavior){return this._request(t,R.ONBOARD,[e])}signup(e,t=this._defaultBehavior){return this._request(t,R.SIGNUP,[e])}login(e,t=this._defaultBehavior){return this._request(t,R.LOGIN,[e])}logout(e,t=this._defaultBehavior){return this._request(t,R.LOGOUT,[e])}export(e,t=this._defaultBehavior){return this._request(t,R.EXPORT,[e])}changePassword(e,t=this._defaultBehavior){return this._request(t,R.CHANGE_PASSWORD,[e])}addAddress(e,t=this._defaultBehavior){return this._request(t,R.ADD_ADDRESS,[e])}rename(e,t=this._defaultBehavior){return this._request(t,R.RENAME,[e])}addVestingContract(e,t=this._defaultBehavior){return this._request(t,R.ADD_VESTING_CONTRACT,[e])}migrate(e=this._defaultBehavior){return this._request(e,R.MIGRATE,[{appName:"Account list"}])}activateBitcoin(e,t=this._defaultBehavior){return this._request(t,R.ACTIVATE_BITCOIN,[e])}activatePolygon(e,t=this._defaultBehavior){return this._request(t,R.ACTIVATE_POLYGON,[e])}list(e=this._iframeBehavior){return this._request(e,R.LIST,[])}cashlinks(e=this._iframeBehavior){return this._request(e,R.LIST_CASHLINKS,[])}addBtcAddresses(e,t=this._iframeBehavior){return this._request(t,R.ADD_BTC_ADDRESSES,[e])}_request(e,t,r){return e.request(this._endpoint,t,r)}}O.BehaviorType=g,O.RequestType=R,O.RedirectRequestBehavior=I,O.PopupRequestBehavior=y,O.AccountType=A,O.CashlinkState=v,O.CashlinkTheme=f,O.Currency=E,O.PaymentType=m,O.PaymentState=S,O.MSG_PREFIX="Nimiq Signed Message:\n";export default O; +class e{static byteLength(t){const[r,s]=e._getLengths(t);return e._byteLength(r,s)}static decode(t){e._initRevLookup();const[r,s]=e._getLengths(t),i=new Uint8Array(e._byteLength(r,s));let n=0;const o=s>0?r-4:r;let a=0;for(;a>16&255,i[n++]=r>>8&255,i[n++]=255&r}if(2===s){const r=e._revLookup[t.charCodeAt(a)]<<2|e._revLookup[t.charCodeAt(a+1)]>>4;i[n++]=255&r}if(1===s){const r=e._revLookup[t.charCodeAt(a)]<<10|e._revLookup[t.charCodeAt(a+1)]<<4|e._revLookup[t.charCodeAt(a+2)]>>2;i[n++]=r>>8&255,i[n]=255&r}return i}static encode(t){const r=t.length,s=r%3,i=[];for(let n=0,o=r-s;no?o:n+16383));if(1===s){const s=t[r-1];i.push(e._lookup[s>>2]+e._lookup[s<<4&63]+"==")}else if(2===s){const s=(t[r-2]<<8)+t[r-1];i.push(e._lookup[s>>10]+e._lookup[s>>4&63]+e._lookup[s<<2&63]+"=")}return i.join("")}static encodeUrl(t){return e.encode(t).replace(/\//g,"_").replace(/\+/g,"-").replace(/=/g,".")}static decodeUrl(t){return e.decode(t.replace(/_/g,"/").replace(/-/g,"+").replace(/\./g,"="))}static _initRevLookup(){if(0===e._revLookup.length){e._revLookup=[];for(let t=0,r=e._lookup.length;t0)throw new Error("Invalid string. Length must be a multiple of 4");let r=e.indexOf("=");return-1===r&&(r=t),[r,r===t?0:4-r%4]}static _byteLength(e,t){return 3*(e+t)/4-t}static _tripletToBase64(t){return e._lookup[t>>18&63]+e._lookup[t>>12&63]+e._lookup[t>>6&63]+e._lookup[63&t]}static _encodeChunk(t,r,s){const i=[];for(let n=r;nthis._checkIfServerClosed(),300)))}async call(e,...t){return this._call({command:e,args:t,id:n.generateRandomId()})}close(){this._connectionState=0,window.removeEventListener("message",this._receiveListener),window.clearInterval(this._serverCloseCheckInterval),this._serverCloseCheckInterval=-1;for(const[e,{reject:t}]of this._responseHandlers){const r=this._waitingRequests.getState(e);t("Connection was closed","number"==typeof e?e:void 0,r)}this._waitingRequests.clear(),this._responseHandlers.clear(),this._target&&this._target.closed&&(this._target=null)}_receive(e){return e.source===this._target&&super._receive(e)}async _call(e){if(!this._target||this._target.closed)throw new Error("Connection was closed.");if(2!==this._connectionState)throw new Error("Client is not connected, call init first");return new Promise((t,r)=>{this._responseHandlers.set(e.id,{resolve:t,reject:r}),this._waitingRequests.add(e.id,e.command),console.debug("RpcClient REQUEST",e.command,e.args),this._target.postMessage(e,this._allowedOrigin)})}_connect(){if(2!==this._connectionState)return this._connectionState=1,new Promise((e,t)=>{const r=t=>{const{source:i,origin:n,data:o}=t;if(i===this._target&&o.status===s.OK&&"pong"===o.result&&1===o.id&&("*"===this._allowedOrigin||n===this._allowedOrigin)){if(o.result.stack){const e=new Error(o.result.message);e.stack=o.result.stack,o.result.name&&(e.name=o.result.name),console.error(e)}window.removeEventListener("message",r),this._connectionState=2,console.log("RpcClient: Connection established"),e(!0)}};window.addEventListener("message",r);const i=()=>{if(2!==this._connectionState){if(0===this._connectionState||this._checkIfServerClosed())return window.removeEventListener("message",r),void t(new Error("Connection was closed"));try{this._target.postMessage({command:"ping",id:1},this._allowedOrigin)}catch(e){console.error(`postMessage failed: ${e}`)}window.setTimeout(i,100)}};window.setTimeout(i,100)})}_checkIfServerClosed(){return!(this._target&&!this._target.closed)&&(this.close(),!0)}}class h extends c{constructor(e,t,r=!0){super(t,!0),this._target=e,this._preserveRequests=r}async init(){const e=a.receiveRedirectResponse(window.location);if(e)return void this._receive(e);if(this._rejectOnBack())return;const t=new URLSearchParams(window.location.search);if(t.has(a.URL_SEARCHPARAM_NAME)){const e=window.sessionStorage.getItem(`response-${t.get(a.URL_SEARCHPARAM_NAME)}`);if(e)return void this._receive(i.parse(e),!1)}}close(){}call(e,t,s,...i){if(s&&"boolean"!=typeof s){if("object"==typeof s){if(s.responseMethod===r.POST_MESSAGE){if(!window.opener&&!window.parent)throw new Error("Window has no opener or parent, responseMethod: ResponseMethod.POST_MESSAGE would fail.");console.warn("Response will skip at least one rpc call, which will result in an unknown response.")}this._call(e,t,s,...i)}}else"boolean"==typeof s&&console.warn("RedirectRpcClient.call(string, string, boolean, any[]) is deprecated. Use RedirectRpcClient.call(string, string, CallOptions, any[]) with an appropriate CallOptions object instead."),this._call(e,t,{responseMethod:r.HTTP_GET,handleHistoryBack:!!s},...i)}callAndSaveLocalState(e,t,s,i=!1,...n){console.warn("RedirectRpcClient.callAndSaveLocalState() is deprecated. Use RedirectRpcClient.call() with an apropriate CallOptions object instead."),this._call(e,s,{responseMethod:r.HTTP_GET,state:t||void 0,handleHistoryBack:i},...n)}_receive(e,t=!0){const r=super._receive(e);return r&&t&&window.sessionStorage.setItem(`response-${e.data.id}`,i.stringify(e)),r}_call(e,t,s,...i){const o=n.generateRandomId(),c=s.responseMethod||r.HTTP_GET,l=a.prepareRedirectInvocation(this._target,o,e,t,i,c);this._waitingRequests.add(o,t,s.state||null),s.handleHistoryBack&&history.replaceState(Object.assign({},history.state,{rpcBackRejectionId:o}),""),console.debug("RpcClient REQUEST",t,i),window.location.href=l}_rejectOnBack(){if(!history.state||!history.state.rpcBackRejectionId)return!1;const e=history.state.rpcBackRejectionId;history.replaceState(Object.assign({},history.state,{rpcBackRejectionId:null}),"");const t=this._getCallback(e),r=this._waitingRequests.getState(e);if(t){this._preserveRequests||(this._waitingRequests.remove(e),this._responseHandlers.delete(e)),console.debug("RpcClient BACK");const s=new Error("Request aborted");return t.reject(s,e,r),!0}return!1}}class d{static getBrowserInfo(){return{browser:d.detectBrowser(),version:d.detectVersion(),isMobile:d.isMobile()}}static isMobile(){return/i?Phone|iP(ad|od)|Android|BlackBerry|Opera Mini|WPDesktop|Mobi(le)?|Silk/i.test(navigator.userAgent)}static detectBrowser(){if(d._detectedBrowser)return d._detectedBrowser;const e=navigator.userAgent;return/Edge\//i.test(e)?d._detectedBrowser=d.Browser.EDGE:/(Opera|OPR)\//i.test(e)?d._detectedBrowser=d.Browser.OPERA:/Firefox\//i.test(e)?d._detectedBrowser=d.Browser.FIREFOX:/Chrome\//i.test(e)?d._detectedBrowser=0!==navigator.plugins.length||0!==navigator.mimeTypes.length||d.isMobile()?d.Browser.CHROME:d.Browser.BRAVE:/^((?!chrome|android).)*safari/i.test(e)?d._detectedBrowser=d.Browser.SAFARI:d._detectedBrowser=d.Browser.UNKNOWN,d._detectedBrowser}static detectVersion(){if(void 0!==d._detectedVersion)return d._detectedVersion;let e;switch(d.detectBrowser()){case d.Browser.EDGE:e=/Edge\/(\S+)/i;break;case d.Browser.OPERA:e=/(Opera|OPR)\/(\S+)/i;break;case d.Browser.FIREFOX:e=/Firefox\/(\S+)/i;break;case d.Browser.CHROME:e=/Chrome\/(\S+)/i;break;case d.Browser.SAFARI:e=/(iP(hone|ad|od).*?OS |Version\/)(\S+)/i;break;case d.Browser.BRAVE:default:return d._detectedVersion=null,null}const t=navigator.userAgent.match(e);if(!t)return d._detectedVersion=null,null;const r=t[t.length-1].replace(/_/g,"."),s=r.split("."),i=[];for(let e=0;e<4;++e)i.push(parseInt(s[e],10)||0);const[n,o,a,c]=i;return d._detectedVersion={versionString:r,major:n,minor:o,build:a,patch:c},d._detectedVersion}static isChrome(){return d.detectBrowser()===d.Browser.CHROME}static isFirefox(){return d.detectBrowser()===d.Browser.FIREFOX}static isOpera(){return d.detectBrowser()===d.Browser.OPERA}static isEdge(){return d.detectBrowser()===d.Browser.EDGE}static isSafari(){return d.detectBrowser()===d.Browser.SAFARI}static isBrave(){return d.detectBrowser()===d.Browser.BRAVE}static isIOS(){return/iPad|iPhone|iPod/.test(navigator.userAgent)&&!window.MSStream}static isBadIOS(){const e=d.getBrowserInfo();return e.browser===d.Browser.SAFARI&&e.isMobile&&e.version&&(e.version.major<11||11===e.version.major&&2===e.version.minor)}static isPrivateMode(){return new Promise(e=>{const t=()=>e(!0),r=()=>e(!1);if(window.webkitRequestFileSystem)window.webkitRequestFileSystem(0,0,r,t);else{if(document.documentElement&&"MozAppearance"in document.documentElement.style){const e=indexedDB.open(null);return e.onerror=t,void(e.onsuccess=r)}if((()=>/Constructor/.test(window.HTMLElement)||window.safari&&window.safari.pushNotification&&"[object SafariRemoteNotification]"===window.safari.pushNotification.toString())())try{window.openDatabase(null,null,null,null)}catch(e){return void t()}window.indexedDB||!window.PointerEvent&&!window.MSPointerEvent?r():t()}})}}!function(e){let t;!function(e){e.CHROME="chrome",e.FIREFOX="firefox",e.OPERA="opera",e.EDGE="edge",e.SAFARI="safari",e.BRAVE="brave",e.UNKNOWN="unknown"}(t=e.Browser||(e.Browser={}))}(d||(d={}));var u=d,p={"popup-overlay":"A popup has been opened,\nclick anywhere to bring it back to the front."};const _={de:{"popup-overlay":"Ein Popup hat sich geöffnet,\nklicke hier, um zurück zum Popup zu kommen."},en:p,es:{"popup-overlay":"Se ha abierto una ventana emergente.\nHaga click en cualquier lugar para traer la ventana al primer plano."},fil:{"popup-overlay":"Nag-bukas ang isang pop-up.\nMaaring pindutin kahit saan para ibalik ito sa harap."},fr:{"popup-overlay":"Une popup a été ouverte,\ncliquez n'importe où pour la ramener au premier plan."},nl:{"popup-overlay":"Er is een pop-up geopend,\nklik op het scherm om het weer naar voren te brengen."},pl:{"popup-overlay":"Pojawiło się wyskakujące okno.\nAby je zobaczyć, kliknij w dowolnym miejscu."},pt:{"popup-overlay":"Um popup foi aberto,\nclique em qualquer lado para o trazer para a frente."},ru:{"popup-overlay":"Открыто всплывающее окно.\nНажмите где-нибудь, чтобы вернуть его на передний план."},tr:{"popup-overlay":"Bir popup penceresi açıldı,\nöne çekmek için herhangi bir yere tıkla. "},uk:{"popup-overlay":"Відкрито випадаюче вікно.\nклацніть будь-де щоб перейти до ньго."},zh:{"popup-overlay":"弹出窗口已打开,\n单击任意位置即可回到上一页"}};class g{constructor(e){this._type=e}static getAllowedOrigin(e){return new URL(e).origin}async request(e,t,r){throw new Error("Not implemented")}}var w,R,A,m,S,E,v,f;!function(e){e[e.REDIRECT=0]="REDIRECT",e[e.POPUP=1]="POPUP",e[e.IFRAME=2]="IFRAME"}(w||(w={}));class I extends g{constructor(e,t){super(w.REDIRECT);const r=window.location;if(this._returnUrl=e||`${r.origin}${r.pathname}`,this._localState=t||{},void 0!==this._localState.__command)throw new Error("Invalid localState: Property '__command' is reserved")}static withLocalState(e){return new I(void 0,e)}async request(e,t,r){const s=g.getAllowedOrigin(e),i=new h(e,s);await i.init();const n=Object.assign({},this._localState,{__command:t});i.callAndSaveLocalState(this._returnUrl,n,t,!0,...await Promise.all(r))}}class y extends g{constructor(e=y.DEFAULT_FEATURES,t){super(w.POPUP),this.shouldRetryRequest=!1,this._popupFeatures=e,this._options={...y.DEFAULT_OPTIONS,...t}}async request(e,t,r){const s=g.getAllowedOrigin(e),i=this.appendOverlay();do{this.shouldRetryRequest=!1;try{return this.popup=this.createPopup(e),this.client=new l(this.popup,s),await this.client.init(),await this.client.call(t,...await Promise.all(r))}catch(e){if(!this.shouldRetryRequest)throw e}finally{this.shouldRetryRequest||(this.removeOverlay(i),this.client&&this.client.close(),this.popup&&this.popup.close())}}while(this.shouldRetryRequest);throw this.popup&&this.popup.close(),this.client&&this.client.close(),i&&this.removeOverlay(i),new Error("Unexpected error occurred")}createPopup(e){const t=window.open(e,"NimiqAccounts",this._popupFeatures);if(!t)throw new Error("Failed to open popup");return t}appendOverlay(){if(!this._options.overlay)return null;const e=document.createElement.bind(document),t=(e,t)=>e.appendChild(t),r=e("div");r.id="nimiq-hub-overlay";const s=r.style;s.position="fixed",s.top="0",s.right="0",s.bottom="0",s.left="0",s.background="rgba(31, 35, 72, 0.8)",s.display="flex",s.flexDirection="column",s.alignItems="center",s.justifyContent="space-between",s.cursor="pointer",s.color="white",s.textAlign="center",s.opacity="0",s.transition="opacity 0.6s ease",s.zIndex="99999",r.addEventListener("click",()=>{u.isIOS()?(this.shouldRetryRequest=!0,this.popup&&this.popup.close(),this.client&&this.client.close()):this.popup&&this.popup.focus()}),t(r,e("div"));const i=e("div");i.textContent=function(e,t){if(!t){const e=document.cookie.match(/(^| )lang=([^;]+)/);t=e&&e[2]||navigator.language.split("-")[0]}return(_[t]||p)[e]||p[e]}("popup-overlay");const n=i.style;n.padding="20px",n.fontFamily='Muli, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif',n.fontSize="24px",n.fontWeight="600",n.lineHeight="40px",n.whiteSpace="pre-line",t(r,i);const o=e("img");o.src='data:image/svg+xml,',o.style.marginBottom="56px",t(r,o);const a=e("div"),c=a.style;return a.innerHTML="×",c.position="absolute",c.top="8px",c.right="8px",c.fontSize="24px",c.lineHeight="32px",c.fontWeight="600",c.width="32px",c.height="32px",c.opacity="0.8",a.addEventListener("click",e=>{this.popup&&this.popup.close(),e.stopPropagation()}),t(r,a),setTimeout(()=>r.style.opacity="1",100),t(document.body,r)}removeOverlay(e){e&&(e.style.opacity="0",setTimeout(()=>document.body.removeChild(e),400))}}y.DEFAULT_FEATURES="",y.DEFAULT_OPTIONS={overlay:!0};class C extends g{constructor(){super(w.IFRAME),this._iframe=null,this._client=null}async request(e,t,r){if(this._iframe&&this._iframe.src!==`${e}${C.IFRAME_PATH_SUFFIX}`)throw new Error("Hub iframe is already opened with another endpoint");const s=g.getAllowedOrigin(e);if(this._iframe||(this._iframe=await this.createIFrame(e)),!this._iframe.contentWindow)throw new Error(`IFrame contentWindow is ${typeof this._iframe.contentWindow}`);return this._client||(this._client=new l(this._iframe.contentWindow,s),await this._client.init()),await this._client.call(t,...await Promise.all(r))}async createIFrame(e){return new Promise((t,r)=>{const s=document.createElement("iframe");s.name="NimiqAccountsIFrame",s.style.display="none",document.body.appendChild(s),s.src=`${e}${C.IFRAME_PATH_SUFFIX}`,s.onload=(()=>t(s)),s.onerror=r})}}C.IFRAME_PATH_SUFFIX="/iframe.html",function(e){e.LIST="list",e.LIST_CASHLINKS="list-cashlinks",e.MIGRATE="migrate",e.CHECKOUT="checkout",e.SIGN_MESSAGE="sign-message",e.SIGN_TRANSACTION="sign-transaction",e.SIGN_MULTISIG_TRANSACTION="sign-multisig-transaction",e.SIGN_STAKING="sign-staking",e.ONBOARD="onboard",e.SIGNUP="signup",e.LOGIN="login",e.EXPORT="export",e.CHANGE_PASSWORD="change-password",e.LOGOUT="logout",e.ADD_ADDRESS="add-address",e.RENAME="rename",e.ADD_VESTING_CONTRACT="add-vesting-contract",e.CHOOSE_ADDRESS="choose-address",e.CREATE_CASHLINK="create-cashlink",e.MANAGE_CASHLINK="manage-cashlink",e.SIGN_BTC_TRANSACTION="sign-btc-transaction",e.ADD_BTC_ADDRESSES="add-btc-addresses",e.SIGN_POLYGON_TRANSACTION="sign-polygon-transaction",e.ACTIVATE_BITCOIN="activate-bitcoin",e.ACTIVATE_POLYGON="activate-polygon",e.SETUP_SWAP="setup-swap",e.REFUND_SWAP="refund-swap",e.CONNECT_ACCOUNT="connect-account"}(R||(R={})),function(e){e[e.LEGACY=1]="LEGACY",e[e.BIP39=2]="BIP39",e[e.LEDGER=3]="LEDGER"}(A||(A={})),function(e){e[e.DIRECT=0]="DIRECT",e[e.OASIS=1]="OASIS"}(m||(m={})),function(e){e.NIM="nim",e.BTC="btc",e.ETH="eth"}(S||(S={})),function(e){e.NOT_FOUND="NOT_FOUND",e.PAID="PAID",e.UNDERPAID="UNDERPAID",e.OVERPAID="OVERPAID"}(E||(E={})),function(e){e[e.UNKNOWN=-1]="UNKNOWN",e[e.UNCHARGED=0]="UNCHARGED",e[e.CHARGING=1]="CHARGING",e[e.UNCLAIMED=2]="UNCLAIMED",e[e.CLAIMING=3]="CLAIMING",e[e.CLAIMED=4]="CLAIMED"}(v||(v={})),function(e){e[e.UNSPECIFIED=0]="UNSPECIFIED",e[e.STANDARD=1]="STANDARD",e[e.CHRISTMAS=2]="CHRISTMAS",e[e.LUNAR_NEW_YEAR=3]="LUNAR_NEW_YEAR",e[e.EASTER=4]="EASTER",e[e.GENERIC=5]="GENERIC",e[e.BIRTHDAY=6]="BIRTHDAY"}(f||(f={}));class T{constructor(e=T.DEFAULT_ENDPOINT,t){this._endpoint=e,this._defaultBehavior=t||new y(`left=${window.innerWidth/2-400},top=75,width=800,height=850,location=yes,dependent=yes`),this._checkoutDefaultBehavior=t||new y(`left=${window.innerWidth/2-400},top=50,width=800,height=895,location=yes,dependent=yes`),this._iframeBehavior=new C,this._redirectClient=new h("",g.getAllowedOrigin(this._endpoint))}static get PaymentMethod(){return console.warn("PaymentMethod has been renamed to PaymentType. Access via HubApi.PaymentMethod will soon get disabled. Use HubApi.PaymentType instead."),m}static get DEFAULT_ENDPOINT(){const e=location.hostname.match(/(?:[^.]+\.[^.]+|localhost)$/),t=e?e[0]:location.hostname;switch(t){case"nimiq.com":case"nimiq-testnet.com":return`https://hub.${t}`;case"bs-local.com":return`${window.location.protocol}//bs-local.com:8080`;default:return"http://localhost:8080"}}checkRedirectResponse(){return this._redirectClient.init()}on(e,t,r){this._redirectClient.onResponse(e,(e,r,s)=>t(e,s),(e,t,s)=>{r&&r(e,s)})}createCashlink(e,t=this._defaultBehavior){return this._request(t,R.CREATE_CASHLINK,[e])}manageCashlink(e,t=this._defaultBehavior){return this._request(t,R.MANAGE_CASHLINK,[e])}checkout(e,t=this._checkoutDefaultBehavior){return this._request(t,R.CHECKOUT,[e])}chooseAddress(e,t=this._defaultBehavior){return this._request(t,R.CHOOSE_ADDRESS,[e])}signTransaction(e,t=this._defaultBehavior){return this._request(t,R.SIGN_TRANSACTION,[e])}signStaking(e,t=this._defaultBehavior){return this._request(t,R.SIGN_STAKING,[e])}signMessage(e,t=this._defaultBehavior){return this._request(t,R.SIGN_MESSAGE,[e])}signBtcTransaction(e,t=this._defaultBehavior){return this._request(t,R.SIGN_BTC_TRANSACTION,[e])}signPolygonTransaction(e,t=this._defaultBehavior){return this._request(t,R.SIGN_POLYGON_TRANSACTION,[e])}setupSwap(e,t=this._defaultBehavior){return this._request(t,R.SETUP_SWAP,[e])}refundSwap(e,t=this._defaultBehavior){return this._request(t,R.REFUND_SWAP,[e])}signMultisigTransaction(e,t=this._defaultBehavior){return this._request(t,R.SIGN_MULTISIG_TRANSACTION,[e])}connectAccount(e,t=this._defaultBehavior){return this._request(t,R.CONNECT_ACCOUNT,[e])}onboard(e,t=this._defaultBehavior){return this._request(t,R.ONBOARD,[e])}signup(e,t=this._defaultBehavior){return this._request(t,R.SIGNUP,[e])}login(e,t=this._defaultBehavior){return this._request(t,R.LOGIN,[e])}logout(e,t=this._defaultBehavior){return this._request(t,R.LOGOUT,[e])}export(e,t=this._defaultBehavior){return this._request(t,R.EXPORT,[e])}changePassword(e,t=this._defaultBehavior){return this._request(t,R.CHANGE_PASSWORD,[e])}addAddress(e,t=this._defaultBehavior){return this._request(t,R.ADD_ADDRESS,[e])}rename(e,t=this._defaultBehavior){return this._request(t,R.RENAME,[e])}addVestingContract(e,t=this._defaultBehavior){return this._request(t,R.ADD_VESTING_CONTRACT,[e])}migrate(e=this._defaultBehavior){return this._request(e,R.MIGRATE,[{appName:"Account list"}])}activateBitcoin(e,t=this._defaultBehavior){return this._request(t,R.ACTIVATE_BITCOIN,[e])}activatePolygon(e,t=this._defaultBehavior){return this._request(t,R.ACTIVATE_POLYGON,[e])}list(e=this._iframeBehavior){return this._request(e,R.LIST,[])}cashlinks(e=this._iframeBehavior){return this._request(e,R.LIST_CASHLINKS,[])}addBtcAddresses(e,t=this._iframeBehavior){return this._request(t,R.ADD_BTC_ADDRESSES,[e])}_request(e,t,r){return e.request(this._endpoint,t,r)}}T.BehaviorType=w,T.RequestType=R,T.RedirectRequestBehavior=I,T.PopupRequestBehavior=y,T.AccountType=A,T.CashlinkState=v,T.CashlinkTheme=f,T.Currency=S,T.PaymentType=m,T.PaymentState=E,T.MSG_PREFIX="Nimiq Signed Message:\n";export default T; diff --git a/client/dist/standalone/HubApi.standalone.umd.js b/client/dist/standalone/HubApi.standalone.umd.js index 5b85135c..203520ac 100644 --- a/client/dist/standalone/HubApi.standalone.umd.js +++ b/client/dist/standalone/HubApi.standalone.umd.js @@ -1 +1 @@ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).HubApi=t()}(this,function(){"use strict";class e{static byteLength(t){const[r,s]=e._getLengths(t);return e._byteLength(r,s)}static decode(t){e._initRevLookup();const[r,s]=e._getLengths(t),i=new Uint8Array(e._byteLength(r,s));let n=0;const o=s>0?r-4:r;let a=0;for(;a>16&255,i[n++]=r>>8&255,i[n++]=255&r}if(2===s){const r=e._revLookup[t.charCodeAt(a)]<<2|e._revLookup[t.charCodeAt(a+1)]>>4;i[n++]=255&r}if(1===s){const r=e._revLookup[t.charCodeAt(a)]<<10|e._revLookup[t.charCodeAt(a+1)]<<4|e._revLookup[t.charCodeAt(a+2)]>>2;i[n++]=r>>8&255,i[n]=255&r}return i}static encode(t){const r=t.length,s=r%3,i=[];for(let n=0,o=r-s;no?o:n+16383));if(1===s){const s=t[r-1];i.push(e._lookup[s>>2]+e._lookup[s<<4&63]+"==")}else if(2===s){const s=(t[r-2]<<8)+t[r-1];i.push(e._lookup[s>>10]+e._lookup[s>>4&63]+e._lookup[s<<2&63]+"=")}return i.join("")}static encodeUrl(t){return e.encode(t).replace(/\//g,"_").replace(/\+/g,"-").replace(/=/g,".")}static decodeUrl(t){return e.decode(t.replace(/_/g,"/").replace(/-/g,"+").replace(/\./g,"="))}static _initRevLookup(){if(0===e._revLookup.length){e._revLookup=[];for(let t=0,r=e._lookup.length;t0)throw new Error("Invalid string. Length must be a multiple of 4");let r=e.indexOf("=");return-1===r&&(r=t),[r,r===t?0:4-r%4]}static _byteLength(e,t){return 3*(e+t)/4-t}static _tripletToBase64(t){return e._lookup[t>>18&63]+e._lookup[t>>12&63]+e._lookup[t>>6&63]+e._lookup[63&t]}static _encodeChunk(t,r,s){const i=[];for(let n=r;nthis._checkIfServerClosed(),300)))}async call(e,...t){return this._call({command:e,args:t,id:n.generateRandomId()})}close(){this._connectionState=0,window.removeEventListener("message",this._receiveListener),window.clearInterval(this._serverCloseCheckInterval),this._serverCloseCheckInterval=-1;for(const[e,{reject:t}]of this._responseHandlers){const r=this._waitingRequests.getState(e);t("Connection was closed","number"==typeof e?e:void 0,r)}this._waitingRequests.clear(),this._responseHandlers.clear(),this._target&&this._target.closed&&(this._target=null)}_receive(e){return e.source===this._target&&super._receive(e)}async _call(e){if(!this._target||this._target.closed)throw new Error("Connection was closed.");if(2!==this._connectionState)throw new Error("Client is not connected, call init first");return new Promise((t,r)=>{this._responseHandlers.set(e.id,{resolve:t,reject:r}),this._waitingRequests.add(e.id,e.command),console.debug("RpcClient REQUEST",e.command,e.args),this._target.postMessage(e,this._allowedOrigin)})}_connect(){if(2!==this._connectionState)return this._connectionState=1,new Promise((e,t)=>{const r=t=>{const{source:i,origin:n,data:o}=t;if(i===this._target&&o.status===s.OK&&"pong"===o.result&&1===o.id&&("*"===this._allowedOrigin||n===this._allowedOrigin)){if(o.result.stack){const e=new Error(o.result.message);e.stack=o.result.stack,o.result.name&&(e.name=o.result.name),console.error(e)}window.removeEventListener("message",r),this._connectionState=2,console.log("RpcClient: Connection established"),e(!0)}};window.addEventListener("message",r);const i=()=>{if(2!==this._connectionState){if(0===this._connectionState||this._checkIfServerClosed())return window.removeEventListener("message",r),void t(new Error("Connection was closed"));try{this._target.postMessage({command:"ping",id:1},this._allowedOrigin)}catch(e){console.error(`postMessage failed: ${e}`)}window.setTimeout(i,100)}};window.setTimeout(i,100)})}_checkIfServerClosed(){return!(this._target&&!this._target.closed)&&(this.close(),!0)}}class d extends c{constructor(e,t,r=!0){super(t,!0),this._target=e,this._preserveRequests=r}async init(){const e=a.receiveRedirectResponse(window.location);if(e)return void this._receive(e);if(this._rejectOnBack())return;const t=new URLSearchParams(window.location.search);if(t.has(a.URL_SEARCHPARAM_NAME)){const e=window.sessionStorage.getItem(`response-${t.get(a.URL_SEARCHPARAM_NAME)}`);if(e)return void this._receive(i.parse(e),!1)}}close(){}call(e,t,s,...i){if(s&&"boolean"!=typeof s){if("object"==typeof s){if(s.responseMethod===r.POST_MESSAGE){if(!window.opener&&!window.parent)throw new Error("Window has no opener or parent, responseMethod: ResponseMethod.POST_MESSAGE would fail.");console.warn("Response will skip at least one rpc call, which will result in an unknown response.")}this._call(e,t,s,...i)}}else"boolean"==typeof s&&console.warn("RedirectRpcClient.call(string, string, boolean, any[]) is deprecated. Use RedirectRpcClient.call(string, string, CallOptions, any[]) with an appropriate CallOptions object instead."),this._call(e,t,{responseMethod:r.HTTP_GET,handleHistoryBack:!!s},...i)}callAndSaveLocalState(e,t,s,i=!1,...n){console.warn("RedirectRpcClient.callAndSaveLocalState() is deprecated. Use RedirectRpcClient.call() with an apropriate CallOptions object instead."),this._call(e,s,{responseMethod:r.HTTP_GET,state:t||void 0,handleHistoryBack:i},...n)}_receive(e,t=!0){const r=super._receive(e);return r&&t&&window.sessionStorage.setItem(`response-${e.data.id}`,i.stringify(e)),r}_call(e,t,s,...i){const o=n.generateRandomId(),c=s.responseMethod||r.HTTP_GET,l=a.prepareRedirectInvocation(this._target,o,e,t,i,c);this._waitingRequests.add(o,t,s.state||null),s.handleHistoryBack&&history.replaceState(Object.assign({},history.state,{rpcBackRejectionId:o}),""),console.debug("RpcClient REQUEST",t,i),window.location.href=l}_rejectOnBack(){if(!history.state||!history.state.rpcBackRejectionId)return!1;const e=history.state.rpcBackRejectionId;history.replaceState(Object.assign({},history.state,{rpcBackRejectionId:null}),"");const t=this._getCallback(e),r=this._waitingRequests.getState(e);if(t){this._preserveRequests||(this._waitingRequests.remove(e),this._responseHandlers.delete(e)),console.debug("RpcClient BACK");const s=new Error("Request aborted");return t.reject(s,e,r),!0}return!1}}class h{static getBrowserInfo(){return{browser:h.detectBrowser(),version:h.detectVersion(),isMobile:h.isMobile()}}static isMobile(){return/i?Phone|iP(ad|od)|Android|BlackBerry|Opera Mini|WPDesktop|Mobi(le)?|Silk/i.test(navigator.userAgent)}static detectBrowser(){if(h._detectedBrowser)return h._detectedBrowser;const e=navigator.userAgent;return/Edge\//i.test(e)?h._detectedBrowser=h.Browser.EDGE:/(Opera|OPR)\//i.test(e)?h._detectedBrowser=h.Browser.OPERA:/Firefox\//i.test(e)?h._detectedBrowser=h.Browser.FIREFOX:/Chrome\//i.test(e)?h._detectedBrowser=0!==navigator.plugins.length||0!==navigator.mimeTypes.length||h.isMobile()?h.Browser.CHROME:h.Browser.BRAVE:/^((?!chrome|android).)*safari/i.test(e)?h._detectedBrowser=h.Browser.SAFARI:h._detectedBrowser=h.Browser.UNKNOWN,h._detectedBrowser}static detectVersion(){if(void 0!==h._detectedVersion)return h._detectedVersion;let e;switch(h.detectBrowser()){case h.Browser.EDGE:e=/Edge\/(\S+)/i;break;case h.Browser.OPERA:e=/(Opera|OPR)\/(\S+)/i;break;case h.Browser.FIREFOX:e=/Firefox\/(\S+)/i;break;case h.Browser.CHROME:e=/Chrome\/(\S+)/i;break;case h.Browser.SAFARI:e=/(iP(hone|ad|od).*?OS |Version\/)(\S+)/i;break;case h.Browser.BRAVE:default:return h._detectedVersion=null,null}const t=navigator.userAgent.match(e);if(!t)return h._detectedVersion=null,null;const r=t[t.length-1].replace(/_/g,"."),s=r.split("."),i=[];for(let e=0;e<4;++e)i.push(parseInt(s[e],10)||0);const[n,o,a,c]=i;return h._detectedVersion={versionString:r,major:n,minor:o,build:a,patch:c},h._detectedVersion}static isChrome(){return h.detectBrowser()===h.Browser.CHROME}static isFirefox(){return h.detectBrowser()===h.Browser.FIREFOX}static isOpera(){return h.detectBrowser()===h.Browser.OPERA}static isEdge(){return h.detectBrowser()===h.Browser.EDGE}static isSafari(){return h.detectBrowser()===h.Browser.SAFARI}static isBrave(){return h.detectBrowser()===h.Browser.BRAVE}static isIOS(){return/iPad|iPhone|iPod/.test(navigator.userAgent)&&!window.MSStream}static isBadIOS(){const e=h.getBrowserInfo();return e.browser===h.Browser.SAFARI&&e.isMobile&&e.version&&(e.version.major<11||11===e.version.major&&2===e.version.minor)}static isPrivateMode(){return new Promise(e=>{const t=()=>e(!0),r=()=>e(!1);if(window.webkitRequestFileSystem)window.webkitRequestFileSystem(0,0,r,t);else{if(document.documentElement&&"MozAppearance"in document.documentElement.style){const e=indexedDB.open(null);return e.onerror=t,void(e.onsuccess=r)}if((()=>/Constructor/.test(window.HTMLElement)||window.safari&&window.safari.pushNotification&&"[object SafariRemoteNotification]"===window.safari.pushNotification.toString())())try{window.openDatabase(null,null,null,null)}catch(e){return void t()}window.indexedDB||!window.PointerEvent&&!window.MSPointerEvent?r():t()}})}}!function(e){let t;!function(e){e.CHROME="chrome",e.FIREFOX="firefox",e.OPERA="opera",e.EDGE="edge",e.SAFARI="safari",e.BRAVE="brave",e.UNKNOWN="unknown"}(t=e.Browser||(e.Browser={}))}(h||(h={}));var u=h,p={"popup-overlay":"A popup has been opened,\nclick anywhere to bring it back to the front."};const _={de:{"popup-overlay":"Ein Popup hat sich geöffnet,\nklicke hier, um zurück zum Popup zu kommen."},en:p,es:{"popup-overlay":"Se ha abierto una ventana emergente.\nHaga click en cualquier lugar para traer la ventana al primer plano."},fil:{"popup-overlay":"Nag-bukas ang isang pop-up.\nMaaring pindutin kahit saan para ibalik ito sa harap."},fr:{"popup-overlay":"Une popup a été ouverte,\ncliquez n'importe où pour la ramener au premier plan."},nl:{"popup-overlay":"Er is een pop-up geopend,\nklik op het scherm om het weer naar voren te brengen."},pl:{"popup-overlay":"Pojawiło się wyskakujące okno.\nAby je zobaczyć, kliknij w dowolnym miejscu."},pt:{"popup-overlay":"Um popup foi aberto,\nclique em qualquer lado para o trazer para a frente."},ru:{"popup-overlay":"Открыто всплывающее окно.\nНажмите где-нибудь, чтобы вернуть его на передний план."},tr:{"popup-overlay":"Bir popup penceresi açıldı,\nöne çekmek için herhangi bir yere tıkla. "},uk:{"popup-overlay":"Відкрито випадаюче вікно.\nклацніть будь-де щоб перейти до ньго."},zh:{"popup-overlay":"弹出窗口已打开,\n单击任意位置即可回到上一页"}};class w{constructor(e){this._type=e}static getAllowedOrigin(e){return new URL(e).origin}async request(e,t,r){throw new Error("Not implemented")}}var g,R,A,m,f,E,S,v;!function(e){e[e.REDIRECT=0]="REDIRECT",e[e.POPUP=1]="POPUP",e[e.IFRAME=2]="IFRAME"}(g||(g={}));class I extends w{constructor(e,t){super(g.REDIRECT);const r=window.location;if(this._returnUrl=e||`${r.origin}${r.pathname}`,this._localState=t||{},void 0!==this._localState.__command)throw new Error("Invalid localState: Property '__command' is reserved")}static withLocalState(e){return new I(void 0,e)}async request(e,t,r){const s=w.getAllowedOrigin(e),i=new d(e,s);await i.init();const n=Object.assign({},this._localState,{__command:t});i.callAndSaveLocalState(this._returnUrl,n,t,!0,...await Promise.all(r))}}class y extends w{constructor(e=y.DEFAULT_FEATURES,t){super(g.POPUP),this.shouldRetryRequest=!1,this._popupFeatures=e,this._options={...y.DEFAULT_OPTIONS,...t}}async request(e,t,r){const s=w.getAllowedOrigin(e),i=this.appendOverlay();do{this.shouldRetryRequest=!1;try{return this.popup=this.createPopup(e),this.client=new l(this.popup,s),await this.client.init(),await this.client.call(t,...await Promise.all(r))}catch(e){if(!this.shouldRetryRequest)throw e}finally{this.shouldRetryRequest||(this.removeOverlay(i),this.client&&this.client.close(),this.popup&&this.popup.close())}}while(this.shouldRetryRequest);throw this.popup&&this.popup.close(),this.client&&this.client.close(),i&&this.removeOverlay(i),new Error("Unexpected error occurred")}createPopup(e){const t=window.open(e,"NimiqAccounts",this._popupFeatures);if(!t)throw new Error("Failed to open popup");return t}appendOverlay(){if(!this._options.overlay)return null;const e=document.createElement.bind(document),t=(e,t)=>e.appendChild(t),r=e("div");r.id="nimiq-hub-overlay";const s=r.style;s.position="fixed",s.top="0",s.right="0",s.bottom="0",s.left="0",s.background="rgba(31, 35, 72, 0.8)",s.display="flex",s.flexDirection="column",s.alignItems="center",s.justifyContent="space-between",s.cursor="pointer",s.color="white",s.textAlign="center",s.opacity="0",s.transition="opacity 0.6s ease",s.zIndex="99999",r.addEventListener("click",()=>{u.isIOS()?(this.shouldRetryRequest=!0,this.popup&&this.popup.close(),this.client&&this.client.close()):this.popup&&this.popup.focus()}),t(r,e("div"));const i=e("div");i.textContent=function(e,t){if(!t){const e=document.cookie.match(/(^| )lang=([^;]+)/);t=e&&e[2]||navigator.language.split("-")[0]}return(_[t]||p)[e]||p[e]}("popup-overlay");const n=i.style;n.padding="20px",n.fontFamily='Muli, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif',n.fontSize="24px",n.fontWeight="600",n.lineHeight="40px",n.whiteSpace="pre-line",t(r,i);const o=e("img");o.src='data:image/svg+xml,',o.style.marginBottom="56px",t(r,o);const a=e("div"),c=a.style;return a.innerHTML="×",c.position="absolute",c.top="8px",c.right="8px",c.fontSize="24px",c.lineHeight="32px",c.fontWeight="600",c.width="32px",c.height="32px",c.opacity="0.8",a.addEventListener("click",e=>{this.popup&&this.popup.close(),e.stopPropagation()}),t(r,a),setTimeout(()=>r.style.opacity="1",100),t(document.body,r)}removeOverlay(e){e&&(e.style.opacity="0",setTimeout(()=>document.body.removeChild(e),400))}}y.DEFAULT_FEATURES="",y.DEFAULT_OPTIONS={overlay:!0};class C extends w{constructor(){super(g.IFRAME),this._iframe=null,this._client=null}async request(e,t,r){if(this._iframe&&this._iframe.src!==`${e}${C.IFRAME_PATH_SUFFIX}`)throw new Error("Hub iframe is already opened with another endpoint");const s=w.getAllowedOrigin(e);if(this._iframe||(this._iframe=await this.createIFrame(e)),!this._iframe.contentWindow)throw new Error(`IFrame contentWindow is ${typeof this._iframe.contentWindow}`);return this._client||(this._client=new l(this._iframe.contentWindow,s),await this._client.init()),await this._client.call(t,...await Promise.all(r))}async createIFrame(e){return new Promise((t,r)=>{const s=document.createElement("iframe");s.name="NimiqAccountsIFrame",s.style.display="none",document.body.appendChild(s),s.src=`${e}${C.IFRAME_PATH_SUFFIX}`,s.onload=(()=>t(s)),s.onerror=r})}}C.IFRAME_PATH_SUFFIX="/iframe.html",function(e){e.LIST="list",e.LIST_CASHLINKS="list-cashlinks",e.MIGRATE="migrate",e.CHECKOUT="checkout",e.SIGN_MESSAGE="sign-message",e.SIGN_TRANSACTION="sign-transaction",e.SIGN_STAKING="sign-staking",e.ONBOARD="onboard",e.SIGNUP="signup",e.LOGIN="login",e.EXPORT="export",e.CHANGE_PASSWORD="change-password",e.LOGOUT="logout",e.ADD_ADDRESS="add-address",e.RENAME="rename",e.ADD_VESTING_CONTRACT="add-vesting-contract",e.CHOOSE_ADDRESS="choose-address",e.CREATE_CASHLINK="create-cashlink",e.MANAGE_CASHLINK="manage-cashlink",e.SIGN_BTC_TRANSACTION="sign-btc-transaction",e.ADD_BTC_ADDRESSES="add-btc-addresses",e.SIGN_POLYGON_TRANSACTION="sign-polygon-transaction",e.ACTIVATE_BITCOIN="activate-bitcoin",e.ACTIVATE_POLYGON="activate-polygon",e.SETUP_SWAP="setup-swap",e.REFUND_SWAP="refund-swap"}(R||(R={})),function(e){e[e.LEGACY=1]="LEGACY",e[e.BIP39=2]="BIP39",e[e.LEDGER=3]="LEDGER"}(A||(A={})),function(e){e[e.DIRECT=0]="DIRECT",e[e.OASIS=1]="OASIS"}(m||(m={})),function(e){e.NIM="nim",e.BTC="btc",e.ETH="eth"}(f||(f={})),function(e){e.NOT_FOUND="NOT_FOUND",e.PAID="PAID",e.UNDERPAID="UNDERPAID",e.OVERPAID="OVERPAID"}(E||(E={})),function(e){e[e.UNKNOWN=-1]="UNKNOWN",e[e.UNCHARGED=0]="UNCHARGED",e[e.CHARGING=1]="CHARGING",e[e.UNCLAIMED=2]="UNCLAIMED",e[e.CLAIMING=3]="CLAIMING",e[e.CLAIMED=4]="CLAIMED"}(S||(S={})),function(e){e[e.UNSPECIFIED=0]="UNSPECIFIED",e[e.STANDARD=1]="STANDARD",e[e.CHRISTMAS=2]="CHRISTMAS",e[e.LUNAR_NEW_YEAR=3]="LUNAR_NEW_YEAR",e[e.EASTER=4]="EASTER",e[e.GENERIC=5]="GENERIC",e[e.BIRTHDAY=6]="BIRTHDAY"}(v||(v={}));class O{constructor(e=O.DEFAULT_ENDPOINT,t){this._endpoint=e,this._defaultBehavior=t||new y(`left=${window.innerWidth/2-400},top=75,width=800,height=850,location=yes,dependent=yes`),this._checkoutDefaultBehavior=t||new y(`left=${window.innerWidth/2-400},top=50,width=800,height=895,location=yes,dependent=yes`),this._iframeBehavior=new C,this._redirectClient=new d("",w.getAllowedOrigin(this._endpoint))}static get PaymentMethod(){return console.warn("PaymentMethod has been renamed to PaymentType. Access via HubApi.PaymentMethod will soon get disabled. Use HubApi.PaymentType instead."),m}static get DEFAULT_ENDPOINT(){const e=location.hostname.match(/(?:[^.]+\.[^.]+|localhost)$/),t=e?e[0]:location.hostname;switch(t){case"nimiq.com":case"nimiq-testnet.com":return`https://hub.${t}`;case"bs-local.com":return`${window.location.protocol}//bs-local.com:8080`;default:return"http://localhost:8080"}}checkRedirectResponse(){return this._redirectClient.init()}on(e,t,r){this._redirectClient.onResponse(e,(e,r,s)=>t(e,s),(e,t,s)=>{r&&r(e,s)})}createCashlink(e,t=this._defaultBehavior){return this._request(t,R.CREATE_CASHLINK,[e])}manageCashlink(e,t=this._defaultBehavior){return this._request(t,R.MANAGE_CASHLINK,[e])}checkout(e,t=this._checkoutDefaultBehavior){return this._request(t,R.CHECKOUT,[e])}chooseAddress(e,t=this._defaultBehavior){return this._request(t,R.CHOOSE_ADDRESS,[e])}signTransaction(e,t=this._defaultBehavior){return this._request(t,R.SIGN_TRANSACTION,[e])}signStaking(e,t=this._defaultBehavior){return this._request(t,R.SIGN_STAKING,[e])}signMessage(e,t=this._defaultBehavior){return this._request(t,R.SIGN_MESSAGE,[e])}signBtcTransaction(e,t=this._defaultBehavior){return this._request(t,R.SIGN_BTC_TRANSACTION,[e])}signPolygonTransaction(e,t=this._defaultBehavior){return this._request(t,R.SIGN_POLYGON_TRANSACTION,[e])}setupSwap(e,t=this._defaultBehavior){return this._request(t,R.SETUP_SWAP,[e])}refundSwap(e,t=this._defaultBehavior){return this._request(t,R.REFUND_SWAP,[e])}onboard(e,t=this._defaultBehavior){return this._request(t,R.ONBOARD,[e])}signup(e,t=this._defaultBehavior){return this._request(t,R.SIGNUP,[e])}login(e,t=this._defaultBehavior){return this._request(t,R.LOGIN,[e])}logout(e,t=this._defaultBehavior){return this._request(t,R.LOGOUT,[e])}export(e,t=this._defaultBehavior){return this._request(t,R.EXPORT,[e])}changePassword(e,t=this._defaultBehavior){return this._request(t,R.CHANGE_PASSWORD,[e])}addAddress(e,t=this._defaultBehavior){return this._request(t,R.ADD_ADDRESS,[e])}rename(e,t=this._defaultBehavior){return this._request(t,R.RENAME,[e])}addVestingContract(e,t=this._defaultBehavior){return this._request(t,R.ADD_VESTING_CONTRACT,[e])}migrate(e=this._defaultBehavior){return this._request(e,R.MIGRATE,[{appName:"Account list"}])}activateBitcoin(e,t=this._defaultBehavior){return this._request(t,R.ACTIVATE_BITCOIN,[e])}activatePolygon(e,t=this._defaultBehavior){return this._request(t,R.ACTIVATE_POLYGON,[e])}list(e=this._iframeBehavior){return this._request(e,R.LIST,[])}cashlinks(e=this._iframeBehavior){return this._request(e,R.LIST_CASHLINKS,[])}addBtcAddresses(e,t=this._iframeBehavior){return this._request(t,R.ADD_BTC_ADDRESSES,[e])}_request(e,t,r){return e.request(this._endpoint,t,r)}}return O.BehaviorType=g,O.RequestType=R,O.RedirectRequestBehavior=I,O.PopupRequestBehavior=y,O.AccountType=A,O.CashlinkState=S,O.CashlinkTheme=v,O.Currency=f,O.PaymentType=m,O.PaymentState=E,O.MSG_PREFIX="Nimiq Signed Message:\n",O}); +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).HubApi=t()}(this,function(){"use strict";class e{static byteLength(t){const[r,s]=e._getLengths(t);return e._byteLength(r,s)}static decode(t){e._initRevLookup();const[r,s]=e._getLengths(t),i=new Uint8Array(e._byteLength(r,s));let n=0;const o=s>0?r-4:r;let a=0;for(;a>16&255,i[n++]=r>>8&255,i[n++]=255&r}if(2===s){const r=e._revLookup[t.charCodeAt(a)]<<2|e._revLookup[t.charCodeAt(a+1)]>>4;i[n++]=255&r}if(1===s){const r=e._revLookup[t.charCodeAt(a)]<<10|e._revLookup[t.charCodeAt(a+1)]<<4|e._revLookup[t.charCodeAt(a+2)]>>2;i[n++]=r>>8&255,i[n]=255&r}return i}static encode(t){const r=t.length,s=r%3,i=[];for(let n=0,o=r-s;no?o:n+16383));if(1===s){const s=t[r-1];i.push(e._lookup[s>>2]+e._lookup[s<<4&63]+"==")}else if(2===s){const s=(t[r-2]<<8)+t[r-1];i.push(e._lookup[s>>10]+e._lookup[s>>4&63]+e._lookup[s<<2&63]+"=")}return i.join("")}static encodeUrl(t){return e.encode(t).replace(/\//g,"_").replace(/\+/g,"-").replace(/=/g,".")}static decodeUrl(t){return e.decode(t.replace(/_/g,"/").replace(/-/g,"+").replace(/\./g,"="))}static _initRevLookup(){if(0===e._revLookup.length){e._revLookup=[];for(let t=0,r=e._lookup.length;t0)throw new Error("Invalid string. Length must be a multiple of 4");let r=e.indexOf("=");return-1===r&&(r=t),[r,r===t?0:4-r%4]}static _byteLength(e,t){return 3*(e+t)/4-t}static _tripletToBase64(t){return e._lookup[t>>18&63]+e._lookup[t>>12&63]+e._lookup[t>>6&63]+e._lookup[63&t]}static _encodeChunk(t,r,s){const i=[];for(let n=r;nthis._checkIfServerClosed(),300)))}async call(e,...t){return this._call({command:e,args:t,id:n.generateRandomId()})}close(){this._connectionState=0,window.removeEventListener("message",this._receiveListener),window.clearInterval(this._serverCloseCheckInterval),this._serverCloseCheckInterval=-1;for(const[e,{reject:t}]of this._responseHandlers){const r=this._waitingRequests.getState(e);t("Connection was closed","number"==typeof e?e:void 0,r)}this._waitingRequests.clear(),this._responseHandlers.clear(),this._target&&this._target.closed&&(this._target=null)}_receive(e){return e.source===this._target&&super._receive(e)}async _call(e){if(!this._target||this._target.closed)throw new Error("Connection was closed.");if(2!==this._connectionState)throw new Error("Client is not connected, call init first");return new Promise((t,r)=>{this._responseHandlers.set(e.id,{resolve:t,reject:r}),this._waitingRequests.add(e.id,e.command),console.debug("RpcClient REQUEST",e.command,e.args),this._target.postMessage(e,this._allowedOrigin)})}_connect(){if(2!==this._connectionState)return this._connectionState=1,new Promise((e,t)=>{const r=t=>{const{source:i,origin:n,data:o}=t;if(i===this._target&&o.status===s.OK&&"pong"===o.result&&1===o.id&&("*"===this._allowedOrigin||n===this._allowedOrigin)){if(o.result.stack){const e=new Error(o.result.message);e.stack=o.result.stack,o.result.name&&(e.name=o.result.name),console.error(e)}window.removeEventListener("message",r),this._connectionState=2,console.log("RpcClient: Connection established"),e(!0)}};window.addEventListener("message",r);const i=()=>{if(2!==this._connectionState){if(0===this._connectionState||this._checkIfServerClosed())return window.removeEventListener("message",r),void t(new Error("Connection was closed"));try{this._target.postMessage({command:"ping",id:1},this._allowedOrigin)}catch(e){console.error(`postMessage failed: ${e}`)}window.setTimeout(i,100)}};window.setTimeout(i,100)})}_checkIfServerClosed(){return!(this._target&&!this._target.closed)&&(this.close(),!0)}}class h extends c{constructor(e,t,r=!0){super(t,!0),this._target=e,this._preserveRequests=r}async init(){const e=a.receiveRedirectResponse(window.location);if(e)return void this._receive(e);if(this._rejectOnBack())return;const t=new URLSearchParams(window.location.search);if(t.has(a.URL_SEARCHPARAM_NAME)){const e=window.sessionStorage.getItem(`response-${t.get(a.URL_SEARCHPARAM_NAME)}`);if(e)return void this._receive(i.parse(e),!1)}}close(){}call(e,t,s,...i){if(s&&"boolean"!=typeof s){if("object"==typeof s){if(s.responseMethod===r.POST_MESSAGE){if(!window.opener&&!window.parent)throw new Error("Window has no opener or parent, responseMethod: ResponseMethod.POST_MESSAGE would fail.");console.warn("Response will skip at least one rpc call, which will result in an unknown response.")}this._call(e,t,s,...i)}}else"boolean"==typeof s&&console.warn("RedirectRpcClient.call(string, string, boolean, any[]) is deprecated. Use RedirectRpcClient.call(string, string, CallOptions, any[]) with an appropriate CallOptions object instead."),this._call(e,t,{responseMethod:r.HTTP_GET,handleHistoryBack:!!s},...i)}callAndSaveLocalState(e,t,s,i=!1,...n){console.warn("RedirectRpcClient.callAndSaveLocalState() is deprecated. Use RedirectRpcClient.call() with an apropriate CallOptions object instead."),this._call(e,s,{responseMethod:r.HTTP_GET,state:t||void 0,handleHistoryBack:i},...n)}_receive(e,t=!0){const r=super._receive(e);return r&&t&&window.sessionStorage.setItem(`response-${e.data.id}`,i.stringify(e)),r}_call(e,t,s,...i){const o=n.generateRandomId(),c=s.responseMethod||r.HTTP_GET,l=a.prepareRedirectInvocation(this._target,o,e,t,i,c);this._waitingRequests.add(o,t,s.state||null),s.handleHistoryBack&&history.replaceState(Object.assign({},history.state,{rpcBackRejectionId:o}),""),console.debug("RpcClient REQUEST",t,i),window.location.href=l}_rejectOnBack(){if(!history.state||!history.state.rpcBackRejectionId)return!1;const e=history.state.rpcBackRejectionId;history.replaceState(Object.assign({},history.state,{rpcBackRejectionId:null}),"");const t=this._getCallback(e),r=this._waitingRequests.getState(e);if(t){this._preserveRequests||(this._waitingRequests.remove(e),this._responseHandlers.delete(e)),console.debug("RpcClient BACK");const s=new Error("Request aborted");return t.reject(s,e,r),!0}return!1}}class d{static getBrowserInfo(){return{browser:d.detectBrowser(),version:d.detectVersion(),isMobile:d.isMobile()}}static isMobile(){return/i?Phone|iP(ad|od)|Android|BlackBerry|Opera Mini|WPDesktop|Mobi(le)?|Silk/i.test(navigator.userAgent)}static detectBrowser(){if(d._detectedBrowser)return d._detectedBrowser;const e=navigator.userAgent;return/Edge\//i.test(e)?d._detectedBrowser=d.Browser.EDGE:/(Opera|OPR)\//i.test(e)?d._detectedBrowser=d.Browser.OPERA:/Firefox\//i.test(e)?d._detectedBrowser=d.Browser.FIREFOX:/Chrome\//i.test(e)?d._detectedBrowser=0!==navigator.plugins.length||0!==navigator.mimeTypes.length||d.isMobile()?d.Browser.CHROME:d.Browser.BRAVE:/^((?!chrome|android).)*safari/i.test(e)?d._detectedBrowser=d.Browser.SAFARI:d._detectedBrowser=d.Browser.UNKNOWN,d._detectedBrowser}static detectVersion(){if(void 0!==d._detectedVersion)return d._detectedVersion;let e;switch(d.detectBrowser()){case d.Browser.EDGE:e=/Edge\/(\S+)/i;break;case d.Browser.OPERA:e=/(Opera|OPR)\/(\S+)/i;break;case d.Browser.FIREFOX:e=/Firefox\/(\S+)/i;break;case d.Browser.CHROME:e=/Chrome\/(\S+)/i;break;case d.Browser.SAFARI:e=/(iP(hone|ad|od).*?OS |Version\/)(\S+)/i;break;case d.Browser.BRAVE:default:return d._detectedVersion=null,null}const t=navigator.userAgent.match(e);if(!t)return d._detectedVersion=null,null;const r=t[t.length-1].replace(/_/g,"."),s=r.split("."),i=[];for(let e=0;e<4;++e)i.push(parseInt(s[e],10)||0);const[n,o,a,c]=i;return d._detectedVersion={versionString:r,major:n,minor:o,build:a,patch:c},d._detectedVersion}static isChrome(){return d.detectBrowser()===d.Browser.CHROME}static isFirefox(){return d.detectBrowser()===d.Browser.FIREFOX}static isOpera(){return d.detectBrowser()===d.Browser.OPERA}static isEdge(){return d.detectBrowser()===d.Browser.EDGE}static isSafari(){return d.detectBrowser()===d.Browser.SAFARI}static isBrave(){return d.detectBrowser()===d.Browser.BRAVE}static isIOS(){return/iPad|iPhone|iPod/.test(navigator.userAgent)&&!window.MSStream}static isBadIOS(){const e=d.getBrowserInfo();return e.browser===d.Browser.SAFARI&&e.isMobile&&e.version&&(e.version.major<11||11===e.version.major&&2===e.version.minor)}static isPrivateMode(){return new Promise(e=>{const t=()=>e(!0),r=()=>e(!1);if(window.webkitRequestFileSystem)window.webkitRequestFileSystem(0,0,r,t);else{if(document.documentElement&&"MozAppearance"in document.documentElement.style){const e=indexedDB.open(null);return e.onerror=t,void(e.onsuccess=r)}if((()=>/Constructor/.test(window.HTMLElement)||window.safari&&window.safari.pushNotification&&"[object SafariRemoteNotification]"===window.safari.pushNotification.toString())())try{window.openDatabase(null,null,null,null)}catch(e){return void t()}window.indexedDB||!window.PointerEvent&&!window.MSPointerEvent?r():t()}})}}!function(e){let t;!function(e){e.CHROME="chrome",e.FIREFOX="firefox",e.OPERA="opera",e.EDGE="edge",e.SAFARI="safari",e.BRAVE="brave",e.UNKNOWN="unknown"}(t=e.Browser||(e.Browser={}))}(d||(d={}));var u=d,p={"popup-overlay":"A popup has been opened,\nclick anywhere to bring it back to the front."};const _={de:{"popup-overlay":"Ein Popup hat sich geöffnet,\nklicke hier, um zurück zum Popup zu kommen."},en:p,es:{"popup-overlay":"Se ha abierto una ventana emergente.\nHaga click en cualquier lugar para traer la ventana al primer plano."},fil:{"popup-overlay":"Nag-bukas ang isang pop-up.\nMaaring pindutin kahit saan para ibalik ito sa harap."},fr:{"popup-overlay":"Une popup a été ouverte,\ncliquez n'importe où pour la ramener au premier plan."},nl:{"popup-overlay":"Er is een pop-up geopend,\nklik op het scherm om het weer naar voren te brengen."},pl:{"popup-overlay":"Pojawiło się wyskakujące okno.\nAby je zobaczyć, kliknij w dowolnym miejscu."},pt:{"popup-overlay":"Um popup foi aberto,\nclique em qualquer lado para o trazer para a frente."},ru:{"popup-overlay":"Открыто всплывающее окно.\nНажмите где-нибудь, чтобы вернуть его на передний план."},tr:{"popup-overlay":"Bir popup penceresi açıldı,\nöne çekmek için herhangi bir yere tıkla. "},uk:{"popup-overlay":"Відкрито випадаюче вікно.\nклацніть будь-де щоб перейти до ньго."},zh:{"popup-overlay":"弹出窗口已打开,\n单击任意位置即可回到上一页"}};class g{constructor(e){this._type=e}static getAllowedOrigin(e){return new URL(e).origin}async request(e,t,r){throw new Error("Not implemented")}}var w,A,R,m,f,S,E,v;!function(e){e[e.REDIRECT=0]="REDIRECT",e[e.POPUP=1]="POPUP",e[e.IFRAME=2]="IFRAME"}(w||(w={}));class I extends g{constructor(e,t){super(w.REDIRECT);const r=window.location;if(this._returnUrl=e||`${r.origin}${r.pathname}`,this._localState=t||{},void 0!==this._localState.__command)throw new Error("Invalid localState: Property '__command' is reserved")}static withLocalState(e){return new I(void 0,e)}async request(e,t,r){const s=g.getAllowedOrigin(e),i=new h(e,s);await i.init();const n=Object.assign({},this._localState,{__command:t});i.callAndSaveLocalState(this._returnUrl,n,t,!0,...await Promise.all(r))}}class y extends g{constructor(e=y.DEFAULT_FEATURES,t){super(w.POPUP),this.shouldRetryRequest=!1,this._popupFeatures=e,this._options={...y.DEFAULT_OPTIONS,...t}}async request(e,t,r){const s=g.getAllowedOrigin(e),i=this.appendOverlay();do{this.shouldRetryRequest=!1;try{return this.popup=this.createPopup(e),this.client=new l(this.popup,s),await this.client.init(),await this.client.call(t,...await Promise.all(r))}catch(e){if(!this.shouldRetryRequest)throw e}finally{this.shouldRetryRequest||(this.removeOverlay(i),this.client&&this.client.close(),this.popup&&this.popup.close())}}while(this.shouldRetryRequest);throw this.popup&&this.popup.close(),this.client&&this.client.close(),i&&this.removeOverlay(i),new Error("Unexpected error occurred")}createPopup(e){const t=window.open(e,"NimiqAccounts",this._popupFeatures);if(!t)throw new Error("Failed to open popup");return t}appendOverlay(){if(!this._options.overlay)return null;const e=document.createElement.bind(document),t=(e,t)=>e.appendChild(t),r=e("div");r.id="nimiq-hub-overlay";const s=r.style;s.position="fixed",s.top="0",s.right="0",s.bottom="0",s.left="0",s.background="rgba(31, 35, 72, 0.8)",s.display="flex",s.flexDirection="column",s.alignItems="center",s.justifyContent="space-between",s.cursor="pointer",s.color="white",s.textAlign="center",s.opacity="0",s.transition="opacity 0.6s ease",s.zIndex="99999",r.addEventListener("click",()=>{u.isIOS()?(this.shouldRetryRequest=!0,this.popup&&this.popup.close(),this.client&&this.client.close()):this.popup&&this.popup.focus()}),t(r,e("div"));const i=e("div");i.textContent=function(e,t){if(!t){const e=document.cookie.match(/(^| )lang=([^;]+)/);t=e&&e[2]||navigator.language.split("-")[0]}return(_[t]||p)[e]||p[e]}("popup-overlay");const n=i.style;n.padding="20px",n.fontFamily='Muli, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif',n.fontSize="24px",n.fontWeight="600",n.lineHeight="40px",n.whiteSpace="pre-line",t(r,i);const o=e("img");o.src='data:image/svg+xml,',o.style.marginBottom="56px",t(r,o);const a=e("div"),c=a.style;return a.innerHTML="×",c.position="absolute",c.top="8px",c.right="8px",c.fontSize="24px",c.lineHeight="32px",c.fontWeight="600",c.width="32px",c.height="32px",c.opacity="0.8",a.addEventListener("click",e=>{this.popup&&this.popup.close(),e.stopPropagation()}),t(r,a),setTimeout(()=>r.style.opacity="1",100),t(document.body,r)}removeOverlay(e){e&&(e.style.opacity="0",setTimeout(()=>document.body.removeChild(e),400))}}y.DEFAULT_FEATURES="",y.DEFAULT_OPTIONS={overlay:!0};class C extends g{constructor(){super(w.IFRAME),this._iframe=null,this._client=null}async request(e,t,r){if(this._iframe&&this._iframe.src!==`${e}${C.IFRAME_PATH_SUFFIX}`)throw new Error("Hub iframe is already opened with another endpoint");const s=g.getAllowedOrigin(e);if(this._iframe||(this._iframe=await this.createIFrame(e)),!this._iframe.contentWindow)throw new Error(`IFrame contentWindow is ${typeof this._iframe.contentWindow}`);return this._client||(this._client=new l(this._iframe.contentWindow,s),await this._client.init()),await this._client.call(t,...await Promise.all(r))}async createIFrame(e){return new Promise((t,r)=>{const s=document.createElement("iframe");s.name="NimiqAccountsIFrame",s.style.display="none",document.body.appendChild(s),s.src=`${e}${C.IFRAME_PATH_SUFFIX}`,s.onload=(()=>t(s)),s.onerror=r})}}C.IFRAME_PATH_SUFFIX="/iframe.html",function(e){e.LIST="list",e.LIST_CASHLINKS="list-cashlinks",e.MIGRATE="migrate",e.CHECKOUT="checkout",e.SIGN_MESSAGE="sign-message",e.SIGN_TRANSACTION="sign-transaction",e.SIGN_MULTISIG_TRANSACTION="sign-multisig-transaction",e.SIGN_STAKING="sign-staking",e.ONBOARD="onboard",e.SIGNUP="signup",e.LOGIN="login",e.EXPORT="export",e.CHANGE_PASSWORD="change-password",e.LOGOUT="logout",e.ADD_ADDRESS="add-address",e.RENAME="rename",e.ADD_VESTING_CONTRACT="add-vesting-contract",e.CHOOSE_ADDRESS="choose-address",e.CREATE_CASHLINK="create-cashlink",e.MANAGE_CASHLINK="manage-cashlink",e.SIGN_BTC_TRANSACTION="sign-btc-transaction",e.ADD_BTC_ADDRESSES="add-btc-addresses",e.SIGN_POLYGON_TRANSACTION="sign-polygon-transaction",e.ACTIVATE_BITCOIN="activate-bitcoin",e.ACTIVATE_POLYGON="activate-polygon",e.SETUP_SWAP="setup-swap",e.REFUND_SWAP="refund-swap",e.CONNECT_ACCOUNT="connect-account"}(A||(A={})),function(e){e[e.LEGACY=1]="LEGACY",e[e.BIP39=2]="BIP39",e[e.LEDGER=3]="LEDGER"}(R||(R={})),function(e){e[e.DIRECT=0]="DIRECT",e[e.OASIS=1]="OASIS"}(m||(m={})),function(e){e.NIM="nim",e.BTC="btc",e.ETH="eth"}(f||(f={})),function(e){e.NOT_FOUND="NOT_FOUND",e.PAID="PAID",e.UNDERPAID="UNDERPAID",e.OVERPAID="OVERPAID"}(S||(S={})),function(e){e[e.UNKNOWN=-1]="UNKNOWN",e[e.UNCHARGED=0]="UNCHARGED",e[e.CHARGING=1]="CHARGING",e[e.UNCLAIMED=2]="UNCLAIMED",e[e.CLAIMING=3]="CLAIMING",e[e.CLAIMED=4]="CLAIMED"}(E||(E={})),function(e){e[e.UNSPECIFIED=0]="UNSPECIFIED",e[e.STANDARD=1]="STANDARD",e[e.CHRISTMAS=2]="CHRISTMAS",e[e.LUNAR_NEW_YEAR=3]="LUNAR_NEW_YEAR",e[e.EASTER=4]="EASTER",e[e.GENERIC=5]="GENERIC",e[e.BIRTHDAY=6]="BIRTHDAY"}(v||(v={}));class T{constructor(e=T.DEFAULT_ENDPOINT,t){this._endpoint=e,this._defaultBehavior=t||new y(`left=${window.innerWidth/2-400},top=75,width=800,height=850,location=yes,dependent=yes`),this._checkoutDefaultBehavior=t||new y(`left=${window.innerWidth/2-400},top=50,width=800,height=895,location=yes,dependent=yes`),this._iframeBehavior=new C,this._redirectClient=new h("",g.getAllowedOrigin(this._endpoint))}static get PaymentMethod(){return console.warn("PaymentMethod has been renamed to PaymentType. Access via HubApi.PaymentMethod will soon get disabled. Use HubApi.PaymentType instead."),m}static get DEFAULT_ENDPOINT(){const e=location.hostname.match(/(?:[^.]+\.[^.]+|localhost)$/),t=e?e[0]:location.hostname;switch(t){case"nimiq.com":case"nimiq-testnet.com":return`https://hub.${t}`;case"bs-local.com":return`${window.location.protocol}//bs-local.com:8080`;default:return"http://localhost:8080"}}checkRedirectResponse(){return this._redirectClient.init()}on(e,t,r){this._redirectClient.onResponse(e,(e,r,s)=>t(e,s),(e,t,s)=>{r&&r(e,s)})}createCashlink(e,t=this._defaultBehavior){return this._request(t,A.CREATE_CASHLINK,[e])}manageCashlink(e,t=this._defaultBehavior){return this._request(t,A.MANAGE_CASHLINK,[e])}checkout(e,t=this._checkoutDefaultBehavior){return this._request(t,A.CHECKOUT,[e])}chooseAddress(e,t=this._defaultBehavior){return this._request(t,A.CHOOSE_ADDRESS,[e])}signTransaction(e,t=this._defaultBehavior){return this._request(t,A.SIGN_TRANSACTION,[e])}signStaking(e,t=this._defaultBehavior){return this._request(t,A.SIGN_STAKING,[e])}signMessage(e,t=this._defaultBehavior){return this._request(t,A.SIGN_MESSAGE,[e])}signBtcTransaction(e,t=this._defaultBehavior){return this._request(t,A.SIGN_BTC_TRANSACTION,[e])}signPolygonTransaction(e,t=this._defaultBehavior){return this._request(t,A.SIGN_POLYGON_TRANSACTION,[e])}setupSwap(e,t=this._defaultBehavior){return this._request(t,A.SETUP_SWAP,[e])}refundSwap(e,t=this._defaultBehavior){return this._request(t,A.REFUND_SWAP,[e])}signMultisigTransaction(e,t=this._defaultBehavior){return this._request(t,A.SIGN_MULTISIG_TRANSACTION,[e])}connectAccount(e,t=this._defaultBehavior){return this._request(t,A.CONNECT_ACCOUNT,[e])}onboard(e,t=this._defaultBehavior){return this._request(t,A.ONBOARD,[e])}signup(e,t=this._defaultBehavior){return this._request(t,A.SIGNUP,[e])}login(e,t=this._defaultBehavior){return this._request(t,A.LOGIN,[e])}logout(e,t=this._defaultBehavior){return this._request(t,A.LOGOUT,[e])}export(e,t=this._defaultBehavior){return this._request(t,A.EXPORT,[e])}changePassword(e,t=this._defaultBehavior){return this._request(t,A.CHANGE_PASSWORD,[e])}addAddress(e,t=this._defaultBehavior){return this._request(t,A.ADD_ADDRESS,[e])}rename(e,t=this._defaultBehavior){return this._request(t,A.RENAME,[e])}addVestingContract(e,t=this._defaultBehavior){return this._request(t,A.ADD_VESTING_CONTRACT,[e])}migrate(e=this._defaultBehavior){return this._request(e,A.MIGRATE,[{appName:"Account list"}])}activateBitcoin(e,t=this._defaultBehavior){return this._request(t,A.ACTIVATE_BITCOIN,[e])}activatePolygon(e,t=this._defaultBehavior){return this._request(t,A.ACTIVATE_POLYGON,[e])}list(e=this._iframeBehavior){return this._request(e,A.LIST,[])}cashlinks(e=this._iframeBehavior){return this._request(e,A.LIST_CASHLINKS,[])}addBtcAddresses(e,t=this._iframeBehavior){return this._request(t,A.ADD_BTC_ADDRESSES,[e])}_request(e,t,r){return e.request(this._endpoint,t,r)}}return T.BehaviorType=w,T.RequestType=A,T.RedirectRequestBehavior=I,T.PopupRequestBehavior=y,T.AccountType=R,T.CashlinkState=E,T.CashlinkTheme=v,T.Currency=f,T.PaymentType=m,T.PaymentState=S,T.MSG_PREFIX="Nimiq Signed Message:\n",T}); diff --git a/package.json b/package.json index ed840f71..f8816aa2 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "@nimiq/electrum-client": "https://github.com/nimiq/electrum-client#build", "@nimiq/fastspot-api": "^1.10.2", "@nimiq/iqons": "^1.5.2", - "@nimiq/keyguard-client": "https://gitpkg.now.sh/nimiq/keyguard?scripts.postinstall=cd%20client%20%26%26%20.%2Fbuild-gitpkg.sh&a62aa9f557e2ac4c0d7306828e423230f423a0f1", + "@nimiq/keyguard-client": "https://gitpkg.now.sh/nimiq/keyguard?scripts.postinstall=cd%20client%20%26%26%20.%2Fbuild-gitpkg.sh&fbbcf067a5043d9d56bd24c5a2ac79f63355fac1", "@nimiq/ledger-api": "^3.1.1", "@nimiq/oasis-api": "^1.1.1", "@nimiq/rpc": "^0.4.1", diff --git a/src/i18n/en.po b/src/i18n/en.po index 728bb66f..02e1f85e 100644 --- a/src/i18n/en.po +++ b/src/i18n/en.po @@ -291,6 +291,10 @@ msgstr "" msgid "Choose an Account" msgstr "" +#: src/views/ConnectAccount.vue:5 +msgid "Choose an Account to log in" +msgstr "" + #: src/views/CashlinkReceive.vue:64 #: src/views/ChooseAddress.vue:18 #: src/views/ChooseAddress.vue:5 @@ -697,7 +701,12 @@ msgstr "" msgid "Login File saved!" msgstr "" +#: src/views/ConnectAccountSuccess.vue:4 +msgid "Login successful" +msgstr "" + #: src/views/ChooseAddress.vue:67 +#: src/views/ConnectAccount.vue:40 msgid "Login to another account" msgstr "" diff --git a/src/lib/RequestParser.ts b/src/lib/RequestParser.ts index 30ba9db8..25b8c0c8 100644 --- a/src/lib/RequestParser.ts +++ b/src/lib/RequestParser.ts @@ -795,35 +795,31 @@ export class RequestParser { signer: Nimiq.Address.fromAny(signMultisigTxRequest.signer), sender: Nimiq.Address.fromString(signMultisigTxRequest.sender), - senderType: signMultisigTxRequest.senderType || Nimiq.Account.Type.BASIC, + senderType: signMultisigTxRequest.senderType || Nimiq.AccountType.Basic, senderLabel: signMultisigTxRequest.senderLabel, recipient: Nimiq.Address.fromString(signMultisigTxRequest.recipient), - recipientType: signMultisigTxRequest.recipientType || Nimiq.Account.Type.BASIC, + recipientType: signMultisigTxRequest.recipientType || Nimiq.AccountType.Basic, recipientLabel: signMultisigTxRequest.recipientLabel, value: signMultisigTxRequest.value, fee: signMultisigTxRequest.fee || 0, data: parseMessage(signMultisigTxRequest.extraData) || new Uint8Array(0), - flags: signMultisigTxRequest.flags || Nimiq.Transaction.Flag.NONE, + flags: signMultisigTxRequest.flags || Nimiq.TransactionFlag.None, validityStartHeight: signMultisigTxRequest.validityStartHeight, multisigConfig: { publicKeys: signMultisigTxRequest.multisigConfig.publicKeys.map((bytes) => parseBytes(bytes)), - numberOfSigners: signMultisigTxRequest.multisigConfig.numberOfSigners, - signerPublicKeys: signMultisigTxRequest.multisigConfig.signerPublicKeys - ? signMultisigTxRequest.multisigConfig.signerPublicKeys.map((bytes) => parseBytes(bytes)) - : signMultisigTxRequest.multisigConfig.publicKeys.map((bytes) => parseBytes(bytes)), - secret: 'aggregatedSecret' in signMultisigTxRequest.multisigConfig.secret - ? {aggregatedSecret: parseBytes( - signMultisigTxRequest.multisigConfig.secret.aggregatedSecret, - ) } + signers: signMultisigTxRequest.multisigConfig.signers.map((signer) => ({ + publicKey: parseBytes(signer.publicKey), + commitments: signer.commitments.map((bytes) => parseBytes(bytes)), + })), + secrets: Array.isArray(signMultisigTxRequest.multisigConfig.secrets) + ? signMultisigTxRequest.multisigConfig.secrets.map((bytes) => parseBytes(bytes)) : { - encryptedSecrets: signMultisigTxRequest.multisigConfig.secret.encryptedSecrets.map( + encrypted: signMultisigTxRequest.multisigConfig.secrets.encrypted.map( (bytes) => parseBytes(bytes), ), - bScalar: parseBytes(signMultisigTxRequest.multisigConfig.secret.bScalar), - keyParams: signMultisigTxRequest.multisigConfig.secret.keyParams, + keyParams: signMultisigTxRequest.multisigConfig.secrets.keyParams, }, - aggregatedCommitment: parseBytes(signMultisigTxRequest.multisigConfig.aggregatedCommitment), userName: signMultisigTxRequest.multisigConfig.userName, }, }; @@ -836,7 +832,7 @@ export class RequestParser { } if (connectAccountRequest.appLogoUrl) { - let origin; + let origin: string; try { origin = new URL(connectAccountRequest.appLogoUrl).origin; } catch (err) { diff --git a/src/lib/RequestTypes.ts b/src/lib/RequestTypes.ts index 1a0d6004..3ee5c6b8 100644 --- a/src/lib/RequestTypes.ts +++ b/src/lib/RequestTypes.ts @@ -56,20 +56,18 @@ export interface ParsedSignTransactionRequest extends ParsedBasicRequest { export interface ParsedMultisigInfo { publicKeys: Uint8Array[]; - numberOfSigners: number; - signerPublicKeys: Uint8Array[]; // Can be omitted when all publicKeys need to sign - secret: { - aggregatedSecret: Uint8Array; - } | { - encryptedSecrets: Uint8Array[]; - bScalar: Uint8Array; + signers: Array<{ + publicKey: Uint8Array; + commitments: Uint8Array[]; + }>; + secrets: Uint8Array[] | { + encrypted: Uint8Array[]; keyParams: { kdf: string; iterations: number; keySize: number; }; }; - aggregatedCommitment: Uint8Array; userName?: string; } @@ -77,10 +75,10 @@ export interface ParsedSignMultisigTransactionRequest extends ParsedBasicRequest signer: Nimiq.Address; sender: Nimiq.Address; - senderType: Nimiq.Account.Type; + senderType: Nimiq.AccountType; senderLabel: string; recipient: Nimiq.Address; - recipientType: Nimiq.Account.Type; + recipientType: Nimiq.AccountType; recipientLabel?: string; value: number; fee?: number; diff --git a/src/views/ConnectAccountSuccess.vue b/src/views/ConnectAccountSuccess.vue index a4b7459b..c5c1f3aa 100644 --- a/src/views/ConnectAccountSuccess.vue +++ b/src/views/ConnectAccountSuccess.vue @@ -17,7 +17,6 @@ import StatusScreen from '../components/StatusScreen.vue'; import { SmallPage, CheckmarkIcon } from '@nimiq/vue-components'; import { WalletInfo } from '../lib/WalletInfo'; import { WalletType } from '../lib/Constants'; -import { loadNimiq } from '../lib/Helpers'; import { ParsedConnectAccountRequest } from '../lib/RequestTypes'; import { WalletStore } from '../lib/WalletStore'; @@ -32,8 +31,6 @@ export default class ConnectAccountSuccess extends Vue { private async mounted() { const startTime = Date.now(); - const nimiqPromise = loadNimiq(); // Required for deriving address from public key - const wallet = this.findWalletByKeyId(this.keyguardRequest.keyId)!; const walletTypeName: Record = { @@ -48,8 +45,6 @@ export default class ConnectAccountSuccess extends Vue { wallet.permissions[this.rpcState.origin] = walletPermissions; await WalletStore.Instance.put(wallet); - await nimiqPromise; - const result: ConnectedAccount = { signatures: this.keyguardResult.signatures.map(({signature, publicKey}) => ({ signer: new Nimiq.PublicKey(publicKey).toAddress().toUserFriendlyAddress(), diff --git a/src/views/SignMultisigTransaction.vue b/src/views/SignMultisigTransaction.vue index 94928b12..2472cfa6 100644 --- a/src/views/SignMultisigTransaction.vue +++ b/src/views/SignMultisigTransaction.vue @@ -53,7 +53,7 @@ export default class SignMultisigTransaction extends Vue { value: this.request.value, fee: this.request.fee || 0, validityStartHeight: this.request.validityStartHeight, - data: this.request.data, + recipientData: this.request.data, flags: this.request.flags, multisigConfig: this.request.multisigConfig, diff --git a/yarn.lock b/yarn.lock index 91d7db04..dad69321 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1843,9 +1843,9 @@ dependencies: dom-parser "^0.1.5" -"@nimiq/keyguard-client@https://gitpkg.now.sh/nimiq/keyguard?scripts.postinstall=cd%20client%20%26%26%20.%2Fbuild-gitpkg.sh&a62aa9f557e2ac4c0d7306828e423230f423a0f1": +"@nimiq/keyguard-client@https://gitpkg.now.sh/nimiq/keyguard?scripts.postinstall=cd%20client%20%26%26%20.%2Fbuild-gitpkg.sh&fbbcf067a5043d9d56bd24c5a2ac79f63355fac1": version "1.0.0" - resolved "https://gitpkg.now.sh/nimiq/keyguard?scripts.postinstall=cd%20client%20%26%26%20.%2Fbuild-gitpkg.sh&a62aa9f557e2ac4c0d7306828e423230f423a0f1#b821554c4e4751e93cd9e287cd3617812e2a3ea2" + resolved "https://gitpkg.now.sh/nimiq/keyguard?scripts.postinstall=cd%20client%20%26%26%20.%2Fbuild-gitpkg.sh&fbbcf067a5043d9d56bd24c5a2ac79f63355fac1#69723c531cb46fd97466bf35d6cfadd612836ff6" "@nimiq/ledger-api@^3.1.1": version "3.1.1"