From 2257817dd008da720d4ab875f47e67c9920fd1b8 Mon Sep 17 00:00:00 2001 From: Aleksey_Levin Date: Sun, 7 Jan 2024 16:02:05 +0800 Subject: [PATCH 01/18] add init actions --- .github/workflows/github-actions-demo.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .github/workflows/github-actions-demo.yml diff --git a/.github/workflows/github-actions-demo.yml b/.github/workflows/github-actions-demo.yml new file mode 100644 index 0000000..e5bb161 --- /dev/null +++ b/.github/workflows/github-actions-demo.yml @@ -0,0 +1,18 @@ +name: GitHub Actions Demo +run-name: ${{ github.actor }} is testing out GitHub Actions 🚀 +on: [push] +jobs: + Explore-GitHub-Actions: + runs-on: ubuntu-latest + steps: + - run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event." + - run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!" + - run: echo "🔎 The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}." + - name: Check out repository code + uses: actions/checkout@v4 + - run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner." + - run: echo "🖥️ The workflow is now ready to test your code on the runner." + - name: List files in the repository + run: | + ls ${{ github.workspace }} + - run: echo "🍏 This job's status is ${{ job.status }}." \ No newline at end of file From 365252e53a22d00e97b93156ae07b8f8558f8f81 Mon Sep 17 00:00:00 2001 From: Aleksey_Levin Date: Sun, 7 Jan 2024 16:11:33 +0800 Subject: [PATCH 02/18] change actions --- .github/workflows/github-actions-demo.yml | 25 ++++++++++++----------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/.github/workflows/github-actions-demo.yml b/.github/workflows/github-actions-demo.yml index e5bb161..7e8f7bd 100644 --- a/.github/workflows/github-actions-demo.yml +++ b/.github/workflows/github-actions-demo.yml @@ -2,17 +2,18 @@ name: GitHub Actions Demo run-name: ${{ github.actor }} is testing out GitHub Actions 🚀 on: [push] jobs: - Explore-GitHub-Actions: + init: + strategy: + matrix: + node-version: [ 17.x ] runs-on: ubuntu-latest steps: - - run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event." - - run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!" - - run: echo "🔎 The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}." - - name: Check out repository code - uses: actions/checkout@v4 - - run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner." - - run: echo "🖥️ The workflow is now ready to test your code on the runner." - - name: List files in the repository - run: | - ls ${{ github.workspace }} - - run: echo "🍏 This job's status is ${{ job.status }}." \ No newline at end of file + - uses: actions/checkout@v3 + - name: Starting NodeJs ${{ matrix.node-version}} + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + - name: install modules + run: yarn + - name: build project + run: yarn build \ No newline at end of file From aae840773179850a3caa8b87a5bc36d9b92dea4d Mon Sep 17 00:00:00 2001 From: Aleksey_Levin Date: Sun, 7 Jan 2024 16:13:21 +0800 Subject: [PATCH 03/18] change actions --- .github/workflows/github-actions-demo.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/github-actions-demo.yml b/.github/workflows/github-actions-demo.yml index 7e8f7bd..581a81e 100644 --- a/.github/workflows/github-actions-demo.yml +++ b/.github/workflows/github-actions-demo.yml @@ -9,11 +9,18 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 + with: + path: frontend/casino - name: Starting NodeJs ${{ matrix.node-version}} uses: actions/setup-node@v3 with: + path: frontend/casino node-version: ${{ matrix.node-version }} - name: install modules + with: + path: frontend/casino run: yarn - name: build project + with: + path: frontend/casino run: yarn build \ No newline at end of file From 3a818dc71fcf0ab100c333823e080a9690c25cda Mon Sep 17 00:00:00 2001 From: Aleksey_Levin Date: Sun, 7 Jan 2024 16:14:44 +0800 Subject: [PATCH 04/18] change actions --- .github/workflows/github-actions-demo.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/github-actions-demo.yml b/.github/workflows/github-actions-demo.yml index 581a81e..4fa3bce 100644 --- a/.github/workflows/github-actions-demo.yml +++ b/.github/workflows/github-actions-demo.yml @@ -9,18 +9,12 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - with: - path: frontend/casino - name: Starting NodeJs ${{ matrix.node-version}} uses: actions/setup-node@v3 with: path: frontend/casino node-version: ${{ matrix.node-version }} - name: install modules - with: - path: frontend/casino run: yarn - name: build project - with: - path: frontend/casino run: yarn build \ No newline at end of file From 73babdae42e5cdea28f8b1193dac8aa6091fe72a Mon Sep 17 00:00:00 2001 From: Aleksey_Levin Date: Sun, 7 Jan 2024 16:17:24 +0800 Subject: [PATCH 05/18] change actions --- .github/workflows/github-actions-demo.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/github-actions-demo.yml b/.github/workflows/github-actions-demo.yml index 4fa3bce..08f52bb 100644 --- a/.github/workflows/github-actions-demo.yml +++ b/.github/workflows/github-actions-demo.yml @@ -12,9 +12,9 @@ jobs: - name: Starting NodeJs ${{ matrix.node-version}} uses: actions/setup-node@v3 with: - path: frontend/casino node-version: ${{ matrix.node-version }} - - name: install modules - run: yarn - - name: build project - run: yarn build \ No newline at end of file + - name: build + run: | + yarn + yarn build + working-directory: frontend/casino From 1e92f8941c9032776e36179b5cd83606f20f53e4 Mon Sep 17 00:00:00 2001 From: Aleksey_Levin Date: Sun, 7 Jan 2024 16:18:43 +0800 Subject: [PATCH 06/18] change actions --- .github/workflows/github-actions-demo.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/github-actions-demo.yml b/.github/workflows/github-actions-demo.yml index 08f52bb..59e7658 100644 --- a/.github/workflows/github-actions-demo.yml +++ b/.github/workflows/github-actions-demo.yml @@ -5,7 +5,7 @@ jobs: init: strategy: matrix: - node-version: [ 17.x ] + node-version: [ 18.x ] runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 From f89ee43665b508b10a1ee7cab002f58c93ed1b36 Mon Sep 17 00:00:00 2001 From: Aleksey_Levin Date: Sun, 7 Jan 2024 16:26:17 +0800 Subject: [PATCH 07/18] fix build --- frontend/casino/src/app/components/App/AppNav/AppNav.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/casino/src/app/components/App/AppNav/AppNav.tsx b/frontend/casino/src/app/components/App/AppNav/AppNav.tsx index 55c669c..7677f1b 100644 --- a/frontend/casino/src/app/components/App/AppNav/AppNav.tsx +++ b/frontend/casino/src/app/components/App/AppNav/AppNav.tsx @@ -36,5 +36,6 @@ export const AppNav = () => { + ) }; \ No newline at end of file From 52516ca528a0ee4da863c3f76b310357143c82ef Mon Sep 17 00:00:00 2001 From: Aleksey_Levin Date: Sun, 7 Jan 2024 16:32:46 +0800 Subject: [PATCH 08/18] fix build --- frontend/casino/src/app/hooks/index.ts | 1 - frontend/casino/src/app/hooks/useStores.tsx | 19 ------------------- .../src/app/pages/MainPage/MainPage.tsx | 1 - 3 files changed, 21 deletions(-) delete mode 100644 frontend/casino/src/app/hooks/useStores.tsx diff --git a/frontend/casino/src/app/hooks/index.ts b/frontend/casino/src/app/hooks/index.ts index 0922071..e7a8053 100644 --- a/frontend/casino/src/app/hooks/index.ts +++ b/frontend/casino/src/app/hooks/index.ts @@ -2,4 +2,3 @@ export * from './useDOMRef.ts' export * from './useMediaMui.ts' export * from './useScrollTop.ts' export * from './useScrollWindow.ts' -export * from './useStores.tsx' diff --git a/frontend/casino/src/app/hooks/useStores.tsx b/frontend/casino/src/app/hooks/useStores.tsx deleted file mode 100644 index bf8aa8b..0000000 --- a/frontend/casino/src/app/hooks/useStores.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { observer } from 'mobx-react-lite' -import { createContext, type PropsWithChildren, useContext } from 'react' - -import { type RootStore, rootStore } from '../stores/RootStore' - -export const StoreContext = createContext(rootStore) - -export const StoreProvider = observer(function StoreProvider({ - children, -// eslint-disable-next-line @typescript-eslint/ban-types -}: PropsWithChildren): JSX.Element { - return ( - {children} - ) -}) - -export function useStores(): RootStore { - return useContext(StoreContext) -} diff --git a/frontend/casino/src/app/pages/MainPage/MainPage.tsx b/frontend/casino/src/app/pages/MainPage/MainPage.tsx index 49bbbe0..65b6159 100644 --- a/frontend/casino/src/app/pages/MainPage/MainPage.tsx +++ b/frontend/casino/src/app/pages/MainPage/MainPage.tsx @@ -1,4 +1,3 @@ -import CoinIcon from "../../components/icons/CoinIcon"; import ContainerLayout from "../../utils/ContainerLayout"; import GamepadIcon from "../../components/icons/GamepadIcon"; From 4801bebcc536e55f9edf773d947f7970f3d99351 Mon Sep 17 00:00:00 2001 From: Aleksey_Levin Date: Sun, 7 Jan 2024 17:03:08 +0800 Subject: [PATCH 09/18] fix build --- .../casino/src/app/components/App/AppNav/AppNav.tsx | 10 ++-------- .../web3/connect/ui/ConnectButton/ConnectButton.tsx | 13 ++++++++++--- .../ui/DisconnectButton/DisconnectButton.tsx | 13 ++++++++++--- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/frontend/casino/src/app/components/App/AppNav/AppNav.tsx b/frontend/casino/src/app/components/App/AppNav/AppNav.tsx index 7677f1b..baf2ec9 100644 --- a/frontend/casino/src/app/components/App/AppNav/AppNav.tsx +++ b/frontend/casino/src/app/components/App/AppNav/AppNav.tsx @@ -1,6 +1,6 @@ import CoinIcon from "../../icons/CoinIcon"; import ProfileIcon from "../../icons/ProfileIcon"; -import WalletIcon from "../../icons/WalletIcon"; +import {ConnectStateButton} from "../../../web3/connect"; export const AppNav = () => { return ( @@ -21,13 +21,7 @@ export const AppNav = () => { {/* placeholder for balance */} 0.000000 -
- {/* todo: load from .svg file in assets */} - - -
+
Robin F. diff --git a/frontend/casino/src/app/web3/connect/ui/ConnectButton/ConnectButton.tsx b/frontend/casino/src/app/web3/connect/ui/ConnectButton/ConnectButton.tsx index 4d8863a..40ff470 100644 --- a/frontend/casino/src/app/web3/connect/ui/ConnectButton/ConnectButton.tsx +++ b/frontend/casino/src/app/web3/connect/ui/ConnectButton/ConnectButton.tsx @@ -1,10 +1,17 @@ import {useConnect} from "../../lib/useConnect.ts"; +import WalletIcon from "../../../../components/icons/WalletIcon.tsx"; export const ConnectButton = () => { const { connect } = useConnect() return ( - +
+ {/* todo: load from .vg file in assets */} + + +
); }; \ No newline at end of file diff --git a/frontend/casino/src/app/web3/connect/ui/DisconnectButton/DisconnectButton.tsx b/frontend/casino/src/app/web3/connect/ui/DisconnectButton/DisconnectButton.tsx index e487a1c..2fcb996 100644 --- a/frontend/casino/src/app/web3/connect/ui/DisconnectButton/DisconnectButton.tsx +++ b/frontend/casino/src/app/web3/connect/ui/DisconnectButton/DisconnectButton.tsx @@ -1,10 +1,17 @@ import {useConnect} from "../../lib/useConnect.ts"; +import WalletIcon from "../../../../components/icons/WalletIcon.tsx"; export const DisconnectButton = () => { const { disconnect } = useConnect() return ( - +
+ {/* todo: load from .svg file in assets */} + + +
); }; \ No newline at end of file From 6edfebf24b9c3b1deaa27cbc6013da0bd18b5a25 Mon Sep 17 00:00:00 2001 From: Aleksey_Levin Date: Sun, 7 Jan 2024 17:25:59 +0800 Subject: [PATCH 10/18] feat: fix routes --- frontend/casino/src/app/pages/MainPage/MainPage.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/casino/src/app/pages/MainPage/MainPage.tsx b/frontend/casino/src/app/pages/MainPage/MainPage.tsx index 65b6159..b4c4ccd 100644 --- a/frontend/casino/src/app/pages/MainPage/MainPage.tsx +++ b/frontend/casino/src/app/pages/MainPage/MainPage.tsx @@ -1,5 +1,6 @@ import ContainerLayout from "../../utils/ContainerLayout"; import GamepadIcon from "../../components/icons/GamepadIcon"; +import {Link} from "react-router-dom"; export const MainPage = () => { return ( @@ -54,7 +55,7 @@ export const MainPage = () => {
DICE - Play now + Play now
From f36506d167fad2d4d2f1b0ae6d239509b2d44b33 Mon Sep 17 00:00:00 2001 From: Aleksey_Levin Date: Sun, 7 Jan 2024 17:31:28 +0800 Subject: [PATCH 11/18] fix img --- .../src/app/pages/DiceGamePage/DiceGamePage.tsx | 5 +++-- frontend/casino/src/app/pages/MainPage/MainPage.tsx | 12 ++++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/frontend/casino/src/app/pages/DiceGamePage/DiceGamePage.tsx b/frontend/casino/src/app/pages/DiceGamePage/DiceGamePage.tsx index 9b57608..56fe64d 100644 --- a/frontend/casino/src/app/pages/DiceGamePage/DiceGamePage.tsx +++ b/frontend/casino/src/app/pages/DiceGamePage/DiceGamePage.tsx @@ -1,5 +1,6 @@ import ContainerLayout from "../../utils/ContainerLayout" import { DicePlayButton } from "../../components/web3/DicePlayButton" +import diceImg from '../../../assets/img/dice-img.png' export const DiceGamePage = () => { return ( @@ -12,8 +13,8 @@ export const DiceGamePage = () => {
- Dice - Dice + Dice + Dice
{/* Кнопка для бека */} diff --git a/frontend/casino/src/app/pages/MainPage/MainPage.tsx b/frontend/casino/src/app/pages/MainPage/MainPage.tsx index b4c4ccd..df3055b 100644 --- a/frontend/casino/src/app/pages/MainPage/MainPage.tsx +++ b/frontend/casino/src/app/pages/MainPage/MainPage.tsx @@ -1,13 +1,17 @@ import ContainerLayout from "../../utils/ContainerLayout"; import GamepadIcon from "../../components/icons/GamepadIcon"; import {Link} from "react-router-dom"; +import casinoBg from '../../../assets/img/casino-bg-image.png' +import diceSmall from '../../../assets/img/dices-small.png' +import rpsSmall from '../../../assets/img/rps-small.png' +import slotMachine from '../../../assets/img/slot-machine-small.png' export const MainPage = () => { return (
Icon @@ -47,7 +51,7 @@ export const MainPage = () => {
Icon @@ -63,7 +67,7 @@ export const MainPage = () => {
Icon @@ -80,7 +84,7 @@ export const MainPage = () => {
Icon From 3a9af7396bd71e57fd40d23c792ede6b53340545 Mon Sep 17 00:00:00 2001 From: Aleksey_Levin Date: Sun, 7 Jan 2024 17:35:08 +0800 Subject: [PATCH 12/18] fix img --- frontend/casino/src/app/components/App/AppNav/AppNav.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/casino/src/app/components/App/AppNav/AppNav.tsx b/frontend/casino/src/app/components/App/AppNav/AppNav.tsx index baf2ec9..d56de3f 100644 --- a/frontend/casino/src/app/components/App/AppNav/AppNav.tsx +++ b/frontend/casino/src/app/components/App/AppNav/AppNav.tsx @@ -1,6 +1,7 @@ import CoinIcon from "../../icons/CoinIcon"; import ProfileIcon from "../../icons/ProfileIcon"; import {ConnectStateButton} from "../../../web3/connect"; +import chipImg from '../../../../assets/icons/chip.png' export const AppNav = () => { return ( @@ -8,7 +9,7 @@ export const AppNav = () => {
- Icon + Icon ZaSlot .bet From 2b44465bec57d5264ca97a51be20d032fd4e257d Mon Sep 17 00:00:00 2001 From: Aleksey_Levin Date: Sun, 7 Jan 2024 19:56:39 +0800 Subject: [PATCH 13/18] feat: add dice game --- .../components/App/AppLayout/AppLayout.tsx | 2 +- .../src/app/components/App/AppNav/AppNav.tsx | 10 +++-- .../app/components/web3/DicePlayButton.tsx | 30 ++++++++++++-- .../casino/src/app/hooks/useIntervalAsync.ts | 7 ++-- .../casino/src/app/hooks/useStatusState.ts | 5 +-- frontend/casino/src/app/hooks/useStores.tsx | 18 +++++++++ .../app/pages/DiceGamePage/DiceGamePage.tsx | 33 +++++++++++++--- frontend/casino/src/app/stores/RootStore.ts | 11 ++++++ .../casino/src/app/stores/User/UserStore.ts | 13 +++++++ .../app/web3/balance/CheckBalanceButton.tsx | 18 +++++++++ .../src/app/web3/balance/useCheckBalance.ts | 36 +++++++++++++++++ .../functions/Roulette/usePlayRoulette.ts | 14 +++---- .../src/app/web3/functions/config/config.ts | 5 ++- .../app/web3/functions/utils/useGetResult.ts | 39 ++++++++++++++----- 14 files changed, 203 insertions(+), 38 deletions(-) create mode 100644 frontend/casino/src/app/hooks/useStores.tsx create mode 100644 frontend/casino/src/app/stores/RootStore.ts create mode 100644 frontend/casino/src/app/stores/User/UserStore.ts create mode 100644 frontend/casino/src/app/web3/balance/CheckBalanceButton.tsx create mode 100644 frontend/casino/src/app/web3/balance/useCheckBalance.ts diff --git a/frontend/casino/src/app/components/App/AppLayout/AppLayout.tsx b/frontend/casino/src/app/components/App/AppLayout/AppLayout.tsx index 1300de0..d7be121 100644 --- a/frontend/casino/src/app/components/App/AppLayout/AppLayout.tsx +++ b/frontend/casino/src/app/components/App/AppLayout/AppLayout.tsx @@ -1,5 +1,5 @@ import { observer } from 'mobx-react-lite' -import { type FC } from 'react' +import {type FC} from 'react' import { Outlet } from 'react-router-dom' import { useScrollTop } from '../../../hooks/useScrollTop.ts' diff --git a/frontend/casino/src/app/components/App/AppNav/AppNav.tsx b/frontend/casino/src/app/components/App/AppNav/AppNav.tsx index d56de3f..6c199b3 100644 --- a/frontend/casino/src/app/components/App/AppNav/AppNav.tsx +++ b/frontend/casino/src/app/components/App/AppNav/AppNav.tsx @@ -2,8 +2,12 @@ import CoinIcon from "../../icons/CoinIcon"; import ProfileIcon from "../../icons/ProfileIcon"; import {ConnectStateButton} from "../../../web3/connect"; import chipImg from '../../../../assets/icons/chip.png' +import {useStores} from "../../../hooks/useStores.tsx"; +import {observer} from "mobx-react-lite"; +import {CheckBalanceButton} from "../../../web3/balance/CheckBalanceButton.tsx"; -export const AppNav = () => { +export const AppNav = observer(() => { + const { userStore } = useStores() return (
@@ -20,7 +24,7 @@ export const AppNav = () => {
{/* placeholder for balance */} - 0.000000 + {userStore.balance ? {userStore.balance} : }
@@ -33,4 +37,4 @@ export const AppNav = () => {
) -}; \ No newline at end of file +}) \ No newline at end of file diff --git a/frontend/casino/src/app/components/web3/DicePlayButton.tsx b/frontend/casino/src/app/components/web3/DicePlayButton.tsx index bf7dfe4..ebaa673 100644 --- a/frontend/casino/src/app/components/web3/DicePlayButton.tsx +++ b/frontend/casino/src/app/components/web3/DicePlayButton.tsx @@ -1,7 +1,31 @@ -export const DicePlayButton = () => { +import {usePlayRoulette} from "../../web3/functions/Roulette/usePlayRoulette.ts"; +import {FC, useEffect} from "react"; + +interface DicePlayButtonProps { + value: number + onSuccess: (result: unknown) => void + onLoading: () => void +} + +export const DicePlayButton: FC = ({ value, onSuccess, onLoading }) => { + const { playRoulette, result, isLoading } = usePlayRoulette() + + useEffect(() => { + if (result) onSuccess(result) + }, [result]) + + useEffect(() => { + if (isLoading) onLoading() + }, [isLoading]) + return ( - ) } \ No newline at end of file diff --git a/frontend/casino/src/app/hooks/useIntervalAsync.ts b/frontend/casino/src/app/hooks/useIntervalAsync.ts index 81e1a4e..faf529c 100644 --- a/frontend/casino/src/app/hooks/useIntervalAsync.ts +++ b/frontend/casino/src/app/hooks/useIntervalAsync.ts @@ -1,6 +1,7 @@ import { useCallback, useEffect, useRef, useState } from 'react' +import {IGetResult} from "../web3/functions/utils/useGetResult.ts"; -const useIntervalAsync = (fn: (tx: string) => Promise, ms: number) => { +const useIntervalAsync = (fn: ({tx, notificationKey}: IGetResult) => Promise, ms: number) => { const runningCount = useRef(0) const timeout = useRef() const mountedRef = useRef(false) @@ -17,9 +18,9 @@ const useIntervalAsync = (fn: (tx: string) => Promise, ms: numbe [ms], ) - const run = useCallback(async (tx: string) => { + const run = useCallback(async (tx: string, notificationKey?: string) => { runningCount.current += 1 - const result = await fn(tx) + const result = await fn({tx, notificationKey}) runningCount.current -= 1 next(run) diff --git a/frontend/casino/src/app/hooks/useStatusState.ts b/frontend/casino/src/app/hooks/useStatusState.ts index 07e8911..2185f37 100644 --- a/frontend/casino/src/app/hooks/useStatusState.ts +++ b/frontend/casino/src/app/hooks/useStatusState.ts @@ -1,10 +1,7 @@ import { useCallback, useState } from 'react' -import { useAccount } from 'wagmi' import {stringifyError} from "../utils/error/stringifyError.ts"; export function useStatusState() { - const { isConnected } = useAccount() - const [isLoading, setIsLoading] = useState(false) const [error, setError] = useState() const [result, setResult] = useState() @@ -26,7 +23,7 @@ export function useStatusState() { throw err } } - }, [isConnected]) + }, []) return { statuses: { diff --git a/frontend/casino/src/app/hooks/useStores.tsx b/frontend/casino/src/app/hooks/useStores.tsx new file mode 100644 index 0000000..09b39c4 --- /dev/null +++ b/frontend/casino/src/app/hooks/useStores.tsx @@ -0,0 +1,18 @@ +import { createContext, type PropsWithChildren, useContext } from 'react' + +import { type RootStore, rootStore } from '../stores/RootStore' + +export const StoreContext = createContext(rootStore) + +export function StoreProvider({ + children, +// eslint-disable-next-line @typescript-eslint/ban-types +}: PropsWithChildren): JSX.Element { + return ( + {children} + ) +} + +export function useStores(): RootStore { + return useContext(StoreContext) +} diff --git a/frontend/casino/src/app/pages/DiceGamePage/DiceGamePage.tsx b/frontend/casino/src/app/pages/DiceGamePage/DiceGamePage.tsx index 56fe64d..38e338e 100644 --- a/frontend/casino/src/app/pages/DiceGamePage/DiceGamePage.tsx +++ b/frontend/casino/src/app/pages/DiceGamePage/DiceGamePage.tsx @@ -1,8 +1,29 @@ import ContainerLayout from "../../utils/ContainerLayout" import { DicePlayButton } from "../../components/web3/DicePlayButton" import diceImg from '../../../assets/img/dice-img.png' +import {useState} from "react"; +import {useStores} from "../../hooks/useStores.tsx"; +import {observer} from "mobx-react-lite"; + +export const DiceGamePage = observer(() => { + const [diceValue, setDiceValue] = useState() + const [isLoading, setIsLoading] = useState(false) + const { userStore } = useStores() + + const onSuccess = (result: unknown) => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error + setDiceValue(result.value) + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error + userStore.setBalance(result.balance ?? '0') + setIsLoading(false) + } + + const onLoading = () => { + setIsLoading(true) + } -export const DiceGamePage = () => { return (
@@ -17,16 +38,16 @@ export const DiceGamePage = () => { Dice
{/* Кнопка для бека */} - +
Вы загадали: 5
-
- Выпало число: 5 -
+ {(diceValue && !isLoading) &&
+ Выпало число: {diceValue} +
}
) -} \ No newline at end of file +}) \ No newline at end of file diff --git a/frontend/casino/src/app/stores/RootStore.ts b/frontend/casino/src/app/stores/RootStore.ts new file mode 100644 index 0000000..7f47d60 --- /dev/null +++ b/frontend/casino/src/app/stores/RootStore.ts @@ -0,0 +1,11 @@ +import { UserStore } from './User/UserStore' + +export class RootStore { + userStore: UserStore + + constructor() { + this.userStore = new UserStore() + } +} + +export const rootStore = new RootStore() diff --git a/frontend/casino/src/app/stores/User/UserStore.ts b/frontend/casino/src/app/stores/User/UserStore.ts new file mode 100644 index 0000000..a103eaa --- /dev/null +++ b/frontend/casino/src/app/stores/User/UserStore.ts @@ -0,0 +1,13 @@ +import { makeAutoObservable } from 'mobx' + +export class UserStore { + balance: string | undefined = undefined + constructor() { + makeAutoObservable(this) + } + + setBalance(balance: string) { + this.balance = balance + console.log(balance) + } +} diff --git a/frontend/casino/src/app/web3/balance/CheckBalanceButton.tsx b/frontend/casino/src/app/web3/balance/CheckBalanceButton.tsx new file mode 100644 index 0000000..24d31fd --- /dev/null +++ b/frontend/casino/src/app/web3/balance/CheckBalanceButton.tsx @@ -0,0 +1,18 @@ +import {useCheckBalance} from "./useCheckBalance.ts"; +import {observer} from "mobx-react-lite"; +import {useEffect} from "react"; +import {useStores} from "../../hooks/useStores.tsx"; + +export const CheckBalanceButton = observer(() => { + const { checkBalance, result } = useCheckBalance() + const { userStore } = useStores() + useEffect(() => { + if (result) userStore.setBalance(result.balance) + }, [result]) + + return ( + + ); +}); \ No newline at end of file diff --git a/frontend/casino/src/app/web3/balance/useCheckBalance.ts b/frontend/casino/src/app/web3/balance/useCheckBalance.ts new file mode 100644 index 0000000..dd867ee --- /dev/null +++ b/frontend/casino/src/app/web3/balance/useCheckBalance.ts @@ -0,0 +1,36 @@ +import {useWalletConnect} from "@cityofzion/wallet-connect-sdk-react"; +import {useCallback} from "react"; +import {useGetResult} from "../functions/utils/useGetResult.ts"; +import {config} from "../functions/config/config.ts"; + +export const useCheckBalance = () => { + const wcSdk = useWalletConnect() + const { getResult, ...statuses } = useGetResult() + + const checkBalance = useCallback(async () => { + console.log(config.zaCoin.contractAddress) + const address = wcSdk.getAccountAddress() + + if (!address) return + + const resp = await wcSdk.invokeFunction({ + invocations: [{ + scriptHash: config.zaCoin.contractAddress, + operation: 'balanceOf', + args: [ + { type: 'Hash160', value: address }, + ] + }], + signers: [{ + scopes: 'Global', + }] + }) + console.log(resp) + await getResult(resp, 'balance') + }, [wcSdk, getResult]) + + return { + checkBalance, + ...statuses + } +} \ No newline at end of file diff --git a/frontend/casino/src/app/web3/functions/Roulette/usePlayRoulette.ts b/frontend/casino/src/app/web3/functions/Roulette/usePlayRoulette.ts index a6ef32b..1e95dad 100644 --- a/frontend/casino/src/app/web3/functions/Roulette/usePlayRoulette.ts +++ b/frontend/casino/src/app/web3/functions/Roulette/usePlayRoulette.ts @@ -1,15 +1,13 @@ import {useWalletConnect} from "@cityofzion/wallet-connect-sdk-react"; import {useCallback} from "react"; import {useGetResult} from "../utils/useGetResult.ts"; -import {useStatusState} from "../../../hooks/useStatusState.ts"; import {config} from "../config/config.ts"; export const usePlayRoulette = () => { const wcSdk = useWalletConnect() - const { getResult } = useGetResult() - const { statuses, wrapPromise } = useStatusState() + const { getResult, ...statuses } = useGetResult() - const playRoulette = useCallback(wrapPromise(async () => { + const playRoulette = useCallback(async (value: number) => { // const resp = await wcSdk.invokeFunction({ // invocations: [{ // scriptHash: '270c825a5ac041e18be45074bbb942255164a214', @@ -22,13 +20,14 @@ export const usePlayRoulette = () => { // scopes: 'Global', // }] // }) + console.log(config.roulette.contractAddress) const resp = await wcSdk.invokeFunction({ invocations: [{ scriptHash: config.roulette.contractAddress, operation: 'playRoulette', args: [ { type: 'Integer', value: '40' }, - { type: 'Integer', value: '3' }, + { type: 'Integer', value: value.toString() }, ] }], signers: [{ @@ -36,9 +35,8 @@ export const usePlayRoulette = () => { }] }) console.log(resp) - const result = await getResult(resp) - console.log(result) - }), [wcSdk, getResult, wrapPromise]) + await getResult(resp, 'rouletteNumber') + }, [wcSdk, getResult]) return { playRoulette, diff --git a/frontend/casino/src/app/web3/functions/config/config.ts b/frontend/casino/src/app/web3/functions/config/config.ts index acd1174..f620989 100644 --- a/frontend/casino/src/app/web3/functions/config/config.ts +++ b/frontend/casino/src/app/web3/functions/config/config.ts @@ -3,9 +3,12 @@ export const config = { contractAddress: '13f7312810758d0e2271e2c620ba93f3568e0e8c' }, roulette: { - contractAddress: '13f7312810758d0e2271e2c620ba93f3568e0e8c' + contractAddress: '9a8e8297364f134f29bafe1322323af73e5ab434' }, slotMachine: { contractAddress: '13f7312810758d0e2271e2c620ba93f3568e0e8c' + }, + zaCoin: { + contractAddress: 'fdfb5c2974779e9cb9347e083a80054feae55a2d' } } \ No newline at end of file diff --git a/frontend/casino/src/app/web3/functions/utils/useGetResult.ts b/frontend/casino/src/app/web3/functions/utils/useGetResult.ts index 3ab4106..6af0a99 100644 --- a/frontend/casino/src/app/web3/functions/utils/useGetResult.ts +++ b/frontend/casino/src/app/web3/functions/utils/useGetResult.ts @@ -1,36 +1,57 @@ import {useCallback} from "react"; import axios from "axios"; import useIntervalAsync from "../../../hooks/useIntervalAsync.ts"; +import {useStatusState} from "../../../hooks/useStatusState.ts"; + +export interface IGetResult { + tx: string; + notificationKey?: string +} const baseUrlToGet = 'https://dora.coz.io/api/v2/neo3/testnet/log/' export const useGetResult = () => { + const { statuses, wrapPromise } = useStatusState<{ value: string, balance: string} | undefined, IGetResult>() const getResultReq = useCallback(async (tx: string | undefined) => { const result = await axios.get(baseUrlToGet + tx) console.log(result) return result }, []) - const { run: runIsApprovedRefetch } = useIntervalAsync(async (tx) => { + const { run: runIsApprovedRefetch } = useIntervalAsync(wrapPromise(async ({tx, notificationKey}) => { if (!tx) return try { const result = await getResultReq(tx) if (!result) setTimeout(() => { runIsApprovedRefetch(tx) }, 3000) - return result - } catch (e) { setTimeout(() => { - runIsApprovedRefetch(tx) - }, 3000) } - }, 3000) - const getResult = useCallback(async (tx: string | undefined) => { + let balance; + + if (notificationKey === 'balance') { + balance = result.data?.stack[0].value + } else { + balance = result.data?.notifications?.find((item: { event_name: string | undefined; }) => item?.event_name === 'playerBalance')?.state?.value[0].value + } + const value = result.data?.notifications?.find((item: { event_name: string | undefined; }) => item?.event_name === notificationKey)?.state?.value[0].value + + return { + value, + balance + } + } catch (e) { setTimeout(() => { + runIsApprovedRefetch(tx, notificationKey) + }, 3000) } + }), 3000) + + const getResult = useCallback(async (tx: string | undefined, notificationKey?: string) => { if (!tx) return console.log(tx) - const result = await runIsApprovedRefetch(tx) + const result = await runIsApprovedRefetch(tx, notificationKey) console.log(result) }, [runIsApprovedRefetch]) return { - getResult + getResult, + ...statuses } } \ No newline at end of file From 6ab48df7aef88126f993f1c57a924c74cead9b4b Mon Sep 17 00:00:00 2001 From: Aleksey_Levin Date: Sun, 7 Jan 2024 20:35:11 +0800 Subject: [PATCH 14/18] feat: edit dice --- .../app/components/web3/DicePlayButton.tsx | 8 +++-- .../app/pages/DiceGamePage/DiceGamePage.tsx | 4 +-- .../app/web3/functions/Craps/usePlayCraps.ts | 31 ++++++------------- .../src/app/web3/functions/config/config.ts | 2 +- 4 files changed, 17 insertions(+), 28 deletions(-) diff --git a/frontend/casino/src/app/components/web3/DicePlayButton.tsx b/frontend/casino/src/app/components/web3/DicePlayButton.tsx index ebaa673..f111e2a 100644 --- a/frontend/casino/src/app/components/web3/DicePlayButton.tsx +++ b/frontend/casino/src/app/components/web3/DicePlayButton.tsx @@ -1,14 +1,16 @@ import {usePlayRoulette} from "../../web3/functions/Roulette/usePlayRoulette.ts"; import {FC, useEffect} from "react"; +import {usePlayCraps} from "../../web3/functions/Craps/usePlayCraps.ts"; interface DicePlayButtonProps { value: number onSuccess: (result: unknown) => void onLoading: () => void + secondValue: number } -export const DicePlayButton: FC = ({ value, onSuccess, onLoading }) => { - const { playRoulette, result, isLoading } = usePlayRoulette() +export const DicePlayButton: FC = ({ value, onSuccess, onLoading, secondValue }) => { + const { playCraps, result, isLoading } = usePlayCraps() useEffect(() => { if (result) onSuccess(result) @@ -19,7 +21,7 @@ export const DicePlayButton: FC = ({ value, onSuccess, onLo }, [isLoading]) return ( -
{/* Кнопка для бека */} - +
- Вы загадали: 5 + Вы загадали: 5 и 6
{(diceValue && !isLoading) &&
Выпало число: {diceValue} diff --git a/frontend/casino/src/app/web3/functions/Craps/usePlayCraps.ts b/frontend/casino/src/app/web3/functions/Craps/usePlayCraps.ts index cf86b2b..78af54f 100644 --- a/frontend/casino/src/app/web3/functions/Craps/usePlayCraps.ts +++ b/frontend/casino/src/app/web3/functions/Craps/usePlayCraps.ts @@ -1,34 +1,22 @@ import {useWalletConnect} from "@cityofzion/wallet-connect-sdk-react"; import {useCallback} from "react"; import {useGetResult} from "../utils/useGetResult.ts"; -import {useStatusState} from "../../../hooks/useStatusState.ts"; -import { config } from "../config/config.ts"; +import {config} from "../config/config.ts"; export const usePlayCraps = () => { const wcSdk = useWalletConnect() - const { getResult } = useGetResult() - const { statuses, wrapPromise } = useStatusState() + const { getResult, ...statuses } = useGetResult() - const playCraps = useCallback(wrapPromise(async () => { - // const resp = await wcSdk.invokeFunction({ - // invocations: [{ - // scriptHash: '270c825a5ac041e18be45074bbb942255164a214', - // operation: 'balanceOf', - // args: [ - // { type: 'Hash160', value: 'NQCLAHuu4umnR99KB5m7U8ppJFtWqhw6DS' }, - // ] - // }], - // signers: [{ - // scopes: 'Global', - // }] - // }) + const playCraps = useCallback(async (value: number, secondValue: number) => { + console.log(config.craps.contractAddress) const resp = await wcSdk.invokeFunction({ invocations: [{ scriptHash: config.craps.contractAddress, - operation: 'playRoulette', + operation: 'playCraps', args: [ { type: 'Integer', value: '40' }, - { type: 'Integer', value: '3' }, + { type: 'Integer', value: value.toString() }, + { type: 'Integer', value: secondValue.toString() }, ] }], signers: [{ @@ -36,9 +24,8 @@ export const usePlayCraps = () => { }] }) console.log(resp) - const result = await getResult(resp) - console.log(result) - }), [wcSdk, getResult, wrapPromise]) + await getResult(resp, 'rouletteNumber') + }, [wcSdk, getResult]) return { playCraps, diff --git a/frontend/casino/src/app/web3/functions/config/config.ts b/frontend/casino/src/app/web3/functions/config/config.ts index f620989..67c82c5 100644 --- a/frontend/casino/src/app/web3/functions/config/config.ts +++ b/frontend/casino/src/app/web3/functions/config/config.ts @@ -1,6 +1,6 @@ export const config = { craps: { - contractAddress: '13f7312810758d0e2271e2c620ba93f3568e0e8c' + contractAddress: 'b068a57e65eb0cb13ab5409b70c1d43ccee7d1f5' }, roulette: { contractAddress: '9a8e8297364f134f29bafe1322323af73e5ab434' From 20bd3bb410a17af519d04e1d1ae4f12b8c208c93 Mon Sep 17 00:00:00 2001 From: Aleksey_Levin Date: Sun, 7 Jan 2024 20:38:22 +0800 Subject: [PATCH 15/18] feat: edit dice --- frontend/casino/src/app/components/web3/DicePlayButton.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/casino/src/app/components/web3/DicePlayButton.tsx b/frontend/casino/src/app/components/web3/DicePlayButton.tsx index f111e2a..9789cf9 100644 --- a/frontend/casino/src/app/components/web3/DicePlayButton.tsx +++ b/frontend/casino/src/app/components/web3/DicePlayButton.tsx @@ -1,4 +1,3 @@ -import {usePlayRoulette} from "../../web3/functions/Roulette/usePlayRoulette.ts"; import {FC, useEffect} from "react"; import {usePlayCraps} from "../../web3/functions/Craps/usePlayCraps.ts"; From 50be2dbc1d4e6db7b54c81271c64051888106512 Mon Sep 17 00:00:00 2001 From: Aleksey_Levin Date: Mon, 8 Jan 2024 13:56:25 +0800 Subject: [PATCH 16/18] feat: edit loading --- .../src/app/components/Loading/Loading.tsx | 20 ++++++++++++++++++ frontend/casino/src/assets/Capibebra.gif | Bin 0 -> 58124 bytes frontend/casino/src/main.tsx | 8 +++++-- 3 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 frontend/casino/src/app/components/Loading/Loading.tsx create mode 100644 frontend/casino/src/assets/Capibebra.gif diff --git a/frontend/casino/src/app/components/Loading/Loading.tsx b/frontend/casino/src/app/components/Loading/Loading.tsx new file mode 100644 index 0000000..b089bbd --- /dev/null +++ b/frontend/casino/src/app/components/Loading/Loading.tsx @@ -0,0 +1,20 @@ +import LoadingImg from '../../../assets/Capibebra.gif' +import { styled } from '../../../styles' + +const LoadingStyle = styled('div', { + width: '100vw', + height: '100vh', + display: 'flex', + justifyContent: 'center', + alignItems: 'center', +}) + +const Loading = () => { + return ( + + + + ) +} + +export default Loading diff --git a/frontend/casino/src/assets/Capibebra.gif b/frontend/casino/src/assets/Capibebra.gif new file mode 100644 index 0000000000000000000000000000000000000000..ffff13c7a61c6d733e252801b9dcc6c6ca9da55b GIT binary patch literal 58124 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 Zd)I5nL~q&uy|T&rQ`CC{209w`{{cM8NcI2# literal 0 HcmV?d00001 diff --git a/frontend/casino/src/main.tsx b/frontend/casino/src/main.tsx index cabfbb3..057b2ac 100644 --- a/frontend/casino/src/main.tsx +++ b/frontend/casino/src/main.tsx @@ -1,10 +1,14 @@ import React from 'react' import ReactDOM from 'react-dom/client' -import { App } from './App.tsx' import './index.css' +import Loading from "./app/components/Loading/Loading.tsx"; + +const App = React.lazy(() => import('./App').then(module => ({ default: module.App }))) ReactDOM.createRoot(document.getElementById('root')!).render( - + }> + + , ) From 82dfd7188fae59f5c5009ada09c107070424a618 Mon Sep 17 00:00:00 2001 From: Aleksey_Levin Date: Mon, 8 Jan 2024 15:10:41 +0800 Subject: [PATCH 17/18] add timeout to loading page --- frontend/casino/src/main.tsx | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/frontend/casino/src/main.tsx b/frontend/casino/src/main.tsx index 057b2ac..1a94a35 100644 --- a/frontend/casino/src/main.tsx +++ b/frontend/casino/src/main.tsx @@ -3,12 +3,17 @@ import ReactDOM from 'react-dom/client' import './index.css' import Loading from "./app/components/Loading/Loading.tsx"; -const App = React.lazy(() => import('./App').then(module => ({ default: module.App }))) +const App = React.lazy(() => + new Promise(( resolve ) => { + setTimeout(async () => { + resolve(import('./App')) + }, 3000) + }).then(module => ({ default: module.App }))) ReactDOM.createRoot(document.getElementById('root')!).render( - - }> - - - , + + }> + + + , ) From 170b86d4bd9ec69d6cddb03fb6cc56a58853aebb Mon Sep 17 00:00:00 2001 From: Dmitriy <89843200+quazzaar@users.noreply.github.com> Date: Tue, 9 Jan 2024 01:08:11 +0300 Subject: [PATCH 18/18] rps fix --- RPS/rps.go | 86 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 44 insertions(+), 42 deletions(-) diff --git a/RPS/rps.go b/RPS/rps.go index 9e35748..f527aa4 100644 --- a/RPS/rps.go +++ b/RPS/rps.go @@ -1,7 +1,6 @@ package RPS import ( - "github.com/nspcc-dev/neo-go/pkg/interop" "github.com/nspcc-dev/neo-go/pkg/interop/contract" "github.com/nspcc-dev/neo-go/pkg/interop/runtime" @@ -9,14 +8,12 @@ import ( ) const ( - gasDecimals = 1_0000_0000 - initialBalance = 3000 zaCoinHashKey = "zaCoinHash" ) type Result struct { - win bool - tie bool + win bool + tie bool lose bool } @@ -25,64 +22,71 @@ func _deploy(data interface{}, isUpdate bool) { return } - // Parse hash of forint contract from incoming data args := data.(struct { zaCoinHash interop.Hash160 }) if len(args.zaCoinHash) != interop.Hash160Len { - panic("invalid hash of zaCoin contract") - } - + panic("invalid hash of zaCoin contract") + } ctx := storage.GetContext() storage.Put(ctx, zaCoinHashKey, args.zaCoinHash) } -func PlayRPS(playerChoice string) { - - computerChoice := (runtime.GetRandom() % 3) + 1 - if computerChoice == 1 { - computerChoice := "rock" - } else if computerChoice == 2 { - computerChoice := "paper" - } else { - computerChoice := "scissors" +func PlayRPS(playerChoice string, ctx storage.Context, playerOwner interop.Hash160, bet int) { + + if playerChoice != "rock" && playerChoice != "paper" && playerChoice != "scissors" { + panic("invalid player choice") + } + if bet <= 0 { + panic("bet must be positive") } - result := isWinner(playerChoice, computerChoice) + computerChoice := (runtime.GetRandom() % 3) + 1 - if result.tie { - return - } else if result.win { - changePlayerBalance(ctx, playerOwner, bet) - } else { - changePlayerBalance(ctx, playerOwner, -bet) - } + var computerChoiceString string + switch computerChoice { + case 0: + computerChoiceString = "rock" + case 1: + computerChoiceString = "paper" + case 2: + computerChoiceString = "scissors" + } + + result := isWinner(playerChoice, computerChoiceString) + + if result.tie { + panic("game tied: player chose " + playerChoice + ", computer chose " + computerChoiceString) + } else if result.win { + changePlayerBalance(ctx, playerOwner, bet) + } else { + panic("player lost: player chose " + playerChoice + ", computer chose " + computerChoiceString) + } } func isWinner(playerChoice, computerChoice string) Result { if playerChoice == computerChoice { - return Result{tie: true} - } + return Result{tie: true} + } - if playerChoice == "rock" && computerChoice == "scissors" { - return Result{win: true} - } + if playerChoice == "rock" && computerChoice == "scissors" { + return Result{win: true} + } - if playerChoice == "scissors" && computerChoice == "paper" { - return Result{win: true} - } + if playerChoice == "scissors" && computerChoice == "paper" { + return Result{win: true} + } - if playerChoice == "paper" && computerChoice == "rock" { - return Result{win: true} - } + if playerChoice == "paper" && computerChoice == "rock" { + return Result{win: true} + } - return Result{lose: true} + return Result{lose: true} } - func OnNEP17Payment(from interop.Hash160, amount int, data any) { ctx := storage.GetContext() zaCoinHash := storage.Get(ctx, zaCoinHashKey).(interop.Hash160) @@ -100,15 +104,13 @@ func changePlayerBalance(ctx storage.Context, playerOwner interop.Hash160, balan var from, to interop.Hash160 var transferAmount int if balanceChange > 0 { - // Transfer funds from contract to player owner from = playerContract to = playerOwner transferAmount = balanceChange } else { - // Transfer funds from player owner to contract from = playerOwner to = playerContract - transferAmount = -balanceChange // We flip sender/receiver, but keep amount positive + transferAmount = -balanceChange } transferred := contract.Call(zaCoinHash, "transfer", contract.All, from, to, transferAmount, nil).(bool)