├── app ├── env.d.ts ├── public │ └── favicon.ico ├── .vscode │ ├── extensions.json │ └── settings.json ├── src │ ├── axios.ts │ ├── quasar-variables.sass │ ├── pages │ │ ├── LoginPage.vue │ │ └── IndexPage.vue │ ├── App.vue │ ├── assets │ │ ├── logo.svg │ │ ├── main.css │ │ └── base.css │ ├── components │ │ ├── icons │ │ │ ├── IconSupport.vue │ │ │ ├── IconTooling.vue │ │ │ ├── IconCommunity.vue │ │ │ ├── IconDocumentation.vue │ │ │ └── IconEcosystem.vue │ │ ├── NearLogin.vue │ │ ├── LeaderBoard.vue │ │ └── PlayGame.vue │ ├── main.ts │ ├── auth.ts │ ├── router │ │ └── index.ts │ ├── ws.js │ ├── crypto.ts │ └── game.ts ├── .prettierrc.json ├── tsconfig.json ├── index.html ├── .eslintrc.cjs ├── tsconfig.app.json ├── tsconfig.node.json ├── vite.config.ts ├── README.md └── package.json ├── logic ├── leaderboard │ ├── res │ │ └── leaderboard.wasm │ ├── relayer │ │ ├── package.json │ │ ├── mock-ws-server.js │ │ ├── ws.js │ │ ├── relayer.js │ │ └── yarn.lock │ ├── build.sh │ ├── Cargo.toml │ ├── tests │ │ └── sandbox.rs │ └── src │ │ └── lib.rs └── rock-paper-scissors │ ├── res │ └── rock_paper_scissors.wasm │ ├── build.sh │ ├── Cargo.toml │ ├── src │ ├── errors.rs │ ├── player_idx.rs │ ├── commitment.rs │ ├── choice.rs │ ├── key.rs │ ├── repr.rs │ └── lib.rs │ └── Cargo.lock ├── .gitignore ├── .github └── workflows │ └── deploy-vue.yml └── README.md /app/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /app/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calimero-network/rock-paper-scissors/HEAD/app/public/favicon.ico -------------------------------------------------------------------------------- /logic/leaderboard/res/leaderboard.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calimero-network/rock-paper-scissors/HEAD/logic/leaderboard/res/leaderboard.wasm -------------------------------------------------------------------------------- /app/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "Vue.volar", 4 | "dbaeumer.vscode-eslint", 5 | "esbenp.prettier-vscode" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /app/src/axios.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | const nearApi = axios.create({ baseURL: 'https://rpc.testnet.near.org/' }) 4 | 5 | export { axios, nearApi } 6 | -------------------------------------------------------------------------------- /logic/rock-paper-scissors/res/rock_paper_scissors.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calimero-network/rock-paper-scissors/HEAD/logic/rock-paper-scissors/res/rock_paper_scissors.wasm -------------------------------------------------------------------------------- /app/.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/prettierrc", 3 | "semi": false, 4 | "tabWidth": 2, 5 | "singleQuote": true, 6 | "printWidth": 100, 7 | "trailingComma": "none" 8 | } -------------------------------------------------------------------------------- /app/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.codeActionsOnSave": { 3 | "source.fixAll": "explicit" 4 | }, 5 | "editor.formatOnSave": true, 6 | "editor.defaultFormatter": "esbenp.prettier-vscode" 7 | } 8 | -------------------------------------------------------------------------------- /app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { 5 | "path": "./tsconfig.node.json" 6 | }, 7 | { 8 | "path": "./tsconfig.app.json" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /app/src/quasar-variables.sass: -------------------------------------------------------------------------------- 1 | $primary : #1976D2 2 | $secondary : #26A69A 3 | $accent : #9C27B0 4 | 5 | $dark : #1D1D1D 6 | 7 | $positive : #21BA45 8 | $negative : #C10015 9 | $info : #31CCEC 10 | $warning : #F2C037 -------------------------------------------------------------------------------- /app/src/pages/LoginPage.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | -------------------------------------------------------------------------------- /app/src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/assets/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /logic/leaderboard/relayer/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "relayer", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "author": "Saeed", 6 | "license": "MIT", 7 | "dependencies": { 8 | "command-line-args": "^5.2.1", 9 | "near-api-js": "^4.0.1", 10 | "prompt-sync": "^4.2.0", 11 | "ws": "^8.17.1" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/src/components/icons/IconSupport.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite App 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | require('@rushstack/eslint-patch/modern-module-resolution') 3 | 4 | module.exports = { 5 | root: true, 6 | 'extends': [ 7 | 'plugin:vue/vue3-essential', 8 | 'eslint:recommended', 9 | '@vue/eslint-config-typescript', 10 | '@vue/eslint-config-prettier/skip-formatting' 11 | ], 12 | parserOptions: { 13 | ecmaVersion: 'latest' 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@vue/tsconfig/tsconfig.dom.json", 3 | "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], 4 | "exclude": ["src/**/__tests__/*"], 5 | "compilerOptions": { 6 | "composite": true, 7 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", 8 | 9 | "baseUrl": ".", 10 | "paths": { 11 | "@/*": ["./src/*"] 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main.ts: -------------------------------------------------------------------------------- 1 | import './assets/main.css' 2 | 3 | import { createApp } from 'vue' 4 | import App from './App.vue' 5 | import router from './router' 6 | import { Quasar } from 'quasar' 7 | import '@quasar/extras/material-icons/material-icons.css' 8 | import 'quasar/src/css/index.sass' 9 | 10 | const app = createApp(App) 11 | 12 | app.use(router) 13 | app.use(Quasar, { 14 | plugins: {} // import Quasar plugins and add here 15 | }) 16 | 17 | app.mount('#app') 18 | -------------------------------------------------------------------------------- /app/src/auth.ts: -------------------------------------------------------------------------------- 1 | import { LocalStorage } from 'quasar' 2 | 3 | export interface ClientKey { 4 | privateKey: string 5 | publicKey: string 6 | } 7 | 8 | export const isAuthenticated = () => { 9 | return LocalStorage.hasItem('client-key') 10 | } 11 | 12 | export const getClientKey = (): ClientKey | null => { 13 | const keyStr: string | null = LocalStorage.getItem('client-key') 14 | if (keyStr) { 15 | return JSON.parse(keyStr) 16 | } 17 | return null 18 | } 19 | -------------------------------------------------------------------------------- /logic/leaderboard/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | rustup target add wasm32-unknown-unknown 3 | set -e 4 | 5 | cd "$(dirname $0)" 6 | 7 | TARGET="${CARGO_TARGET_DIR:-target}" 8 | 9 | cargo build --target wasm32-unknown-unknown --profile app-release 10 | 11 | mkdir -p res 12 | 13 | cp $TARGET/wasm32-unknown-unknown/app-release/leaderboard.wasm ./res/ 14 | 15 | if command -v wasm-opt > /dev/null; then 16 | wasm-opt -Oz ./res/leaderboard.wasm -o ./res/leaderboard.wasm 17 | fi 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | .DS_Store 12 | dist 13 | dist-ssr 14 | coverage 15 | *.local 16 | 17 | /cypress/videos/ 18 | /cypress/screenshots/ 19 | 20 | # Editor directories and files 21 | .vscode/* 22 | !.vscode/extensions.json 23 | .idea 24 | *.suo 25 | *.ntvs* 26 | *.njsproj 27 | *.sln 28 | *.sw? 29 | 30 | *.tsbuildinfo 31 | 32 | .idea/ 33 | data/ 34 | target/ 35 | -------------------------------------------------------------------------------- /app/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@tsconfig/node20/tsconfig.json", 3 | "include": [ 4 | "vite.config.*", 5 | "vitest.config.*", 6 | "cypress.config.*", 7 | "nightwatch.conf.*", 8 | "playwright.config.*" 9 | ], 10 | "compilerOptions": { 11 | "composite": true, 12 | "noEmit": true, 13 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 14 | 15 | "module": "ESNext", 16 | "moduleResolution": "Bundler", 17 | "types": ["node"] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /logic/rock-paper-scissors/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | cd "$(dirname $0)" 5 | 6 | TARGET="${CARGO_TARGET_DIR:-target}" 7 | 8 | rustup target add wasm32-unknown-unknown 9 | 10 | cargo build --target wasm32-unknown-unknown --profile app-release 11 | 12 | mkdir -p res 13 | 14 | cp $TARGET/wasm32-unknown-unknown/app-release/rock_paper_scissors.wasm ./res/ 15 | 16 | if command -v wasm-opt > /dev/null; then 17 | wasm-opt -Oz ./res/rock_paper_scissors.wasm -o ./res/rock_paper_scissors.wasm 18 | fi 19 | -------------------------------------------------------------------------------- /app/src/router/index.ts: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHistory } from 'vue-router' 2 | import IndexPage from '../pages/IndexPage.vue' 3 | import NearLoginPage from '../pages/LoginPage.vue' 4 | 5 | const router = createRouter({ 6 | history: createWebHistory(import.meta.env.BASE_URL), 7 | routes: [ 8 | { 9 | path: '/', 10 | name: 'home', 11 | component: IndexPage 12 | }, 13 | { 14 | path: '/login', 15 | name: 'login', 16 | component: NearLoginPage 17 | } 18 | ] 19 | }) 20 | 21 | export default router 22 | -------------------------------------------------------------------------------- /logic/leaderboard/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "leaderboard" 3 | description = "leaderboard" 4 | version = "0.1.0" 5 | edition = "2021" 6 | 7 | [lib] 8 | crate-type = ["cdylib", "rlib"] 9 | 10 | [dependencies] 11 | near-sdk = "5.5.0" 12 | 13 | [dev-dependencies] 14 | near-sdk = { version = "5.5.0", features = ["unit-testing"] } 15 | tokio = "1.35.1" 16 | near-workspaces = "0.15.0" 17 | serde_json = "1.0.113" 18 | 19 | [profile.app-release] 20 | inherits = "release" 21 | codegen-units = 1 22 | opt-level = "z" 23 | lto = true 24 | debug = false 25 | panic = "abort" 26 | overflow-checks = true -------------------------------------------------------------------------------- /app/src/assets/main.css: -------------------------------------------------------------------------------- 1 | @import './base.css'; 2 | 3 | #app { 4 | max-width: 1280px; 5 | margin: 0 auto; 6 | padding: 2rem; 7 | font-weight: normal; 8 | } 9 | 10 | a, 11 | .green { 12 | text-decoration: none; 13 | color: hsla(160, 100%, 37%, 1); 14 | transition: 0.4s; 15 | padding: 3px; 16 | } 17 | 18 | @media (hover: hover) { 19 | a:hover { 20 | background-color: hsla(160, 100%, 37%, 0.2); 21 | } 22 | } 23 | 24 | @media (min-width: 1024px) { 25 | body { 26 | display: flex; 27 | place-items: center; 28 | } 29 | 30 | #app { 31 | display: grid; 32 | padding: 0 2rem; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/src/pages/IndexPage.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 24 | -------------------------------------------------------------------------------- /logic/rock-paper-scissors/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rock-paper-scissors" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | bs58 = "0.5.0" 11 | calimero-sdk = { git = "https://github.com/calimero-network/core", branch = "master" } 12 | calimero-storage = { git = "https://github.com/calimero-network/core", branch = "master" } 13 | ed25519-dalek = {version = "2.1.1",features = ["rand_core"]} 14 | rand_chacha = "0.3.1" 15 | sha3 = "0.10.8" 16 | 17 | [profile.app-release] 18 | inherits = "release" 19 | codegen-units = 1 20 | opt-level = "z" 21 | lto = true 22 | debug = false 23 | panic = "abort" 24 | overflow-checks = true -------------------------------------------------------------------------------- /logic/rock-paper-scissors/src/errors.rs: -------------------------------------------------------------------------------- 1 | use calimero_sdk::serde::Serialize; 2 | 3 | #[derive(Debug, Serialize)] 4 | #[serde(crate = "calimero_sdk::serde")] 5 | pub enum JoinError { 6 | GameFull, 7 | } 8 | 9 | #[derive(Debug, Serialize)] 10 | #[serde(crate = "calimero_sdk::serde")] 11 | pub enum CommitError { 12 | NotReady, 13 | AlreadyCommitted, 14 | InvalidSignature, 15 | } 16 | 17 | #[derive(Debug, Serialize)] 18 | #[serde(crate = "calimero_sdk::serde")] 19 | pub enum RevealError { 20 | NotReady, 21 | NotCommitted, 22 | InvalidNonce, 23 | } 24 | 25 | #[derive(Debug, Serialize)] 26 | #[serde(crate = "calimero_sdk::serde")] 27 | pub enum ResetError { 28 | NotReady, 29 | InvalidSignature, 30 | } 31 | -------------------------------------------------------------------------------- /app/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { fileURLToPath, URL } from 'node:url' 2 | 3 | import { defineConfig } from 'vite' 4 | import vue from '@vitejs/plugin-vue' 5 | import { nodePolyfills } from 'vite-plugin-node-polyfills' 6 | import { quasar, transformAssetUrls } from '@quasar/vite-plugin' 7 | 8 | // https://vitejs.dev/config/ 9 | export default defineConfig({ 10 | plugins: [ 11 | vue({ 12 | template: { transformAssetUrls } 13 | }), 14 | nodePolyfills(), 15 | quasar({ 16 | sassVariables: 'src/quasar-variables.sass' 17 | }) 18 | ], 19 | resolve: { 20 | alias: { 21 | '@': fileURLToPath(new URL('./src', import.meta.url)) 22 | } 23 | }, 24 | base: process.env.NODE_ENV === 'production' ? '/rock-paper-scissors/' : '/' 25 | }) 26 | -------------------------------------------------------------------------------- /logic/rock-paper-scissors/src/player_idx.rs: -------------------------------------------------------------------------------- 1 | use calimero_sdk::serde::{Deserialize, Deserializer, Serialize}; 2 | 3 | #[derive(Copy, Clone, Serialize)] 4 | #[serde(crate = "calimero_sdk::serde")] 5 | pub struct PlayerIdx(pub usize); 6 | 7 | impl PlayerIdx { 8 | pub fn other(&self) -> PlayerIdx { 9 | PlayerIdx(1 - self.0) 10 | } 11 | 12 | pub fn is_first(&self) -> bool { 13 | self.0 == 0 14 | } 15 | } 16 | 17 | impl<'de> Deserialize<'de> for PlayerIdx { 18 | fn deserialize(deserializer: D) -> Result 19 | where 20 | D: Deserializer<'de>, 21 | { 22 | let value = Deserialize::deserialize(deserializer)?; 23 | match value { 24 | 0 | 1 => Ok(PlayerIdx(value)), 25 | _ => Err(calimero_sdk::serde::de::Error::custom( 26 | "Player index must be 0 or 1", 27 | )), 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /logic/rock-paper-scissors/src/commitment.rs: -------------------------------------------------------------------------------- 1 | use calimero_sdk::borsh::{BorshDeserialize, BorshSerialize}; 2 | use sha3::{Digest, Sha3_256}; 3 | 4 | use crate::Choice; 5 | 6 | #[derive(Eq, Clone, Debug, PartialEq, BorshSerialize, BorshDeserialize)] 7 | #[borsh(crate = "calimero_sdk::borsh")] 8 | pub struct Commitment([u8; 32]); 9 | 10 | pub type Nonce = [u8; 32]; 11 | 12 | impl Commitment { 13 | pub fn of(choice: Choice, nonce: &Nonce) -> Self { 14 | let mut hasher = Sha3_256::new(); 15 | 16 | hasher.update(&[choice as u8]); 17 | hasher.update(nonce); 18 | 19 | Commitment(hasher.finalize().into()) 20 | } 21 | 22 | pub const fn from_bytes(bytes: &[u8; 32]) -> Self { 23 | Commitment(*bytes) 24 | } 25 | 26 | pub const fn to_bytes(&self) -> [u8; 32] { 27 | self.0 28 | } 29 | } 30 | 31 | impl AsRef<[u8]> for Commitment { 32 | fn as_ref(&self) -> &[u8] { 33 | &self.0 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/src/components/icons/IconTooling.vue: -------------------------------------------------------------------------------- 1 | 2 | 20 | -------------------------------------------------------------------------------- /app/src/components/icons/IconCommunity.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /app/README.md: -------------------------------------------------------------------------------- 1 | # Rock, paper and scissors UI 2 | 3 | This template should help get you started developing with Vue 3 in Vite. 4 | 5 | ## Recommended IDE Setup 6 | 7 | [VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur). 8 | 9 | ## Type Support for `.vue` Imports in TS 10 | 11 | TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types. 12 | 13 | ## Customize configuration 14 | 15 | See [Vite Configuration Reference](https://vitejs.dev/config/). 16 | 17 | ## Project Setup 18 | 19 | ```sh 20 | npm install 21 | ``` 22 | 23 | ### Compile and Hot-Reload for Development 24 | 25 | ```sh 26 | npm run dev 27 | ``` 28 | 29 | ### Type-Check, Compile and Minify for Production 30 | 31 | ```sh 32 | npm run build 33 | ``` 34 | 35 | ### Lint with [ESLint](https://eslint.org/) 36 | 37 | ```sh 38 | npm run lint 39 | ``` 40 | -------------------------------------------------------------------------------- /app/src/components/icons/IconDocumentation.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /app/src/ws.js: -------------------------------------------------------------------------------- 1 | 2 | // Listen for messages 3 | 4 | export default class GameEventListener { 5 | constructor(nodeUrl, applicationId) { 6 | this.ws = new WebSocket(`${nodeUrl}/ws`); 7 | this.ws.addEventListener("open", () => { 8 | console.log('here') 9 | const request = { 10 | id: this.getRandomRequestId(), 11 | method: "subscribe", 12 | params: { 13 | applicationIds: [applicationId], 14 | }, 15 | }; 16 | this.ws.send(JSON.stringify(request)); 17 | }); 18 | 19 | this.events = {}; 20 | this.ws.addEventListener("message", (event) => { 21 | this.parseMessage(event.data) 22 | }); 23 | } 24 | 25 | on(event, func) { 26 | this.events[event] = func; 27 | } 28 | 29 | parseMessage(msg) { 30 | const event = JSON.parse(msg); 31 | const events = event.result.data?.events; 32 | if (events) { 33 | events.forEach(e => { 34 | if (e.kind in this.events) { 35 | let bytes = new Int8Array(e.data); 36 | let str = new TextDecoder().decode(bytes); 37 | this.events[e.kind](JSON.parse(str)) 38 | } 39 | }) 40 | } 41 | } 42 | 43 | getRandomRequestId() { 44 | return Math.floor(Math.random() * Math.pow(2, 32)); 45 | }; 46 | 47 | } 48 | -------------------------------------------------------------------------------- /logic/leaderboard/relayer/mock-ws-server.js: -------------------------------------------------------------------------------- 1 | const { WebSocketServer } = require('ws'); 2 | const prompt = require('prompt-sync')({ sigint: true }); 3 | 4 | const wss = new WebSocketServer({ port: 8080 }); 5 | 6 | console.log('Waiting for a new connection...'); 7 | 8 | wss.on('connection', function connection(ws) { 9 | let keepAsking = true; 10 | ws.on('error', () => keepAsking = false); 11 | 12 | ws.on('message', function message(data) { 13 | console.log('received: %s', data); 14 | }); 15 | 16 | while (keepAsking) { 17 | console.log('-'.repeat(process.stdout.columns)); 18 | const action = prompt('What to do? add-score/get-score: '); 19 | if (action === 'add-score') { 20 | const account = prompt('Account: '); 21 | const app = prompt('Application: '); 22 | const score = parseInt(prompt('score: ')); 23 | ws.send(JSON.stringify({ 24 | action: 'add-score', 25 | app, 26 | account, 27 | score 28 | })); 29 | } else if (action === 'get-score') { 30 | const account = prompt('Account: '); 31 | const app = prompt('Application: '); 32 | ws.send(JSON.stringify({ 33 | action: 'get-score', 34 | app, 35 | account, 36 | })); 37 | } else { 38 | ws.close(); 39 | } 40 | } 41 | }); 42 | -------------------------------------------------------------------------------- /logic/rock-paper-scissors/src/choice.rs: -------------------------------------------------------------------------------- 1 | use std::cmp::Ordering; 2 | 3 | use crate::commitment::Commitment; 4 | use crate::commitment::Nonce; 5 | use calimero_sdk::borsh::{BorshDeserialize, BorshSerialize}; 6 | use calimero_sdk::serde::{Deserialize, Serialize}; 7 | 8 | #[derive( 9 | Eq, Copy, Clone, Debug, PartialEq, Serialize, Deserialize, BorshSerialize, BorshDeserialize, 10 | )] 11 | #[borsh(crate = "calimero_sdk::borsh")] 12 | #[serde(crate = "calimero_sdk::serde")] 13 | #[repr(u8)] 14 | pub enum Choice { 15 | Rock, 16 | Paper, 17 | Scissors, 18 | } 19 | 20 | use Choice::*; 21 | 22 | impl Choice { 23 | pub fn determine(commitment: &Commitment, nonce: &Nonce) -> Option { 24 | let choices = [Rock, Paper, Scissors]; 25 | 26 | for choice in choices { 27 | if *commitment == Commitment::of(choice, nonce) { 28 | return Some(choice); 29 | } 30 | } 31 | 32 | None 33 | } 34 | } 35 | 36 | impl PartialOrd for Choice { 37 | fn partial_cmp(&self, other: &Self) -> Option { 38 | match (self, other) { 39 | (Rock, Scissors) | (Scissors, Paper) | (Paper, Rock) => Some(Ordering::Greater), 40 | (Scissors, Rock) | (Paper, Scissors) | (Rock, Paper) => Some(Ordering::Less), 41 | _ => Some(Ordering::Equal), 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/components/NearLogin.vue: -------------------------------------------------------------------------------- 1 | 12 | 53 | -------------------------------------------------------------------------------- /logic/leaderboard/relayer/ws.js: -------------------------------------------------------------------------------- 1 | 2 | // Listen for messages 3 | const WebSocket = require('ws'); 4 | 5 | module.exports = class GameEventListener { 6 | constructor(nodeUrl, applicationId) { 7 | this.ws = new WebSocket(`${nodeUrl}/ws`); 8 | this.ws.on('open', () => { 9 | const request = { 10 | id: this.getRandomRequestId(), 11 | method: 'subscribe', 12 | params: { 13 | applicationIds: [applicationId], 14 | }, 15 | }; 16 | this.ws.send(JSON.stringify(request)); 17 | }); 18 | 19 | this.events = {}; 20 | this.ws.on('message', async (event) => { 21 | const utf8Decoder = new TextDecoder('UTF-8'); 22 | const data = utf8Decoder.decode(event); 23 | await this.parseMessage(data); 24 | }); 25 | } 26 | 27 | on(event, func) { 28 | this.events[event] = func; 29 | } 30 | 31 | parseMessage(msg) { 32 | try { 33 | const event = JSON.parse(msg); 34 | for (const e of event.result.data.events) { 35 | if (e.kind in this.events) { 36 | let bytes = new Int8Array(e.data); 37 | let str = new TextDecoder().decode(bytes); 38 | this.events[e.kind](JSON.parse(str)); 39 | } 40 | } 41 | } catch (e) { 42 | console.error(`Failed to parse the json: ${e}`); 43 | } 44 | } 45 | 46 | getRandomRequestId() { 47 | return Math.floor(Math.random() * Math.pow(2, 32)); 48 | } 49 | }; 50 | 51 | -------------------------------------------------------------------------------- /app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rock-paper-scissors", 3 | "version": "0.0.0", 4 | "private": true, 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "run-p type-check \"build-only {@}\" --", 9 | "preview": "vite preview", 10 | "build-only": "vite build", 11 | "type-check": "vue-tsc --build --force", 12 | "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore", 13 | "format": "prettier --write src/" 14 | }, 15 | "dependencies": { 16 | "@calimero-is-near/calimero-p2p-sdk": "^0.0.13", 17 | "@quasar/extras": "^1.16.11", 18 | "quasar": "^2.16.4", 19 | "react-dom": "^18.3.1", 20 | "veaury": "^2.4.0", 21 | "vite-plugin-node-polyfills": "^0.22.0", 22 | "vue": "^3.4.21", 23 | "vue-router": "^4.3.0" 24 | }, 25 | "devDependencies": { 26 | "@quasar/vite-plugin": "^1.7.0", 27 | "@rushstack/eslint-patch": "^1.8.0", 28 | "@tsconfig/node20": "^20.1.4", 29 | "@types/node": "^20.12.5", 30 | "@vitejs/plugin-vue": "^5.0.4", 31 | "@vue/eslint-config-prettier": "^9.0.0", 32 | "sass": "^1.33.0", 33 | "@vue/eslint-config-typescript": "^13.0.0", 34 | "@vue/tsconfig": "^0.5.1", 35 | "eslint": "^8.57.0", 36 | "eslint-plugin-vue": "^9.23.0", 37 | "npm-run-all2": "^6.1.2", 38 | "prettier": "^3.2.5", 39 | "typescript": "~5.4.0", 40 | "vite": "^5.2.8", 41 | "vue-tsc": "^2.0.11" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app/src/crypto.ts: -------------------------------------------------------------------------------- 1 | import { unmarshalPrivateKey } from '@libp2p/crypto/keys' 2 | import type { PrivateKey } from '@libp2p/interface' 3 | import bs58 from 'bs58' 4 | import { getClientKey, type ClientKey } from './auth' 5 | 6 | export enum WalletType { 7 | NEAR = 'NEAR', 8 | ETH = 'ETH' 9 | } 10 | 11 | export interface AxiosHeader { 12 | [key: string]: string 13 | } 14 | 15 | export async function createAuthHeader(payload: string): Promise { 16 | const privateKey: PrivateKey | null = await getPrivateKey() 17 | 18 | if (!privateKey) { 19 | return null 20 | } 21 | 22 | const encoder = new TextEncoder() 23 | const contentBuff = encoder.encode(payload) 24 | 25 | const signing_key = bs58.encode(privateKey.public.bytes) 26 | 27 | const hashBuffer = await crypto.subtle.digest('SHA-256', contentBuff) 28 | const hashArray = new Uint8Array(hashBuffer) 29 | 30 | const signature = await privateKey.sign(hashArray) 31 | const signatureBase58 = bs58.encode(signature) 32 | const contentBase58 = bs58.encode(hashArray) 33 | 34 | const headers: AxiosHeader = { 35 | wallet_type: WalletType.NEAR, 36 | signing_key: signing_key, 37 | signature: signatureBase58, 38 | challenge: contentBase58 39 | } 40 | 41 | return headers 42 | } 43 | 44 | export async function getPrivateKey(): Promise { 45 | try { 46 | const clientKey: ClientKey | null = getClientKey() 47 | console.log(clientKey) 48 | if (!clientKey) { 49 | return null 50 | } 51 | return await unmarshalPrivateKey(bs58.decode(clientKey.privateKey)) 52 | } catch (error) { 53 | console.error('Error extracting private key:', error) 54 | return null 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /.github/workflows/deploy-vue.yml: -------------------------------------------------------------------------------- 1 | name: Deploy 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | deploy: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v4 17 | 18 | - name: Setup Node.js 19 | uses: actions/setup-node@v4 20 | with: 21 | node-version: "18" 22 | 23 | - name: Install dependencies 24 | working-directory: ./app 25 | run: yarn install 26 | 27 | - name: Build 28 | working-directory: ./app 29 | run: yarn build-only 30 | 31 | - name: Deploy 32 | uses: peaceiris/actions-gh-pages@v4 33 | with: 34 | github_token: ${{ secrets.GITHUB_TOKEN }} 35 | publish_dir: ./app/dist 36 | 37 | notify-on-failure: 38 | runs-on: ubuntu-latest 39 | needs: [deploy] 40 | if: failure() 41 | steps: 42 | - name: Notify failure 43 | uses: "ravsamhq/notify-slack-action@2.5.0" 44 | with: 45 | status: failure 46 | notification_title: "Deploy failed on ${{ github.ref_name }} - <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|View Failure>" 47 | message_format: ":fire: *Deploy Rock-paper-scissors site to Pages* in <${{ github.server_url }}/${{ github.repository }}/${{ github.ref_name }}|${{ github.repository }}>" 48 | footer: "Linked Repo <${{ github.server_url }}/${{ github.repository }}|${{ github.repository }}> | <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|View Failure>" 49 | env: 50 | SLACK_WEBHOOK_URL: ${{ secrets.DEPLOY_FAIL_SLACK }} 51 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rock Paper Scissors Game with Calimero SDK and Vue.js 2 | 3 | This repository contains the implementation of the classic game Rock Paper Scissors, built using the Calimero Application SDK and a user interface (UI) implemented in Vue.js. 4 | 5 | ## Project Structure 6 | 7 | The project is structured into two main parts: 8 | 9 | 1. **Logic Folder:** This folder contains the contract for the game, implemented using the Calimero SDK. It also includes a build script to compile the contract into a WebAssembly (WASM) file. 10 | 11 | 2. **Vue.js UI:** The user interface for the game is implemented using Vue.js. It interacts with the deployed contract to facilitate the gameplay. 12 | 13 | ## Getting Started 14 | 15 | Follow these steps to get the project up and running: 16 | 17 | ### Running local nodes 18 | You need to run Calimero nodes on your machine to get started. Follow the [Getting started](https://calimero-network.github.io/getting-started/setup) documentation. 19 | 20 | ### Building the Contract 21 | 22 | 1. Navigate to the `logic/rock-paper-scissors` folder. 23 | 2. Run the build script to compile the contract into a WASM file. 24 | 25 | ### Deploying the Contract 26 | 27 | Follow the deployment instructions provided in the [Calimero documentation](https://calimero-network.github.io/build/publish-app). You need to deploy the game on at least two nodes to play the game. 28 | 29 | ### Building the UI 30 | 31 | 1. Ensure you have `yarn` installed. If not, you can install it using `npm install -g yarn`. 32 | 2. Run `yarn dev` in the `app` folder, to start the development server for the Vue.js application. 33 | 3. Enter the calimero node URL you got from the first step and click `Connect` 34 | 4. Run another instance of the UI and connect to another node. 35 | 5. Now you have two players that can start playing the game! 36 | 37 | -------------------------------------------------------------------------------- /app/src/components/LeaderBoard.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 72 | -------------------------------------------------------------------------------- /app/src/components/icons/IconEcosystem.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /logic/leaderboard/tests/sandbox.rs: -------------------------------------------------------------------------------- 1 | use near_sdk::json_types::U128; 2 | use near_sdk::NearToken; 3 | use serde_json::json; 4 | 5 | #[tokio::test] 6 | async fn test_score_board_contract() -> Result<(), Box> { 7 | let sandbox = near_workspaces::sandbox().await?; 8 | let wasm = tokio::fs::read("res/leaderboard.wasm").await?; 9 | 10 | let contract = sandbox.dev_deploy(&wasm).await?; 11 | 12 | let alice_account = sandbox.dev_create_account().await?; 13 | let bob_account = sandbox.dev_create_account().await?; 14 | 15 | let alice_outcome = alice_account 16 | .call(contract.id(), "add_score") 17 | .args_json(json!({"app_name": "test_app", "account_id": alice_account.id(), "score": "10"})) 18 | .deposit(NearToken::from_near(0)) 19 | .transact() 20 | .await?; 21 | 22 | assert!(alice_outcome.is_success()); 23 | 24 | let score: Option = contract 25 | .view("get_score") 26 | .args_json(json!({"app_name": "test_app", "account_id": alice_account.id()})) 27 | .await? 28 | .json()?; 29 | 30 | assert_eq!(score, Some(U128(10))); 31 | 32 | let score: Option = contract 33 | .view("get_score") 34 | .args_json(json!({"app_name": "test_app", "account_id": bob_account.id()})) 35 | .await? 36 | .json()?; 37 | 38 | assert_eq!(score, None); 39 | 40 | let alice_outcome = alice_account 41 | .call(contract.id(), "add_score") 42 | .args_json( 43 | json!({"app_name": "test_app_2", "account_id": alice_account.id(), "score": "100"}), 44 | ) 45 | .deposit(NearToken::from_near(0)) 46 | .transact() 47 | .await?; 48 | 49 | assert!(alice_outcome.is_success()); 50 | 51 | let score: Option = contract 52 | .view("get_score") 53 | .args_json(json!({"app_name": "test_app", "account_id": alice_account.id()})) 54 | .await? 55 | .json()?; 56 | assert_eq!(score, Some(U128(10))); 57 | 58 | let score: Option = contract 59 | .view("get_score") 60 | .args_json(json!({"app_name": "test_app_2", "account_id": alice_account.id()})) 61 | .await? 62 | .json()?; 63 | assert_eq!(score, Some(U128(100))); 64 | 65 | Ok(()) 66 | } 67 | -------------------------------------------------------------------------------- /logic/rock-paper-scissors/src/key.rs: -------------------------------------------------------------------------------- 1 | use calimero_sdk::serde::{Deserialize, Serialize}; 2 | use ed25519_dalek::{Signature, SigningKey, VerifyingKey}; 3 | 4 | use crate::repr::{Repr, ReprBytes}; 5 | use crate::Commitment; 6 | 7 | #[derive(Debug, Serialize, Deserialize)] 8 | #[serde(crate = "calimero_sdk::serde")] 9 | pub struct KeyComponents { 10 | pub pk: Repr, 11 | pub sk: Repr, 12 | } 13 | 14 | impl ReprBytes for VerifyingKey { 15 | type Bytes = [u8; 32]; 16 | 17 | fn to_bytes(&self) -> Self::Bytes { 18 | self.to_bytes() 19 | } 20 | 21 | fn from_bytes(f: F) -> Option> 22 | where 23 | F: FnOnce(&mut Self::Bytes) -> Option, 24 | { 25 | let mut bytes = [0; 32]; 26 | if let Some(err) = f(&mut bytes) { 27 | return Some(Err(err)); 28 | } 29 | Some(Ok(VerifyingKey::from_bytes(&bytes).ok()?)) 30 | } 31 | } 32 | 33 | impl ReprBytes for SigningKey { 34 | type Bytes = [u8; 32]; 35 | 36 | fn to_bytes(&self) -> Self::Bytes { 37 | self.to_bytes() 38 | } 39 | 40 | fn from_bytes(f: F) -> Option> 41 | where 42 | F: FnOnce(&mut Self::Bytes) -> Option, 43 | { 44 | let mut bytes = [0; 32]; 45 | 46 | Some(f(&mut bytes).map_or_else(|| Ok(SigningKey::from_bytes(&bytes)), Err)) 47 | } 48 | } 49 | 50 | impl ReprBytes for Signature { 51 | type Bytes = [u8; 64]; 52 | 53 | fn to_bytes(&self) -> Self::Bytes { 54 | self.to_bytes() 55 | } 56 | 57 | fn from_bytes(f: F) -> Option> 58 | where 59 | F: FnOnce(&mut Self::Bytes) -> Option, 60 | { 61 | let mut bytes = [0; 64]; 62 | 63 | Some(f(&mut bytes).map_or_else(|| Ok(Signature::from_bytes(&bytes)), Err)) 64 | } 65 | } 66 | 67 | impl ReprBytes for Commitment { 68 | type Bytes = [u8; 32]; 69 | 70 | fn to_bytes(&self) -> Self::Bytes { 71 | self.to_bytes() 72 | } 73 | 74 | fn from_bytes(f: F) -> Option> 75 | where 76 | F: FnOnce(&mut Self::Bytes) -> Option, 77 | { 78 | let mut bytes = [0; 32]; 79 | 80 | Some(f(&mut bytes).map_or_else(|| Ok(Commitment::from_bytes(&bytes)), Err)) 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /app/src/assets/base.css: -------------------------------------------------------------------------------- 1 | /* color palette from */ 2 | :root { 3 | --vt-c-white: #ffffff; 4 | --vt-c-white-soft: #f8f8f8; 5 | --vt-c-white-mute: #f2f2f2; 6 | 7 | --vt-c-black: #181818; 8 | --vt-c-black-soft: #222222; 9 | --vt-c-black-mute: #282828; 10 | 11 | --vt-c-indigo: #2c3e50; 12 | 13 | --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); 14 | --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); 15 | --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); 16 | --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); 17 | 18 | --vt-c-text-light-1: var(--vt-c-indigo); 19 | --vt-c-text-light-2: rgba(60, 60, 60, 0.66); 20 | --vt-c-text-dark-1: var(--vt-c-white); 21 | --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); 22 | } 23 | 24 | /* semantic color variables for this project */ 25 | :root { 26 | --color-background: var(--vt-c-white); 27 | --color-background-soft: var(--vt-c-white-soft); 28 | --color-background-mute: var(--vt-c-white-mute); 29 | 30 | --color-border: var(--vt-c-divider-light-2); 31 | --color-border-hover: var(--vt-c-divider-light-1); 32 | 33 | --color-heading: var(--vt-c-text-light-1); 34 | --color-text: var(--vt-c-text-light-1); 35 | 36 | --section-gap: 160px; 37 | } 38 | 39 | @media (prefers-color-scheme: dark) { 40 | :root { 41 | --color-background: var(--vt-c-black); 42 | --color-background-soft: var(--vt-c-black-soft); 43 | --color-background-mute: var(--vt-c-black-mute); 44 | 45 | --color-border: var(--vt-c-divider-dark-2); 46 | --color-border-hover: var(--vt-c-divider-dark-1); 47 | 48 | --color-heading: var(--vt-c-text-dark-1); 49 | --color-text: var(--vt-c-text-dark-2); 50 | } 51 | } 52 | 53 | *, 54 | *::before, 55 | *::after { 56 | box-sizing: border-box; 57 | margin: 0; 58 | font-weight: normal; 59 | } 60 | 61 | body { 62 | min-height: 100vh; 63 | color: var(--color-text); 64 | background: var(--color-background); 65 | transition: 66 | color 0.5s, 67 | background-color 0.5s; 68 | line-height: 1.6; 69 | font-family: 70 | Inter, 71 | -apple-system, 72 | BlinkMacSystemFont, 73 | 'Segoe UI', 74 | Roboto, 75 | Oxygen, 76 | Ubuntu, 77 | Cantarell, 78 | 'Fira Sans', 79 | 'Droid Sans', 80 | 'Helvetica Neue', 81 | sans-serif; 82 | font-size: 15px; 83 | text-rendering: optimizeLegibility; 84 | -webkit-font-smoothing: antialiased; 85 | -moz-osx-font-smoothing: grayscale; 86 | } 87 | -------------------------------------------------------------------------------- /logic/leaderboard/src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::collections::BTreeMap; 2 | 3 | use near_sdk::json_types::U128; 4 | use near_sdk::near; 5 | use near_sdk::store::{LookupMap, UnorderedMap}; 6 | 7 | type UserName = String; 8 | 9 | #[near(contract_state)] 10 | pub struct LeaderBoard { 11 | scores: LookupMap>, // Key is app name, value is the leaderboard itself 12 | } 13 | 14 | impl Default for LeaderBoard { 15 | fn default() -> Self { 16 | Self { 17 | scores: LookupMap::new(b"m"), 18 | } 19 | } 20 | } 21 | 22 | #[near] 23 | impl LeaderBoard { 24 | pub fn add_score(&mut self, app_name: String, account_id: UserName, score: U128) { 25 | let app_leaderboard = self 26 | .scores 27 | .entry(app_name.clone()) 28 | .or_insert_with(|| UnorderedMap::new(app_name.as_bytes())); 29 | 30 | let new_score = app_leaderboard.entry(account_id.clone()).or_default().0 + score.0; 31 | app_leaderboard.insert(account_id, U128(new_score)); 32 | } 33 | 34 | pub fn get_score(&self, app_name: String, account_id: UserName) -> Option { 35 | self.scores 36 | .get(&app_name)? 37 | .get(&account_id) 38 | .map(|score| score.clone()) 39 | } 40 | 41 | pub fn get_scores(&self, app_name: String) -> Option> { 42 | let mut map = BTreeMap::new(); 43 | for (k, v) in self.scores.get(&app_name)? { 44 | map.insert(k.to_string(), v.0); 45 | } 46 | Some(map) 47 | } 48 | } 49 | 50 | #[cfg(test)] 51 | mod tests { 52 | use super::*; 53 | 54 | #[test] 55 | fn add_score() { 56 | let mut leader_board = LeaderBoard::default(); 57 | let account = "alice.testnet".to_string(); 58 | leader_board.add_score("test_app".to_string(), account.clone(), U128(10)); 59 | 60 | let score = leader_board.get_score("test_app".to_string(), account); 61 | assert_eq!(score, Some(U128(10))); 62 | } 63 | 64 | #[test] 65 | fn get_score_of_absent_account() { 66 | let mut leader_board = LeaderBoard::default(); 67 | let account = "alice.testnet".to_string(); 68 | leader_board.add_score("test_app".to_string(), account.clone(), U128(10)); 69 | 70 | let bob_account = "bob.testnet".to_string(); 71 | 72 | let score = leader_board.get_score("test_app".to_string(), bob_account); 73 | assert_eq!(score, None); 74 | } 75 | 76 | #[test] 77 | fn get_score_of_absent_app() { 78 | let mut leader_board = LeaderBoard::default(); 79 | let account = "alice.testnet".to_string(); 80 | leader_board.add_score("test_app".to_string(), account.clone(), U128(10)); 81 | 82 | let score = leader_board.get_score("test_app_2".to_string(), account); 83 | assert_eq!(score, None); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /logic/rock-paper-scissors/src/repr.rs: -------------------------------------------------------------------------------- 1 | use std::marker::PhantomData; 2 | use std::ops::Deref; 3 | use std::{fmt, io}; 4 | 5 | use bs58::decode::DecodeTarget; 6 | use calimero_sdk::borsh::{BorshDeserialize, BorshSerialize}; 7 | use calimero_sdk::serde::{de, ser, Deserialize, Serialize}; 8 | 9 | #[derive(Eq, Copy, Clone, PartialEq)] 10 | pub enum Bs58 {} 11 | 12 | #[derive(Eq, Copy, Clone, PartialEq)] 13 | pub enum Raw {} 14 | 15 | mod private { 16 | pub trait Sealed {} 17 | } 18 | 19 | pub trait ReprFormat: private::Sealed {} 20 | 21 | impl private::Sealed for Bs58 {} 22 | impl ReprFormat for Bs58 {} 23 | 24 | impl private::Sealed for Raw {} 25 | impl ReprFormat for Raw {} 26 | 27 | #[derive(Eq, Copy, Clone, PartialEq)] 28 | pub struct Repr { 29 | data: T, 30 | _phantom: PhantomData, 31 | } 32 | 33 | pub trait ReprBytes { 34 | type Bytes: AsRef<[u8]>; 35 | 36 | fn to_bytes(&self) -> Self::Bytes; 37 | fn from_bytes(f: F) -> Option> 38 | where 39 | F: FnOnce(&mut Self::Bytes) -> Option, 40 | Self: Sized; 41 | } 42 | 43 | impl From for Repr { 44 | fn from(data: T) -> Self { 45 | Repr { 46 | data, 47 | _phantom: PhantomData, 48 | } 49 | } 50 | } 51 | 52 | impl From> for Repr { 53 | fn from(repr: Repr) -> Self { 54 | Repr { 55 | data: repr.data, 56 | _phantom: PhantomData, 57 | } 58 | } 59 | } 60 | 61 | impl Deref for Repr { 62 | type Target = T; 63 | 64 | fn deref(&self) -> &Self::Target { 65 | &self.data 66 | } 67 | } 68 | 69 | impl Default for Repr { 70 | fn default() -> Self { 71 | Repr::from(T::default()) 72 | } 73 | } 74 | 75 | impl fmt::Debug for Repr { 76 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 77 | self.data.fmt(f) 78 | } 79 | } 80 | 81 | impl Serialize for Repr { 82 | fn serialize(&self, serializer: S) -> Result 83 | where 84 | S: ser::Serializer, 85 | { 86 | let bytes = self.data.to_bytes(); 87 | let encoded = bs58::encode(bytes).into_string(); 88 | serializer.serialize_str(&encoded) 89 | } 90 | } 91 | 92 | impl<'de, T: ReprBytes> Deserialize<'de> for Repr 93 | where 94 | T::Bytes: DecodeTarget, 95 | { 96 | fn deserialize(deserializer: D) -> Result 97 | where 98 | D: de::Deserializer<'de>, 99 | { 100 | let encoded = ::deserialize(deserializer)?; 101 | 102 | let data = match T::from_bytes(|bytes| bs58::decode(&encoded).onto(bytes).err()) { 103 | Some(data) => data.map_err(de::Error::custom)?, 104 | None => return Err(de::Error::custom("Invalid key")), 105 | }; 106 | 107 | Ok(Repr::from(data)) 108 | } 109 | } 110 | 111 | impl BorshSerialize for Repr 112 | where 113 | T::Bytes: BorshSerialize, 114 | { 115 | fn serialize(&self, writer: &mut W) -> Result<(), io::Error> { 116 | self.data.to_bytes().serialize(writer) 117 | } 118 | } 119 | 120 | impl BorshDeserialize for Repr 121 | where 122 | T::Bytes: BorshDeserialize, 123 | { 124 | fn deserialize_reader(reader: &mut R) -> io::Result { 125 | let bytes = T::Bytes::deserialize_reader(reader)?; 126 | 127 | let data = match T::from_bytes(|data| { 128 | *data = bytes; 129 | 130 | None::<()> 131 | }) { 132 | Some(data) => unsafe { data.unwrap_unchecked() }, 133 | None => return Err(io::ErrorKind::InvalidData.into()), 134 | }; 135 | 136 | Ok(Repr::from(data)) 137 | } 138 | } 139 | 140 | impl BorshSerialize for Repr { 141 | fn serialize(&self, writer: &mut W) -> Result<(), io::Error> { 142 | self.data.serialize(writer) 143 | } 144 | } 145 | 146 | impl BorshDeserialize for Repr { 147 | fn deserialize_reader(reader: &mut R) -> io::Result { 148 | let data = T::deserialize_reader(reader)?; 149 | 150 | Ok(Repr::from(data)) 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /logic/leaderboard/relayer/relayer.js: -------------------------------------------------------------------------------- 1 | const nearAPI = require('near-api-js'); 2 | const fs = require('fs'); 3 | const commandLineArgs = require('command-line-args'); 4 | const GameEventListener = require('./ws'); 5 | 6 | const { Contract } = nearAPI; 7 | 8 | const createKeyStore = async () => { 9 | const { KeyPair, keyStores } = nearAPI; 10 | 11 | const ACCOUNT_ID = 'highfalutin-act.testnet'; 12 | const NETWORK_ID = 'testnet'; 13 | const KEY_PATH = 14 | '/home/saeed/.near-credentials/testnet/highfalutin-act.testnet.json'; 15 | 16 | const credentials = JSON.parse(fs.readFileSync(KEY_PATH)); 17 | const myKeyStore = new keyStores.InMemoryKeyStore(); 18 | myKeyStore.setKey( 19 | NETWORK_ID, 20 | ACCOUNT_ID, 21 | KeyPair.fromString(credentials.private_key) 22 | ); 23 | 24 | return myKeyStore; 25 | }; 26 | 27 | let keyStore; 28 | const connectToNear = async () => { 29 | keyStore = await createKeyStore(); 30 | const connectionConfig = { 31 | networkId: 'testnet', 32 | keyStore, 33 | nodeUrl: 'https://rpc.testnet.near.org', 34 | walletUrl: 'https://testnet.mynearwallet.com/', 35 | helperUrl: 'https://helper.testnet.near.org', 36 | explorerUrl: 'https://testnet.nearblocks.io', 37 | }; 38 | const { connect } = nearAPI; 39 | const nearConnection = await connect(connectionConfig); 40 | return nearConnection; 41 | }; 42 | 43 | const addScore = async (account_id, app_name, score) => { 44 | if (contract === null) { 45 | throw new Error('Contract is not initialized'); 46 | } 47 | 48 | const account = await near.account('highfalutin-act.testnet'); 49 | await contract.add_score({ 50 | signerAccount: account, 51 | args: { 52 | app_name, 53 | account_id, 54 | score, 55 | }, 56 | }); 57 | }; 58 | 59 | const getScore = async (account_id, app_name) => { 60 | if (contract === null) { 61 | throw new Error('Contract is not initialized'); 62 | } 63 | 64 | return await contract.get_score({ 65 | app_name, 66 | account_id, 67 | }); 68 | }; 69 | 70 | const getScores = async (app_name) => { 71 | if (contract === null) { 72 | throw new Error('Contract is not initialized'); 73 | } 74 | 75 | return await contract.get_scores({ 76 | app_name, 77 | }); 78 | }; 79 | 80 | let contract = null; 81 | let near = null; 82 | 83 | async function main() { 84 | const optionDefinitions = [ 85 | { name: 'subscribe', type: Boolean }, 86 | { name: 'add-score', type: Boolean }, 87 | { name: 'get-score', type: Boolean }, 88 | { name: 'get-scores', type: Boolean }, 89 | { name: 'account', type: String }, 90 | { name: 'score', type: Number }, 91 | { name: 'app', type: String }, 92 | { name: 'applicationId', type: String }, 93 | { name: 'nodeUrl', type: String }, 94 | ]; 95 | 96 | const options = commandLineArgs(optionDefinitions); 97 | 98 | const nearConnection = await connectToNear(); 99 | near = nearConnection; 100 | contract = new Contract( 101 | nearConnection.connection, 102 | 'highfalutin-act.testnet', 103 | { 104 | changeMethods: ['add_score'], 105 | viewMethods: ['get_version', 'get_score', 'get_scores'], 106 | } 107 | ); 108 | if (options.subscribe) { 109 | const { applicationId, nodeUrl } = options; 110 | console.log(`Subscribed for the events of ${applicationId}`); 111 | subscribe(applicationId, nodeUrl); 112 | } else if (options['add-score']) { 113 | const { account, app, score } = options; 114 | await addScore(account, app, score); 115 | console.log( 116 | `Score added for account: ${account}, app: ${app}, score: ${score}` 117 | ); 118 | } else if (options['get-score']) { 119 | const { account, app } = options; 120 | const score = await getScore(account, app); 121 | console.log(`${account} score is: ${score}`); 122 | } else if (options['get-scores']) { 123 | const { app } = options; 124 | const scores = await getScores(app); 125 | console.log(`Scores for ${app}: ${JSON.stringify(scores)}`); 126 | } 127 | } 128 | 129 | let eventListener; 130 | let players = {}; 131 | const subscribe = (applicationId, nodeUrl) => { 132 | eventListener = new GameEventListener(nodeUrl, applicationId); 133 | eventListener.on('NewPlayer', (player) => { 134 | players[player.id] = player.name; 135 | }); 136 | 137 | eventListener.on('GameOver', (winner) => { 138 | addScore(players[winner.winner], 'rsp', 1000).then(() => 139 | console.log(`Score added for ${players[winner.winner]}`) 140 | ).catch(e => { 141 | console.error(`Failed to add the score. ${e}`); 142 | }); 143 | }); 144 | }; 145 | 146 | main().catch((error) => { 147 | console.error(error); 148 | process.exitCode = 1; 149 | }); 150 | -------------------------------------------------------------------------------- /app/src/game.ts: -------------------------------------------------------------------------------- 1 | import { 2 | JsonRpcClient, 3 | type RequestConfig, 4 | type RpcQueryResponse, 5 | type RpcResult 6 | } from '@calimero-is-near/calimero-p2p-sdk/lib' 7 | import { createAuthHeader, type AxiosHeader } from './crypto' 8 | 9 | interface VersionRequest { 10 | // ignore 11 | } 12 | 13 | interface CreateKeyPairRequest { 14 | seed: number[] 15 | } 16 | 17 | interface KeyComponents { 18 | pk: string 19 | sk: string 20 | } 21 | 22 | interface PrepareRequest { 23 | signing_key: string 24 | choice: string 25 | nonce: number[] 26 | } 27 | 28 | interface JoinRequest { 29 | player_name: string 30 | public_key: string 31 | } 32 | 33 | interface CommitRequest { 34 | player_idx: number 35 | commitment: string 36 | signature: string 37 | } 38 | 39 | interface ResetRequest { 40 | player_idx: number 41 | commitment: string 42 | signature: string 43 | } 44 | 45 | export class Game { 46 | constructor(nodeUrl: string, applicationId: string) { 47 | this.applicationId = applicationId 48 | this.seed = new Uint8Array(32) 49 | crypto.getRandomValues(this.seed) 50 | this.nonce = new Uint8Array(32) 51 | crypto.getRandomValues(this.nonce) 52 | this.jsonRpcClient = new JsonRpcClient(nodeUrl, '/jsonrpc') 53 | } 54 | 55 | async query( 56 | method: string, 57 | params: Args 58 | ): Promise>> { 59 | const authHeaders: AxiosHeader | null = await createAuthHeader(JSON.stringify(params)) 60 | if (authHeaders === null) { 61 | throw new Error('Failed to getVersion') 62 | } 63 | console.log('*****************************') 64 | console.log(authHeaders) 65 | console.log('*****************************') 66 | const config: RequestConfig = { 67 | headers: authHeaders, 68 | timeout: 10000 69 | } 70 | return this.jsonRpcClient.query( 71 | { 72 | method, 73 | applicationId: this.applicationId, 74 | argsJson: params 75 | }, 76 | config 77 | ) 78 | } 79 | 80 | async mutate( 81 | method: string, 82 | params: Args 83 | ): Promise>> { 84 | const authHeaders: AxiosHeader | null = await createAuthHeader(JSON.stringify(params)) 85 | if (authHeaders === null) { 86 | throw new Error('Failed to getVersion') 87 | } 88 | const config: RequestConfig = { 89 | headers: authHeaders, 90 | timeout: 10000 91 | } 92 | return this.jsonRpcClient.mutate( 93 | { 94 | method, 95 | applicationId: this.applicationId, 96 | argsJson: params 97 | }, 98 | config 99 | ) 100 | } 101 | 102 | async getVersion(): Promise { 103 | const params: VersionRequest = {} 104 | const response = await this.query('version', params) 105 | return response.result?.output 106 | } 107 | 108 | async reset() { 109 | if (!(this.playerIdx && this.commitment && this.signature)) { 110 | throw new Error('Unable to call reset.') 111 | } 112 | 113 | await this.mutate('reset', { 114 | player_idx: this.playerIdx, 115 | commitment: this.commitment, 116 | signature: this.signature 117 | }) 118 | } 119 | 120 | async join(playerName: string): Promise { 121 | const params: CreateKeyPairRequest = { 122 | seed: Array.from(this.seed) 123 | } 124 | const keysResponse = await this.query( 125 | 'create_keypair', 126 | params 127 | ) 128 | 129 | const keys = keysResponse.result?.output 130 | this.keys = keys 131 | 132 | const joinParams: JoinRequest = { 133 | player_name: playerName, 134 | public_key: keys!.pk 135 | } 136 | const joinResponse = await this.mutate('join', joinParams) 137 | 138 | this.playerIdx = joinResponse.result?.output 139 | return this.playerIdx 140 | } 141 | 142 | async submit(choice: string) { 143 | const params: PrepareRequest = { 144 | signing_key: this.keys!.sk, 145 | choice, 146 | nonce: Array.from(this.nonce) 147 | } 148 | const prepareResponse = await this.query('prepare', params) 149 | 150 | this.commitment = prepareResponse.result?.output![0] 151 | this.signature = prepareResponse.result?.output![1] 152 | await this.mutate('commit', { 153 | player_idx: this.playerIdx!, 154 | commitment: this.commitment!, 155 | signature: this.signature! 156 | }) 157 | } 158 | 159 | async reveal() { 160 | await this.mutate('reveal', { 161 | player_idx: this.playerIdx, 162 | nonce: Array.from(this.nonce) 163 | }) 164 | } 165 | 166 | async hardReset() { 167 | await this.mutate('reset_state', {}) 168 | } 169 | 170 | applicationId: string 171 | seed: Uint8Array 172 | nonce: Uint8Array 173 | jsonRpcClient: JsonRpcClient 174 | keys: KeyComponents | undefined 175 | commitment: string | undefined 176 | signature: string | undefined 177 | playerIdx: number | undefined 178 | } 179 | -------------------------------------------------------------------------------- /app/src/components/PlayGame.vue: -------------------------------------------------------------------------------- 1 | 85 | 86 | 201 | -------------------------------------------------------------------------------- /logic/rock-paper-scissors/src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::cmp::Ordering; 2 | 3 | use calimero_sdk::app; 4 | use calimero_sdk::borsh::{BorshDeserialize, BorshSerialize}; 5 | use calimero_sdk::serde::{Deserialize, Serialize}; 6 | use ed25519_dalek::{Signature, Signer, SigningKey, Verifier, VerifyingKey}; 7 | use rand_chacha::rand_core::SeedableRng; 8 | use rand_chacha::ChaCha20Rng; 9 | 10 | mod choice; 11 | mod commitment; 12 | mod errors; 13 | mod key; 14 | mod player_idx; 15 | mod repr; 16 | 17 | use crate::commitment::Commitment; 18 | use crate::commitment::Nonce; 19 | 20 | use choice::Choice; 21 | use errors::{CommitError, JoinError, ResetError, RevealError}; 22 | use key::KeyComponents; 23 | use player_idx::PlayerIdx; 24 | use repr::Repr; 25 | 26 | #[app::state(emits = for<'a> Event<'a>)] 27 | #[derive(Default, Debug, BorshSerialize, BorshDeserialize)] 28 | #[borsh(crate = "calimero_sdk::borsh")] 29 | struct Game { 30 | players: [Option; 2], 31 | } 32 | 33 | #[derive(Default, Debug, BorshSerialize, BorshDeserialize)] 34 | #[borsh(crate = "calimero_sdk::borsh")] 35 | struct Player { 36 | state: Option, 37 | public_key: Repr, 38 | name: String, 39 | } 40 | 41 | #[derive(Debug, Clone, PartialEq, BorshSerialize, BorshDeserialize, Deserialize, Serialize)] 42 | #[borsh(crate = "calimero_sdk::borsh")] 43 | #[serde(crate = "calimero_sdk::serde")] 44 | enum State { 45 | Committed(Repr), 46 | Revealed(Choice), 47 | } 48 | 49 | #[app::event] 50 | pub enum Event<'a> { 51 | PlayerCommited { id: PlayerIdx }, 52 | NewPlayer { id: PlayerIdx, name: &'a str }, 53 | PlayerRevealed { id: PlayerIdx, reveal: &'a Choice }, 54 | GameOver { winner: Option }, 55 | StateDumped, 56 | } 57 | 58 | pub type Seed = [u8; 32]; 59 | 60 | #[app::logic] 61 | impl Game { 62 | #[app::init] 63 | pub fn init() -> Game { 64 | Game::default() 65 | } 66 | 67 | pub fn create_keypair(seed: Seed) -> KeyComponents { 68 | let mut csprng = ChaCha20Rng::from_seed(seed); 69 | 70 | let keypair = SigningKey::generate(&mut csprng); 71 | 72 | KeyComponents { 73 | pk: Repr::from(keypair.verifying_key()), 74 | sk: Repr::from(keypair), 75 | } 76 | } 77 | 78 | pub fn join( 79 | &mut self, 80 | player_name: String, 81 | public_key: Repr, 82 | ) -> Result { 83 | let Some((index, player)) = self 84 | .players 85 | .iter_mut() 86 | .enumerate() 87 | .find(|(_, player)| player.is_none()) 88 | else { 89 | return Err(JoinError::GameFull); 90 | }; 91 | 92 | app::emit!(Event::NewPlayer { 93 | id: PlayerIdx(index), 94 | name: &player_name 95 | }); 96 | 97 | *player = Some(Player { 98 | state: None, 99 | public_key: Repr::from(public_key), 100 | name: player_name, 101 | }); 102 | 103 | Ok(index) 104 | } 105 | 106 | pub fn state(&self) -> [Option<(&str, &State)>; 2] { 107 | let mut states = [None, None]; 108 | 109 | for (i, player) in self.players.iter().enumerate() { 110 | if let Some(Player { 111 | state: Some(state), 112 | name, 113 | .. 114 | }) = player 115 | { 116 | states[i] = Some((name.as_str(), state)); 117 | } 118 | } 119 | 120 | states 121 | } 122 | 123 | pub fn prepare( 124 | signing_key: Repr, 125 | choice: Choice, 126 | nonce: Nonce, 127 | ) -> (Repr, Repr) { 128 | let commitment = Commitment::of(choice, &nonce); 129 | 130 | let signature = signing_key.sign(commitment.as_ref()); 131 | 132 | (Repr::from(commitment), Repr::from(signature)) 133 | } 134 | 135 | fn players(&mut self, my_idx: PlayerIdx) -> (Option<&mut Player>, Option<&mut Player>) { 136 | let [a, b] = self.players.each_mut(); 137 | if my_idx.is_first() { 138 | return (a.as_mut(), b.as_mut()); 139 | } 140 | (b.as_mut(), a.as_mut()) 141 | } 142 | 143 | pub fn commit_result( 144 | &mut self, 145 | player_idx: PlayerIdx, 146 | commitment: Repr, 147 | signature: Repr, 148 | ) -> Result<(), CommitError> { 149 | let (Some(player), Some(_)) = self.players(player_idx) else { 150 | return Err(CommitError::NotReady); 151 | }; 152 | 153 | if player.state.is_some() { 154 | return Err(CommitError::AlreadyCommitted); 155 | } 156 | 157 | player 158 | .public_key 159 | .verify(commitment.as_ref(), &signature) 160 | .map_err(|_| CommitError::InvalidSignature)?; 161 | 162 | app::emit!(Event::PlayerCommited { id: player_idx }); 163 | 164 | player.state = Some(State::Committed(commitment)); 165 | 166 | Ok(()) 167 | } 168 | 169 | pub fn reveal(&mut self, player_idx: PlayerIdx, nonce: Nonce) -> Result<(), RevealError> { 170 | let (Some(player), Some(other_player)) = self.players(player_idx) else { 171 | return Err(RevealError::NotReady); 172 | }; 173 | 174 | let Some(State::Committed(commitment)) = &player.state else { 175 | return Err(RevealError::NotCommitted); 176 | }; 177 | 178 | let choice = Choice::determine(commitment, &nonce).ok_or(RevealError::InvalidNonce)?; 179 | 180 | app::emit!(Event::PlayerRevealed { 181 | id: player_idx, 182 | reveal: &choice 183 | }); 184 | 185 | player.state = Some(State::Revealed(choice)); 186 | 187 | if let Some(State::Revealed(other)) = &other_player.state { 188 | match choice.partial_cmp(other) { 189 | Some(Ordering::Less) => app::emit!(Event::GameOver { 190 | winner: Some(player_idx.other()) 191 | }), 192 | Some(Ordering::Equal) => app::emit!(Event::GameOver { winner: None }), 193 | Some(Ordering::Greater) => app::emit!(Event::GameOver { 194 | winner: Some(player_idx) 195 | }), 196 | None => {} 197 | } 198 | } 199 | 200 | Ok(()) 201 | } 202 | 203 | pub fn reset( 204 | &mut self, 205 | player_idx: PlayerIdx, 206 | commitment: Repr, 207 | signature: Repr, 208 | ) -> Result<(), ResetError> { 209 | let (Some(player), _) = self.players(player_idx) else { 210 | return Err(ResetError::NotReady); 211 | }; 212 | 213 | player 214 | .public_key 215 | .verify(commitment.as_ref(), &signature) 216 | .map_err(|_| ResetError::InvalidSignature)?; 217 | 218 | self.players = Default::default(); 219 | 220 | app::emit!(Event::StateDumped); 221 | 222 | Ok(()) 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /logic/leaderboard/relayer/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@near-js/accounts@1.2.0": 6 | version "1.2.0" 7 | resolved "https://registry.yarnpkg.com/@near-js/accounts/-/accounts-1.2.0.tgz#d0ffe0ddd976c04b0f27122d4bd737202fb82747" 8 | integrity sha512-0D/Tl7i2rqqVydGwu9zWBFOk6P7t4Zs2Gfo7l+8jNjOoioYsH/YCWaOheoH7SVu4wQ3xP9YEyjvZ8JL6xzYyHA== 9 | dependencies: 10 | "@near-js/crypto" "1.2.3" 11 | "@near-js/providers" "0.2.1" 12 | "@near-js/signers" "0.1.3" 13 | "@near-js/transactions" "1.2.1" 14 | "@near-js/types" "0.2.0" 15 | "@near-js/utils" "0.2.1" 16 | borsh "1.0.0" 17 | depd "2.0.0" 18 | is-my-json-valid "^2.20.6" 19 | lru_map "0.4.1" 20 | near-abi "0.1.1" 21 | 22 | "@near-js/crypto@1.2.3": 23 | version "1.2.3" 24 | resolved "https://registry.yarnpkg.com/@near-js/crypto/-/crypto-1.2.3.tgz#ba318d77b9eed79ef92a86f7a2c84562cb2f6b9d" 25 | integrity sha512-BuNE+tdcxwImxktFtuAxLiVejFDtn1X92kejcDcYc6f7e0ku9yMntdw98LMb+5ls+xlRuF1UDoi/hUF1LPVpyQ== 26 | dependencies: 27 | "@near-js/types" "0.2.0" 28 | "@near-js/utils" "0.2.1" 29 | "@noble/curves" "1.2.0" 30 | borsh "1.0.0" 31 | randombytes "2.1.0" 32 | 33 | "@near-js/keystores-browser@0.0.11": 34 | version "0.0.11" 35 | resolved "https://registry.yarnpkg.com/@near-js/keystores-browser/-/keystores-browser-0.0.11.tgz#dc0dab662fb2045f978fe1c725f03f0fd11f8267" 36 | integrity sha512-AQ86ST+keKjM5iektKLXu3q94lN8pG6R/LXVoIgm5/hi63n2QzhAd0XlUj9fcyPrfoGOckwUu6pFtXPbveBypw== 37 | dependencies: 38 | "@near-js/crypto" "1.2.3" 39 | "@near-js/keystores" "0.0.11" 40 | 41 | "@near-js/keystores-node@0.0.11": 42 | version "0.0.11" 43 | resolved "https://registry.yarnpkg.com/@near-js/keystores-node/-/keystores-node-0.0.11.tgz#b711c6fc0451d4115936734690e08de51e440ef4" 44 | integrity sha512-KeBl7oL8AwUwTilYPV3apEcL1P+UMAGJQvmkEFl9lyK7mftyjogehdqjqFREAdQpR+4jX5NXvU8ZJIShebK3ZA== 45 | dependencies: 46 | "@near-js/crypto" "1.2.3" 47 | "@near-js/keystores" "0.0.11" 48 | 49 | "@near-js/keystores@0.0.11": 50 | version "0.0.11" 51 | resolved "https://registry.yarnpkg.com/@near-js/keystores/-/keystores-0.0.11.tgz#570c70c4c5bb6ba64a94b8bff4cc71cc23265aec" 52 | integrity sha512-B/VkSNIT8vxMozDbK9O54YQGa4JT/rFnB0W+0cN3na38sQHdvzK015X2RHK8mfS0isP/iIT9QzIQtYZcI3M83Q== 53 | dependencies: 54 | "@near-js/crypto" "1.2.3" 55 | "@near-js/types" "0.2.0" 56 | 57 | "@near-js/providers@0.2.1": 58 | version "0.2.1" 59 | resolved "https://registry.yarnpkg.com/@near-js/providers/-/providers-0.2.1.tgz#1d195638b07fd542e202a61dd8c571034ec7cd62" 60 | integrity sha512-F5ZVlXynGopg3BjK3ihyA28tnOk/cM7kUhc/bw5aJg+m+oa1yuBkaAp9JbihagbLZpWOZiDJmkrdkpvTvQlHag== 61 | dependencies: 62 | "@near-js/transactions" "1.2.1" 63 | "@near-js/types" "0.2.0" 64 | "@near-js/utils" "0.2.1" 65 | borsh "1.0.0" 66 | http-errors "1.7.2" 67 | optionalDependencies: 68 | node-fetch "2.6.7" 69 | 70 | "@near-js/signers@0.1.3": 71 | version "0.1.3" 72 | resolved "https://registry.yarnpkg.com/@near-js/signers/-/signers-0.1.3.tgz#7ac9c630536457c3cd94c4faf901b7033a76b6bc" 73 | integrity sha512-Eim6ZsQUgsaSzi+oyR9cQesOO2QcZmhK+tawZan1vni8y+JvKnSH6r3krzbtvKWqIlx/kJ+PsIV74YIxPY5Uhw== 74 | dependencies: 75 | "@near-js/crypto" "1.2.3" 76 | "@near-js/keystores" "0.0.11" 77 | "@noble/hashes" "1.3.3" 78 | 79 | "@near-js/transactions@1.2.1": 80 | version "1.2.1" 81 | resolved "https://registry.yarnpkg.com/@near-js/transactions/-/transactions-1.2.1.tgz#f9a304cd2a35f292557c3764473127b231c06892" 82 | integrity sha512-w2EXgTRXJ+Zxqh8lVnQuRnpCEm6Cq7NxqAcfH6x0BPuSXye5kR9d0n2ut8AGkSXWeooKKEUnDhi6UcXadfoerg== 83 | dependencies: 84 | "@near-js/crypto" "1.2.3" 85 | "@near-js/signers" "0.1.3" 86 | "@near-js/types" "0.2.0" 87 | "@near-js/utils" "0.2.1" 88 | "@noble/hashes" "1.3.3" 89 | borsh "1.0.0" 90 | 91 | "@near-js/types@0.2.0": 92 | version "0.2.0" 93 | resolved "https://registry.yarnpkg.com/@near-js/types/-/types-0.2.0.tgz#5370c3e9230103222b2827dbd6370f03c4e996d1" 94 | integrity sha512-pTahjni0+PzStseFtnnI9nqmh+ZrHqBqeERo3B3OCXUC/qEie0ZSBMSMt80SgqnaGAy5/CqkCLO9zOx1gA8Cwg== 95 | 96 | "@near-js/utils@0.2.1": 97 | version "0.2.1" 98 | resolved "https://registry.yarnpkg.com/@near-js/utils/-/utils-0.2.1.tgz#6798cf8c3a6ed8057da002401e24409c49454a82" 99 | integrity sha512-u7yR1fmxIcYoiITR1spTvqciXbMXNvlrmRcneNt9DWeQP7yPdbCQtRB7lMN2KI7ONkUf3U7xiheQDDmk2vFI0w== 100 | dependencies: 101 | "@near-js/types" "0.2.0" 102 | bs58 "4.0.0" 103 | depd "2.0.0" 104 | mustache "4.0.0" 105 | 106 | "@near-js/wallet-account@1.2.1": 107 | version "1.2.1" 108 | resolved "https://registry.yarnpkg.com/@near-js/wallet-account/-/wallet-account-1.2.1.tgz#f94ebd9c0e58e437045e17467c283d692c3ad6e4" 109 | integrity sha512-T1k15LN9YIgz1Ca3u76GFxtyDSSKNeBTqEKOJZiOMPse9HjXeiI/ycrOVzmEG/a+ZJ5tipQwcDDChUsY4nTQ1w== 110 | dependencies: 111 | "@near-js/accounts" "1.2.0" 112 | "@near-js/crypto" "1.2.3" 113 | "@near-js/keystores" "0.0.11" 114 | "@near-js/providers" "0.2.1" 115 | "@near-js/signers" "0.1.3" 116 | "@near-js/transactions" "1.2.1" 117 | "@near-js/types" "0.2.0" 118 | "@near-js/utils" "0.2.1" 119 | borsh "1.0.0" 120 | 121 | "@noble/curves@1.2.0": 122 | version "1.2.0" 123 | resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.2.0.tgz#92d7e12e4e49b23105a2555c6984d41733d65c35" 124 | integrity sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw== 125 | dependencies: 126 | "@noble/hashes" "1.3.2" 127 | 128 | "@noble/hashes@1.3.2": 129 | version "1.3.2" 130 | resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39" 131 | integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ== 132 | 133 | "@noble/hashes@1.3.3": 134 | version "1.3.3" 135 | resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.3.tgz#39908da56a4adc270147bb07968bf3b16cfe1699" 136 | integrity sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA== 137 | 138 | "@types/json-schema@^7.0.11": 139 | version "7.0.15" 140 | resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" 141 | integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== 142 | 143 | ansi-regex@^4.1.0: 144 | version "4.1.1" 145 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed" 146 | integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== 147 | 148 | array-back@^3.0.1, array-back@^3.1.0: 149 | version "3.1.0" 150 | resolved "https://registry.yarnpkg.com/array-back/-/array-back-3.1.0.tgz#b8859d7a508871c9a7b2cf42f99428f65e96bfb0" 151 | integrity sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q== 152 | 153 | base-x@^2.0.1: 154 | version "2.0.6" 155 | resolved "https://registry.yarnpkg.com/base-x/-/base-x-2.0.6.tgz#4582a91ebcec99ee06f4e4032030b0cf1c2941d8" 156 | integrity sha512-UAmjxz9KbK+YIi66xej+pZVo/vxUOh49ubEvZW5egCbxhur05pBb+hwuireQwKO4nDpsNm64/jEei17LEpsr5g== 157 | dependencies: 158 | safe-buffer "^5.0.1" 159 | 160 | borsh@1.0.0: 161 | version "1.0.0" 162 | resolved "https://registry.yarnpkg.com/borsh/-/borsh-1.0.0.tgz#b564c8cc8f7a91e3772b9aef9e07f62b84213c1f" 163 | integrity sha512-fSVWzzemnyfF89EPwlUNsrS5swF5CrtiN4e+h0/lLf4dz2he4L3ndM20PS9wj7ICSkXJe/TQUHdaPTq15b1mNQ== 164 | 165 | bs58@4.0.0: 166 | version "4.0.0" 167 | resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.0.tgz#65f5deaf6d74e6135a99f763ca6209ab424b9172" 168 | integrity sha512-/jcGuUuSebyxwLLfKrbKnCJttxRf9PM51EnHTwmFKBxl4z1SGkoAhrfd6uZKE0dcjQTfm6XzTP8DPr1tzE4KIw== 169 | dependencies: 170 | base-x "^2.0.1" 171 | 172 | command-line-args@^5.2.1: 173 | version "5.2.1" 174 | resolved "https://registry.yarnpkg.com/command-line-args/-/command-line-args-5.2.1.tgz#c44c32e437a57d7c51157696893c5909e9cec42e" 175 | integrity sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg== 176 | dependencies: 177 | array-back "^3.1.0" 178 | find-replace "^3.0.0" 179 | lodash.camelcase "^4.3.0" 180 | typical "^4.0.0" 181 | 182 | depd@2.0.0: 183 | version "2.0.0" 184 | resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" 185 | integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== 186 | 187 | depd@~1.1.2: 188 | version "1.1.2" 189 | resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" 190 | integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== 191 | 192 | find-replace@^3.0.0: 193 | version "3.0.0" 194 | resolved "https://registry.yarnpkg.com/find-replace/-/find-replace-3.0.0.tgz#3e7e23d3b05167a76f770c9fbd5258b0def68c38" 195 | integrity sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ== 196 | dependencies: 197 | array-back "^3.0.1" 198 | 199 | generate-function@^2.0.0: 200 | version "2.3.1" 201 | resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.3.1.tgz#f069617690c10c868e73b8465746764f97c3479f" 202 | integrity sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ== 203 | dependencies: 204 | is-property "^1.0.2" 205 | 206 | generate-object-property@^1.1.0: 207 | version "1.2.0" 208 | resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" 209 | integrity sha512-TuOwZWgJ2VAMEGJvAyPWvpqxSANF0LDpmyHauMjFYzaACvn+QTT/AZomvPCzVBV7yDN3OmwHQ5OvHaeLKre3JQ== 210 | dependencies: 211 | is-property "^1.0.0" 212 | 213 | http-errors@1.7.2: 214 | version "1.7.2" 215 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" 216 | integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== 217 | dependencies: 218 | depd "~1.1.2" 219 | inherits "2.0.3" 220 | setprototypeof "1.1.1" 221 | statuses ">= 1.5.0 < 2" 222 | toidentifier "1.0.0" 223 | 224 | inherits@2.0.3: 225 | version "2.0.3" 226 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 227 | integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== 228 | 229 | is-my-ip-valid@^1.0.0: 230 | version "1.0.1" 231 | resolved "https://registry.yarnpkg.com/is-my-ip-valid/-/is-my-ip-valid-1.0.1.tgz#f7220d1146257c98672e6fba097a9f3f2d348442" 232 | integrity sha512-jxc8cBcOWbNK2i2aTkCZP6i7wkHF1bqKFrwEHuN5Jtg5BSaZHUZQ/JTOJwoV41YvHnOaRyWWh72T/KvfNz9DJg== 233 | 234 | is-my-json-valid@^2.20.6: 235 | version "2.20.6" 236 | resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.20.6.tgz#a9d89e56a36493c77bda1440d69ae0dc46a08387" 237 | integrity sha512-1JQwulVNjx8UqkPE/bqDaxtH4PXCe/2VRh/y3p99heOV87HG4Id5/VfDswd+YiAfHcRTfDlWgISycnHuhZq1aw== 238 | dependencies: 239 | generate-function "^2.0.0" 240 | generate-object-property "^1.1.0" 241 | is-my-ip-valid "^1.0.0" 242 | jsonpointer "^5.0.0" 243 | xtend "^4.0.0" 244 | 245 | is-property@^1.0.0, is-property@^1.0.2: 246 | version "1.0.2" 247 | resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" 248 | integrity sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g== 249 | 250 | jsonpointer@^5.0.0: 251 | version "5.0.1" 252 | resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-5.0.1.tgz#2110e0af0900fd37467b5907ecd13a7884a1b559" 253 | integrity sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ== 254 | 255 | lodash.camelcase@^4.3.0: 256 | version "4.3.0" 257 | resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" 258 | integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== 259 | 260 | lru_map@0.4.1: 261 | version "0.4.1" 262 | resolved "https://registry.yarnpkg.com/lru_map/-/lru_map-0.4.1.tgz#f7b4046283c79fb7370c36f8fca6aee4324b0a98" 263 | integrity sha512-I+lBvqMMFfqaV8CJCISjI3wbjmwVu/VyOoU7+qtu9d7ioW5klMgsTTiUOUp+DJvfTTzKXoPbyC6YfgkNcyPSOg== 264 | 265 | mustache@4.0.0: 266 | version "4.0.0" 267 | resolved "https://registry.yarnpkg.com/mustache/-/mustache-4.0.0.tgz#7f02465dbb5b435859d154831c032acdfbbefb31" 268 | integrity sha512-FJgjyX/IVkbXBXYUwH+OYwQKqWpFPLaLVESd70yHjSDunwzV2hZOoTBvPf4KLoxesUzzyfTH6F784Uqd7Wm5yA== 269 | 270 | near-abi@0.1.1: 271 | version "0.1.1" 272 | resolved "https://registry.yarnpkg.com/near-abi/-/near-abi-0.1.1.tgz#b7ead408ca4ad11de4fe3e595d30a7a8bc5307e0" 273 | integrity sha512-RVDI8O+KVxRpC3KycJ1bpfVj9Zv+xvq9PlW1yIFl46GhrnLw83/72HqHGjGDjQ8DtltkcpSjY9X3YIGZ+1QyzQ== 274 | dependencies: 275 | "@types/json-schema" "^7.0.11" 276 | 277 | near-api-js@^4.0.1: 278 | version "4.0.1" 279 | resolved "https://registry.yarnpkg.com/near-api-js/-/near-api-js-4.0.1.tgz#ac99ef0fc11f24a733ba9c93bd7f094311f891dd" 280 | integrity sha512-lBLgxhXhY7M05UI0ppBOzfArkMCXRvtKiHVgpxrSqN/mp3WCcWV5C+Y/dwx9U6JtaNG8UWxrvB8kHqKyWGeisw== 281 | dependencies: 282 | "@near-js/accounts" "1.2.0" 283 | "@near-js/crypto" "1.2.3" 284 | "@near-js/keystores" "0.0.11" 285 | "@near-js/keystores-browser" "0.0.11" 286 | "@near-js/keystores-node" "0.0.11" 287 | "@near-js/providers" "0.2.1" 288 | "@near-js/signers" "0.1.3" 289 | "@near-js/transactions" "1.2.1" 290 | "@near-js/types" "0.2.0" 291 | "@near-js/utils" "0.2.1" 292 | "@near-js/wallet-account" "1.2.1" 293 | "@noble/curves" "1.2.0" 294 | borsh "1.0.0" 295 | depd "2.0.0" 296 | http-errors "1.7.2" 297 | near-abi "0.1.1" 298 | node-fetch "2.6.7" 299 | 300 | node-fetch@2.6.7: 301 | version "2.6.7" 302 | resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" 303 | integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== 304 | dependencies: 305 | whatwg-url "^5.0.0" 306 | 307 | prompt-sync@^4.2.0: 308 | version "4.2.0" 309 | resolved "https://registry.yarnpkg.com/prompt-sync/-/prompt-sync-4.2.0.tgz#0198f73c5b70e3b03e4b9033a50540a7c9a1d7f4" 310 | integrity sha512-BuEzzc5zptP5LsgV5MZETjDaKSWfchl5U9Luiu8SKp7iZWD5tZalOxvNcZRwv+d2phNFr8xlbxmFNcRKfJOzJw== 311 | dependencies: 312 | strip-ansi "^5.0.0" 313 | 314 | randombytes@2.1.0: 315 | version "2.1.0" 316 | resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" 317 | integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== 318 | dependencies: 319 | safe-buffer "^5.1.0" 320 | 321 | safe-buffer@^5.0.1, safe-buffer@^5.1.0: 322 | version "5.2.1" 323 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" 324 | integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== 325 | 326 | setprototypeof@1.1.1: 327 | version "1.1.1" 328 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" 329 | integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== 330 | 331 | "statuses@>= 1.5.0 < 2": 332 | version "1.5.0" 333 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" 334 | integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== 335 | 336 | strip-ansi@^5.0.0: 337 | version "5.2.0" 338 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" 339 | integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== 340 | dependencies: 341 | ansi-regex "^4.1.0" 342 | 343 | toidentifier@1.0.0: 344 | version "1.0.0" 345 | resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" 346 | integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== 347 | 348 | tr46@~0.0.3: 349 | version "0.0.3" 350 | resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" 351 | integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== 352 | 353 | typical@^4.0.0: 354 | version "4.0.0" 355 | resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4" 356 | integrity sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw== 357 | 358 | webidl-conversions@^3.0.0: 359 | version "3.0.1" 360 | resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" 361 | integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== 362 | 363 | whatwg-url@^5.0.0: 364 | version "5.0.0" 365 | resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" 366 | integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== 367 | dependencies: 368 | tr46 "~0.0.3" 369 | webidl-conversions "^3.0.0" 370 | 371 | ws@^8.17.1: 372 | version "8.17.1" 373 | resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b" 374 | integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ== 375 | 376 | xtend@^4.0.0: 377 | version "4.0.2" 378 | resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" 379 | integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== 380 | -------------------------------------------------------------------------------- /logic/rock-paper-scissors/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "base64ct" 7 | version = "1.6.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" 10 | 11 | [[package]] 12 | name = "block-buffer" 13 | version = "0.10.4" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 16 | dependencies = [ 17 | "generic-array", 18 | ] 19 | 20 | [[package]] 21 | name = "borsh" 22 | version = "1.5.3" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "2506947f73ad44e344215ccd6403ac2ae18cd8e046e581a441bf8d199f257f03" 25 | dependencies = [ 26 | "borsh-derive", 27 | "cfg_aliases", 28 | ] 29 | 30 | [[package]] 31 | name = "borsh-derive" 32 | version = "1.5.3" 33 | source = "registry+https://github.com/rust-lang/crates.io-index" 34 | checksum = "c2593a3b8b938bd68373196c9832f516be11fa487ef4ae745eb282e6a56a7244" 35 | dependencies = [ 36 | "once_cell", 37 | "proc-macro-crate", 38 | "proc-macro2", 39 | "quote", 40 | "syn", 41 | ] 42 | 43 | [[package]] 44 | name = "bs58" 45 | version = "0.5.1" 46 | source = "registry+https://github.com/rust-lang/crates.io-index" 47 | checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" 48 | dependencies = [ 49 | "tinyvec", 50 | ] 51 | 52 | [[package]] 53 | name = "byteorder" 54 | version = "1.5.0" 55 | source = "registry+https://github.com/rust-lang/crates.io-index" 56 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 57 | 58 | [[package]] 59 | name = "calimero-sdk" 60 | version = "0.1.0" 61 | source = "git+https://github.com/calimero-network/core?branch=master#f6ccc8196aea1e501fbcc6294870682ea12df614" 62 | dependencies = [ 63 | "borsh", 64 | "bs58", 65 | "calimero-sdk-macros", 66 | "cfg-if", 67 | "serde", 68 | "serde_json", 69 | ] 70 | 71 | [[package]] 72 | name = "calimero-sdk-macros" 73 | version = "0.1.0" 74 | source = "git+https://github.com/calimero-network/core?branch=master#f6ccc8196aea1e501fbcc6294870682ea12df614" 75 | dependencies = [ 76 | "prettyplease", 77 | "proc-macro2", 78 | "quote", 79 | "syn", 80 | "thiserror", 81 | ] 82 | 83 | [[package]] 84 | name = "calimero-storage" 85 | version = "0.1.0" 86 | source = "git+https://github.com/calimero-network/core?branch=master#f6ccc8196aea1e501fbcc6294870682ea12df614" 87 | dependencies = [ 88 | "borsh", 89 | "calimero-sdk", 90 | "calimero-storage-macros", 91 | "eyre", 92 | "fixedstr", 93 | "hex", 94 | "indexmap", 95 | "rand", 96 | "serde", 97 | "sha2", 98 | "thiserror", 99 | ] 100 | 101 | [[package]] 102 | name = "calimero-storage-macros" 103 | version = "0.1.0" 104 | source = "git+https://github.com/calimero-network/core?branch=master#f6ccc8196aea1e501fbcc6294870682ea12df614" 105 | dependencies = [ 106 | "borsh", 107 | "quote", 108 | "syn", 109 | ] 110 | 111 | [[package]] 112 | name = "cfg-if" 113 | version = "1.0.0" 114 | source = "registry+https://github.com/rust-lang/crates.io-index" 115 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 116 | 117 | [[package]] 118 | name = "cfg_aliases" 119 | version = "0.2.1" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" 122 | 123 | [[package]] 124 | name = "const-oid" 125 | version = "0.9.6" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" 128 | 129 | [[package]] 130 | name = "cpufeatures" 131 | version = "0.2.16" 132 | source = "registry+https://github.com/rust-lang/crates.io-index" 133 | checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" 134 | dependencies = [ 135 | "libc", 136 | ] 137 | 138 | [[package]] 139 | name = "crypto-common" 140 | version = "0.1.6" 141 | source = "registry+https://github.com/rust-lang/crates.io-index" 142 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 143 | dependencies = [ 144 | "generic-array", 145 | "typenum", 146 | ] 147 | 148 | [[package]] 149 | name = "curve25519-dalek" 150 | version = "4.1.3" 151 | source = "registry+https://github.com/rust-lang/crates.io-index" 152 | checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" 153 | dependencies = [ 154 | "cfg-if", 155 | "cpufeatures", 156 | "curve25519-dalek-derive", 157 | "digest", 158 | "fiat-crypto", 159 | "rustc_version", 160 | "subtle", 161 | "zeroize", 162 | ] 163 | 164 | [[package]] 165 | name = "curve25519-dalek-derive" 166 | version = "0.1.1" 167 | source = "registry+https://github.com/rust-lang/crates.io-index" 168 | checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" 169 | dependencies = [ 170 | "proc-macro2", 171 | "quote", 172 | "syn", 173 | ] 174 | 175 | [[package]] 176 | name = "der" 177 | version = "0.7.9" 178 | source = "registry+https://github.com/rust-lang/crates.io-index" 179 | checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" 180 | dependencies = [ 181 | "const-oid", 182 | "zeroize", 183 | ] 184 | 185 | [[package]] 186 | name = "digest" 187 | version = "0.10.7" 188 | source = "registry+https://github.com/rust-lang/crates.io-index" 189 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 190 | dependencies = [ 191 | "block-buffer", 192 | "crypto-common", 193 | ] 194 | 195 | [[package]] 196 | name = "ed25519" 197 | version = "2.2.3" 198 | source = "registry+https://github.com/rust-lang/crates.io-index" 199 | checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" 200 | dependencies = [ 201 | "pkcs8", 202 | "signature", 203 | ] 204 | 205 | [[package]] 206 | name = "ed25519-dalek" 207 | version = "2.1.1" 208 | source = "registry+https://github.com/rust-lang/crates.io-index" 209 | checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" 210 | dependencies = [ 211 | "curve25519-dalek", 212 | "ed25519", 213 | "rand_core", 214 | "serde", 215 | "sha2", 216 | "subtle", 217 | "zeroize", 218 | ] 219 | 220 | [[package]] 221 | name = "equivalent" 222 | version = "1.0.1" 223 | source = "registry+https://github.com/rust-lang/crates.io-index" 224 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 225 | 226 | [[package]] 227 | name = "eyre" 228 | version = "0.6.12" 229 | source = "registry+https://github.com/rust-lang/crates.io-index" 230 | checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" 231 | dependencies = [ 232 | "indenter", 233 | "once_cell", 234 | ] 235 | 236 | [[package]] 237 | name = "fiat-crypto" 238 | version = "0.2.9" 239 | source = "registry+https://github.com/rust-lang/crates.io-index" 240 | checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" 241 | 242 | [[package]] 243 | name = "fixedstr" 244 | version = "0.5.8" 245 | source = "registry+https://github.com/rust-lang/crates.io-index" 246 | checksum = "60aba7afd9b1b9e1950c2b7e8bcac3cc44a273c62a02717dedca2d0a1aee694d" 247 | dependencies = [ 248 | "serde", 249 | ] 250 | 251 | [[package]] 252 | name = "generic-array" 253 | version = "0.14.7" 254 | source = "registry+https://github.com/rust-lang/crates.io-index" 255 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 256 | dependencies = [ 257 | "typenum", 258 | "version_check", 259 | ] 260 | 261 | [[package]] 262 | name = "getrandom" 263 | version = "0.2.15" 264 | source = "registry+https://github.com/rust-lang/crates.io-index" 265 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 266 | dependencies = [ 267 | "cfg-if", 268 | "libc", 269 | "wasi", 270 | ] 271 | 272 | [[package]] 273 | name = "hashbrown" 274 | version = "0.15.2" 275 | source = "registry+https://github.com/rust-lang/crates.io-index" 276 | checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" 277 | 278 | [[package]] 279 | name = "hex" 280 | version = "0.4.3" 281 | source = "registry+https://github.com/rust-lang/crates.io-index" 282 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 283 | 284 | [[package]] 285 | name = "indenter" 286 | version = "0.3.3" 287 | source = "registry+https://github.com/rust-lang/crates.io-index" 288 | checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" 289 | 290 | [[package]] 291 | name = "indexmap" 292 | version = "2.7.0" 293 | source = "registry+https://github.com/rust-lang/crates.io-index" 294 | checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" 295 | dependencies = [ 296 | "equivalent", 297 | "hashbrown", 298 | ] 299 | 300 | [[package]] 301 | name = "itoa" 302 | version = "1.0.14" 303 | source = "registry+https://github.com/rust-lang/crates.io-index" 304 | checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" 305 | 306 | [[package]] 307 | name = "keccak" 308 | version = "0.1.5" 309 | source = "registry+https://github.com/rust-lang/crates.io-index" 310 | checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" 311 | dependencies = [ 312 | "cpufeatures", 313 | ] 314 | 315 | [[package]] 316 | name = "libc" 317 | version = "0.2.169" 318 | source = "registry+https://github.com/rust-lang/crates.io-index" 319 | checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" 320 | 321 | [[package]] 322 | name = "memchr" 323 | version = "2.7.4" 324 | source = "registry+https://github.com/rust-lang/crates.io-index" 325 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 326 | 327 | [[package]] 328 | name = "once_cell" 329 | version = "1.20.2" 330 | source = "registry+https://github.com/rust-lang/crates.io-index" 331 | checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" 332 | 333 | [[package]] 334 | name = "pkcs8" 335 | version = "0.10.2" 336 | source = "registry+https://github.com/rust-lang/crates.io-index" 337 | checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" 338 | dependencies = [ 339 | "der", 340 | "spki", 341 | ] 342 | 343 | [[package]] 344 | name = "ppv-lite86" 345 | version = "0.2.20" 346 | source = "registry+https://github.com/rust-lang/crates.io-index" 347 | checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" 348 | dependencies = [ 349 | "zerocopy", 350 | ] 351 | 352 | [[package]] 353 | name = "prettyplease" 354 | version = "0.2.25" 355 | source = "registry+https://github.com/rust-lang/crates.io-index" 356 | checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" 357 | dependencies = [ 358 | "proc-macro2", 359 | "syn", 360 | ] 361 | 362 | [[package]] 363 | name = "proc-macro-crate" 364 | version = "3.2.0" 365 | source = "registry+https://github.com/rust-lang/crates.io-index" 366 | checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" 367 | dependencies = [ 368 | "toml_edit", 369 | ] 370 | 371 | [[package]] 372 | name = "proc-macro2" 373 | version = "1.0.92" 374 | source = "registry+https://github.com/rust-lang/crates.io-index" 375 | checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" 376 | dependencies = [ 377 | "unicode-ident", 378 | ] 379 | 380 | [[package]] 381 | name = "quote" 382 | version = "1.0.37" 383 | source = "registry+https://github.com/rust-lang/crates.io-index" 384 | checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" 385 | dependencies = [ 386 | "proc-macro2", 387 | ] 388 | 389 | [[package]] 390 | name = "rand" 391 | version = "0.8.5" 392 | source = "registry+https://github.com/rust-lang/crates.io-index" 393 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 394 | dependencies = [ 395 | "libc", 396 | "rand_chacha", 397 | "rand_core", 398 | ] 399 | 400 | [[package]] 401 | name = "rand_chacha" 402 | version = "0.3.1" 403 | source = "registry+https://github.com/rust-lang/crates.io-index" 404 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 405 | dependencies = [ 406 | "ppv-lite86", 407 | "rand_core", 408 | ] 409 | 410 | [[package]] 411 | name = "rand_core" 412 | version = "0.6.4" 413 | source = "registry+https://github.com/rust-lang/crates.io-index" 414 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 415 | dependencies = [ 416 | "getrandom", 417 | ] 418 | 419 | [[package]] 420 | name = "rock-paper-scissors" 421 | version = "0.1.0" 422 | dependencies = [ 423 | "bs58", 424 | "calimero-sdk", 425 | "calimero-storage", 426 | "ed25519-dalek", 427 | "rand_chacha", 428 | "sha3", 429 | ] 430 | 431 | [[package]] 432 | name = "rustc_version" 433 | version = "0.4.1" 434 | source = "registry+https://github.com/rust-lang/crates.io-index" 435 | checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" 436 | dependencies = [ 437 | "semver", 438 | ] 439 | 440 | [[package]] 441 | name = "ryu" 442 | version = "1.0.18" 443 | source = "registry+https://github.com/rust-lang/crates.io-index" 444 | checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" 445 | 446 | [[package]] 447 | name = "semver" 448 | version = "1.0.24" 449 | source = "registry+https://github.com/rust-lang/crates.io-index" 450 | checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" 451 | 452 | [[package]] 453 | name = "serde" 454 | version = "1.0.216" 455 | source = "registry+https://github.com/rust-lang/crates.io-index" 456 | checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" 457 | dependencies = [ 458 | "serde_derive", 459 | ] 460 | 461 | [[package]] 462 | name = "serde_derive" 463 | version = "1.0.216" 464 | source = "registry+https://github.com/rust-lang/crates.io-index" 465 | checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" 466 | dependencies = [ 467 | "proc-macro2", 468 | "quote", 469 | "syn", 470 | ] 471 | 472 | [[package]] 473 | name = "serde_json" 474 | version = "1.0.134" 475 | source = "registry+https://github.com/rust-lang/crates.io-index" 476 | checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d" 477 | dependencies = [ 478 | "itoa", 479 | "memchr", 480 | "ryu", 481 | "serde", 482 | ] 483 | 484 | [[package]] 485 | name = "sha2" 486 | version = "0.10.8" 487 | source = "registry+https://github.com/rust-lang/crates.io-index" 488 | checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" 489 | dependencies = [ 490 | "cfg-if", 491 | "cpufeatures", 492 | "digest", 493 | ] 494 | 495 | [[package]] 496 | name = "sha3" 497 | version = "0.10.8" 498 | source = "registry+https://github.com/rust-lang/crates.io-index" 499 | checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" 500 | dependencies = [ 501 | "digest", 502 | "keccak", 503 | ] 504 | 505 | [[package]] 506 | name = "signature" 507 | version = "2.2.0" 508 | source = "registry+https://github.com/rust-lang/crates.io-index" 509 | checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" 510 | dependencies = [ 511 | "rand_core", 512 | ] 513 | 514 | [[package]] 515 | name = "spki" 516 | version = "0.7.3" 517 | source = "registry+https://github.com/rust-lang/crates.io-index" 518 | checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" 519 | dependencies = [ 520 | "base64ct", 521 | "der", 522 | ] 523 | 524 | [[package]] 525 | name = "subtle" 526 | version = "2.6.1" 527 | source = "registry+https://github.com/rust-lang/crates.io-index" 528 | checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 529 | 530 | [[package]] 531 | name = "syn" 532 | version = "2.0.91" 533 | source = "registry+https://github.com/rust-lang/crates.io-index" 534 | checksum = "d53cbcb5a243bd33b7858b1d7f4aca2153490815872d86d955d6ea29f743c035" 535 | dependencies = [ 536 | "proc-macro2", 537 | "quote", 538 | "unicode-ident", 539 | ] 540 | 541 | [[package]] 542 | name = "thiserror" 543 | version = "1.0.69" 544 | source = "registry+https://github.com/rust-lang/crates.io-index" 545 | checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" 546 | dependencies = [ 547 | "thiserror-impl", 548 | ] 549 | 550 | [[package]] 551 | name = "thiserror-impl" 552 | version = "1.0.69" 553 | source = "registry+https://github.com/rust-lang/crates.io-index" 554 | checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" 555 | dependencies = [ 556 | "proc-macro2", 557 | "quote", 558 | "syn", 559 | ] 560 | 561 | [[package]] 562 | name = "tinyvec" 563 | version = "1.8.1" 564 | source = "registry+https://github.com/rust-lang/crates.io-index" 565 | checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8" 566 | dependencies = [ 567 | "tinyvec_macros", 568 | ] 569 | 570 | [[package]] 571 | name = "tinyvec_macros" 572 | version = "0.1.1" 573 | source = "registry+https://github.com/rust-lang/crates.io-index" 574 | checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" 575 | 576 | [[package]] 577 | name = "toml_datetime" 578 | version = "0.6.8" 579 | source = "registry+https://github.com/rust-lang/crates.io-index" 580 | checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" 581 | 582 | [[package]] 583 | name = "toml_edit" 584 | version = "0.22.22" 585 | source = "registry+https://github.com/rust-lang/crates.io-index" 586 | checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" 587 | dependencies = [ 588 | "indexmap", 589 | "toml_datetime", 590 | "winnow", 591 | ] 592 | 593 | [[package]] 594 | name = "typenum" 595 | version = "1.17.0" 596 | source = "registry+https://github.com/rust-lang/crates.io-index" 597 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 598 | 599 | [[package]] 600 | name = "unicode-ident" 601 | version = "1.0.14" 602 | source = "registry+https://github.com/rust-lang/crates.io-index" 603 | checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" 604 | 605 | [[package]] 606 | name = "version_check" 607 | version = "0.9.5" 608 | source = "registry+https://github.com/rust-lang/crates.io-index" 609 | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 610 | 611 | [[package]] 612 | name = "wasi" 613 | version = "0.11.0+wasi-snapshot-preview1" 614 | source = "registry+https://github.com/rust-lang/crates.io-index" 615 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 616 | 617 | [[package]] 618 | name = "winnow" 619 | version = "0.6.20" 620 | source = "registry+https://github.com/rust-lang/crates.io-index" 621 | checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" 622 | dependencies = [ 623 | "memchr", 624 | ] 625 | 626 | [[package]] 627 | name = "zerocopy" 628 | version = "0.7.35" 629 | source = "registry+https://github.com/rust-lang/crates.io-index" 630 | checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" 631 | dependencies = [ 632 | "byteorder", 633 | "zerocopy-derive", 634 | ] 635 | 636 | [[package]] 637 | name = "zerocopy-derive" 638 | version = "0.7.35" 639 | source = "registry+https://github.com/rust-lang/crates.io-index" 640 | checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" 641 | dependencies = [ 642 | "proc-macro2", 643 | "quote", 644 | "syn", 645 | ] 646 | 647 | [[package]] 648 | name = "zeroize" 649 | version = "1.8.1" 650 | source = "registry+https://github.com/rust-lang/crates.io-index" 651 | checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" 652 | --------------------------------------------------------------------------------