Skip to content
This repository has been archived by the owner on Jun 19, 2024. It is now read-only.

Commit

Permalink
feat: telegram webapps support (#158)
Browse files Browse the repository at this point in the history
  • Loading branch information
aorumbayev committed Apr 23, 2023
1 parent 132748d commit bdcdeab
Show file tree
Hide file tree
Showing 23 changed files with 571 additions and 180 deletions.
2 changes: 1 addition & 1 deletion api/storage/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@
"web3.storage": "4.5.4"
},
"devDependencies": {
"@vercel/node": "2.10.3"
"@vercel/node": "2.12.0"
}
}
74 changes: 74 additions & 0 deletions api/storage/validate-hash.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { webcrypto } from 'crypto';
import type { NextApiRequest, NextApiResponse } from 'next';

type Data = { ok: boolean } | { error: string };

async function isHashValid(data: Record<string, string>, botToken: string) {
const encoder = new TextEncoder();

const checkString = Object.keys(data)
.filter((key) => key !== `hash`)
.map((key) => `${key}=${data[key]}`)
.sort()
.join(`\n`);

const secretKey = await webcrypto.subtle.importKey(
`raw`,
encoder.encode(`WebAppData`),
{ name: `HMAC`, hash: `SHA-256` },
true,
[`sign`],
);

const secret = await webcrypto.subtle.sign(
`HMAC`,
secretKey,
encoder.encode(botToken),
);

const signatureKey = await webcrypto.subtle.importKey(
`raw`,
secret,
{ name: `HMAC`, hash: `SHA-256` },
true,
[`sign`],
);

const signature = await webcrypto.subtle.sign(
`HMAC`,
signatureKey,
encoder.encode(checkString),
);

const hex = Buffer.from(signature).toString(`hex`);

return data.hash === hex;
}

export default async function handler(
req: NextApiRequest,
res: NextApiResponse<Data>,
) {
if (req.method !== `POST`) {
return res.status(405).json({ error: `Method not allowed` });
}

if (!req.body.hash) {
return res.status(400).json({
error: `Missing required field hash`,
});
}

if (!process.env.BOT_TOKEN) {
return res.status(500).json({ error: `Internal server error` });
}

const data = Object.fromEntries(new URLSearchParams(req.body.hash));
const isValid = await isHashValid(data, process.env.BOT_TOKEN);

if (isValid) {
return res.status(200).json({ ok: true });
}

return res.status(403).json({ error: `Invalid hash` });
}
83 changes: 57 additions & 26 deletions api/storage/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -35,23 +35,35 @@
dependencies:
"@jridgewell/trace-mapping" "0.3.9"

"@edge-runtime/format@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@edge-runtime/format/-/format-1.1.0.tgz#5a209221a8bae7791d6e465c480f146249d1e15f"
integrity sha512-MkLDDtPhXZIMx83NykdFmOpF7gVWIdd6GBHYb8V/E+PKWvD2pK/qWx9B30oN1iDJ2XBm0SGDjz02S8nDHI9lMQ==
"@edge-runtime/format@2.0.1":
version "2.0.1"
resolved "https://registry.yarnpkg.com/@edge-runtime/format/-/format-2.0.1.tgz#765295809ff6a0938da739e13ef327d95a418395"
integrity sha512-aE+9DtBvQyg349srixtXEUNauWtIv5HTKPy8Q9dvG1NvpldVIvvhcDBI+SuvDVM8kQl8phbYnp2NTNloBCn/Yg==

"@edge-runtime/primitives@2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@edge-runtime/primitives/-/primitives-2.0.0.tgz#b4bf44f9cab36aee3027fe4c3ff3cc1d5713e155"
integrity sha512-AXqUq1zruTJAICrllUvZcgciIcEGHdF6KJ3r6FM0n4k8LpFxZ62tPWVIJ9HKm+xt+ncTBUZxwgUaQ73QMUQEKw==

