Skip to content

Commit

Permalink
Merge pull request #59 from JetonDAO/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
arssly authored Oct 15, 2024
2 parents 23dcf2f + ee33588 commit 9505d1a
Show file tree
Hide file tree
Showing 261 changed files with 22,257 additions and 6,334 deletions.
8 changes: 8 additions & 0 deletions .github/actions/deploy/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ inputs:
piesocket-api-key:
description: "PieSocket API Key"
required: true
base-url:
description: "Base URL for WebApp"
required: true
contracts-addr:
description: "Contracts Address"
required: true
outputs:
cloudflare-preview-url:
description: "Couldflare Preview URL"
Expand All @@ -20,6 +26,8 @@ runs:
shell: bash
env:
PIESOCKET_API_KEY: ${{ inputs.piesocket-api-key }}
NEXT_PUBLIC_BASE_URL: ${{ inputs.base-url }}
NEXT_PUBLIC_CONTRACTS_ADDR: ${{ inputs.contracts-addr }}
run: npm run build
- name: Deploy To Cloudflare
id: deploy
Expand Down
9 changes: 7 additions & 2 deletions .github/actions/setup/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,20 @@ runs:
- name: Cache Turbo Build Setup
uses: actions/cache@v4
with:
path: .turbo
path: |
~/.cargo
.turbo
key: ${{ runner.os }}-release-job-${{ github.sha }}
restore-keys: |
${{ runner.os }}-release-job-
- name: Insall circom
shell: bash
run: cargo install --git https://github.com/iden3/circom.git --tag v2.1.9
- name: Setup Node.js Environment
uses: actions/setup-node@v4
with:
node-version: 20
cache: "npm"
- name: Install Dependencies
shell: bash
run: npm install
run: npm ci
2 changes: 2 additions & 0 deletions .github/workflows/cicd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ jobs:
with:
cloudflare-api-token: ${{ secrets.CLOUDFLARE_API_TOKEN }}
piesocket-api-key: ${{ secrets.PIESOCKET_API_KEY }}
base-url: ${{ secrets.BASE_URL }}
contracts-addr: ${{ secrets.CONTRACTS_ADDR }}
- name: Comment Preview URL
uses: actions/github-script@v7
if: github.event_name == 'pull_request'
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -148,3 +148,7 @@ dist
# Misc
.DS_Store
*.pem

# Aptos
.aptos

26 changes: 22 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
# jeton
# Jeton: A Decentralized and Trustless Poker Platform

Decentralized poker protocol enabling trustless, transparent, and community-governed gameplay – powered by JatonDAO.
Jeton is a decentralized poker platform designed to ensure fairness and transparency in online poker games. Built on the Aptos blockchain, Jeton eliminates the need for players to trust a central authority by leveraging zk-SNARKs (Zero-Knowledge Succinct Non-Interactive Arguments of Knowledge) and Elgamal encryption. These cryptographic techniques guarantee that the cards are shuffled, encrypted, and dealt fairly without revealing any information to players or the platform itself.

The platform utilizes Elgamal encryption on the JubJub elliptic curve to securely encrypt cards and zk-SNARK circuits to verify both the shuffle and decryption processes. Each player participates in shuffling the deck and generating decryption shares, ensuring no individual player or entity can manipulate the outcome. Smart contracts on the Aptos blockchain handle the game logic and verify cryptographic proofs, providing a fully decentralized and tamper-proof environment for online poker.

For a more detailed explanation of the algorithms, security considerations, and cryptographic methods used in Jeton, you can read the [full project overview](project-overview.md).

## What's inside?

This Turborepo includes the following packages/apps:

### Apps and Packages

