UNPKG

@slide-computer/signer-web

Version:

JavaScript and TypeScript library to communicate with web signers on the Internet Computer

131 lines (106 loc) 3.96 kB
# @slide-computer/signer-web JavaScript and TypeScript library to communicate with web signers on the Internet Computer. --- ## Installation Using signer web: ``` npm i --save @slide-computer/signer-web ``` ## In the browser: ``` import { PostMessageTransport } from "@slide-computer/signer-web"; ``` To create an ICRC-29 post message transport, run ```js const transport = new PostMessageTransport({ openWindow: () => window.open(SIGNER_RPC_URL, SIGNER_WINDOW_NAME) }); ``` Either use with `@slide-computer/signer` ```js const signer = new Signer({transport}); ``` Or directly in your custom implementation ```js actionButton.onClick = async () => { // Must be established within a click handler // to avoid the signer popup from being blocked. const channel = await transport.establishChannel(); const listener = channel.registerListener((response) => { // Process incoming responses }); // Send outgoing requests channel.send(JSON_RPC_REQUEST); } ``` ### Channels must be established in a click handler The following code will work fine without throwing an error: ```js const transfer = async (amount) => { await icpActorSigner.transfer(targetAddress, amount); } transferButton.onClick = () => transfer(50000n); ``` But this code will throw an error: ```js const transferFrom = async (amount) => { const allowance = await icpActorAnonymous.allowance(userAddress); // <- Issue if (allowance < amount) { await icpActorSigner.approve(amount - allowance); } await dappActor.transferWithAllowance(userAddress, amount); } swapButton.onClick = () => transferFrom(50000n); ``` In the second example, a function call with `await` has moved all the calls below outside the context of the click handler. In some browsers - particularly Safari - this means that the popup opened when the post message transport channel is established will be **blocked**. The post message transport's `detectNonClickEstablishment` option (default: true) detects this in all browsers and throws an error to make sure this issue can be caught by a developer even if they're not using a browser that would have blocked the popup. There are multiple ways to fix this error: 1. Make the `await` function calls outside the click handler: ```js const allowance = await icpActorAnonymous.allowance(userAddress); const transferFrom = async (amount) => { if (allowance < amount) { await icpActorSigner.approve(amount - allowance); } await dappActor.transferWithAllowance(userAddress, amount); } swapButton.onClick = () => transferFrom(50000n); ``` 2. Establish the transport channel first in your click handler: ```js const transferFrom = async (amount) => { await signer.openChannel(); // or: await agent.signer.openChannel(); const allowance = await icpActorAnonymous.allowance(userAddress); if (allowance < amount) { await icpActorSigner.approve(amount - allowance); } await dappActor.transferWithAllowance(userAddress, amount); } swapButton.onClick = () => transferFrom(50000n); ``` 3. Disable this error by setting `detectNonClickEstablishment` to `false`, be aware that this does not resolve the underlying issue of popups possibly being blocked in some browsers. ### Establishing a communication channel as a signer with a relying party ```js new HeartBeatServer({ onEstablish: (origin, source) => { // 1. Show origin to user to identify the relying party // 2. Use origin and source to communicate with relying party }, onEstablishTimeout: () => { // Wrong place // Seems you arrived here for approval, // but no service has requested it. }, onDisconnect: () => { // Connection closed // It seems like the connection with // the service closed unexpectedly. } }); ```