"@edge-runtime/primitives@2.1.2":
version "2.1.2"
resolved "https://registry.yarnpkg.com/@edge-runtime/primitives/-/primitives-2.1.2.tgz#8ff657f12a7f8c7fc4e3a0c10ec19356ef2d656d"
integrity sha512-SR04SMDybALlhIYIi0hiuEUwIl0b7Sn+RKwQkX6hydg4+AKMzBNDFhj2nqHDD1+xkHArV9EhmJIb6iGjShwSzg==

"@edge-runtime/vm@2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@edge-runtime/vm/-/vm-2.0.0.tgz#9170d2d03761eff4e27687888c4b2d9af1f94c7d"
integrity sha512-BOLrAX8IWHRXu1siZocwLguKJPEUv7cr+rG8tI4hvHgMdIsBWHJlLeB8EjuUVnIURFrUiM49lVKn8DRrECmngw==
dependencies:
"@edge-runtime/primitives" "2.0.0"

"@edge-runtime/vm@2.1.2":
version "2.1.2"
resolved "https://registry.yarnpkg.com/@edge-runtime/vm/-/vm-2.1.2.tgz#d760ce27b659c17c470b23453321769c08d213f5"
integrity sha512-j4H5S26NJhYOyjVMN8T/YJuwwslfnEX1P0j6N2Rq1FaubgNowdYunA9nlO7lg8Rgjv6dqJ2zKuM7GD1HFtNSGw==
dependencies:
"@edge-runtime/primitives" "2.1.2"

"@ipld/car@^3.0.1", "@ipld/car@^3.1.4", "@ipld/car@^3.2.3":
version "3.2.4"
resolved "https://registry.yarnpkg.com/@ipld/car/-/car-3.2.4.tgz#115951ba2255ec51d865773a074e422c169fb01c"
Expand Down Expand Up @@ -269,32 +281,41 @@
resolved "https://registry.yarnpkg.com/@vercel/build-utils/-/build-utils-6.7.1.tgz#94bccb959d9f2dcdecb7744c939b546073902373"
integrity sha512-Ecc9oQBSVwk1suENcRcj1L6gQrUt4+0XA9oPFxrUpoFEk04lP/ZV3qAQPk+ex08N+vfUulYdqb+cmVTnwqsmqw==

"@vercel/error-utils@1.0.8":
version "1.0.8"
resolved "https://registry.yarnpkg.com/@vercel/error-utils/-/error-utils-1.0.8.tgz#5cefc4142820846d011cf048ddfb0afda81d484b"
integrity sha512-s+f7jP2oH1koICbQ8e3K9hOpOeUct7rbCnF9qsNwXemq850wAh2e90tp9R6oYBM0BNpiLRRm+oG5zD2sCIm3HQ==

"@vercel/node-bridge@4.0.1":
version "4.0.1"
resolved "https://registry.yarnpkg.com/@vercel/node-bridge/-/node-bridge-4.0.1.tgz#e4f41188f61d9cd4e7c44de31d436dd447e1978c"
integrity sha512-XEfKfnLGzlIBpad7eGNPql1HnMhoSTv9q3uDNC4axdaAC/kI5yvl8kXjuCPAXYvpbJnVQPpcSUC5/r5ap8F3jA==

"@vercel/node@2.10.3":
version "2.10.3"
resolved "https://registry.yarnpkg.com/@vercel/node/-/node-2.10.3.tgz#24a65d9f7e69161762c85df630601f3852308c26"
integrity sha512-R6YwD7YTV4OPEjXnthTP2Zn96ZF2TAjmBhGKfYC9ZuqlmFzSxqyuHn+RUSkknkKBO46b4OzaNdi5XVnAdJizLA==
"@vercel/node@2.12.0":
version "2.12.0"
resolved "https://registry.yarnpkg.com/@vercel/node/-/node-2.12.0.tgz#2eff4ffb04ae3ca19a7fd7e49e4f376791284abb"
integrity sha512-QItQ4DjKrHqTMk/hmtX64V5RfDdp+fDoFzbSbPUICkIOHK3EBCJ5c/392Iv05AwSv+mJIALZUGRQz5o4HKvs6A==
dependencies:
"@edge-runtime/vm" "2.0.0"
"@types/node" "14.18.33"
"@vercel/build-utils" "6.7.1"
"@vercel/error-utils" "1.0.8"
"@vercel/node-bridge" "4.0.1"
"@vercel/static-config" "2.0.15"
edge-runtime "2.0.0"
"@vercel/static-config" "2.0.16"
async-listen "1.2.0"
edge-runtime "2.1.4"
esbuild "0.14.47"
exit-hook "2.2.1"
node-fetch "2.6.7"
path-to-regexp "6.2.1"
ts-morph "12.0.0"
ts-node "10.9.1"
typescript "4.3.4"

