Skip to content

Commit

Permalink
ton_proof example
Browse files Browse the repository at this point in the history
  • Loading branch information
sorokin0andrey committed Nov 15, 2022
1 parent f753edc commit 0012de4
Show file tree
Hide file tree
Showing 13 changed files with 279 additions and 123 deletions.
12 changes: 6 additions & 6 deletions docs/asset-manifest.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"files": {
"main.css": "/demo-dapp/static/css/main.86f220c3.css",
"main.js": "/demo-dapp/static/js/main.afdb6703.js",
"main.css": "/demo-dapp/static/css/main.82265efa.css",
"main.js": "/demo-dapp/static/js/main.888dd217.js",
"index.html": "/demo-dapp/index.html",
"main.86f220c3.css.map": "/demo-dapp/static/css/main.86f220c3.css.map",
"main.afdb6703.js.map": "/demo-dapp/static/js/main.afdb6703.js.map"
"main.82265efa.css.map": "/demo-dapp/static/css/main.82265efa.css.map",
"main.888dd217.js.map": "/demo-dapp/static/js/main.888dd217.js.map"
},
"entrypoints": [
"static/css/main.86f220c3.css",
"static/js/main.afdb6703.js"
"static/css/main.82265efa.css",
"static/js/main.888dd217.js"
]
}
2 changes: 1 addition & 1 deletion docs/index.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/demo-dapp/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Example of a dapp that connects to the wallet via ton-connect v2"/><title>Demo Dapp</title><script defer="defer" src="/demo-dapp/static/js/main.afdb6703.js"></script><link href="/demo-dapp/static/css/main.86f220c3.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/demo-dapp/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Example of a dapp that connects to the wallet via ton-connect v2"/><title>Demo Dapp</title><script defer="defer" src="/demo-dapp/static/js/main.888dd217.js"></script><link href="/demo-dapp/static/css/main.82265efa.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions docs/static/css/main.82265efa.css.map

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion docs/static/css/main.86f220c3.css.map

This file was deleted.

Large diffs are not rendered by default.

File renamed without changes.

Large diffs are not rendered by default.

35 changes: 18 additions & 17 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@
import React, { useEffect } from 'react';
import { AppTitle } from 'src/components/AppTitle/AppTitle';
import { AuthButton } from 'src/components/AuthButton/AuthButton';
import './app.scss';
import { TxForm } from 'src/components/TxForm/TxForm';
import { connector } from 'src/connector';
import React, { useEffect } from "react";
import { AppTitle } from "src/components/AppTitle/AppTitle";
import { AuthButton } from "src/components/AuthButton/AuthButton";
import "./app.scss";
import { TxForm } from "src/components/TxForm/TxForm";
import { connector } from "src/connector";
import { TonProofDemo } from "./components/TonProofDemo/TonProofDemo";

function App() {

useEffect(() => {
connector.restoreConnection();
}, []);
useEffect(() => {
connector.restoreConnection();
}, []);

return (
<div className="app">
<header>
<AppTitle />
<AuthButton />
</header>
<main>
<TxForm />
</main>
<header>
<AppTitle />
<AuthButton />
</header>
<main>
<TxForm />
<TonProofDemo />
</main>
</div>
);
}
Expand Down
81 changes: 81 additions & 0 deletions src/TonProofDemoApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { TonProofItemReply } from "@tonconnect/protocol";
import { Account } from "@tonconnect/sdk";
import { connector } from "./connector";

class TonProofDemoApiService {
localStorageKey = "demo-api-access-token";

host = "https://demo.tonconnect.dev";

accessToken: string | null = null;

constructor() {
this.accessToken = localStorage.getItem(this.localStorageKey);

connector.onStatusChange((wallet) => {
if (!wallet) {
this.reset();
}

const tonProof = wallet?.connectItems?.tonProof;

if (tonProof) {
this.checkProof(tonProof, wallet.account);
}
});
}

async generatePayload() {
const response = await (
await fetch(`${this.host}/ton-proof/generatePayload`, {
method: "POST",
})
).json();

return response.payload as string;
}

async checkProof(proof: TonProofItemReply["proof"], account: Account) {
try {
const reqBody = {
address: account.address,
network: account.chain,
proof,
};

const response = await (
await fetch(`${this.host}/ton-proof/checkProof`, {
method: "POST",
body: JSON.stringify(reqBody),
})
).json();

if (response?.token) {
localStorage.setItem(this.localStorageKey, response.token);
this.accessToken = response.token;
}
} catch (e) {
console.log("checkProof error:", e);
}
}

async getAccountInfo(account: Account) {
const response = await (
await fetch(`${this.host}/dapp/getAccountInfo?network=${account.chain}`, {
headers: {
Authorization: `Bearer ${this.accessToken}`,
"Content-Type": "application/json",
},
})
).json();

return response as {};
}

reset() {
this.accessToken = null;
localStorage.removeItem(this.localStorageKey);
}
}

export const TonProofDemoApi = new TonProofDemoApiService();
192 changes: 100 additions & 92 deletions src/components/AuthButton/AuthButton.tsx
Original file line number Diff line number Diff line change
@@ -1,108 +1,116 @@
import React, { useCallback, useEffect, useState } from 'react';
import { useRecoilValueLoadable } from 'recoil';
import { connector } from 'src/connector';
import { useForceUpdate } from 'src/hooks/useForceUpdate';
import { useSlicedAddress } from 'src/hooks/useSlicedAddress';
import { useTonWallet } from 'src/hooks/useTonWallet';
import { Button, Dropdown, Menu, Modal, notification, Space } from 'antd';
import { DownOutlined } from '@ant-design/icons';
import { useTonWalletConnectionError } from 'src/hooks/useTonWalletConnectionError';
import { walletsListQuery } from 'src/state/wallets-list';
import { isMobile } from 'src/utils';
import QRCode from 'react-qr-code';
import './style.scss';
import React, { useCallback, useEffect, useState } from "react";
import { useRecoilValueLoadable } from "recoil";
import { connector } from "src/connector";
import { useForceUpdate } from "src/hooks/useForceUpdate";
import { useSlicedAddress } from "src/hooks/useSlicedAddress";
import { useTonWallet } from "src/hooks/useTonWallet";
import { Button, Dropdown, Menu, Modal, notification, Space } from "antd";
import { DownOutlined } from "@ant-design/icons";
import { useTonWalletConnectionError } from "src/hooks/useTonWalletConnectionError";
import { walletsListQuery } from "src/state/wallets-list";
import { isMobile } from "src/utils";
import QRCode from "react-qr-code";
import "./style.scss";
import { TonProofDemoApi } from "src/TonProofDemoApi";

const menu = (
<Menu
onClick={() => connector.disconnect()}
items={[
{
label: 'Disconnect',
key: '1',
}
]}
/>
<Menu
onClick={() => connector.disconnect()}
items={[
{
label: "Disconnect",
key: "1",
},
]}
/>
);

