Merge branch 'dev' into dev_frontend

This commit is contained in:
LewinUp 2024-01-09 16:21:11 +08:00 committed by GitHub
commit 7ce025914d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 334 additions and 136 deletions

View file

@ -0,0 +1,20 @@
name: GitHub Actions Demo
run-name: ${{ github.actor }} is testing out GitHub Actions 🚀
on: [push]
jobs:
init:
strategy:
matrix:
node-version: [ 18.x ]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Starting NodeJs ${{ matrix.node-version}}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- name: build
run: |
yarn
yarn build
working-directory: frontend/casino

View file

@ -1,7 +1,6 @@
package RPS package RPS
import ( import (
"github.com/nspcc-dev/neo-go/pkg/interop" "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/contract"
"github.com/nspcc-dev/neo-go/pkg/interop/runtime" "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
@ -9,14 +8,12 @@ import (
) )
const ( const (
gasDecimals = 1_0000_0000
initialBalance = 3000
zaCoinHashKey = "zaCoinHash" zaCoinHashKey = "zaCoinHash"
) )
type Result struct { type Result struct {
win bool win bool
tie bool tie bool
lose bool lose bool
} }
@ -25,64 +22,71 @@ func _deploy(data interface{}, isUpdate bool) {
return return
} }
// Parse hash of forint contract from incoming data
args := data.(struct { args := data.(struct {
zaCoinHash interop.Hash160 zaCoinHash interop.Hash160
}) })
if len(args.zaCoinHash) != interop.Hash160Len { if len(args.zaCoinHash) != interop.Hash160Len {
panic("invalid hash of zaCoin contract") panic("invalid hash of zaCoin contract")
} }
ctx := storage.GetContext() ctx := storage.GetContext()
storage.Put(ctx, zaCoinHashKey, args.zaCoinHash) storage.Put(ctx, zaCoinHashKey, args.zaCoinHash)
} }
func PlayRPS(playerChoice string) { func PlayRPS(playerChoice string, ctx storage.Context, playerOwner interop.Hash160, bet int) {
computerChoice := (runtime.GetRandom() % 3) + 1 if playerChoice != "rock" && playerChoice != "paper" && playerChoice != "scissors" {
if computerChoice == 1 { panic("invalid player choice")
computerChoice := "rock" }
} else if computerChoice == 2 { if bet <= 0 {
computerChoice := "paper" panic("bet must be positive")
} else {
computerChoice := "scissors"
} }
result := isWinner(playerChoice, computerChoice) computerChoice := (runtime.GetRandom() % 3) + 1
if result.tie { var computerChoiceString string
return switch computerChoice {
} else if result.win { case 0:
changePlayerBalance(ctx, playerOwner, bet) computerChoiceString = "rock"
} else { case 1:
changePlayerBalance(ctx, playerOwner, -bet) 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 { func isWinner(playerChoice, computerChoice string) Result {
if playerChoice == computerChoice { if playerChoice == computerChoice {
return Result{tie: true} return Result{tie: true}
} }
if playerChoice == "rock" && computerChoice == "scissors" { if playerChoice == "rock" && computerChoice == "scissors" {
return Result{win: true} return Result{win: true}
} }
if playerChoice == "scissors" && computerChoice == "paper" { if playerChoice == "scissors" && computerChoice == "paper" {
return Result{win: true} return Result{win: true}
} }
if playerChoice == "paper" && computerChoice == "rock" { if playerChoice == "paper" && computerChoice == "rock" {
return Result{win: true} return Result{win: true}
} }
return Result{lose: true} return Result{lose: true}
} }
func OnNEP17Payment(from interop.Hash160, amount int, data any) { func OnNEP17Payment(from interop.Hash160, amount int, data any) {
ctx := storage.GetContext() ctx := storage.GetContext()
zaCoinHash := storage.Get(ctx, zaCoinHashKey).(interop.Hash160) 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 from, to interop.Hash160
var transferAmount int var transferAmount int
if balanceChange > 0 { if balanceChange > 0 {
// Transfer funds from contract to player owner
from = playerContract from = playerContract
to = playerOwner to = playerOwner
transferAmount = balanceChange transferAmount = balanceChange
} else { } else {
// Transfer funds from player owner to contract
from = playerOwner from = playerOwner
to = playerContract 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) transferred := contract.Call(zaCoinHash, "transfer", contract.All, from, to, transferAmount, nil).(bool)

View file

@ -1,5 +1,5 @@
import { observer } from 'mobx-react-lite' import { observer } from 'mobx-react-lite'
import { type FC } from 'react' import {type FC} from 'react'
import { Outlet } from 'react-router-dom' import { Outlet } from 'react-router-dom'
import { useScrollTop } from '../../../hooks/useScrollTop.ts' import { useScrollTop } from '../../../hooks/useScrollTop.ts'

View file

@ -1,14 +1,19 @@
import CoinIcon from "../../icons/CoinIcon"; import CoinIcon from "../../icons/CoinIcon";
import ProfileIcon from "../../icons/ProfileIcon"; import ProfileIcon from "../../icons/ProfileIcon";
import WalletIcon from "../../icons/WalletIcon"; 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 ( return (
<div style={{ height: 'max-content' }} className="bg-[#30333C] text-white py-2 z-50 sticky top-0"> <div style={{ height: 'max-content' }} className="bg-[#30333C] text-white py-2 z-50 sticky top-0">
<div className="container mx-auto"> <div className="container mx-auto">
<div className="flex flex-row justify-between"> <div className="flex flex-row justify-between">
<a href="/" className="flex flex-row items-center"> <a href="/" className="flex flex-row items-center">
<img src="src/assets/icons/chip.png" alt="Icon" className="w-[53px] h-[53px] mr-[15px]" /> <img src={chipImg} alt="Icon" className="w-[53px] h-[53px] mr-[15px]" />
<span className="font-semibold text-3xl"> <span className="font-semibold text-3xl">
<span className="bg-gradient-to-b from-white via-blue-400 to-red-400 bg-clip-text text-transparent">Z</span>aSlot <span className="bg-gradient-to-b from-white via-blue-400 to-red-400 bg-clip-text text-transparent">Z</span>aSlot
<span className="text-gray-400">.bet</span> <span className="text-gray-400">.bet</span>
@ -19,15 +24,9 @@ export const AppNav = () => {
<div className="flex flex-row gap-[3px] items-center px-[15px] py-[11px]"> <div className="flex flex-row gap-[3px] items-center px-[15px] py-[11px]">
<CoinIcon /> <CoinIcon />
{/* placeholder for balance */} {/* placeholder for balance */}
<span>0.000000</span> {userStore.balance ? <span>{userStore.balance}</span> : <CheckBalanceButton/>}
</div>
<div className="flex flex-row items-center rounded-[100px] border-[2px] border-[#4F5563] bg-[#3B414F] px-[14px] py-[11px] gap-[3px] cursor-pointer">
{/* todo: load from .svg file in assets */}
<WalletIcon />
<button>
Wallet
</button>
</div> </div>
<ConnectStateButton/>
</div> </div>
<div className="flex flex-row items-center"> <div className="flex flex-row items-center">
<span>Robin F.</span> <span>Robin F.</span>
@ -37,5 +36,5 @@ export const AppNav = () => {
</div> </div>
</div> </div>
</div> </div>
) )
}; })

View file

@ -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 (
<LoadingStyle>
<img src={LoadingImg} />
</LoadingStyle>
)
}
export default Loading

View file

@ -1,7 +1,32 @@
export const DicePlayButton = () => { 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<DicePlayButtonProps> = ({ value, onSuccess, onLoading, secondValue }) => {
const { playCraps, result, isLoading } = usePlayCraps()
useEffect(() => {
if (result) onSuccess(result)
}, [result])
useEffect(() => {
if (isLoading) onLoading()
}, [isLoading])
return ( return (
<button className="bg-rose-700 rounded-[100px] shadow text-white text-2xl font-bold py-5 px-10 hover:bg-rose-600"> <button onClick={() => { playCraps(value, secondValue) }} className="bg-rose-700 rounded-[100px] shadow text-white text-2xl font-bold py-5 px-10 hover:bg-rose-600">
Бросить {
isLoading && 'Loading'
}
{
(!isLoading && !result) && 'Играть'
}
</button> </button>
) )
} }

View file

@ -2,4 +2,3 @@ export * from './useDOMRef.ts'
export * from './useMediaMui.ts' export * from './useMediaMui.ts'
export * from './useScrollTop.ts' export * from './useScrollTop.ts'
export * from './useScrollWindow.ts' export * from './useScrollWindow.ts'
export * from './useStores.tsx'

View file

@ -1,6 +1,7 @@
import { useCallback, useEffect, useRef, useState } from 'react' import { useCallback, useEffect, useRef, useState } from 'react'
import {IGetResult} from "../web3/functions/utils/useGetResult.ts";
const useIntervalAsync = <R = unknown>(fn: (tx: string) => Promise<R>, ms: number) => { const useIntervalAsync = <R = unknown>(fn: ({tx, notificationKey}: IGetResult) => Promise<R>, ms: number) => {
const runningCount = useRef(0) const runningCount = useRef(0)
const timeout = useRef<number>() const timeout = useRef<number>()
const mountedRef = useRef(false) const mountedRef = useRef(false)
@ -17,9 +18,9 @@ const useIntervalAsync = <R = unknown>(fn: (tx: string) => Promise<R>, ms: numbe
[ms], [ms],
) )
const run = useCallback(async (tx: string) => { const run = useCallback(async (tx: string, notificationKey?: string) => {
runningCount.current += 1 runningCount.current += 1
const result = await fn(tx) const result = await fn({tx, notificationKey})
runningCount.current -= 1 runningCount.current -= 1
next(run) next(run)

View file

@ -1,10 +1,7 @@
import { useCallback, useState } from 'react' import { useCallback, useState } from 'react'
import { useAccount } from 'wagmi'
import {stringifyError} from "../utils/error/stringifyError.ts"; import {stringifyError} from "../utils/error/stringifyError.ts";
export function useStatusState<ResultType, Arguments = void>() { export function useStatusState<ResultType, Arguments = void>() {
const { isConnected } = useAccount()
const [isLoading, setIsLoading] = useState(false) const [isLoading, setIsLoading] = useState(false)
const [error, setError] = useState<string>() const [error, setError] = useState<string>()
const [result, setResult] = useState<ResultType>() const [result, setResult] = useState<ResultType>()
@ -26,7 +23,7 @@ export function useStatusState<ResultType, Arguments = void>() {
throw err throw err
} }
} }
}, [isConnected]) }, [])
return { return {
statuses: { statuses: {

View file

@ -1,18 +1,17 @@
import { observer } from 'mobx-react-lite'
import { createContext, type PropsWithChildren, useContext } from 'react' import { createContext, type PropsWithChildren, useContext } from 'react'
import { type RootStore, rootStore } from '../stores/RootStore' import { type RootStore, rootStore } from '../stores/RootStore'
export const StoreContext = createContext<RootStore>(rootStore) export const StoreContext = createContext<RootStore>(rootStore)
export const StoreProvider = observer(function StoreProvider({ export function StoreProvider({
children, children,
// eslint-disable-next-line @typescript-eslint/ban-types // eslint-disable-next-line @typescript-eslint/ban-types
}: PropsWithChildren): JSX.Element { }: PropsWithChildren): JSX.Element {
return ( return (
<StoreContext.Provider value={rootStore}>{children}</StoreContext.Provider> <StoreContext.Provider value={rootStore}>{children}</StoreContext.Provider>
) )
}) }
export function useStores(): RootStore { export function useStores(): RootStore {
return useContext(StoreContext) return useContext(StoreContext)

View file

@ -1,7 +1,29 @@
import ContainerLayout from "../../utils/ContainerLayout" import ContainerLayout from "../../utils/ContainerLayout"
import { DicePlayButton } from "../../components/web3/DicePlayButton" 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<string | undefined>()
const [isLoading, setIsLoading] = useState<boolean>(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 ( return (
<ContainerLayout> <ContainerLayout>
<div className="flex flex-col items-center text-white"> <div className="flex flex-col items-center text-white">
@ -12,20 +34,20 @@ export const DiceGamePage = () => {
<div className="absolute w-[710px] h-[456px] bg-lime-800 rounded-[187px] blur-[300px]" /> <div className="absolute w-[710px] h-[456px] bg-lime-800 rounded-[187px] blur-[300px]" />
</div> </div>
<div className="flex flex-row min-w-full justify-center gap-10 relative mt-12"> <div className="flex flex-row min-w-full justify-center gap-10 relative mt-12">
<img src="src/assets/img/dice-img.png" alt="Dice" /> <img src={diceImg} alt="Dice" />
<img src="src/assets/img/dice-img.png" alt="Dice" /> <img src={diceImg} alt="Dice" />
</div> </div>
{/* Кнопка для бека */} {/* Кнопка для бека */}
<DicePlayButton /> <DicePlayButton onLoading={onLoading} onSuccess={onSuccess} value={5} secondValue={6}/>
<div className="flex flex-row justify-around w-full font-semibold"> <div className="flex flex-row justify-around w-full font-semibold">
<div className="bg-gray-500 rounded-[30px] py-5 px-10 text-2xl"> <div className="bg-gray-500 rounded-[30px] py-5 px-10 text-2xl">
Вы загадали: 5 Вы загадали: 5 и 6
</div>
<div className="bg-gray-800 rounded-[30px] py-5 px-10 text-2xl">
Выпало число: 5
</div> </div>
{(diceValue && !isLoading) && <div className="bg-gray-800 rounded-[30px] py-5 px-10 text-2xl">
Выпало число: {diceValue}
</div>}
</div> </div>
</div> </div>
</ContainerLayout> </ContainerLayout>
) )
} })

View file

@ -1,13 +1,17 @@
import CoinIcon from "../../components/icons/CoinIcon";
import ContainerLayout from "../../utils/ContainerLayout"; import ContainerLayout from "../../utils/ContainerLayout";
import GamepadIcon from "../../components/icons/GamepadIcon"; 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 = () => { export const MainPage = () => {
return ( return (
<ContainerLayout> <ContainerLayout>
<div className="absolute w-[1235px] h-[629px] overflow-hidden"> <div className="absolute w-[1235px] h-[629px] overflow-hidden">
<img <img
src="src/assets/img/casino-bg-image.png" src={casinoBg}
alt="Icon" alt="Icon"
className="w-full h-full object-cover filter brightness-80 blur-[4px]" className="w-full h-full object-cover filter brightness-80 blur-[4px]"
/> />
@ -39,7 +43,7 @@ export const MainPage = () => {
<div className="w-[374px] h-[187.35px] bg-[#323846] rounded-[23px] border-2 border-gray-700 flex flex-row items-center justify-between px-4 py-6 gap-3"> <div className="w-[374px] h-[187.35px] bg-[#323846] rounded-[23px] border-2 border-gray-700 flex flex-row items-center justify-between px-4 py-6 gap-3">
<div className="rounded-full bg-neutral-800 inline-block"> <div className="rounded-full bg-neutral-800 inline-block">
<img <img
src="src/assets/img/dices-small.png" src={diceSmall}
alt="Icon" alt="Icon"
className="object-cover" className="object-cover"
/> />
@ -47,7 +51,7 @@ export const MainPage = () => {
<div className="flex flex-col h-full justify-between"> <div className="flex flex-col h-full justify-between">
<div className="flex flex-row justify-between min-w-[200px] my-auto items-center"> <div className="flex flex-row justify-between min-w-[200px] my-auto items-center">
<span className="text-xl font-bold">DICE</span> <span className="text-xl font-bold">DICE</span>
<a href="/dice" className="min-w-[100px]max-h-[45px] bg-blue-500 rounded-[10px] border border-blue-400 font-bold px-3 items-center flex justify-center py-2">Play now</a> <Link to="dice" className="min-w-[100px] max-h-[45px] bg-blue-500 rounded-[10px] border border-blue-400 font-bold px-3 items-center flex justify-center">Play now</Link>
</div> </div>
</div> </div>
</div> </div>
@ -55,7 +59,7 @@ export const MainPage = () => {
<div className="w-[404px] h-[187.35px] bg-[#323846] rounded-[23px] border-2 border-gray-700 flex flex-row items-center justify-between px-4 py-6 gap-3"> <div className="w-[404px] h-[187.35px] bg-[#323846] rounded-[23px] border-2 border-gray-700 flex flex-row items-center justify-between px-4 py-6 gap-3">
<div className="rounded-full w-[140px] bg-neutral-800 inline-block"> <div className="rounded-full w-[140px] bg-neutral-800 inline-block">
<img <img
src="src/assets/img/rps-small.png" src={rpsSmall}
alt="Icon" alt="Icon"
className="object-cover" className="object-cover"
/> />
@ -71,7 +75,7 @@ export const MainPage = () => {
<div className="w-[374px] h-[187.35px] bg-[#323846] rounded-[23px] border-2 border-gray-700 flex flex-row items-center justify-between px-4 py-6 gap-3"> <div className="w-[374px] h-[187.35px] bg-[#323846] rounded-[23px] border-2 border-gray-700 flex flex-row items-center justify-between px-4 py-6 gap-3">
<div className="rounded-full bg-neutral-800 inline-block"> <div className="rounded-full bg-neutral-800 inline-block">
<img <img
src="src/assets/img/slot-machine-small.png" src={slotMachine}
alt="Icon" alt="Icon"
className="object-cover" className="object-cover"
/> />

View file

@ -0,0 +1,11 @@
import { UserStore } from './User/UserStore'
export class RootStore {
userStore: UserStore
constructor() {
this.userStore = new UserStore()
}
}
export const rootStore = new RootStore()

View file

@ -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)
}
}

View file

@ -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 (
<button onClick={checkBalance}>
Check balance
</button>
);
});

View file

@ -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
}
}

View file

@ -1,10 +1,17 @@
import {useConnect} from "../../lib/useConnect.ts"; import {useConnect} from "../../lib/useConnect.ts";
import WalletIcon from "../../../../components/icons/WalletIcon.tsx";
export const ConnectButton = () => { export const ConnectButton = () => {
const { connect } = useConnect() const { connect } = useConnect()
return ( return (
<button onClick={connect}> <div
Connect onClick={connect}
</button> className="flex flex-row items-center rounded-[100px] border-[2px] border-[#4F5563] bg-[#3B414F] px-[14px] py-[11px] gap-[3px] cursor-pointer">
{/* todo: load from .vg file in assets */}
<WalletIcon/>
<button>
Connect
</button>
</div>
); );
}; };

View file

@ -1,10 +1,17 @@
import {useConnect} from "../../lib/useConnect.ts"; import {useConnect} from "../../lib/useConnect.ts";
import WalletIcon from "../../../../components/icons/WalletIcon.tsx";
export const DisconnectButton = () => { export const DisconnectButton = () => {
const { disconnect } = useConnect() const { disconnect } = useConnect()
return ( return (
<button onClick={disconnect}> <div
Disconnect onClick={disconnect}
</button> className="flex flex-row items-center rounded-[100px] border-[2px] border-[#4F5563] bg-[#3B414F] px-[14px] py-[11px] gap-[3px] cursor-pointer">
{/* todo: load from .svg file in assets */}
<WalletIcon/>
<button>
Disconnect
</button>
</div>
); );
}; };

View file

@ -1,34 +1,22 @@
import {useWalletConnect} from "@cityofzion/wallet-connect-sdk-react"; import {useWalletConnect} from "@cityofzion/wallet-connect-sdk-react";
import {useCallback} from "react"; import {useCallback} from "react";
import {useGetResult} from "../utils/useGetResult.ts"; 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 = () => { export const usePlayCraps = () => {
const wcSdk = useWalletConnect() const wcSdk = useWalletConnect()
const { getResult } = useGetResult() const { getResult, ...statuses } = useGetResult()
const { statuses, wrapPromise } = useStatusState()
const playCraps = useCallback(wrapPromise(async () => { const playCraps = useCallback(async (value: number, secondValue: number) => {
// const resp = await wcSdk.invokeFunction({ console.log(config.craps.contractAddress)
// invocations: [{
// scriptHash: '270c825a5ac041e18be45074bbb942255164a214',
// operation: 'balanceOf',
// args: [
// { type: 'Hash160', value: 'NQCLAHuu4umnR99KB5m7U8ppJFtWqhw6DS' },
// ]
// }],
// signers: [{
// scopes: 'Global',
// }]
// })
const resp = await wcSdk.invokeFunction({ const resp = await wcSdk.invokeFunction({
invocations: [{ invocations: [{
scriptHash: config.craps.contractAddress, scriptHash: config.craps.contractAddress,
operation: 'playRoulette', operation: 'playCraps',
args: [ args: [
{ type: 'Integer', value: '40' }, { type: 'Integer', value: '40' },
{ type: 'Integer', value: '3' }, { type: 'Integer', value: value.toString() },
{ type: 'Integer', value: secondValue.toString() },
] ]
}], }],
signers: [{ signers: [{
@ -36,9 +24,8 @@ export const usePlayCraps = () => {
}] }]
}) })
console.log(resp) console.log(resp)
const result = await getResult(resp) await getResult(resp, 'rouletteNumber')
console.log(result) }, [wcSdk, getResult])
}), [wcSdk, getResult, wrapPromise])
return { return {
playCraps, playCraps,

View file

@ -1,15 +1,13 @@
import {useWalletConnect} from "@cityofzion/wallet-connect-sdk-react"; import {useWalletConnect} from "@cityofzion/wallet-connect-sdk-react";
import {useCallback} from "react"; import {useCallback} from "react";
import {useGetResult} from "../utils/useGetResult.ts"; 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 usePlayRoulette = () => { export const usePlayRoulette = () => {
const wcSdk = useWalletConnect() const wcSdk = useWalletConnect()
const { getResult } = useGetResult() const { getResult, ...statuses } = useGetResult()
const { statuses, wrapPromise } = useStatusState()
const playRoulette = useCallback(wrapPromise(async () => { const playRoulette = useCallback(async (value: number) => {
// const resp = await wcSdk.invokeFunction({ // const resp = await wcSdk.invokeFunction({
// invocations: [{ // invocations: [{
// scriptHash: '270c825a5ac041e18be45074bbb942255164a214', // scriptHash: '270c825a5ac041e18be45074bbb942255164a214',
@ -22,13 +20,14 @@ export const usePlayRoulette = () => {
// scopes: 'Global', // scopes: 'Global',
// }] // }]
// }) // })
console.log(config.roulette.contractAddress)
const resp = await wcSdk.invokeFunction({ const resp = await wcSdk.invokeFunction({
invocations: [{ invocations: [{
scriptHash: config.roulette.contractAddress, scriptHash: config.roulette.contractAddress,
operation: 'playRoulette', operation: 'playRoulette',
args: [ args: [
{ type: 'Integer', value: '40' }, { type: 'Integer', value: '40' },
{ type: 'Integer', value: '3' }, { type: 'Integer', value: value.toString() },
] ]
}], }],
signers: [{ signers: [{
@ -36,9 +35,8 @@ export const usePlayRoulette = () => {
}] }]
}) })
console.log(resp) console.log(resp)
const result = await getResult(resp) await getResult(resp, 'rouletteNumber')
console.log(result) }, [wcSdk, getResult])
}), [wcSdk, getResult, wrapPromise])
return { return {
playRoulette, playRoulette,

View file

@ -1,11 +1,14 @@
export const config = { export const config = {
craps: { craps: {
contractAddress: '13f7312810758d0e2271e2c620ba93f3568e0e8c' contractAddress: 'b068a57e65eb0cb13ab5409b70c1d43ccee7d1f5'
}, },
roulette: { roulette: {
contractAddress: '13f7312810758d0e2271e2c620ba93f3568e0e8c' contractAddress: '9a8e8297364f134f29bafe1322323af73e5ab434'
}, },
slotMachine: { slotMachine: {
contractAddress: '13f7312810758d0e2271e2c620ba93f3568e0e8c' contractAddress: '13f7312810758d0e2271e2c620ba93f3568e0e8c'
},
zaCoin: {
contractAddress: 'fdfb5c2974779e9cb9347e083a80054feae55a2d'
} }
} }

View file

@ -1,36 +1,57 @@
import {useCallback} from "react"; import {useCallback} from "react";
import axios from "axios"; import axios from "axios";
import useIntervalAsync from "../../../hooks/useIntervalAsync.ts"; 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/' const baseUrlToGet = 'https://dora.coz.io/api/v2/neo3/testnet/log/'
export const useGetResult = () => { export const useGetResult = () => {
const { statuses, wrapPromise } = useStatusState<{ value: string, balance: string} | undefined, IGetResult>()
const getResultReq = useCallback(async (tx: string | undefined) => { const getResultReq = useCallback(async (tx: string | undefined) => {
const result = await axios.get(baseUrlToGet + tx) const result = await axios.get(baseUrlToGet + tx)
console.log(result) console.log(result)
return result return result
}, []) }, [])
const { run: runIsApprovedRefetch } = useIntervalAsync(async (tx) => { const { run: runIsApprovedRefetch } = useIntervalAsync(wrapPromise(async ({tx, notificationKey}) => {
if (!tx) return if (!tx) return
try { try {
const result = await getResultReq(tx) const result = await getResultReq(tx)
if (!result) setTimeout(() => { if (!result) setTimeout(() => {
runIsApprovedRefetch(tx) runIsApprovedRefetch(tx)
}, 3000) }, 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 if (!tx) return
console.log(tx) console.log(tx)
const result = await runIsApprovedRefetch(tx) const result = await runIsApprovedRefetch(tx, notificationKey)
console.log(result) console.log(result)
}, [runIsApprovedRefetch]) }, [runIsApprovedRefetch])
return { return {
getResult getResult,
...statuses
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

View file

@ -1,10 +1,19 @@
import React from 'react' import React from 'react'
import ReactDOM from 'react-dom/client' import ReactDOM from 'react-dom/client'
import { App } from './App.tsx'
import './index.css' import './index.css'
import Loading from "./app/components/Loading/Loading.tsx";
const App = React.lazy(() =>
new Promise<typeof import("./App")>(( resolve ) => {
setTimeout(async () => {
resolve(import('./App'))
}, 3000)
}).then(module => ({ default: module.App })))
ReactDOM.createRoot(document.getElementById('root')!).render( ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode> <React.StrictMode>
<App /> <React.Suspense fallback={<Loading />}>
</React.StrictMode>, <App />
</React.Suspense>
</React.StrictMode>,
) )