"@vercel/static-config@2.0.15":
version "2.0.15"
resolved "https://registry.yarnpkg.com/@vercel/static-config/-/static-config-2.0.15.tgz#a1e4d052e50cb9493071aaa2b4ca5e05c054fada"
integrity sha512-A/N3ZGiOOMql9JArwBTIfhFngFtmVC7ndKQKp0FoFq8MO79AS5qBBtdpILS5QA71M5v+9CPjVkHxN6QweU55Xg==
"@vercel/static-config@2.0.16":
version "2.0.16"
resolved "https://registry.yarnpkg.com/@vercel/static-config/-/static-config-2.0.16.tgz#2495325056e62b94925d8432b703bbf5625b06e5"
integrity sha512-lULo+NWBMpTJb9kR4AwYYK/2e7wknTJO2iFxgYYOkG5i12WHgPhMnXDKrEOcotxctd0yPKx3TsWVGEXniNm63g==
dependencies:
ajv "8.6.3"
json-schema-to-ts "1.6.4"
Expand Down Expand Up @@ -430,6 +451,16 @@ arrify@^1.0.1:
resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
integrity sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==

async-listen@1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/async-listen/-/async-listen-1.2.0.tgz#861ab6f92e1703ba54498b10ddb9b5da7b69f363"
integrity sha512-CcEtRh/oc9Jc4uWeUwdpG/+Mb2YUHKmdaTf0gUr7Wa+bfp4xx70HOb3RuSTJMvqKNB1TkdTfjLdrcz2X4rkkZA==

async-listen@2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/async-listen/-/async-listen-2.0.3.tgz#be1be5a1b15e6007123e67275450fc4e84955e61"
integrity sha512-WVLi/FGIQaXyfYyNvmkwKT1RZbkzszLLnmW/gFCc5lbVvN/0QQCWpBwRBk2OWSdkkmKRBc8yD6BrKsjA3XKaSw==

available-typed-arrays@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7"
Expand Down Expand Up @@ -633,15 +664,15 @@ dns-over-http-resolver@^1.2.3:
native-fetch "^3.0.0"
receptacle "^1.3.2"

edge-runtime@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/edge-runtime/-/edge-runtime-2.0.0.tgz#4739e1c8f4237db8ad8a16db5f0e28cc6de16aab"
integrity sha512-TmRJhKi4mlM1e+zgF4CSzVU5gJ1sWj7ia+XhVgZ8PYyYUxk4PPjJU8qScpSLsAbdSxoBghLxdMuwuCzdYLd1sQ==
edge-runtime@2.1.4:
version "2.1.4"
resolved "https://registry.yarnpkg.com/edge-runtime/-/edge-runtime-2.1.4.tgz#aea4e103897f451f98a9094df26b07c4d1eb75b3"
integrity sha512-SertKByzAmjm+MkLbFl1q0ko+/90V24dhZgQM8fcdguQaDYVEVtb6okEBGeg8IQgL1/JUP8oSlUIxSI/bvsVRQ==
dependencies:
"@edge-runtime/format" "1.1.0"
"@edge-runtime/vm" "2.0.0"
"@edge-runtime/format" "2.0.1"
"@edge-runtime/vm" "2.1.2"
async-listen "2.0.3"
exit-hook "2.2.1"
http-status "1.5.3"
mri "1.2.0"
picocolors "1.0.0"
pretty-bytes "5.6.0"
Expand Down Expand Up @@ -1033,11 +1064,6 @@ hosted-git-info@^4.0.1:
dependencies:
lru-cache "^6.0.0"