export function AuthButton() {
const [modalUniversalLink, setModalUniversalLink] = useState('');
const forceUpdate = useForceUpdate();
const wallet = useTonWallet();
const onConnectErrorCallback = useCallback(() => {
setModalUniversalLink('');
notification.error({
message: 'Connection was rejected',
description: 'Please approve connection to the dApp in your wallet.'
});
}, []);
useTonWalletConnectionError(onConnectErrorCallback);
const [modalUniversalLink, setModalUniversalLink] = useState("");
const forceUpdate = useForceUpdate();
const wallet = useTonWallet();
const onConnectErrorCallback = useCallback(() => {
setModalUniversalLink("");
notification.error({
message: "Connection was rejected",
description: "Please approve connection to the dApp in your wallet.",
});
}, []);
useTonWalletConnectionError(onConnectErrorCallback);

const walletsList = useRecoilValueLoadable(walletsListQuery);
const walletsList = useRecoilValueLoadable(walletsListQuery);

const address = useSlicedAddress(wallet?.account.address);
const address = useSlicedAddress(wallet?.account.address);

useEffect(() => {
if (modalUniversalLink && wallet) {
setModalUniversalLink('');
}
}, [modalUniversalLink, wallet]);
useEffect(() => {
if (modalUniversalLink && wallet) {
setModalUniversalLink("");
}
}, [modalUniversalLink, wallet]);

// log ton_proof. TODO send to the server
useEffect(() => console.log(wallet), [wallet]);
const handleButtonClick = useCallback(async () => {
const testTonProofPayload = await TonProofDemoApi.generatePayload();

const handleButtonClick = useCallback(async () => {
const testTonProofPayload = 'test_ton_proof 123';
// Use loading screen/UI instead (while wallets list is loading)
if (!(walletsList.state === "hasValue")) {
setTimeout(handleButtonClick, 200);
}

// Use loading screen/UI instead (while wallets list is loading)
if (!(walletsList.state === 'hasValue')) {
setTimeout(handleButtonClick, 200);
}
if (walletsList.contents.embeddedWallet) {
connector.connect(
{ jsBridgeKey: walletsList.contents.embeddedWallet.jsBridgeKey },
{ tonProof: testTonProofPayload }
);
return;
}

if (walletsList.contents.embeddedWallet) {
connector.connect({ jsBridgeKey: walletsList.contents.embeddedWallet.jsBridgeKey}, {tonProof: testTonProofPayload});
return;
}
const tonkeeperConnectionSource = {
universalLink: walletsList.contents.walletsList[0].universalLink,
bridgeUrl: walletsList.contents.walletsList[0].bridgeUrl,
};

const tonkeeperConnectionSource = {
universalLink: walletsList.contents.walletsList[0].universalLink,
bridgeUrl: walletsList.contents.walletsList[0].bridgeUrl
};
const universalLink = connector.connect(tonkeeperConnectionSource, {
tonProof: testTonProofPayload,
});

const universalLink = connector.connect(tonkeeperConnectionSource, {tonProof: testTonProofPayload});
if (isMobile()) {
window.location.assign(universalLink);
} else {
setModalUniversalLink(universalLink);
}
}, [walletsList]);

if (isMobile()) {
window.location.assign(universalLink);
} else {
setModalUniversalLink(universalLink);
}
}, [walletsList]);

return (
<>
<div className="auth-button">
{wallet ?
<Dropdown overlay={menu}>
<Button shape="round" type="primary">
<Space>
{ address }
<DownOutlined/>
</Space>
</Button>
</Dropdown> :
<Button shape="round" type="primary" onClick={handleButtonClick}>
Connect Wallet
</Button>
}
</div>
<Modal title="Connect to Tonkeeper" open={!!modalUniversalLink} onOk={() => setModalUniversalLink('')} onCancel={() => setModalUniversalLink('')}>
<QRCode
size={256}
style={{ height: "260px", maxWidth: "100%", width: "100%" }}
value={modalUniversalLink}
viewBox={`0 0 256 256`}
/>
</Modal>
</>

);
return (
<>
<div className="auth-button">
{wallet ? (
<Dropdown overlay={menu}>
<Button shape="round" type="primary">
<Space>
{address}
<DownOutlined />
</Space>
</Button>
</Dropdown>
) : (
<Button shape="round" type="primary" onClick={handleButtonClick}>
Connect Wallet
</Button>
)}
</div>
<Modal
title="Connect to Tonkeeper"
open={!!modalUniversalLink}
onOk={() => setModalUniversalLink("")}
onCancel={() => setModalUniversalLink("")}
>
<QRCode
size={256}
style={{ height: "260px", maxWidth: "100%", width: "100%" }}
value={modalUniversalLink}
viewBox={`0 0 256 256`}
/>
</Modal>
</>
);
}
Loading

0 comments on commit 0012de4

Please sign in to comment.