ton-connect / sdk

SDK for TON Connect 2.0 — a comprehensive communication protocol between wallets and apps in TON ecosystem
Apache License 2.0
268 stars 69 forks source link

[UI]: Способ авторизации из примера не работает в определенных сценариях #68

Closed stels-cs closed 10 months ago

stels-cs commented 1 year ago

В документации есть способ вызова модального окна авторизации https://github.com/ton-connect/sdk/tree/main/packages/ui#call-connect

const connectedWallet = await tonConnectUI.connectWallet();

Однако он не будет работать правильно если пользователь в первый раз откажется от авторизации. В этом случае промис вернет ошибку, но UI не скроется, пользователь может повторно авторизоваться, но результат авторизации уже не будет обработан.

Вот пример сайта демонстрирующий проблему

<div class="center">
    <button onclick="connectWallet()">Connect wallet</button>
</div>
</body>
<script src="https://unpkg.com/@tonconnect/ui@latest/dist/tonconnect-ui.min.js"></script>
<script>
  const tonConnectUI = new TON_CONNECT_UI.TonConnectUI({
    manifestUrl: 'https://stels-cs.github.io/ton-connect-ui/tcm.json',
    restoreConnection: false,
  });

  async function connectWallet() {
    const connectedWallet = await tonConnectUI.connectWallet(); // Problem
    console.log('connectedWallet', connectedWallet);
  }
</script>

Шаги 1) Перейти сюда https://stels-cs.github.io/ton-connect-ui/demo-ton-ui.html, Нажать кнопку Connect Wallet 2) Отсканировать QR код в приложении Tonkeeper 3) Закрыть диалог авторизации в Tonkeeper, в это время сайт получит сообщение об ошибке, это ожидаемое поведение 4) Так как UI все еще отображается мы можем заново отсканировать QR код в Tonkeeper и авторизоваться 5) Результат авторизации не будет обработан, так как промис уже вернул ошибку

Корректно обработать авторизацию можно только если подписываться на изменение статуса https://github.com/ton-connect/sdk/tree/main/packages/ui#subscribe-to-the-connection-status-changes

stels-cs commented 10 months ago

Ого, круто что починили!

Но проблема все еще существует с TWA, там приложение перезапускается полностью и схема с промисом не будет работать.

Ниже пример TWA, если в попытаться авторизоваться через @wallet бот (вам надо заранее создать в нем TON Space). То сработает только onStatusChange, а если авторизоваться через тонкипер то будет работать и промис после connectWallet t.me/local_presale_bot/tcui

    <div class="center">
        <button onclick="connectWallet()">Connect TON</button>
        <br/>
        <button onclick="disconnectWallet()">Disconnect TON</button>
        <pre id="log"></pre>
    </div>
    <script src="https://unpkg.com/@tonconnect/ui@latest/dist/tonconnect-ui.min.js"></script>
    <script>

        function log(msg) {
            console.log(msg)
            const t = document.createTextNode(msg + "\n")
            document.getElementById('log').appendChild(t);
        }

        const tonConnectUI = new TON_CONNECT_UI.TonConnectUI({
            manifestUrl: 'https://stels-cs.github.io/ton-connect-ui/tcm.json',
            actionsConfiguration:{
                  twaReturnUrl:'https://t.me/local_presale_bot/tcui'    
            }
        });

        tonConnectUI.onStatusChange(wallet => {
            log("onStatusChange: "+wallet?.account.address)
        })

        async function connectWallet() {
            const connectedWallet = await tonConnectUI.connectWallet();
            log("connected after connectWallet");
        }

        function disconnectWallet() {
            tonConnectUI.disconnect();
        }
    </script>
thekiba commented 10 months ago

Как и было замечено, tonConnectUI.connectWallet() был исправлен, и теперь он должен работать корректно, но не с TWA из-за его специфики. Хочу обратить внимание, что из-за невозможности достоверно определить был ли совершен коннект с кошельком или нет, этот метод помечен как устаревший и в будущем будет удалён. Вместо него рекомендуем использовать tonConnectUI.openModal() для открытия модального окна.

Для отслеживания изменений состояния модального окна, необходимо подписаться на события с помощью tonConnectUI.onModalStateChange((state: WalletsModalState) => { ... }). Это позволит реактивно отображать лоадер в зависимости от состояния модального окна.

Также необходимо подписаться на tonConnectUI.onStatusChange(walletAndwalletInfo => { ... }), чтобы реактивно получать информацию о кошельке.

Если используется react, то для него был добавлен useTonConnectModal(), который упрощает управление состоянием модального окна.

import { useTonConnectModal } from '@tonconnect/ui-react';

export const ModalControl = () => {
    const { state, open, close } = useTonConnectModal();

    return (
      <div>
          <div>Modal state: {state?.status}</div>
          <button onClick={open}>Open modal</button>
          <button onClick={close}>Close modal</button>
      </div>
    );
};