http-status@1.5.3:
version "1.5.3"
resolved "https://registry.yarnpkg.com/http-status/-/http-status-1.5.3.tgz#9d1f6adcd1a609f535679f6e1b82811b96c3306e"
integrity sha512-jCClqdnnwigYslmtfb28vPplOgoiZ0siP2Z8C5Ua+3UKbx410v+c+jT+jh1bbI4TvcEySuX0vd/CfFZFbDkJeQ==

iconv-lite@^0.6.2:
version "0.6.3"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501"
Expand Down Expand Up @@ -1842,6 +1868,11 @@ path-parse@^1.0.7:
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==

path-to-regexp@6.2.1:
version "6.2.1"
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.2.1.tgz#d54934d6798eb9e5ef14e7af7962c945906918e5"
integrity sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==

peer-id@^0.16.0:
version "0.16.0"
resolved "https://registry.yarnpkg.com/peer-id/-/peer-id-0.16.0.tgz#0913062cfa4378707fe69c949b5720b3efadbf32"
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "algoworld-swapper",
"description": "Free and trustless ASA swapper, powered by Algorand ⚡️",
"version": "0.9.4",
"version": "1.0.1",
"private": true,
"author": "AlgoWorld <info@algoworld.io>",
"license": "GPL-3.0",
Expand Down Expand Up @@ -48,6 +48,7 @@
"@randlabs/myalgo-connect": "1.4.2",
"@reduxjs/toolkit": "1.9.3",
"@txnlab/use-wallet": "1.2.11",
"@vkruglikov/react-telegram-web-app": "1.8.0",
"@walletconnect/client": "1.8.0",
"algorand-walletconnect-qrcode-modal": "1.8.0",
"algosdk": "2.2.0",
Expand All @@ -66,6 +67,7 @@
"react-tsparticles": "2.9.3",
"react-use": "17.4.0",
"swr": "1.3.0",
"telegram-webapps-types": "1.0.5",
"tsparticles": "2.9.3"
},
"devDependencies": {
Expand Down
3 changes: 2 additions & 1 deletion src/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

import { ChainType } from '@/models/Chain';
import { IpfsGateway } from '@/models/Gateway';
import { PROVIDER_ID } from '@txnlab/use-wallet';
import { PROVIDER_ID as WALLET_PROVIDER_ID } from '@txnlab/use-wallet';

export const CHAIN_TYPE: ChainType = process.env.NEXT_PUBLIC_CHAIN_TYPE
? (process.env.NEXT_PUBLIC_CHAIN_TYPE.trim().toLowerCase() as ChainType)
Expand Down Expand Up @@ -99,4 +99,5 @@ export const PERFORM_SWAP_PERFORM_BUTTON_ID = `AWPerformSwapPerformButton`;
export const PUBLIC_SWAPS_SEARCH_FIELD_ID = `AWPublicSwapsSearchField`;
export const PUBLIC_SWAPS_SEARCH_BUTTON_ID = `AWPublicSwapsSearchButton`;

export const PROVIDER_ID = WALLET_PROVIDER_ID;
export const WALLET_PROVIDER_IDS = [PROVIDER_ID.MYALGO, PROVIDER_ID.PERA];
4 changes: 2 additions & 2 deletions src/components/Dialogs/ConfirmDialog.test.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import * as React from 'react';
import { render } from '@testing-library/react';
import ConfirmDialog from './ConfirmDialog';
import renderWithProviders from '@/__utils__/renderWithProviders';

describe(`ConfirmDialog`, () => {
it(`renders the correct content and handles the buttons correctly`, () => {
const setOpenMock = jest.fn();
const onConfirmMock = jest.fn();
const onSwapVisibilityChangeMock = jest.fn();
const { getByText } = render(
const { getByText } = renderWithProviders(
<ConfirmDialog
title="Test Dialog"
open={true}
Expand Down
Loading

1 comment on commit bdcdeab

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deploy preview for algoworld-swapper ready!

✅ Preview
https://algoworld-swapper-mequat0b9-algoworldexplorer.vercel.app

Built with commit bdcdeab.
This pull request is being automatically deployed with vercel-action

Please sign in to comment.