- `web`: a [Next.js](https://nextjs.org/) app
- `web`: the web application of the jeton protocol, implemented in [Next.js](https://nextjs.org/)
- `@jeton/zk-deck`: a package containing Move, TypeScript, and Circom code, for implementing zero knowledge based playing decks
- `@jeton/smart-contracts`: a Move package responsible for on chain game logic
- `@jeton/ts-sdk`:
- `@jeton/ui`: a React component library shared by `web` application
- `@jeton/tailwindcss-config`:
- `@jeton/typescript-config`: `tsconfig.json`s used throughout the monorepo
Each package/app is 100% [TypeScript](https://www.typescriptlang.org/).

Expand All @@ -30,7 +38,17 @@ Make sure you have the correct versions of Node.js and npm installed:
- **Node.js**: v20.16 or later
- **npm**: v10.8 or later

You can use [NVM](https://github.com/nvm-sh/nvm) to install the required version of node and npm.
You can use [NVM](https://github.com/nvm-sh/nvm) to install the required version
of node and npm.

Also you need rustc and cargo install. It is recommended to use
[rustup](https://rustup.rs/) to install them.

After that you need to also install circom using:

```shell
cargo install --git https://github.com/iden3/circom.git --tag v2.1.9
```

### Cloning the Repository

Expand Down
3 changes: 3 additions & 0 deletions apps/web/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,6 @@ yarn-error.log*
# typescript
*.tsbuildinfo
next-env.d.ts

#generated service worker file
public/sw.js
11 changes: 11 additions & 0 deletions apps/web/addCacheUrls.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { readFileSync, writeFileSync } from "fs";
import { decryptCardShareZkey, shuffleEncryptDeckZkey } from "@jeton/zk-deck";

const SWFile = readFileSync("./src/sw.template.js", "utf-8");

const modifiedSWFile = SWFile.replace(
'"<urlPlaceHolder>"',
`"${decryptCardShareZkey}", "${shuffleEncryptDeckZkey}"`,
);

writeFileSync("./public/sw.js", modifiedSWFile, "utf-8");
26 changes: 25 additions & 1 deletion apps/web/next.config.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,31 @@
import { setupDevPlatform } from "@cloudflare/next-on-pages/next-dev";

/** @type {import('next').NextConfig} */
const nextConfig = {};
const nextConfig = {
webpack(config) {
config.module.rules.push({
test: /\.(mp3|ogg)$/i,
use: [
{
loader: "file-loader",
options: {
name: "[path][name].[ext]",
publicPath: "/_next/static/audio/",
outputPath: "static/audio/",
},
},
],
});
config.module.rules.push({
test: /\.wasm/,
type: "asset/resource",
});
// config.externals.push({
// "node:crypto": "crypto",
// });
return config;
},
};

if (process.env.NODE_ENV === "development") {
await setupDevPlatform();
Expand Down
18 changes: 15 additions & 3 deletions apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,30 @@
"private": true,
"scripts": {
"dev": "next dev",
"dev:service-worker": "tsx ./addCacheUrls.mts",
"build:service-worker": "tsx ./addCacheUrls.mts",
"build": "next build",
"next-on-pages": "npx @cloudflare/next-on-pages",
"start": "next start"
},
"dependencies": {
"@jeton/ts-sdk": "*",
"@jeton/ui": "*",
"@aptos-labs/ts-sdk": "^1.29.1",
"@aptos-labs/wallet-adapter-ant-design": "^3.0.13",
"@aptos-labs/wallet-adapter-react": "^3.6.2",
"@jeton/ts-sdk": "*",
"@jeton/ui": "*",
"@jeton/zk-deck": "*",
"@legendapp/state": "^3.0.0-alpha.29",
"clsx": "^2.1.1",
"framer-motion": "^11.6.0",
"graphql": "^16.9.0",
"graphql-request": "^7.1.0",
"nes.css": "^2.2.1",
"next": "^14.2.8",
"react": "^18.3.1",
"react-dom": "^18.3.1"
"react-dom": "^18.3.1",
"tailwind-merge": "^2.5.2",
"tsx": "^4.19.1"
},
"devDependencies": {
"@cloudflare/next-on-pages": "^1.13.2",
Expand All @@ -28,6 +39,7 @@
"@types/react-dom": "^18",
"autoprefixer": "^10.4.20",
"postcss": "^8.4.41",
"postcss-import": "^16.1.0",
"tailwindcss": "^3.4.10",
"typescript": "^5"
}
Expand Down
5 changes: 3 additions & 2 deletions apps/web/postcss.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
"postcss-import": {}, // Import CSS files first
tailwindcss: {}, // Then apply TailwindCSS
autoprefixer: {}, // Lastly, add vendor prefixes
},
};
1 change: 1 addition & 0 deletions apps/web/public/aptosconnect.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
b76e8b1d-3fe8-442a-b254-47b2dcff3f2a
Binary file added apps/web/public/images/card-back.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/web/public/images/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/web/public/images/pixel-wooden-pattern.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/web/public/images/wood-pattern-light.png
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 apps/web/public/mizuwallet-connect-manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"url": "https://dev.jeton.pages.dev",
"name": "Test Login with mizu",
"iconUrl": "https://dev.jeton.pages.dev/images/logo.png"
}
11 changes: 11 additions & 0 deletions apps/web/public/register-service-worker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
function registerServiceWorker() {
if (typeof window !== "undefined") {
if ("serviceWorker" in navigator) {
navigator.serviceWorker.register("/sw.js").catch((e) => {
console.log("service worker installation error", e);
});
}
}
}

registerServiceWorker();
137 changes: 137 additions & 0 deletions apps/web/src/app/@modal/(.)create/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
"use client";

import { useWallet } from "@aptos-labs/wallet-adapter-react";
import { ChipUnits, type TableInfo } from "@jeton/ts-sdk";
import Modal from "@src/components/Modal";
import { usePathname, useRouter } from "next/navigation";
import React, { useState, type ChangeEvent, type FormEvent, useContext, useEffect } from "react";

export const runtime = "edge";

type FormValues = Omit<TableInfo, "id">;

import { decryptCardShareZkey, shuffleEncryptDeckZkey } from "@jeton/zk-deck";
//@ts-ignore
import decryptCardShareWasm from "@jeton/zk-deck/wasm/decrypt-card-share.wasm";
//@ts-ignore
import shuffleEncryptDeckWasm from "@jeton/zk-deck/wasm/shuffle-encrypt-deck.wasm";
import CheckIn from "@src/components/CheckIn";
import { Input } from "@src/components/Input";
import { JetonContext } from "@src/components/JetonContextProvider";
import useCheckIn from "@src/hooks/useCheckIn";
import type { SignAndSubmitTransaction } from "@src/types/SignAndSubmitTransaction";
import { finalAddressAndSignFunction } from "@src/utils/inAppWallet";

const INITIAL_FORM_VALUES: FormValues = {
smallBlind: 1,
numberOfRaises: 2,
minPlayers: 2,
minBuyIn: 100,
maxBuyIn: 1000,
maxPlayers: 9,
waitingTimeout: 3600,
chipUnit: ChipUnits.apt,
};

const INPUT_FIELDS = [
{ label: "Small Blind", name: "smallBlind" },
{ label: "Number of Raises", name: "numberOfRaises" },
{ label: "Minimum Players", name: "minPlayers" },
{ label: "Minimum Buy-in", name: "minBuyIn" },
{ label: "Maximum Buy-in", name: "maxBuyIn" },
];

export default function GameCreateModal() {
const [loading, setLoading] = useState(false);
const [formValues, setFormValues] = useState<FormValues>(INITIAL_FORM_VALUES);
const { account, signAndSubmitTransaction } = useWallet();
const { checkIn, submitCheckIn } = useCheckIn();
const [isCreating, setIsCreating] = useState(false);

const { createTable } = useContext(JetonContext);
const router = useRouter();

const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target;
setFormValues((prev) => ({
...prev,
[name]: Number.parseInt(value),
}));
};

const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
setLoading(true);

try {
if (!createTable) throw new Error("create Table must exist");
if (!checkIn) throw new Error("Check in you must do");

const TIMEOUT = 300; // 5 minutes
const [finalAddress, finalSignAndSubmit] = finalAddressAndSignFunction(
account!.address,
signAndSubmitTransaction as SignAndSubmitTransaction,
);

const jeton = await createTable(
formValues.smallBlind,
formValues.numberOfRaises,
formValues.minPlayers,
formValues.minBuyIn,
formValues.maxBuyIn,
TIMEOUT,
formValues.chipUnit,
checkIn,
finalAddress,
finalSignAndSubmit,
{
decryptCardShareWasm,
shuffleEncryptDeckWasm,
decryptCardShareZkey,
shuffleEncryptDeckZkey,
},
);

router.push(`/games/${jeton.tableInfo.id}`);
} finally {
setLoading(false);
}
};

return (
<Modal className="animate-scaleUp max-w-md">
{isCreating ? (
<form onSubmit={handleSubmit}>
<div className="text-white text-lg mb-5">Create a New Game</div>
<div className="flex flex-col gap-3">
{INPUT_FIELDS.map(({ label, name }) => (
<Input
key={name}
label={label}
type="number"
value={formValues[name as keyof FormValues]}
name={name}
onChange={handleChange}
/>
))}
</div>
<button
className="nes-btn is-primary rounded-lg w-full py-2 px-4 mt-3"
type="submit"
disabled={loading}
>
{loading ? "Creating..." : "Create Game"}
</button>
</form>
) : (
<CheckIn
onSubmit={(value) =>
submitCheckIn(value, () => {
setIsCreating(true);
})
}
/>
)}
</Modal>
);
}
Loading

0 comments on commit 9505d1a

Please sign in to comment.