Merge branch 'dev' into dev_frontend
This commit is contained in:
commit
7ce025914d
24 changed files with 334 additions and 136 deletions
20
.github/workflows/github-actions-demo.yml
vendored
Normal file
20
.github/workflows/github-actions-demo.yml
vendored
Normal 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
|
86
RPS/rps.go
86
RPS/rps.go
|
@ -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)
|
||||||
|
|
|
@ -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'
|
||||||
|
|
|
@ -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>
|
||||||
)
|
)
|
||||||
};
|
})
|
||||||
|
|
20
frontend/casino/src/app/components/Loading/Loading.tsx
Normal file
20
frontend/casino/src/app/components/Loading/Loading.tsx
Normal 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
|
|
@ -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>
|
||||||
)
|
)
|
||||||
}
|
}
|
|
@ -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'
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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: {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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>
|
||||||
)
|
)
|
||||||
}
|
})
|
|
@ -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"
|
||||||
/>
|
/>
|
||||||
|
|
11
frontend/casino/src/app/stores/RootStore.ts
Normal file
11
frontend/casino/src/app/stores/RootStore.ts
Normal 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()
|
13
frontend/casino/src/app/stores/User/UserStore.ts
Normal file
13
frontend/casino/src/app/stores/User/UserStore.ts
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
18
frontend/casino/src/app/web3/balance/CheckBalanceButton.tsx
Normal file
18
frontend/casino/src/app/web3/balance/CheckBalanceButton.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
});
|
36
frontend/casino/src/app/web3/balance/useCheckBalance.ts
Normal file
36
frontend/casino/src/app/web3/balance/useCheckBalance.ts
Normal 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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
|
@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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'
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
BIN
frontend/casino/src/assets/Capibebra.gif
Normal file
BIN
frontend/casino/src/assets/Capibebra.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 57 KiB |
|
@ -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>,
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue