Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
owenwahlgren committed Sep 3, 2024
1 parent 0c462d5 commit d61b0da
Show file tree
Hide file tree
Showing 19 changed files with 4,818 additions and 0 deletions.
30 changes: 30 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# This is a basic workflow to help you get started with Actions

name: Build and Deploy

on:
push:
branches:
- main

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Checkout 🛎️
uses: actions/[email protected]
- name: install dependencies
run: npm install
- name: Build
run: npm run build
env:
CI: false
- name: Deploy 🚀
uses: JamesIves/[email protected]
with:
branch: gh-pages # The branch the action should deploy to.
folder: dist # The folder the action should deploy.

permissions:
contents: write
24 changes: 24 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
49 changes: 49 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# twa-template

> Starter template for a new TWA interacting with the Avalanche Fuji blockchain using the [Thirdweb SDK](https://portal.thirdweb.com/react/v5/connecting-wallets/ui-components)
> This project is forked from [twa-template](https://github.com/ton-community/twa-template)
# Overview

The project is highly-opinionated, and there are many other alternate routes it could have taken. Some examples:

- A react-based TWA-ready app, interacting with Avalanche Fuji Network
- Uses vite with react (alternative to create-react-app)
- Uses the `thirdweb` npm package

# Prerequesities

- Node.js v16 (other versions may work, needs more testing)
- A [ThirdWeb Client ID](https://thirdweb.com/dashboard/settings/api-keys)

# What does this repo contain?

- A react-based TWA-ready app, interacting with Avalanche Fuji Network
- Github actions set to deploy app to github pages
- A script to connect a telegram bot to the deployed app

# How to use

1. Create a template from this repo with the "Use this template" button

1. Choose a name for your repo
2. `**IMPORTANT!!**` mark "Include all branches", otherwise github pages deployment will not work.

2. Clone this repo and run `yarn`

3. Create a new bot with [botfather](https://t.me/botfather)
1. Type `/newbot`
2. Choose a name for your bot, e.g. `My AVAX TWA`
3. Choose a username for your bot, e.g. `my_avax_twa_482765_bot`
4. Take note of the access token, e.g. `5712441624:AAHmiHvwrrju1F3h29rlVOZLRLnv-B8ZZZ`
5. Run `yarn configbot` to link your bot to the webapp

# Development

1. Run `yarn run dev` and edit the code as needed
2. On push to the `main` branch, the app will be automatically deployed via github actions.

# License

MIT
89 changes: 89 additions & 0 deletions configure.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import axios from "axios";
import { createInterface } from "readline";
import fs from "fs";
import { promisify } from "util";

const rl = createInterface({
input: process.stdin,
output: process.stdout,
});

const question = (question) =>
new Promise((resolve) => rl.question(question, resolve));

function exitError(error) {
console.error(`Error! ${error}`);
process.exit(1);
}

const banner = `
████████╗██╗ ██╗ █████╗ ████████╗██╗ ██╗██╗██████╗ ██████╗ ██╗ ██╗███████╗██████╗
╚══██╔══╝██║ ██║██╔══██╗ ╚══██╔══╝██║ ██║██║██╔══██╗██╔══██╗██║ ██║██╔════╝██╔══██╗
██║ ██║ █╗ ██║███████║ ██║ ███████║██║██████╔╝██║ ██║██║ █╗ ██║█████╗ ██████╔╝
██║ ██║███╗██║██╔══██║ ██║ ██╔══██║██║██╔══██╗██║ ██║██║███╗██║██╔══╝ ██╔══██╗
██║ ╚███╔███╔╝██║ ██║ ██║ ██║ ██║██║██║ ██║██████╔╝╚███╔███╔╝███████╗██████╔╝
╚═╝ ╚══╝╚══╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝╚═╝ ╚═╝╚═════╝ ╚══╝╚══╝ ╚══════╝╚═════╝ /_/
`;

console.log(banner);

let githubUsername, githubRepo, botUsername;

(async () => {
try {
const file = fs.readFileSync(".git/config").toString();
const url = file.match(/url = (.*)/)[1];
console.log(url);
const params = url.match(/github.com[/:]([^/]*)\/(.*)\.git/);
githubUsername = params[1];
githubRepo = params[2];
} catch (e) {}

const accessToken = await question("Enter your bot access token: ");
if (!accessToken?.length > 0) exitError("Token is required");

const githubUsernameQ = await question(
`Enter your github username${
githubUsername ? ` (${githubUsername})` : ``
}: `
);
githubUsername = githubUsernameQ || githubUsername;
if (!githubUsername?.length > 0) exitError("Github username is required");

const githubRepoQ = await question(
`Enter your forked repo name${githubRepo ? ` (${githubRepo})` : ``}: `
);
githubRepo = githubRepoQ || githubRepo;
if (!githubRepo?.length > 0) exitError("Repo name is required");

const getBot = await axios.get(
`https://api.telegram.org/bot${accessToken}/getMe`
).catch(exitError);

botUsername = getBot.data.result.username;
const url = `https://${githubUsername}.github.io/${githubRepo}`;

console.log(`\n\nSetting bot ${botUsername} webapp url to ${url}`);

const resp = await axios.post(
`https://api.telegram.org/bot${accessToken}/setChatMenuButton`,
{
menu_button: {
type: "web_app",
text: "Launch Webapp",
web_app: {
url: url,
},
},
}
).catch(exitError);

if (resp.status === 200) {
console.log(
`\nYou're all set! Visit https://t.me/${botUsername} to interact with your bot`
);
process.exit();
} else {
exitError(`\nSomething went wrong! ${resp.error}`);
}
})();
13 changes: 13 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Avalanche Demo TWA</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
33 changes: 33 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"name": "twa-thirdweb-avax",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"configbot": "node configure.js"
},
"dependencies": {
"@tanstack/react-query": "^4.24.4",
"axios": "^1.7.5",
"buffer": "^6.0.3",
"is-mobile": "^3.1.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"styled-components": "^5.3.6",
"thirdweb": "^5.49.0",
"use-local-storage": "^2.3.6",
"vite-plugin-node-polyfills": "^0.7.0"
},
"devDependencies": {
"@types/node": "^18.11.18",
"@types/react": "^18.0.27",
"@types/react-dom": "^18.0.10",
"@types/styled-components": "^5.1.26",
"@vitejs/plugin-react": "^3.0.1",
"typescript": "^4.9.5",
"vite": "^4.0.4"
}
}
1 change: 1 addition & 0 deletions public/vite.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions src/App.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
:root {
--tg-theme-bg-color: #efeff3;
--tg-theme-button-color: #2eaddc;
--tg-theme-button-text-color: white;
}
60 changes: 60 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import "./App.css";
import { Counter } from "./components/Counter";
import { TransferAvax } from "./components/TransferAvax";
import styled from "styled-components";
import { FlexBoxCol, FlexBoxRow } from "./components/styled/styled";
import { ConnectButton } from "thirdweb/react";
import { createWallet, inAppWallet } from "thirdweb/wallets";
import { createThirdwebClient } from "thirdweb";
import { avalancheFuji } from "thirdweb/chains";

const StyledApp = styled.div`
background-color: #E84142;
color: white;
@media (prefers-color-scheme: dark) {
background-color: #E84142;
color: white;
}
min-height: 100vh;
padding: 20px 20px;
`;

const AppContainer = styled.div`
max-width: 900px;
margin: 0 auto;
`;

export const client = createThirdwebClient({ clientId: "1822bd9eccc84818670b3a1794ada957" });

const wallets = [
inAppWallet({
auth: {
options: [
"email",
"phone",
],
},
}),
createWallet("app.core"),
createWallet("walletConnect")
];

function App() {

return (
<StyledApp>
<AppContainer>
<FlexBoxCol>
<FlexBoxRow>
<ConnectButton client={client} wallets={wallets} chain={avalancheFuji} showAllWallets={false} />
</FlexBoxRow>
<TransferAvax />
<Counter />
</FlexBoxCol>
</AppContainer>
</StyledApp>
);
}

export default App;
71 changes: 71 additions & 0 deletions src/components/Counter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import {
Card,
FlexBoxCol,
FlexBoxRow,
Ellipsis,
} from "./styled/styled";
import { TransactionButton, useReadContract } from "thirdweb/react";
import { getContract, prepareContractCall } from "thirdweb";
import { avalancheFuji } from "thirdweb/chains";
import { client } from "../App";

export function Counter() {
const contract = getContract({
address: "0x7Ff5ca07a5FC4AA062c29E6E32d2691B48598577",
chain: avalancheFuji,
client,
});

const { data } = useReadContract({
contract,
method: "function count() returns (uint)"
});

return (
<div className="Container">
<Card>
<FlexBoxCol>
<h3>Counter</h3>
<FlexBoxRow>
<b>Contract Address</b>
<Ellipsis>{contract.address}</Ellipsis>
</FlexBoxRow>
<FlexBoxRow>
<b>Value</b>
<div>{String(data) ?? "Loading..."}</div>
</FlexBoxRow>
<TransactionButton
transaction={() => {
const transaction = prepareContractCall({
contract,
method: "function increase()",
params: [],
});
return transaction;
}}
onTransactionConfirmed={() => { console.log("Transaction confirmed") }}
onError={() => { console.log("Transaction error") }}
>
Increase Count
</TransactionButton>

<TransactionButton
transaction={() => {
const transaction = prepareContractCall({
contract,
method: "function decrease()",
params: [],
});
return transaction;
}}
onTransactionConfirmed={() => { console.log("Transaction confirmed") }}
onError={() => { console.log("Transaction error") }}
>
Decrease Count
</TransactionButton>

</FlexBoxCol>
</Card>
</div>
);
}
Loading

0 comments on commit d61b0da

Please sign in to comment.