├── .env.example ├── .eslintrc ├── .gitignore ├── .vscode ├── extensions.json └── settings.json ├── LICENSE ├── README.md ├── package.json ├── packages ├── contracts │ ├── .gitignore │ ├── .prettierrc │ ├── .solhint.json │ ├── abi │ │ ├── BlockHashStore.json │ │ ├── Bytes.json │ │ ├── Callbacks.json │ │ ├── CommonBase.json │ │ ├── DecodeSlice.json │ │ ├── EncodeArray.json │ │ ├── Hooks.json │ │ ├── IAccessManagementSystem.json │ │ ├── IBaseWorld.json │ │ ├── ICoreSystem.json │ │ ├── IModule.json │ │ ├── IModuleInstallationSystem.json │ │ ├── IMulticall3.json │ │ ├── IStore.json │ │ ├── IStoreData.json │ │ ├── IStoreEphemeral.json │ │ ├── IStoreErrors.json │ │ ├── IStoreHook.json │ │ ├── IStoreRead.json │ │ ├── IStoreRegistration.json │ │ ├── IStoreWrite.json │ │ ├── ISystemHook.json │ │ ├── IVRFCoordinator.json │ │ ├── IVRFCoordinatorSystem.json │ │ ├── IWorld.json │ │ ├── IWorldCall.json │ │ ├── IWorldData.json │ │ ├── IWorldEphemeral.json │ │ ├── IWorldErrors.json │ │ ├── IWorldKernel.json │ │ ├── IWorldModuleInstallation.json │ │ ├── IWorldRegistrationSystem.json │ │ ├── Memory.json │ │ ├── Mixed.json │ │ ├── MockVRFCoordinator.json │ │ ├── PackedCounterLib.json │ │ ├── PostDeploy.json │ │ ├── RLPReader.json │ │ ├── ResourceSelector.json │ │ ├── SchemaLib.json │ │ ├── Script.json │ │ ├── ScriptBase.json │ │ ├── SliceInstance.json │ │ ├── SliceLib.json │ │ ├── StdChains.json │ │ ├── StdCheats.json │ │ ├── StdCheatsSafe.json │ │ ├── StdUtils.json │ │ ├── Storage.json │ │ ├── StoreCore.json │ │ ├── StoreCoreExtended.json │ │ ├── StoreCoreInternal.json │ │ ├── StoreMetadata.json │ │ ├── StoreSwitch.json │ │ ├── System.json │ │ ├── TableId.json │ │ ├── TestBase.json │ │ ├── TightCoder.json │ │ ├── Utils.json │ │ ├── VRF.json │ │ ├── VRFCoordinator.json │ │ ├── VRFCoordinatorAddress.json │ │ ├── VRFCoordinatorModule.json │ │ ├── VRFCoordinatorSystem.json │ │ ├── Vector2.json │ │ ├── Vm.json │ │ ├── VmSafe.json │ │ ├── WorldContext.json │ │ ├── console.json │ │ ├── console2.json │ │ ├── stdJson.json │ │ ├── stdMath.json │ │ ├── stdStorage.json │ │ └── stdStorageSafe.json │ ├── build_with_abi.sh │ ├── foundry.toml │ ├── mud.config.ts │ ├── package.json │ ├── remappings.txt │ ├── src │ │ ├── BlockHashStore.sol │ │ ├── Tables.sol │ │ ├── VRF.sol │ │ ├── VRFCoordinator.sol │ │ ├── VRFCoordinatorModule.sol │ │ ├── VRFCoordinatorSystem.sol │ │ ├── constants.sol │ │ ├── interfaces │ │ │ └── IVRFCoordinator.sol │ │ ├── libraries │ │ │ └── RLPReader.sol │ │ ├── mocks │ │ │ └── MockVRFCoordinator.sol │ │ ├── tables │ │ │ └── VRFCoordinatorAddress.sol │ │ └── world │ │ │ ├── IVRFCoordinatorSystem.sol │ │ │ └── IWorld.sol │ ├── tsconfig.json │ ├── vrf.json │ └── worlds.json ├── example-client │ ├── .env │ ├── .eslintrc │ ├── .gitignore │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.css │ │ ├── App.tsx │ │ ├── MUDContext.tsx │ │ ├── index.tsx │ │ └── mud │ │ │ ├── contractComponents.ts │ │ │ ├── createClientComponents.ts │ │ │ ├── createSystemCalls.ts │ │ │ ├── getNetworkConfig.ts │ │ │ ├── setup.ts │ │ │ ├── setupNetwork.ts │ │ │ ├── supportedChains.ts │ │ │ └── world.ts │ ├── tsconfig.json │ └── vite.config.ts ├── example-contracts │ ├── .gitignore │ ├── .prettierrc │ ├── .solhint.json │ ├── build_with_abi.sh │ ├── foundry.toml │ ├── mud.config.ts │ ├── package.json │ ├── remappings.txt │ ├── script │ │ └── PostDeploy.s.sol │ ├── src │ │ ├── Tables.sol │ │ ├── VRFCoordinatorModule.sol │ │ ├── systems │ │ │ └── BlackJackSystem.sol │ │ ├── tables │ │ │ ├── BlackJack.sol │ │ │ └── RequestIdToBlackJackUser.sol │ │ └── world │ │ │ ├── IBlackJackSystem.sol │ │ │ └── IWorld.sol │ ├── tsconfig.json │ ├── vrf.json │ └── worlds.json ├── mock-prover │ ├── .gitignore │ ├── package.json │ ├── src │ │ └── index.ts │ └── tsconfig.json └── prover │ ├── .gitignore │ ├── abigen.sh │ ├── bindings │ ├── BlockHashStore.go │ └── VRFCoordinator.go │ ├── go.mod │ ├── go.sum │ ├── main │ └── main.go │ ├── package.json │ ├── server │ └── server.go │ └── vrf │ ├── utils.go │ └── vrf.go ├── pnpm-lock.yaml ├── pnpm-workspace.yaml └── run.sh /.env.example: -------------------------------------------------------------------------------- 1 | USE_MOCK=true 2 | RPC_URL=ws://localhost:8545 3 | PRIVATE_KEY=ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 4 | VRF_JSON_PATH=../example-contracts/vrf.json -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "plugins": ["@typescript-eslint"], 5 | "extends": [ 6 | "eslint:recommended", 7 | "plugin:@typescript-eslint/eslint-recommended", 8 | "plugin:@typescript-eslint/recommended" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | **/.DS_Store 3 | .env 4 | contracts/.env 5 | example-contracts/.env 6 | prover/.env 7 | mock-prover/.env -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["JuanBlanco.solidity"] 3 | } 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "solidity.monoRepoSupport": true, 3 | "[typescriptreact]": { 4 | "editor.defaultFormatter": "esbenp.prettier-vscode" 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2023 Your name 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 14 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 15 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 16 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 17 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 18 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE 19 | OR OTHER DEALINGS IN THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MUDVRF 2 | 3 | **A secure, fast, and easy-to-use random number generator (RNG) for on-chain games built using MUD.** 4 | 5 | ![mudvrf](https://github.com/jtguibas/mudvrf/assets/25734765/09db1c47-3053-47e3-868e-2f2240dbb8aa) 6 | 7 | Accessing secure randomness on apps built on top of [MUD](https://mud.dev/) can be challenging as you either have to roll your own solution or use on-chain pseudorandomness. To solve this proble, the MUDVRF module can get you setup with randomness generated from a VRF in your application within minutes. 8 | 9 | *This project was built during the Autonomous Worlds Hackathon hosted by Lattice and EthGlobal in 2023*. 10 | 11 | ## Get Started 12 | 13 | Begin the MUD development server. 14 | ```sh 15 | git clone https://github.com/succinctlabs/mudvrf.git 16 | cd mudvrf 17 | cp .env.example .env 18 | pnpm install 19 | pnpm run dev 20 | ``` 21 | This setup will not use the VRF and instead use randomness available from your operating system (to use the real VRF, set `USE_MOCK=false` in `.env` but you will need to install Go 1.20+). 22 | 23 | **Open `localhost:3000` in your browser and play some Blackjack!** 24 | 25 | ## Installing MUDVRF 26 | 27 | Install the MUDVRF dependencies into the package where your MUD contracts live. 28 | 29 | ```sh 30 | pnpm add @succinctlabs/mudvrf-contracts 31 | ``` 32 | 33 | Deploy the MUDVRF contracts within your post deploy script (i.e., `PostDeploy.s.sol`). View this [script](https://github.com/succinctlabs/mudvrf/blob/main/packages/example-contracts/script/PostDeploy.s.sol) as a reference. 34 | ```solidity 35 | function run(address worldAddress) external { 36 | // Load the private key from the `PRIVATE_KEY` environment variable (in .env) 37 | uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); 38 | bool useMock = vm.envBool("USE_MOCK"); 39 | 40 | // Deploy MUDVRF contracts 41 | vm.startBroadcast(deployerPrivateKey); 42 | address blockHashStore = address(new BlockHashStore()); 43 | address coordinator; 44 | if (useMock) { 45 | coordinator = address(new MockVRFCoordinator(blockHashStore)); 46 | console.log("-----MOCK COORDINATOR ADDRESS-----"); 47 | } else { 48 | console.log("-----COORDINATOR ADDRESS-----"); 49 | coordinator = address(new VRFCoordinator(blockHashStore)); 50 | } 51 | console.logAddress(coordinator); 52 | IVRFCoordinatorSystem(worldAddress).mudvrf_VRFCoordinatorSy_setCoordinator(coordinator); 53 | vm.stopBroadcast(); 54 | 55 | string memory obj1 = "vrfCoordinatorDeployment"; 56 | string memory finalJson = vm.serializeAddress(obj1, "vrfCoordinatorAddress", coordinator); 57 | finalJson = vm.serializeAddress(obj1, "blockHashStoreAddress", blockHashStore); 58 | vm.writeJson(finalJson, "./vrf.json"); 59 | } 60 | ``` 61 | 62 | Import and use the `VRFCoordinator` inside systems within your MUD project to request randomness. View an example [here](https://github.com/succinctlabs/mudvrf/blob/main/packages/example-contracts/src/systems/BlackJackSystem.sol#L53-L55). 63 | ```solidity 64 | function dealCard() internal returns (bytes32) { 65 | IVRFCoordinator coordinator = IVRFCoordinatorSystem(_world()); 66 | bytes32 requestId = coordinator.mudvrf_VRFCoordinatorSy_requestRandomWords( 67 | ORACLE_ID, 68 | NB_WORDS, 69 | REQUEST_CONFIRMATIONS, 70 | CALLBACK_GAS_LIMIT, 71 | selector 72 | ); 73 | return requestId; 74 | } 75 | 76 | function handleDealCards(bytes32 requestId, uint256[] randomWords) { 77 | // Your logic here! 78 | ... 79 | } 80 | ``` 81 | 82 | Run your MUD development server and also run a VRF prover. You must install Go 1.18+ to generate the proofs if `USE_MOCK=false`. 83 | ```sh 84 | pnpm run dev 85 | 86 | # If USE_MOCK=false, run the following commands in a seperate terminal 87 | cd packages/prover 88 | pnpm run dev 89 | 90 | # If USE_MOCK=true, run the following commands in a seperate terminal 91 | cd packages/mock-prover 92 | pnpm run dev 93 | ``` 94 | 95 | You will see an output like this. 96 | ``` 97 | World Address: 0x5FbDB2315678afecb367f032d93F642f64180aa3 98 | VRFCoordinator Address: 0x7a2088a1bFc9d81c55368AE168C2C02570cB814F 99 | BlockHashStore Address: 0x4A679253410272dd5232B3Ff7cF5dbB88f295319 100 | 101 | Starting VRFRequestWatcher... 102 | Oracle: c1ffd3cfee2d9e5cd67643f8f39fd6e51aad88f6f4ce6ab8827279cfffb92266 103 | 64 104 | 105 | Listening for RequestRandomWords events... 106 | ``` 107 | 108 | ## Repo Structure 109 | 110 | ``` 111 | . 112 | ├── ... 113 | ├── packages 114 | │ ├── contracts # Core implementation of MUD module and VRF 115 | │ ├── prover # Go implementation of VRF prover 116 | │ ├── mock-prover # Typescript implementation of mock VRF prover 117 | │ ├── example-contracts # Example usage of module in a MUD project (solidity) 118 | │ └── example-client # Example usage of module in a MUD project (react) 119 | └── ... 120 | ``` 121 | 122 | ## Security 123 | 124 | This code has not yet been audited, and should not be used in any production systems. 125 | 126 | The randomness generated relies on a 1/N honesty assumption between the underlying chain operators (i.e., validators or sequencers) and the party holding the secret key corresponding to the VRF (i.e, the prover). This is the same security model used by Chainlink in production for their VRF. In the future, an MPC protocol over the VRF can be used to seamlessly add more parties to the security model. 127 | 128 | Our verifiable random function (VRF) implementation is based on the ECVFR (Elliptic Curve Verifiable Random Function) specification, which is an industry-standard approach to constructing VRFs based on elliptic curves. The ECVRF spec is an IETF (Internet Engineering Task Force) standard, and has undergone extensive review to ensure its security and reliability. 129 | 130 | That said, the contracts are not fully audited, so please becareful when using this software in production. The only contracts that have been fully audited is the VRF verifier contract, which is a fork of Chainlink's ECVRF implementation. 131 | 132 | ## Support 133 | 134 | If you need help, reach out to [@jtguibas](https://t.me/jtguibas) on Telegram. -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mudvrf", 3 | "private": true, 4 | "scripts": { 5 | "build": "pnpm recursive run build", 6 | "dev": "bash run.sh", 7 | "foundry:up": "curl -L https://foundry.paradigm.xyz | bash && bash $HOME/.foundry/bin/foundryup", 8 | "initialize": "pnpm recursive run initialize", 9 | "mud:up": "pnpm recursive exec mud set-version -v canary && pnpm install", 10 | "prepare": "(forge --version || pnpm foundry:up)", 11 | "test": "pnpm recursive run test" 12 | }, 13 | "devDependencies": { 14 | "@latticexyz/cli": "2.0.0-alpha.1.165+21066424", 15 | "@typescript-eslint/eslint-plugin": "5.46.1", 16 | "@typescript-eslint/parser": "5.46.1", 17 | "concurrently": "^8.0.1", 18 | "eslint": "8.29.0", 19 | "rimraf": "^3.0.2", 20 | "typescript": "^4.9.5" 21 | }, 22 | "engines": { 23 | "node": "18.x", 24 | "pnpm": "8.x" 25 | }, 26 | "dependencies": { 27 | "cross-env": "^7.0.3", 28 | "cross-var": "^1.1.0", 29 | "dotenv-cli": "^7.2.1" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/contracts/.gitignore: -------------------------------------------------------------------------------- 1 | out/ 2 | cache/ 3 | node_modules/ 4 | bindings/ 5 | artifacts/ 6 | types/ 7 | broadcast/ 8 | 9 | # Ignore MUD deploy artifacts 10 | deploys/**/*.json 11 | -------------------------------------------------------------------------------- /packages/contracts/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["prettier-plugin-solidity"], 3 | "printWidth": 120, 4 | "semi": true, 5 | "tabWidth": 2, 6 | "useTabs": false, 7 | "bracketSpacing": true 8 | } 9 | -------------------------------------------------------------------------------- /packages/contracts/.solhint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "solhint:recommended", 3 | "plugins": ["mud"], 4 | "rules": { 5 | "compiler-version": ["error", ">=0.8.0"], 6 | "avoid-low-level-calls": "off", 7 | "no-inline-assembly": "off", 8 | "func-visibility": ["warn", { "ignoreConstructors": true }], 9 | "no-empty-blocks": "off", 10 | "no-complex-fallback": "off", 11 | "mud/no-msg-sender": "error" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/contracts/abi/BlockHashStore.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "uint256", 6 | "name": "", 7 | "type": "uint256" 8 | } 9 | ], 10 | "name": "blockHashes", 11 | "outputs": [ 12 | { 13 | "internalType": "bytes32", 14 | "name": "", 15 | "type": "bytes32" 16 | } 17 | ], 18 | "stateMutability": "view", 19 | "type": "function" 20 | }, 21 | { 22 | "inputs": [ 23 | { 24 | "internalType": "uint256", 25 | "name": "_n", 26 | "type": "uint256" 27 | } 28 | ], 29 | "name": "getBlockHash", 30 | "outputs": [ 31 | { 32 | "internalType": "bytes32", 33 | "name": "", 34 | "type": "bytes32" 35 | } 36 | ], 37 | "stateMutability": "view", 38 | "type": "function" 39 | }, 40 | { 41 | "inputs": [], 42 | "name": "latestBlockNumber", 43 | "outputs": [ 44 | { 45 | "internalType": "uint256", 46 | "name": "", 47 | "type": "uint256" 48 | } 49 | ], 50 | "stateMutability": "view", 51 | "type": "function" 52 | }, 53 | { 54 | "inputs": [ 55 | { 56 | "internalType": "bytes[]", 57 | "name": "_blockHeaders", 58 | "type": "bytes[]" 59 | } 60 | ], 61 | "name": "storeBlockHashesViaMerkleProofs", 62 | "outputs": [], 63 | "stateMutability": "nonpayable", 64 | "type": "function" 65 | }, 66 | { 67 | "inputs": [ 68 | { 69 | "internalType": "uint256[]", 70 | "name": "_blockNumbers", 71 | "type": "uint256[]" 72 | } 73 | ], 74 | "name": "storeBlockHashesViaOpCode", 75 | "outputs": [], 76 | "stateMutability": "nonpayable", 77 | "type": "function" 78 | } 79 | ] -------------------------------------------------------------------------------- /packages/contracts/abi/Bytes.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /packages/contracts/abi/Callbacks.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /packages/contracts/abi/CommonBase.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /packages/contracts/abi/DecodeSlice.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /packages/contracts/abi/EncodeArray.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /packages/contracts/abi/Hooks.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /packages/contracts/abi/IAccessManagementSystem.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "bytes16", 6 | "name": "namespace", 7 | "type": "bytes16" 8 | }, 9 | { 10 | "internalType": "bytes16", 11 | "name": "name", 12 | "type": "bytes16" 13 | }, 14 | { 15 | "internalType": "address", 16 | "name": "grantee", 17 | "type": "address" 18 | } 19 | ], 20 | "name": "grantAccess", 21 | "outputs": [], 22 | "stateMutability": "nonpayable", 23 | "type": "function" 24 | }, 25 | { 26 | "inputs": [ 27 | { 28 | "internalType": "bytes16", 29 | "name": "namespace", 30 | "type": "bytes16" 31 | }, 32 | { 33 | "internalType": "bytes16", 34 | "name": "name", 35 | "type": "bytes16" 36 | }, 37 | { 38 | "internalType": "address", 39 | "name": "grantee", 40 | "type": "address" 41 | } 42 | ], 43 | "name": "revokeAccess", 44 | "outputs": [], 45 | "stateMutability": "nonpayable", 46 | "type": "function" 47 | } 48 | ] -------------------------------------------------------------------------------- /packages/contracts/abi/ICoreSystem.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /packages/contracts/abi/IModule.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "string", 6 | "name": "resourceSelector", 7 | "type": "string" 8 | } 9 | ], 10 | "name": "RequiredModuleNotFound", 11 | "type": "error" 12 | }, 13 | { 14 | "inputs": [], 15 | "name": "getName", 16 | "outputs": [ 17 | { 18 | "internalType": "bytes16", 19 | "name": "name", 20 | "type": "bytes16" 21 | } 22 | ], 23 | "stateMutability": "view", 24 | "type": "function" 25 | }, 26 | { 27 | "inputs": [ 28 | { 29 | "internalType": "bytes", 30 | "name": "args", 31 | "type": "bytes" 32 | } 33 | ], 34 | "name": "install", 35 | "outputs": [], 36 | "stateMutability": "nonpayable", 37 | "type": "function" 38 | } 39 | ] -------------------------------------------------------------------------------- /packages/contracts/abi/IModuleInstallationSystem.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "contract IModule", 6 | "name": "module", 7 | "type": "address" 8 | }, 9 | { 10 | "internalType": "bytes", 11 | "name": "args", 12 | "type": "bytes" 13 | } 14 | ], 15 | "name": "installModule", 16 | "outputs": [], 17 | "stateMutability": "nonpayable", 18 | "type": "function" 19 | } 20 | ] -------------------------------------------------------------------------------- /packages/contracts/abi/IStoreData.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "anonymous": false, 4 | "inputs": [ 5 | { 6 | "indexed": false, 7 | "internalType": "bytes32", 8 | "name": "table", 9 | "type": "bytes32" 10 | }, 11 | { 12 | "indexed": false, 13 | "internalType": "bytes32[]", 14 | "name": "key", 15 | "type": "bytes32[]" 16 | } 17 | ], 18 | "name": "StoreDeleteRecord", 19 | "type": "event" 20 | }, 21 | { 22 | "anonymous": false, 23 | "inputs": [ 24 | { 25 | "indexed": false, 26 | "internalType": "bytes32", 27 | "name": "table", 28 | "type": "bytes32" 29 | }, 30 | { 31 | "indexed": false, 32 | "internalType": "bytes32[]", 33 | "name": "key", 34 | "type": "bytes32[]" 35 | }, 36 | { 37 | "indexed": false, 38 | "internalType": "uint8", 39 | "name": "schemaIndex", 40 | "type": "uint8" 41 | }, 42 | { 43 | "indexed": false, 44 | "internalType": "bytes", 45 | "name": "data", 46 | "type": "bytes" 47 | } 48 | ], 49 | "name": "StoreSetField", 50 | "type": "event" 51 | }, 52 | { 53 | "anonymous": false, 54 | "inputs": [ 55 | { 56 | "indexed": false, 57 | "internalType": "bytes32", 58 | "name": "table", 59 | "type": "bytes32" 60 | }, 61 | { 62 | "indexed": false, 63 | "internalType": "bytes32[]", 64 | "name": "key", 65 | "type": "bytes32[]" 66 | }, 67 | { 68 | "indexed": false, 69 | "internalType": "bytes", 70 | "name": "data", 71 | "type": "bytes" 72 | } 73 | ], 74 | "name": "StoreSetRecord", 75 | "type": "event" 76 | }, 77 | { 78 | "inputs": [ 79 | { 80 | "internalType": "bytes32", 81 | "name": "table", 82 | "type": "bytes32" 83 | }, 84 | { 85 | "internalType": "bytes32[]", 86 | "name": "key", 87 | "type": "bytes32[]" 88 | } 89 | ], 90 | "name": "deleteRecord", 91 | "outputs": [], 92 | "stateMutability": "nonpayable", 93 | "type": "function" 94 | }, 95 | { 96 | "inputs": [ 97 | { 98 | "internalType": "bytes32", 99 | "name": "table", 100 | "type": "bytes32" 101 | }, 102 | { 103 | "internalType": "bytes32[]", 104 | "name": "key", 105 | "type": "bytes32[]" 106 | }, 107 | { 108 | "internalType": "uint8", 109 | "name": "schemaIndex", 110 | "type": "uint8" 111 | } 112 | ], 113 | "name": "getField", 114 | "outputs": [ 115 | { 116 | "internalType": "bytes", 117 | "name": "data", 118 | "type": "bytes" 119 | } 120 | ], 121 | "stateMutability": "view", 122 | "type": "function" 123 | }, 124 | { 125 | "inputs": [ 126 | { 127 | "internalType": "bytes32", 128 | "name": "table", 129 | "type": "bytes32" 130 | }, 131 | { 132 | "internalType": "bytes32[]", 133 | "name": "key", 134 | "type": "bytes32[]" 135 | }, 136 | { 137 | "internalType": "uint8", 138 | "name": "schemaIndex", 139 | "type": "uint8" 140 | }, 141 | { 142 | "internalType": "Schema", 143 | "name": "schema", 144 | "type": "bytes32" 145 | } 146 | ], 147 | "name": "getFieldLength", 148 | "outputs": [ 149 | { 150 | "internalType": "uint256", 151 | "name": "", 152 | "type": "uint256" 153 | } 154 | ], 155 | "stateMutability": "view", 156 | "type": "function" 157 | }, 158 | { 159 | "inputs": [ 160 | { 161 | "internalType": "bytes32", 162 | "name": "table", 163 | "type": "bytes32" 164 | }, 165 | { 166 | "internalType": "bytes32[]", 167 | "name": "key", 168 | "type": "bytes32[]" 169 | }, 170 | { 171 | "internalType": "uint8", 172 | "name": "schemaIndex", 173 | "type": "uint8" 174 | }, 175 | { 176 | "internalType": "Schema", 177 | "name": "schema", 178 | "type": "bytes32" 179 | }, 180 | { 181 | "internalType": "uint256", 182 | "name": "start", 183 | "type": "uint256" 184 | }, 185 | { 186 | "internalType": "uint256", 187 | "name": "end", 188 | "type": "uint256" 189 | } 190 | ], 191 | "name": "getFieldSlice", 192 | "outputs": [ 193 | { 194 | "internalType": "bytes", 195 | "name": "data", 196 | "type": "bytes" 197 | } 198 | ], 199 | "stateMutability": "view", 200 | "type": "function" 201 | }, 202 | { 203 | "inputs": [ 204 | { 205 | "internalType": "bytes32", 206 | "name": "table", 207 | "type": "bytes32" 208 | } 209 | ], 210 | "name": "getKeySchema", 211 | "outputs": [ 212 | { 213 | "internalType": "Schema", 214 | "name": "schema", 215 | "type": "bytes32" 216 | } 217 | ], 218 | "stateMutability": "view", 219 | "type": "function" 220 | }, 221 | { 222 | "inputs": [ 223 | { 224 | "internalType": "bytes32", 225 | "name": "table", 226 | "type": "bytes32" 227 | }, 228 | { 229 | "internalType": "bytes32[]", 230 | "name": "key", 231 | "type": "bytes32[]" 232 | }, 233 | { 234 | "internalType": "Schema", 235 | "name": "schema", 236 | "type": "bytes32" 237 | } 238 | ], 239 | "name": "getRecord", 240 | "outputs": [ 241 | { 242 | "internalType": "bytes", 243 | "name": "data", 244 | "type": "bytes" 245 | } 246 | ], 247 | "stateMutability": "view", 248 | "type": "function" 249 | }, 250 | { 251 | "inputs": [ 252 | { 253 | "internalType": "bytes32", 254 | "name": "table", 255 | "type": "bytes32" 256 | }, 257 | { 258 | "internalType": "bytes32[]", 259 | "name": "key", 260 | "type": "bytes32[]" 261 | } 262 | ], 263 | "name": "getRecord", 264 | "outputs": [ 265 | { 266 | "internalType": "bytes", 267 | "name": "data", 268 | "type": "bytes" 269 | } 270 | ], 271 | "stateMutability": "view", 272 | "type": "function" 273 | }, 274 | { 275 | "inputs": [ 276 | { 277 | "internalType": "bytes32", 278 | "name": "table", 279 | "type": "bytes32" 280 | } 281 | ], 282 | "name": "getSchema", 283 | "outputs": [ 284 | { 285 | "internalType": "Schema", 286 | "name": "schema", 287 | "type": "bytes32" 288 | } 289 | ], 290 | "stateMutability": "view", 291 | "type": "function" 292 | }, 293 | { 294 | "inputs": [], 295 | "name": "isStore", 296 | "outputs": [], 297 | "stateMutability": "view", 298 | "type": "function" 299 | }, 300 | { 301 | "inputs": [ 302 | { 303 | "internalType": "bytes32", 304 | "name": "table", 305 | "type": "bytes32" 306 | }, 307 | { 308 | "internalType": "bytes32[]", 309 | "name": "key", 310 | "type": "bytes32[]" 311 | }, 312 | { 313 | "internalType": "uint8", 314 | "name": "schemaIndex", 315 | "type": "uint8" 316 | }, 317 | { 318 | "internalType": "uint256", 319 | "name": "byteLengthToPop", 320 | "type": "uint256" 321 | } 322 | ], 323 | "name": "popFromField", 324 | "outputs": [], 325 | "stateMutability": "nonpayable", 326 | "type": "function" 327 | }, 328 | { 329 | "inputs": [ 330 | { 331 | "internalType": "bytes32", 332 | "name": "table", 333 | "type": "bytes32" 334 | }, 335 | { 336 | "internalType": "bytes32[]", 337 | "name": "key", 338 | "type": "bytes32[]" 339 | }, 340 | { 341 | "internalType": "uint8", 342 | "name": "schemaIndex", 343 | "type": "uint8" 344 | }, 345 | { 346 | "internalType": "bytes", 347 | "name": "dataToPush", 348 | "type": "bytes" 349 | } 350 | ], 351 | "name": "pushToField", 352 | "outputs": [], 353 | "stateMutability": "nonpayable", 354 | "type": "function" 355 | }, 356 | { 357 | "inputs": [ 358 | { 359 | "internalType": "bytes32", 360 | "name": "table", 361 | "type": "bytes32" 362 | }, 363 | { 364 | "internalType": "bytes32[]", 365 | "name": "key", 366 | "type": "bytes32[]" 367 | }, 368 | { 369 | "internalType": "uint8", 370 | "name": "schemaIndex", 371 | "type": "uint8" 372 | }, 373 | { 374 | "internalType": "bytes", 375 | "name": "data", 376 | "type": "bytes" 377 | } 378 | ], 379 | "name": "setField", 380 | "outputs": [], 381 | "stateMutability": "nonpayable", 382 | "type": "function" 383 | }, 384 | { 385 | "inputs": [ 386 | { 387 | "internalType": "bytes32", 388 | "name": "table", 389 | "type": "bytes32" 390 | }, 391 | { 392 | "internalType": "bytes32[]", 393 | "name": "key", 394 | "type": "bytes32[]" 395 | }, 396 | { 397 | "internalType": "bytes", 398 | "name": "data", 399 | "type": "bytes" 400 | } 401 | ], 402 | "name": "setRecord", 403 | "outputs": [], 404 | "stateMutability": "nonpayable", 405 | "type": "function" 406 | }, 407 | { 408 | "inputs": [ 409 | { 410 | "internalType": "bytes32", 411 | "name": "table", 412 | "type": "bytes32" 413 | }, 414 | { 415 | "internalType": "bytes32[]", 416 | "name": "key", 417 | "type": "bytes32[]" 418 | }, 419 | { 420 | "internalType": "uint8", 421 | "name": "schemaIndex", 422 | "type": "uint8" 423 | }, 424 | { 425 | "internalType": "uint256", 426 | "name": "startByteIndex", 427 | "type": "uint256" 428 | }, 429 | { 430 | "internalType": "bytes", 431 | "name": "dataToSet", 432 | "type": "bytes" 433 | } 434 | ], 435 | "name": "updateInField", 436 | "outputs": [], 437 | "stateMutability": "nonpayable", 438 | "type": "function" 439 | } 440 | ] -------------------------------------------------------------------------------- /packages/contracts/abi/IStoreEphemeral.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "anonymous": false, 4 | "inputs": [ 5 | { 6 | "indexed": false, 7 | "internalType": "bytes32", 8 | "name": "table", 9 | "type": "bytes32" 10 | }, 11 | { 12 | "indexed": false, 13 | "internalType": "bytes32[]", 14 | "name": "key", 15 | "type": "bytes32[]" 16 | }, 17 | { 18 | "indexed": false, 19 | "internalType": "bytes", 20 | "name": "data", 21 | "type": "bytes" 22 | } 23 | ], 24 | "name": "StoreEphemeralRecord", 25 | "type": "event" 26 | }, 27 | { 28 | "inputs": [ 29 | { 30 | "internalType": "bytes32", 31 | "name": "table", 32 | "type": "bytes32" 33 | }, 34 | { 35 | "internalType": "bytes32[]", 36 | "name": "key", 37 | "type": "bytes32[]" 38 | }, 39 | { 40 | "internalType": "bytes", 41 | "name": "data", 42 | "type": "bytes" 43 | } 44 | ], 45 | "name": "emitEphemeralRecord", 46 | "outputs": [], 47 | "stateMutability": "nonpayable", 48 | "type": "function" 49 | } 50 | ] -------------------------------------------------------------------------------- /packages/contracts/abi/IStoreErrors.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "uint256", 6 | "name": "length", 7 | "type": "uint256" 8 | }, 9 | { 10 | "internalType": "uint256", 11 | "name": "received", 12 | "type": "uint256" 13 | } 14 | ], 15 | "name": "StoreCore_DataIndexOverflow", 16 | "type": "error" 17 | }, 18 | { 19 | "inputs": [ 20 | { 21 | "internalType": "uint256", 22 | "name": "expected", 23 | "type": "uint256" 24 | }, 25 | { 26 | "internalType": "uint256", 27 | "name": "received", 28 | "type": "uint256" 29 | } 30 | ], 31 | "name": "StoreCore_InvalidDataLength", 32 | "type": "error" 33 | }, 34 | { 35 | "inputs": [ 36 | { 37 | "internalType": "uint256", 38 | "name": "expected", 39 | "type": "uint256" 40 | }, 41 | { 42 | "internalType": "uint256", 43 | "name": "received", 44 | "type": "uint256" 45 | } 46 | ], 47 | "name": "StoreCore_InvalidFieldNamesLength", 48 | "type": "error" 49 | }, 50 | { 51 | "inputs": [], 52 | "name": "StoreCore_NotDynamicField", 53 | "type": "error" 54 | }, 55 | { 56 | "inputs": [], 57 | "name": "StoreCore_NotImplemented", 58 | "type": "error" 59 | }, 60 | { 61 | "inputs": [ 62 | { 63 | "internalType": "bytes32", 64 | "name": "tableId", 65 | "type": "bytes32" 66 | }, 67 | { 68 | "internalType": "string", 69 | "name": "tableIdString", 70 | "type": "string" 71 | } 72 | ], 73 | "name": "StoreCore_TableAlreadyExists", 74 | "type": "error" 75 | }, 76 | { 77 | "inputs": [ 78 | { 79 | "internalType": "bytes32", 80 | "name": "tableId", 81 | "type": "bytes32" 82 | }, 83 | { 84 | "internalType": "string", 85 | "name": "tableIdString", 86 | "type": "string" 87 | } 88 | ], 89 | "name": "StoreCore_TableNotFound", 90 | "type": "error" 91 | } 92 | ] -------------------------------------------------------------------------------- /packages/contracts/abi/IStoreHook.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "bytes32", 6 | "name": "table", 7 | "type": "bytes32" 8 | }, 9 | { 10 | "internalType": "bytes32[]", 11 | "name": "key", 12 | "type": "bytes32[]" 13 | }, 14 | { 15 | "internalType": "uint8", 16 | "name": "schemaIndex", 17 | "type": "uint8" 18 | }, 19 | { 20 | "internalType": "bytes", 21 | "name": "data", 22 | "type": "bytes" 23 | } 24 | ], 25 | "name": "onAfterSetField", 26 | "outputs": [], 27 | "stateMutability": "nonpayable", 28 | "type": "function" 29 | }, 30 | { 31 | "inputs": [ 32 | { 33 | "internalType": "bytes32", 34 | "name": "table", 35 | "type": "bytes32" 36 | }, 37 | { 38 | "internalType": "bytes32[]", 39 | "name": "key", 40 | "type": "bytes32[]" 41 | }, 42 | { 43 | "internalType": "uint8", 44 | "name": "schemaIndex", 45 | "type": "uint8" 46 | }, 47 | { 48 | "internalType": "bytes", 49 | "name": "data", 50 | "type": "bytes" 51 | } 52 | ], 53 | "name": "onBeforeSetField", 54 | "outputs": [], 55 | "stateMutability": "nonpayable", 56 | "type": "function" 57 | }, 58 | { 59 | "inputs": [ 60 | { 61 | "internalType": "bytes32", 62 | "name": "table", 63 | "type": "bytes32" 64 | }, 65 | { 66 | "internalType": "bytes32[]", 67 | "name": "key", 68 | "type": "bytes32[]" 69 | } 70 | ], 71 | "name": "onDeleteRecord", 72 | "outputs": [], 73 | "stateMutability": "nonpayable", 74 | "type": "function" 75 | }, 76 | { 77 | "inputs": [ 78 | { 79 | "internalType": "bytes32", 80 | "name": "table", 81 | "type": "bytes32" 82 | }, 83 | { 84 | "internalType": "bytes32[]", 85 | "name": "key", 86 | "type": "bytes32[]" 87 | }, 88 | { 89 | "internalType": "bytes", 90 | "name": "data", 91 | "type": "bytes" 92 | } 93 | ], 94 | "name": "onSetRecord", 95 | "outputs": [], 96 | "stateMutability": "nonpayable", 97 | "type": "function" 98 | } 99 | ] -------------------------------------------------------------------------------- /packages/contracts/abi/IStoreRead.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "bytes32", 6 | "name": "table", 7 | "type": "bytes32" 8 | }, 9 | { 10 | "internalType": "bytes32[]", 11 | "name": "key", 12 | "type": "bytes32[]" 13 | }, 14 | { 15 | "internalType": "uint8", 16 | "name": "schemaIndex", 17 | "type": "uint8" 18 | } 19 | ], 20 | "name": "getField", 21 | "outputs": [ 22 | { 23 | "internalType": "bytes", 24 | "name": "data", 25 | "type": "bytes" 26 | } 27 | ], 28 | "stateMutability": "view", 29 | "type": "function" 30 | }, 31 | { 32 | "inputs": [ 33 | { 34 | "internalType": "bytes32", 35 | "name": "table", 36 | "type": "bytes32" 37 | }, 38 | { 39 | "internalType": "bytes32[]", 40 | "name": "key", 41 | "type": "bytes32[]" 42 | }, 43 | { 44 | "internalType": "uint8", 45 | "name": "schemaIndex", 46 | "type": "uint8" 47 | }, 48 | { 49 | "internalType": "Schema", 50 | "name": "schema", 51 | "type": "bytes32" 52 | } 53 | ], 54 | "name": "getFieldLength", 55 | "outputs": [ 56 | { 57 | "internalType": "uint256", 58 | "name": "", 59 | "type": "uint256" 60 | } 61 | ], 62 | "stateMutability": "view", 63 | "type": "function" 64 | }, 65 | { 66 | "inputs": [ 67 | { 68 | "internalType": "bytes32", 69 | "name": "table", 70 | "type": "bytes32" 71 | }, 72 | { 73 | "internalType": "bytes32[]", 74 | "name": "key", 75 | "type": "bytes32[]" 76 | }, 77 | { 78 | "internalType": "uint8", 79 | "name": "schemaIndex", 80 | "type": "uint8" 81 | }, 82 | { 83 | "internalType": "Schema", 84 | "name": "schema", 85 | "type": "bytes32" 86 | }, 87 | { 88 | "internalType": "uint256", 89 | "name": "start", 90 | "type": "uint256" 91 | }, 92 | { 93 | "internalType": "uint256", 94 | "name": "end", 95 | "type": "uint256" 96 | } 97 | ], 98 | "name": "getFieldSlice", 99 | "outputs": [ 100 | { 101 | "internalType": "bytes", 102 | "name": "data", 103 | "type": "bytes" 104 | } 105 | ], 106 | "stateMutability": "view", 107 | "type": "function" 108 | }, 109 | { 110 | "inputs": [ 111 | { 112 | "internalType": "bytes32", 113 | "name": "table", 114 | "type": "bytes32" 115 | } 116 | ], 117 | "name": "getKeySchema", 118 | "outputs": [ 119 | { 120 | "internalType": "Schema", 121 | "name": "schema", 122 | "type": "bytes32" 123 | } 124 | ], 125 | "stateMutability": "view", 126 | "type": "function" 127 | }, 128 | { 129 | "inputs": [ 130 | { 131 | "internalType": "bytes32", 132 | "name": "table", 133 | "type": "bytes32" 134 | }, 135 | { 136 | "internalType": "bytes32[]", 137 | "name": "key", 138 | "type": "bytes32[]" 139 | }, 140 | { 141 | "internalType": "Schema", 142 | "name": "schema", 143 | "type": "bytes32" 144 | } 145 | ], 146 | "name": "getRecord", 147 | "outputs": [ 148 | { 149 | "internalType": "bytes", 150 | "name": "data", 151 | "type": "bytes" 152 | } 153 | ], 154 | "stateMutability": "view", 155 | "type": "function" 156 | }, 157 | { 158 | "inputs": [ 159 | { 160 | "internalType": "bytes32", 161 | "name": "table", 162 | "type": "bytes32" 163 | }, 164 | { 165 | "internalType": "bytes32[]", 166 | "name": "key", 167 | "type": "bytes32[]" 168 | } 169 | ], 170 | "name": "getRecord", 171 | "outputs": [ 172 | { 173 | "internalType": "bytes", 174 | "name": "data", 175 | "type": "bytes" 176 | } 177 | ], 178 | "stateMutability": "view", 179 | "type": "function" 180 | }, 181 | { 182 | "inputs": [ 183 | { 184 | "internalType": "bytes32", 185 | "name": "table", 186 | "type": "bytes32" 187 | } 188 | ], 189 | "name": "getSchema", 190 | "outputs": [ 191 | { 192 | "internalType": "Schema", 193 | "name": "schema", 194 | "type": "bytes32" 195 | } 196 | ], 197 | "stateMutability": "view", 198 | "type": "function" 199 | }, 200 | { 201 | "inputs": [], 202 | "name": "isStore", 203 | "outputs": [], 204 | "stateMutability": "view", 205 | "type": "function" 206 | } 207 | ] -------------------------------------------------------------------------------- /packages/contracts/abi/IStoreRegistration.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "bytes32", 6 | "name": "table", 7 | "type": "bytes32" 8 | }, 9 | { 10 | "internalType": "Schema", 11 | "name": "schema", 12 | "type": "bytes32" 13 | }, 14 | { 15 | "internalType": "Schema", 16 | "name": "keySchema", 17 | "type": "bytes32" 18 | } 19 | ], 20 | "name": "registerSchema", 21 | "outputs": [], 22 | "stateMutability": "nonpayable", 23 | "type": "function" 24 | }, 25 | { 26 | "inputs": [ 27 | { 28 | "internalType": "bytes32", 29 | "name": "table", 30 | "type": "bytes32" 31 | }, 32 | { 33 | "internalType": "contract IStoreHook", 34 | "name": "hook", 35 | "type": "address" 36 | } 37 | ], 38 | "name": "registerStoreHook", 39 | "outputs": [], 40 | "stateMutability": "nonpayable", 41 | "type": "function" 42 | }, 43 | { 44 | "inputs": [ 45 | { 46 | "internalType": "bytes32", 47 | "name": "table", 48 | "type": "bytes32" 49 | }, 50 | { 51 | "internalType": "string", 52 | "name": "tableName", 53 | "type": "string" 54 | }, 55 | { 56 | "internalType": "string[]", 57 | "name": "fieldNames", 58 | "type": "string[]" 59 | } 60 | ], 61 | "name": "setMetadata", 62 | "outputs": [], 63 | "stateMutability": "nonpayable", 64 | "type": "function" 65 | } 66 | ] -------------------------------------------------------------------------------- /packages/contracts/abi/IStoreWrite.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "anonymous": false, 4 | "inputs": [ 5 | { 6 | "indexed": false, 7 | "internalType": "bytes32", 8 | "name": "table", 9 | "type": "bytes32" 10 | }, 11 | { 12 | "indexed": false, 13 | "internalType": "bytes32[]", 14 | "name": "key", 15 | "type": "bytes32[]" 16 | } 17 | ], 18 | "name": "StoreDeleteRecord", 19 | "type": "event" 20 | }, 21 | { 22 | "anonymous": false, 23 | "inputs": [ 24 | { 25 | "indexed": false, 26 | "internalType": "bytes32", 27 | "name": "table", 28 | "type": "bytes32" 29 | }, 30 | { 31 | "indexed": false, 32 | "internalType": "bytes32[]", 33 | "name": "key", 34 | "type": "bytes32[]" 35 | }, 36 | { 37 | "indexed": false, 38 | "internalType": "uint8", 39 | "name": "schemaIndex", 40 | "type": "uint8" 41 | }, 42 | { 43 | "indexed": false, 44 | "internalType": "bytes", 45 | "name": "data", 46 | "type": "bytes" 47 | } 48 | ], 49 | "name": "StoreSetField", 50 | "type": "event" 51 | }, 52 | { 53 | "anonymous": false, 54 | "inputs": [ 55 | { 56 | "indexed": false, 57 | "internalType": "bytes32", 58 | "name": "table", 59 | "type": "bytes32" 60 | }, 61 | { 62 | "indexed": false, 63 | "internalType": "bytes32[]", 64 | "name": "key", 65 | "type": "bytes32[]" 66 | }, 67 | { 68 | "indexed": false, 69 | "internalType": "bytes", 70 | "name": "data", 71 | "type": "bytes" 72 | } 73 | ], 74 | "name": "StoreSetRecord", 75 | "type": "event" 76 | }, 77 | { 78 | "inputs": [ 79 | { 80 | "internalType": "bytes32", 81 | "name": "table", 82 | "type": "bytes32" 83 | }, 84 | { 85 | "internalType": "bytes32[]", 86 | "name": "key", 87 | "type": "bytes32[]" 88 | } 89 | ], 90 | "name": "deleteRecord", 91 | "outputs": [], 92 | "stateMutability": "nonpayable", 93 | "type": "function" 94 | }, 95 | { 96 | "inputs": [ 97 | { 98 | "internalType": "bytes32", 99 | "name": "table", 100 | "type": "bytes32" 101 | }, 102 | { 103 | "internalType": "bytes32[]", 104 | "name": "key", 105 | "type": "bytes32[]" 106 | }, 107 | { 108 | "internalType": "uint8", 109 | "name": "schemaIndex", 110 | "type": "uint8" 111 | }, 112 | { 113 | "internalType": "uint256", 114 | "name": "byteLengthToPop", 115 | "type": "uint256" 116 | } 117 | ], 118 | "name": "popFromField", 119 | "outputs": [], 120 | "stateMutability": "nonpayable", 121 | "type": "function" 122 | }, 123 | { 124 | "inputs": [ 125 | { 126 | "internalType": "bytes32", 127 | "name": "table", 128 | "type": "bytes32" 129 | }, 130 | { 131 | "internalType": "bytes32[]", 132 | "name": "key", 133 | "type": "bytes32[]" 134 | }, 135 | { 136 | "internalType": "uint8", 137 | "name": "schemaIndex", 138 | "type": "uint8" 139 | }, 140 | { 141 | "internalType": "bytes", 142 | "name": "dataToPush", 143 | "type": "bytes" 144 | } 145 | ], 146 | "name": "pushToField", 147 | "outputs": [], 148 | "stateMutability": "nonpayable", 149 | "type": "function" 150 | }, 151 | { 152 | "inputs": [ 153 | { 154 | "internalType": "bytes32", 155 | "name": "table", 156 | "type": "bytes32" 157 | }, 158 | { 159 | "internalType": "bytes32[]", 160 | "name": "key", 161 | "type": "bytes32[]" 162 | }, 163 | { 164 | "internalType": "uint8", 165 | "name": "schemaIndex", 166 | "type": "uint8" 167 | }, 168 | { 169 | "internalType": "bytes", 170 | "name": "data", 171 | "type": "bytes" 172 | } 173 | ], 174 | "name": "setField", 175 | "outputs": [], 176 | "stateMutability": "nonpayable", 177 | "type": "function" 178 | }, 179 | { 180 | "inputs": [ 181 | { 182 | "internalType": "bytes32", 183 | "name": "table", 184 | "type": "bytes32" 185 | }, 186 | { 187 | "internalType": "bytes32[]", 188 | "name": "key", 189 | "type": "bytes32[]" 190 | }, 191 | { 192 | "internalType": "bytes", 193 | "name": "data", 194 | "type": "bytes" 195 | } 196 | ], 197 | "name": "setRecord", 198 | "outputs": [], 199 | "stateMutability": "nonpayable", 200 | "type": "function" 201 | }, 202 | { 203 | "inputs": [ 204 | { 205 | "internalType": "bytes32", 206 | "name": "table", 207 | "type": "bytes32" 208 | }, 209 | { 210 | "internalType": "bytes32[]", 211 | "name": "key", 212 | "type": "bytes32[]" 213 | }, 214 | { 215 | "internalType": "uint8", 216 | "name": "schemaIndex", 217 | "type": "uint8" 218 | }, 219 | { 220 | "internalType": "uint256", 221 | "name": "startByteIndex", 222 | "type": "uint256" 223 | }, 224 | { 225 | "internalType": "bytes", 226 | "name": "dataToSet", 227 | "type": "bytes" 228 | } 229 | ], 230 | "name": "updateInField", 231 | "outputs": [], 232 | "stateMutability": "nonpayable", 233 | "type": "function" 234 | } 235 | ] -------------------------------------------------------------------------------- /packages/contracts/abi/ISystemHook.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "address", 6 | "name": "msgSender", 7 | "type": "address" 8 | }, 9 | { 10 | "internalType": "address", 11 | "name": "systemAddress", 12 | "type": "address" 13 | }, 14 | { 15 | "internalType": "bytes", 16 | "name": "funcSelectorAndArgs", 17 | "type": "bytes" 18 | } 19 | ], 20 | "name": "onAfterCallSystem", 21 | "outputs": [], 22 | "stateMutability": "nonpayable", 23 | "type": "function" 24 | }, 25 | { 26 | "inputs": [ 27 | { 28 | "internalType": "address", 29 | "name": "msgSender", 30 | "type": "address" 31 | }, 32 | { 33 | "internalType": "address", 34 | "name": "systemAddress", 35 | "type": "address" 36 | }, 37 | { 38 | "internalType": "bytes", 39 | "name": "funcSelectorAndArgs", 40 | "type": "bytes" 41 | } 42 | ], 43 | "name": "onBeforeCallSystem", 44 | "outputs": [], 45 | "stateMutability": "nonpayable", 46 | "type": "function" 47 | } 48 | ] -------------------------------------------------------------------------------- /packages/contracts/abi/IVRFCoordinator.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [], 4 | "name": "FailedToFulfillRandomness", 5 | "type": "error" 6 | }, 7 | { 8 | "inputs": [], 9 | "name": "InvalidCallbackGasLimit", 10 | "type": "error" 11 | }, 12 | { 13 | "inputs": [], 14 | "name": "InvalidCommitment", 15 | "type": "error" 16 | }, 17 | { 18 | "inputs": [], 19 | "name": "InvalidNumberOfWords", 20 | "type": "error" 21 | }, 22 | { 23 | "inputs": [], 24 | "name": "InvalidOracleId", 25 | "type": "error" 26 | }, 27 | { 28 | "inputs": [], 29 | "name": "InvalidRequestConfirmations", 30 | "type": "error" 31 | }, 32 | { 33 | "inputs": [], 34 | "name": "InvalidRequestParameters", 35 | "type": "error" 36 | }, 37 | { 38 | "anonymous": false, 39 | "inputs": [ 40 | { 41 | "indexed": false, 42 | "internalType": "bytes32", 43 | "name": "requestId", 44 | "type": "bytes32" 45 | } 46 | ], 47 | "name": "FulfillRandomWords", 48 | "type": "event" 49 | }, 50 | { 51 | "anonymous": false, 52 | "inputs": [ 53 | { 54 | "indexed": false, 55 | "internalType": "bytes32", 56 | "name": "requestId", 57 | "type": "bytes32" 58 | }, 59 | { 60 | "indexed": false, 61 | "internalType": "address", 62 | "name": "sender", 63 | "type": "address" 64 | }, 65 | { 66 | "indexed": false, 67 | "internalType": "uint256", 68 | "name": "nonce", 69 | "type": "uint256" 70 | }, 71 | { 72 | "indexed": false, 73 | "internalType": "bytes32", 74 | "name": "oracleId", 75 | "type": "bytes32" 76 | }, 77 | { 78 | "indexed": false, 79 | "internalType": "uint32", 80 | "name": "nbWords", 81 | "type": "uint32" 82 | }, 83 | { 84 | "indexed": false, 85 | "internalType": "uint16", 86 | "name": "requestConfirmations", 87 | "type": "uint16" 88 | }, 89 | { 90 | "indexed": false, 91 | "internalType": "uint32", 92 | "name": "callbackGasLimit", 93 | "type": "uint32" 94 | }, 95 | { 96 | "indexed": false, 97 | "internalType": "address", 98 | "name": "callbackAddress", 99 | "type": "address" 100 | }, 101 | { 102 | "indexed": false, 103 | "internalType": "bytes4", 104 | "name": "callbackSelector", 105 | "type": "bytes4" 106 | } 107 | ], 108 | "name": "RequestRandomWords", 109 | "type": "event" 110 | }, 111 | { 112 | "inputs": [ 113 | { 114 | "components": [ 115 | { 116 | "internalType": "uint256[2]", 117 | "name": "pk", 118 | "type": "uint256[2]" 119 | }, 120 | { 121 | "internalType": "uint256[2]", 122 | "name": "gamma", 123 | "type": "uint256[2]" 124 | }, 125 | { 126 | "internalType": "uint256", 127 | "name": "c", 128 | "type": "uint256" 129 | }, 130 | { 131 | "internalType": "uint256", 132 | "name": "s", 133 | "type": "uint256" 134 | }, 135 | { 136 | "internalType": "uint256", 137 | "name": "seed", 138 | "type": "uint256" 139 | }, 140 | { 141 | "internalType": "address", 142 | "name": "uWitness", 143 | "type": "address" 144 | }, 145 | { 146 | "internalType": "uint256[2]", 147 | "name": "cGammaWitness", 148 | "type": "uint256[2]" 149 | }, 150 | { 151 | "internalType": "uint256[2]", 152 | "name": "sHashWitness", 153 | "type": "uint256[2]" 154 | }, 155 | { 156 | "internalType": "uint256", 157 | "name": "zInv", 158 | "type": "uint256" 159 | } 160 | ], 161 | "internalType": "struct VRF.Proof", 162 | "name": "_proof", 163 | "type": "tuple" 164 | }, 165 | { 166 | "components": [ 167 | { 168 | "internalType": "address", 169 | "name": "sender", 170 | "type": "address" 171 | }, 172 | { 173 | "internalType": "uint256", 174 | "name": "nonce", 175 | "type": "uint256" 176 | }, 177 | { 178 | "internalType": "bytes32", 179 | "name": "oracleId", 180 | "type": "bytes32" 181 | }, 182 | { 183 | "internalType": "uint32", 184 | "name": "nbWords", 185 | "type": "uint32" 186 | }, 187 | { 188 | "internalType": "uint16", 189 | "name": "requestConfirmations", 190 | "type": "uint16" 191 | }, 192 | { 193 | "internalType": "uint32", 194 | "name": "callbackGasLimit", 195 | "type": "uint32" 196 | }, 197 | { 198 | "internalType": "address", 199 | "name": "callbackAddress", 200 | "type": "address" 201 | }, 202 | { 203 | "internalType": "bytes4", 204 | "name": "callbackSelector", 205 | "type": "bytes4" 206 | }, 207 | { 208 | "internalType": "uint64", 209 | "name": "blockNumber", 210 | "type": "uint64" 211 | } 212 | ], 213 | "internalType": "struct VRF.Request", 214 | "name": "_request", 215 | "type": "tuple" 216 | } 217 | ], 218 | "name": "fulfillRandomWords", 219 | "outputs": [], 220 | "stateMutability": "nonpayable", 221 | "type": "function" 222 | }, 223 | { 224 | "inputs": [ 225 | { 226 | "internalType": "bytes32", 227 | "name": "_oracleId", 228 | "type": "bytes32" 229 | }, 230 | { 231 | "internalType": "uint32", 232 | "name": "_nbWords", 233 | "type": "uint32" 234 | }, 235 | { 236 | "internalType": "uint16", 237 | "name": "_requestConfirmations", 238 | "type": "uint16" 239 | }, 240 | { 241 | "internalType": "uint32", 242 | "name": "_callbackGasLimit", 243 | "type": "uint32" 244 | }, 245 | { 246 | "internalType": "address", 247 | "name": "_callbackAddress", 248 | "type": "address" 249 | }, 250 | { 251 | "internalType": "bytes4", 252 | "name": "_callbackSelector", 253 | "type": "bytes4" 254 | } 255 | ], 256 | "name": "requestRandomWords", 257 | "outputs": [ 258 | { 259 | "internalType": "bytes32", 260 | "name": "", 261 | "type": "bytes32" 262 | } 263 | ], 264 | "stateMutability": "nonpayable", 265 | "type": "function" 266 | } 267 | ] -------------------------------------------------------------------------------- /packages/contracts/abi/IVRFCoordinatorSystem.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "bytes32", 6 | "name": "_oracleId", 7 | "type": "bytes32" 8 | }, 9 | { 10 | "internalType": "uint32", 11 | "name": "_nbWords", 12 | "type": "uint32" 13 | }, 14 | { 15 | "internalType": "uint16", 16 | "name": "_requestConfirmations", 17 | "type": "uint16" 18 | }, 19 | { 20 | "internalType": "uint32", 21 | "name": "_callbackGasLimit", 22 | "type": "uint32" 23 | }, 24 | { 25 | "internalType": "bytes4", 26 | "name": "_callbackSelector", 27 | "type": "bytes4" 28 | } 29 | ], 30 | "name": "mudvrf_VRFCoordinatorSy_requestRandomWords", 31 | "outputs": [ 32 | { 33 | "internalType": "bytes32", 34 | "name": "", 35 | "type": "bytes32" 36 | } 37 | ], 38 | "stateMutability": "nonpayable", 39 | "type": "function" 40 | }, 41 | { 42 | "inputs": [ 43 | { 44 | "internalType": "address", 45 | "name": "_coordinator", 46 | "type": "address" 47 | } 48 | ], 49 | "name": "mudvrf_VRFCoordinatorSy_setCoordinator", 50 | "outputs": [], 51 | "stateMutability": "nonpayable", 52 | "type": "function" 53 | } 54 | ] -------------------------------------------------------------------------------- /packages/contracts/abi/IWorldCall.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "bytes16", 6 | "name": "namespace", 7 | "type": "bytes16" 8 | }, 9 | { 10 | "internalType": "bytes16", 11 | "name": "name", 12 | "type": "bytes16" 13 | }, 14 | { 15 | "internalType": "bytes", 16 | "name": "funcSelectorAndArgs", 17 | "type": "bytes" 18 | } 19 | ], 20 | "name": "call", 21 | "outputs": [ 22 | { 23 | "internalType": "bytes", 24 | "name": "", 25 | "type": "bytes" 26 | } 27 | ], 28 | "stateMutability": "payable", 29 | "type": "function" 30 | } 31 | ] -------------------------------------------------------------------------------- /packages/contracts/abi/IWorldData.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "bytes16", 6 | "name": "namespace", 7 | "type": "bytes16" 8 | }, 9 | { 10 | "internalType": "bytes16", 11 | "name": "name", 12 | "type": "bytes16" 13 | }, 14 | { 15 | "internalType": "bytes32[]", 16 | "name": "key", 17 | "type": "bytes32[]" 18 | } 19 | ], 20 | "name": "deleteRecord", 21 | "outputs": [], 22 | "stateMutability": "nonpayable", 23 | "type": "function" 24 | }, 25 | { 26 | "inputs": [ 27 | { 28 | "internalType": "bytes16", 29 | "name": "namespace", 30 | "type": "bytes16" 31 | }, 32 | { 33 | "internalType": "bytes16", 34 | "name": "name", 35 | "type": "bytes16" 36 | }, 37 | { 38 | "internalType": "bytes32[]", 39 | "name": "key", 40 | "type": "bytes32[]" 41 | }, 42 | { 43 | "internalType": "uint8", 44 | "name": "schemaIndex", 45 | "type": "uint8" 46 | }, 47 | { 48 | "internalType": "uint256", 49 | "name": "byteLengthToPop", 50 | "type": "uint256" 51 | } 52 | ], 53 | "name": "popFromField", 54 | "outputs": [], 55 | "stateMutability": "nonpayable", 56 | "type": "function" 57 | }, 58 | { 59 | "inputs": [ 60 | { 61 | "internalType": "bytes16", 62 | "name": "namespace", 63 | "type": "bytes16" 64 | }, 65 | { 66 | "internalType": "bytes16", 67 | "name": "name", 68 | "type": "bytes16" 69 | }, 70 | { 71 | "internalType": "bytes32[]", 72 | "name": "key", 73 | "type": "bytes32[]" 74 | }, 75 | { 76 | "internalType": "uint8", 77 | "name": "schemaIndex", 78 | "type": "uint8" 79 | }, 80 | { 81 | "internalType": "bytes", 82 | "name": "dataToPush", 83 | "type": "bytes" 84 | } 85 | ], 86 | "name": "pushToField", 87 | "outputs": [], 88 | "stateMutability": "nonpayable", 89 | "type": "function" 90 | }, 91 | { 92 | "inputs": [ 93 | { 94 | "internalType": "bytes16", 95 | "name": "namespace", 96 | "type": "bytes16" 97 | }, 98 | { 99 | "internalType": "bytes16", 100 | "name": "name", 101 | "type": "bytes16" 102 | }, 103 | { 104 | "internalType": "bytes32[]", 105 | "name": "key", 106 | "type": "bytes32[]" 107 | }, 108 | { 109 | "internalType": "uint8", 110 | "name": "schemaIndex", 111 | "type": "uint8" 112 | }, 113 | { 114 | "internalType": "bytes", 115 | "name": "data", 116 | "type": "bytes" 117 | } 118 | ], 119 | "name": "setField", 120 | "outputs": [], 121 | "stateMutability": "nonpayable", 122 | "type": "function" 123 | }, 124 | { 125 | "inputs": [ 126 | { 127 | "internalType": "bytes16", 128 | "name": "namespace", 129 | "type": "bytes16" 130 | }, 131 | { 132 | "internalType": "bytes16", 133 | "name": "name", 134 | "type": "bytes16" 135 | }, 136 | { 137 | "internalType": "bytes32[]", 138 | "name": "key", 139 | "type": "bytes32[]" 140 | }, 141 | { 142 | "internalType": "bytes", 143 | "name": "data", 144 | "type": "bytes" 145 | } 146 | ], 147 | "name": "setRecord", 148 | "outputs": [], 149 | "stateMutability": "nonpayable", 150 | "type": "function" 151 | }, 152 | { 153 | "inputs": [ 154 | { 155 | "internalType": "bytes16", 156 | "name": "namespace", 157 | "type": "bytes16" 158 | }, 159 | { 160 | "internalType": "bytes16", 161 | "name": "name", 162 | "type": "bytes16" 163 | }, 164 | { 165 | "internalType": "bytes32[]", 166 | "name": "key", 167 | "type": "bytes32[]" 168 | }, 169 | { 170 | "internalType": "uint8", 171 | "name": "schemaIndex", 172 | "type": "uint8" 173 | }, 174 | { 175 | "internalType": "uint256", 176 | "name": "startByteIndex", 177 | "type": "uint256" 178 | }, 179 | { 180 | "internalType": "bytes", 181 | "name": "dataToSet", 182 | "type": "bytes" 183 | } 184 | ], 185 | "name": "updateInField", 186 | "outputs": [], 187 | "stateMutability": "nonpayable", 188 | "type": "function" 189 | } 190 | ] -------------------------------------------------------------------------------- /packages/contracts/abi/IWorldEphemeral.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "bytes16", 6 | "name": "namespace", 7 | "type": "bytes16" 8 | }, 9 | { 10 | "internalType": "bytes16", 11 | "name": "name", 12 | "type": "bytes16" 13 | }, 14 | { 15 | "internalType": "bytes32[]", 16 | "name": "key", 17 | "type": "bytes32[]" 18 | }, 19 | { 20 | "internalType": "bytes", 21 | "name": "data", 22 | "type": "bytes" 23 | } 24 | ], 25 | "name": "emitEphemeralRecord", 26 | "outputs": [], 27 | "stateMutability": "nonpayable", 28 | "type": "function" 29 | } 30 | ] -------------------------------------------------------------------------------- /packages/contracts/abi/IWorldErrors.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "string", 6 | "name": "resource", 7 | "type": "string" 8 | }, 9 | { 10 | "internalType": "address", 11 | "name": "caller", 12 | "type": "address" 13 | } 14 | ], 15 | "name": "AccessDenied", 16 | "type": "error" 17 | }, 18 | { 19 | "inputs": [ 20 | { 21 | "internalType": "bytes4", 22 | "name": "functionSelector", 23 | "type": "bytes4" 24 | } 25 | ], 26 | "name": "FunctionSelectorExists", 27 | "type": "error" 28 | }, 29 | { 30 | "inputs": [ 31 | { 32 | "internalType": "bytes4", 33 | "name": "functionSelector", 34 | "type": "bytes4" 35 | } 36 | ], 37 | "name": "FunctionSelectorNotFound", 38 | "type": "error" 39 | }, 40 | { 41 | "inputs": [ 42 | { 43 | "internalType": "string", 44 | "name": "resource", 45 | "type": "string" 46 | } 47 | ], 48 | "name": "InvalidSelector", 49 | "type": "error" 50 | }, 51 | { 52 | "inputs": [ 53 | { 54 | "internalType": "string", 55 | "name": "module", 56 | "type": "string" 57 | } 58 | ], 59 | "name": "ModuleAlreadyInstalled", 60 | "type": "error" 61 | }, 62 | { 63 | "inputs": [ 64 | { 65 | "internalType": "string", 66 | "name": "resource", 67 | "type": "string" 68 | } 69 | ], 70 | "name": "ResourceExists", 71 | "type": "error" 72 | }, 73 | { 74 | "inputs": [ 75 | { 76 | "internalType": "string", 77 | "name": "resource", 78 | "type": "string" 79 | } 80 | ], 81 | "name": "ResourceNotFound", 82 | "type": "error" 83 | }, 84 | { 85 | "inputs": [ 86 | { 87 | "internalType": "address", 88 | "name": "system", 89 | "type": "address" 90 | } 91 | ], 92 | "name": "SystemExists", 93 | "type": "error" 94 | } 95 | ] -------------------------------------------------------------------------------- /packages/contracts/abi/IWorldKernel.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "string", 6 | "name": "resource", 7 | "type": "string" 8 | }, 9 | { 10 | "internalType": "address", 11 | "name": "caller", 12 | "type": "address" 13 | } 14 | ], 15 | "name": "AccessDenied", 16 | "type": "error" 17 | }, 18 | { 19 | "inputs": [ 20 | { 21 | "internalType": "bytes4", 22 | "name": "functionSelector", 23 | "type": "bytes4" 24 | } 25 | ], 26 | "name": "FunctionSelectorExists", 27 | "type": "error" 28 | }, 29 | { 30 | "inputs": [ 31 | { 32 | "internalType": "bytes4", 33 | "name": "functionSelector", 34 | "type": "bytes4" 35 | } 36 | ], 37 | "name": "FunctionSelectorNotFound", 38 | "type": "error" 39 | }, 40 | { 41 | "inputs": [ 42 | { 43 | "internalType": "string", 44 | "name": "resource", 45 | "type": "string" 46 | } 47 | ], 48 | "name": "InvalidSelector", 49 | "type": "error" 50 | }, 51 | { 52 | "inputs": [ 53 | { 54 | "internalType": "string", 55 | "name": "module", 56 | "type": "string" 57 | } 58 | ], 59 | "name": "ModuleAlreadyInstalled", 60 | "type": "error" 61 | }, 62 | { 63 | "inputs": [ 64 | { 65 | "internalType": "string", 66 | "name": "resource", 67 | "type": "string" 68 | } 69 | ], 70 | "name": "ResourceExists", 71 | "type": "error" 72 | }, 73 | { 74 | "inputs": [ 75 | { 76 | "internalType": "string", 77 | "name": "resource", 78 | "type": "string" 79 | } 80 | ], 81 | "name": "ResourceNotFound", 82 | "type": "error" 83 | }, 84 | { 85 | "inputs": [ 86 | { 87 | "internalType": "address", 88 | "name": "system", 89 | "type": "address" 90 | } 91 | ], 92 | "name": "SystemExists", 93 | "type": "error" 94 | }, 95 | { 96 | "anonymous": false, 97 | "inputs": [], 98 | "name": "HelloWorld", 99 | "type": "event" 100 | }, 101 | { 102 | "inputs": [ 103 | { 104 | "internalType": "bytes16", 105 | "name": "namespace", 106 | "type": "bytes16" 107 | }, 108 | { 109 | "internalType": "bytes16", 110 | "name": "name", 111 | "type": "bytes16" 112 | }, 113 | { 114 | "internalType": "bytes", 115 | "name": "funcSelectorAndArgs", 116 | "type": "bytes" 117 | } 118 | ], 119 | "name": "call", 120 | "outputs": [ 121 | { 122 | "internalType": "bytes", 123 | "name": "", 124 | "type": "bytes" 125 | } 126 | ], 127 | "stateMutability": "payable", 128 | "type": "function" 129 | }, 130 | { 131 | "inputs": [ 132 | { 133 | "internalType": "bytes16", 134 | "name": "namespace", 135 | "type": "bytes16" 136 | }, 137 | { 138 | "internalType": "bytes16", 139 | "name": "name", 140 | "type": "bytes16" 141 | }, 142 | { 143 | "internalType": "bytes32[]", 144 | "name": "key", 145 | "type": "bytes32[]" 146 | } 147 | ], 148 | "name": "deleteRecord", 149 | "outputs": [], 150 | "stateMutability": "nonpayable", 151 | "type": "function" 152 | }, 153 | { 154 | "inputs": [ 155 | { 156 | "internalType": "contract IModule", 157 | "name": "module", 158 | "type": "address" 159 | }, 160 | { 161 | "internalType": "bytes", 162 | "name": "args", 163 | "type": "bytes" 164 | } 165 | ], 166 | "name": "installRootModule", 167 | "outputs": [], 168 | "stateMutability": "nonpayable", 169 | "type": "function" 170 | }, 171 | { 172 | "inputs": [ 173 | { 174 | "internalType": "bytes16", 175 | "name": "namespace", 176 | "type": "bytes16" 177 | }, 178 | { 179 | "internalType": "bytes16", 180 | "name": "name", 181 | "type": "bytes16" 182 | }, 183 | { 184 | "internalType": "bytes32[]", 185 | "name": "key", 186 | "type": "bytes32[]" 187 | }, 188 | { 189 | "internalType": "uint8", 190 | "name": "schemaIndex", 191 | "type": "uint8" 192 | }, 193 | { 194 | "internalType": "uint256", 195 | "name": "byteLengthToPop", 196 | "type": "uint256" 197 | } 198 | ], 199 | "name": "popFromField", 200 | "outputs": [], 201 | "stateMutability": "nonpayable", 202 | "type": "function" 203 | }, 204 | { 205 | "inputs": [ 206 | { 207 | "internalType": "bytes16", 208 | "name": "namespace", 209 | "type": "bytes16" 210 | }, 211 | { 212 | "internalType": "bytes16", 213 | "name": "name", 214 | "type": "bytes16" 215 | }, 216 | { 217 | "internalType": "bytes32[]", 218 | "name": "key", 219 | "type": "bytes32[]" 220 | }, 221 | { 222 | "internalType": "uint8", 223 | "name": "schemaIndex", 224 | "type": "uint8" 225 | }, 226 | { 227 | "internalType": "bytes", 228 | "name": "dataToPush", 229 | "type": "bytes" 230 | } 231 | ], 232 | "name": "pushToField", 233 | "outputs": [], 234 | "stateMutability": "nonpayable", 235 | "type": "function" 236 | }, 237 | { 238 | "inputs": [ 239 | { 240 | "internalType": "bytes16", 241 | "name": "namespace", 242 | "type": "bytes16" 243 | }, 244 | { 245 | "internalType": "bytes16", 246 | "name": "name", 247 | "type": "bytes16" 248 | }, 249 | { 250 | "internalType": "bytes32[]", 251 | "name": "key", 252 | "type": "bytes32[]" 253 | }, 254 | { 255 | "internalType": "uint8", 256 | "name": "schemaIndex", 257 | "type": "uint8" 258 | }, 259 | { 260 | "internalType": "bytes", 261 | "name": "data", 262 | "type": "bytes" 263 | } 264 | ], 265 | "name": "setField", 266 | "outputs": [], 267 | "stateMutability": "nonpayable", 268 | "type": "function" 269 | }, 270 | { 271 | "inputs": [ 272 | { 273 | "internalType": "bytes16", 274 | "name": "namespace", 275 | "type": "bytes16" 276 | }, 277 | { 278 | "internalType": "bytes16", 279 | "name": "name", 280 | "type": "bytes16" 281 | }, 282 | { 283 | "internalType": "bytes32[]", 284 | "name": "key", 285 | "type": "bytes32[]" 286 | }, 287 | { 288 | "internalType": "bytes", 289 | "name": "data", 290 | "type": "bytes" 291 | } 292 | ], 293 | "name": "setRecord", 294 | "outputs": [], 295 | "stateMutability": "nonpayable", 296 | "type": "function" 297 | }, 298 | { 299 | "inputs": [ 300 | { 301 | "internalType": "bytes16", 302 | "name": "namespace", 303 | "type": "bytes16" 304 | }, 305 | { 306 | "internalType": "bytes16", 307 | "name": "name", 308 | "type": "bytes16" 309 | }, 310 | { 311 | "internalType": "bytes32[]", 312 | "name": "key", 313 | "type": "bytes32[]" 314 | }, 315 | { 316 | "internalType": "uint8", 317 | "name": "schemaIndex", 318 | "type": "uint8" 319 | }, 320 | { 321 | "internalType": "uint256", 322 | "name": "startByteIndex", 323 | "type": "uint256" 324 | }, 325 | { 326 | "internalType": "bytes", 327 | "name": "dataToSet", 328 | "type": "bytes" 329 | } 330 | ], 331 | "name": "updateInField", 332 | "outputs": [], 333 | "stateMutability": "nonpayable", 334 | "type": "function" 335 | } 336 | ] -------------------------------------------------------------------------------- /packages/contracts/abi/IWorldModuleInstallation.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "contract IModule", 6 | "name": "module", 7 | "type": "address" 8 | }, 9 | { 10 | "internalType": "bytes", 11 | "name": "args", 12 | "type": "bytes" 13 | } 14 | ], 15 | "name": "installRootModule", 16 | "outputs": [], 17 | "stateMutability": "nonpayable", 18 | "type": "function" 19 | } 20 | ] -------------------------------------------------------------------------------- /packages/contracts/abi/IWorldRegistrationSystem.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "bytes16", 6 | "name": "namespace", 7 | "type": "bytes16" 8 | }, 9 | { 10 | "internalType": "bytes16", 11 | "name": "name", 12 | "type": "bytes16" 13 | }, 14 | { 15 | "internalType": "string", 16 | "name": "systemFunctionName", 17 | "type": "string" 18 | }, 19 | { 20 | "internalType": "string", 21 | "name": "systemFunctionArguments", 22 | "type": "string" 23 | } 24 | ], 25 | "name": "registerFunctionSelector", 26 | "outputs": [ 27 | { 28 | "internalType": "bytes4", 29 | "name": "worldFunctionSelector", 30 | "type": "bytes4" 31 | } 32 | ], 33 | "stateMutability": "nonpayable", 34 | "type": "function" 35 | }, 36 | { 37 | "inputs": [ 38 | { 39 | "internalType": "bytes16", 40 | "name": "namespace", 41 | "type": "bytes16" 42 | }, 43 | { 44 | "internalType": "bytes16", 45 | "name": "name", 46 | "type": "bytes16" 47 | }, 48 | { 49 | "internalType": "address", 50 | "name": "hook", 51 | "type": "address" 52 | } 53 | ], 54 | "name": "registerHook", 55 | "outputs": [], 56 | "stateMutability": "nonpayable", 57 | "type": "function" 58 | }, 59 | { 60 | "inputs": [ 61 | { 62 | "internalType": "bytes16", 63 | "name": "namespace", 64 | "type": "bytes16" 65 | } 66 | ], 67 | "name": "registerNamespace", 68 | "outputs": [], 69 | "stateMutability": "nonpayable", 70 | "type": "function" 71 | }, 72 | { 73 | "inputs": [ 74 | { 75 | "internalType": "bytes16", 76 | "name": "namespace", 77 | "type": "bytes16" 78 | }, 79 | { 80 | "internalType": "bytes16", 81 | "name": "name", 82 | "type": "bytes16" 83 | }, 84 | { 85 | "internalType": "bytes4", 86 | "name": "worldFunctionSelector", 87 | "type": "bytes4" 88 | }, 89 | { 90 | "internalType": "bytes4", 91 | "name": "systemFunctionSelector", 92 | "type": "bytes4" 93 | } 94 | ], 95 | "name": "registerRootFunctionSelector", 96 | "outputs": [ 97 | { 98 | "internalType": "bytes4", 99 | "name": "", 100 | "type": "bytes4" 101 | } 102 | ], 103 | "stateMutability": "nonpayable", 104 | "type": "function" 105 | }, 106 | { 107 | "inputs": [ 108 | { 109 | "internalType": "bytes16", 110 | "name": "namespace", 111 | "type": "bytes16" 112 | }, 113 | { 114 | "internalType": "bytes16", 115 | "name": "name", 116 | "type": "bytes16" 117 | }, 118 | { 119 | "internalType": "contract System", 120 | "name": "system", 121 | "type": "address" 122 | }, 123 | { 124 | "internalType": "bool", 125 | "name": "publicAccess", 126 | "type": "bool" 127 | } 128 | ], 129 | "name": "registerSystem", 130 | "outputs": [ 131 | { 132 | "internalType": "bytes32", 133 | "name": "resourceSelector", 134 | "type": "bytes32" 135 | } 136 | ], 137 | "stateMutability": "nonpayable", 138 | "type": "function" 139 | }, 140 | { 141 | "inputs": [ 142 | { 143 | "internalType": "bytes16", 144 | "name": "namespace", 145 | "type": "bytes16" 146 | }, 147 | { 148 | "internalType": "bytes16", 149 | "name": "name", 150 | "type": "bytes16" 151 | }, 152 | { 153 | "internalType": "contract ISystemHook", 154 | "name": "hook", 155 | "type": "address" 156 | } 157 | ], 158 | "name": "registerSystemHook", 159 | "outputs": [], 160 | "stateMutability": "nonpayable", 161 | "type": "function" 162 | }, 163 | { 164 | "inputs": [ 165 | { 166 | "internalType": "bytes16", 167 | "name": "namespace", 168 | "type": "bytes16" 169 | }, 170 | { 171 | "internalType": "bytes16", 172 | "name": "name", 173 | "type": "bytes16" 174 | }, 175 | { 176 | "internalType": "Schema", 177 | "name": "valueSchema", 178 | "type": "bytes32" 179 | }, 180 | { 181 | "internalType": "Schema", 182 | "name": "keySchema", 183 | "type": "bytes32" 184 | } 185 | ], 186 | "name": "registerTable", 187 | "outputs": [ 188 | { 189 | "internalType": "bytes32", 190 | "name": "resourceSelector", 191 | "type": "bytes32" 192 | } 193 | ], 194 | "stateMutability": "nonpayable", 195 | "type": "function" 196 | }, 197 | { 198 | "inputs": [ 199 | { 200 | "internalType": "bytes16", 201 | "name": "namespace", 202 | "type": "bytes16" 203 | }, 204 | { 205 | "internalType": "bytes16", 206 | "name": "name", 207 | "type": "bytes16" 208 | }, 209 | { 210 | "internalType": "contract IStoreHook", 211 | "name": "hook", 212 | "type": "address" 213 | } 214 | ], 215 | "name": "registerTableHook", 216 | "outputs": [], 217 | "stateMutability": "nonpayable", 218 | "type": "function" 219 | }, 220 | { 221 | "inputs": [ 222 | { 223 | "internalType": "bytes16", 224 | "name": "namespace", 225 | "type": "bytes16" 226 | }, 227 | { 228 | "internalType": "bytes16", 229 | "name": "name", 230 | "type": "bytes16" 231 | }, 232 | { 233 | "internalType": "string", 234 | "name": "tableName", 235 | "type": "string" 236 | }, 237 | { 238 | "internalType": "string[]", 239 | "name": "fieldNames", 240 | "type": "string[]" 241 | } 242 | ], 243 | "name": "setMetadata", 244 | "outputs": [], 245 | "stateMutability": "nonpayable", 246 | "type": "function" 247 | } 248 | ] -------------------------------------------------------------------------------- /packages/contracts/abi/Memory.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /packages/contracts/abi/Mixed.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /packages/contracts/abi/MockVRFCoordinator.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "address", 6 | "name": "_blockHashStore", 7 | "type": "address" 8 | } 9 | ], 10 | "stateMutability": "nonpayable", 11 | "type": "constructor" 12 | }, 13 | { 14 | "inputs": [], 15 | "name": "FailedToFulfillRandomness", 16 | "type": "error" 17 | }, 18 | { 19 | "inputs": [], 20 | "name": "InvalidCallbackGasLimit", 21 | "type": "error" 22 | }, 23 | { 24 | "inputs": [], 25 | "name": "InvalidCommitment", 26 | "type": "error" 27 | }, 28 | { 29 | "inputs": [], 30 | "name": "InvalidNumberOfWords", 31 | "type": "error" 32 | }, 33 | { 34 | "inputs": [], 35 | "name": "InvalidOracleId", 36 | "type": "error" 37 | }, 38 | { 39 | "inputs": [], 40 | "name": "InvalidRequestConfirmations", 41 | "type": "error" 42 | }, 43 | { 44 | "inputs": [], 45 | "name": "InvalidRequestParameters", 46 | "type": "error" 47 | }, 48 | { 49 | "anonymous": false, 50 | "inputs": [ 51 | { 52 | "indexed": false, 53 | "internalType": "bytes32", 54 | "name": "requestId", 55 | "type": "bytes32" 56 | } 57 | ], 58 | "name": "FulfillRandomWords", 59 | "type": "event" 60 | }, 61 | { 62 | "anonymous": false, 63 | "inputs": [ 64 | { 65 | "indexed": false, 66 | "internalType": "bytes32", 67 | "name": "requestId", 68 | "type": "bytes32" 69 | }, 70 | { 71 | "indexed": false, 72 | "internalType": "address", 73 | "name": "sender", 74 | "type": "address" 75 | }, 76 | { 77 | "indexed": false, 78 | "internalType": "uint256", 79 | "name": "nonce", 80 | "type": "uint256" 81 | }, 82 | { 83 | "indexed": false, 84 | "internalType": "bytes32", 85 | "name": "oracleId", 86 | "type": "bytes32" 87 | }, 88 | { 89 | "indexed": false, 90 | "internalType": "uint32", 91 | "name": "nbWords", 92 | "type": "uint32" 93 | }, 94 | { 95 | "indexed": false, 96 | "internalType": "uint16", 97 | "name": "requestConfirmations", 98 | "type": "uint16" 99 | }, 100 | { 101 | "indexed": false, 102 | "internalType": "uint32", 103 | "name": "callbackGasLimit", 104 | "type": "uint32" 105 | }, 106 | { 107 | "indexed": false, 108 | "internalType": "address", 109 | "name": "callbackAddress", 110 | "type": "address" 111 | }, 112 | { 113 | "indexed": false, 114 | "internalType": "bytes4", 115 | "name": "callbackSelector", 116 | "type": "bytes4" 117 | } 118 | ], 119 | "name": "RequestRandomWords", 120 | "type": "event" 121 | }, 122 | { 123 | "inputs": [], 124 | "name": "MAXIMUM_CALLBACK_GAS_LIMIT", 125 | "outputs": [ 126 | { 127 | "internalType": "uint64", 128 | "name": "", 129 | "type": "uint64" 130 | } 131 | ], 132 | "stateMutability": "view", 133 | "type": "function" 134 | }, 135 | { 136 | "inputs": [], 137 | "name": "MAXIMUM_NB_WORDS", 138 | "outputs": [ 139 | { 140 | "internalType": "uint64", 141 | "name": "", 142 | "type": "uint64" 143 | } 144 | ], 145 | "stateMutability": "view", 146 | "type": "function" 147 | }, 148 | { 149 | "inputs": [], 150 | "name": "MINIMUM_REQUEST_CONFIRMATIONS", 151 | "outputs": [ 152 | { 153 | "internalType": "uint16", 154 | "name": "", 155 | "type": "uint16" 156 | } 157 | ], 158 | "stateMutability": "view", 159 | "type": "function" 160 | }, 161 | { 162 | "inputs": [], 163 | "name": "ORACLE_ADDRESS", 164 | "outputs": [ 165 | { 166 | "internalType": "address", 167 | "name": "", 168 | "type": "address" 169 | } 170 | ], 171 | "stateMutability": "view", 172 | "type": "function" 173 | }, 174 | { 175 | "inputs": [], 176 | "name": "ORACLE_ID", 177 | "outputs": [ 178 | { 179 | "internalType": "bytes32", 180 | "name": "", 181 | "type": "bytes32" 182 | } 183 | ], 184 | "stateMutability": "view", 185 | "type": "function" 186 | }, 187 | { 188 | "inputs": [], 189 | "name": "blockHashStore", 190 | "outputs": [ 191 | { 192 | "internalType": "contract BlockHashStore", 193 | "name": "", 194 | "type": "address" 195 | } 196 | ], 197 | "stateMutability": "view", 198 | "type": "function" 199 | }, 200 | { 201 | "inputs": [ 202 | { 203 | "components": [ 204 | { 205 | "internalType": "uint256[2]", 206 | "name": "pk", 207 | "type": "uint256[2]" 208 | }, 209 | { 210 | "internalType": "uint256[2]", 211 | "name": "gamma", 212 | "type": "uint256[2]" 213 | }, 214 | { 215 | "internalType": "uint256", 216 | "name": "c", 217 | "type": "uint256" 218 | }, 219 | { 220 | "internalType": "uint256", 221 | "name": "s", 222 | "type": "uint256" 223 | }, 224 | { 225 | "internalType": "uint256", 226 | "name": "seed", 227 | "type": "uint256" 228 | }, 229 | { 230 | "internalType": "address", 231 | "name": "uWitness", 232 | "type": "address" 233 | }, 234 | { 235 | "internalType": "uint256[2]", 236 | "name": "cGammaWitness", 237 | "type": "uint256[2]" 238 | }, 239 | { 240 | "internalType": "uint256[2]", 241 | "name": "sHashWitness", 242 | "type": "uint256[2]" 243 | }, 244 | { 245 | "internalType": "uint256", 246 | "name": "zInv", 247 | "type": "uint256" 248 | } 249 | ], 250 | "internalType": "struct VRF.Proof", 251 | "name": "_proof", 252 | "type": "tuple" 253 | }, 254 | { 255 | "components": [ 256 | { 257 | "internalType": "address", 258 | "name": "sender", 259 | "type": "address" 260 | }, 261 | { 262 | "internalType": "uint256", 263 | "name": "nonce", 264 | "type": "uint256" 265 | }, 266 | { 267 | "internalType": "bytes32", 268 | "name": "oracleId", 269 | "type": "bytes32" 270 | }, 271 | { 272 | "internalType": "uint32", 273 | "name": "nbWords", 274 | "type": "uint32" 275 | }, 276 | { 277 | "internalType": "uint16", 278 | "name": "requestConfirmations", 279 | "type": "uint16" 280 | }, 281 | { 282 | "internalType": "uint32", 283 | "name": "callbackGasLimit", 284 | "type": "uint32" 285 | }, 286 | { 287 | "internalType": "address", 288 | "name": "callbackAddress", 289 | "type": "address" 290 | }, 291 | { 292 | "internalType": "bytes4", 293 | "name": "callbackSelector", 294 | "type": "bytes4" 295 | }, 296 | { 297 | "internalType": "uint64", 298 | "name": "blockNumber", 299 | "type": "uint64" 300 | } 301 | ], 302 | "internalType": "struct VRF.Request", 303 | "name": "_request", 304 | "type": "tuple" 305 | } 306 | ], 307 | "name": "fulfillRandomWords", 308 | "outputs": [], 309 | "stateMutability": "nonpayable", 310 | "type": "function" 311 | }, 312 | { 313 | "inputs": [], 314 | "name": "nonce", 315 | "outputs": [ 316 | { 317 | "internalType": "uint256", 318 | "name": "", 319 | "type": "uint256" 320 | } 321 | ], 322 | "stateMutability": "view", 323 | "type": "function" 324 | }, 325 | { 326 | "inputs": [ 327 | { 328 | "internalType": "bytes32", 329 | "name": "", 330 | "type": "bytes32" 331 | } 332 | ], 333 | "name": "oracles", 334 | "outputs": [ 335 | { 336 | "internalType": "address", 337 | "name": "", 338 | "type": "address" 339 | } 340 | ], 341 | "stateMutability": "view", 342 | "type": "function" 343 | }, 344 | { 345 | "inputs": [ 346 | { 347 | "internalType": "bytes32", 348 | "name": "_oracleId", 349 | "type": "bytes32" 350 | }, 351 | { 352 | "internalType": "uint32", 353 | "name": "_nbWords", 354 | "type": "uint32" 355 | }, 356 | { 357 | "internalType": "uint16", 358 | "name": "_requestConfirmations", 359 | "type": "uint16" 360 | }, 361 | { 362 | "internalType": "uint32", 363 | "name": "_callbackGasLimit", 364 | "type": "uint32" 365 | }, 366 | { 367 | "internalType": "address", 368 | "name": "_callbackAddress", 369 | "type": "address" 370 | }, 371 | { 372 | "internalType": "bytes4", 373 | "name": "_callbackSelector", 374 | "type": "bytes4" 375 | } 376 | ], 377 | "name": "requestRandomWords", 378 | "outputs": [ 379 | { 380 | "internalType": "bytes32", 381 | "name": "", 382 | "type": "bytes32" 383 | } 384 | ], 385 | "stateMutability": "nonpayable", 386 | "type": "function" 387 | }, 388 | { 389 | "inputs": [ 390 | { 391 | "internalType": "bytes32", 392 | "name": "", 393 | "type": "bytes32" 394 | } 395 | ], 396 | "name": "requests", 397 | "outputs": [ 398 | { 399 | "internalType": "bytes32", 400 | "name": "", 401 | "type": "bytes32" 402 | } 403 | ], 404 | "stateMutability": "view", 405 | "type": "function" 406 | } 407 | ] -------------------------------------------------------------------------------- /packages/contracts/abi/PackedCounterLib.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /packages/contracts/abi/PostDeploy.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [], 4 | "name": "IS_SCRIPT", 5 | "outputs": [ 6 | { 7 | "internalType": "bool", 8 | "name": "", 9 | "type": "bool" 10 | } 11 | ], 12 | "stateMutability": "view", 13 | "type": "function" 14 | }, 15 | { 16 | "inputs": [ 17 | { 18 | "internalType": "address", 19 | "name": "worldAddress", 20 | "type": "address" 21 | } 22 | ], 23 | "name": "run", 24 | "outputs": [], 25 | "stateMutability": "nonpayable", 26 | "type": "function" 27 | } 28 | ] -------------------------------------------------------------------------------- /packages/contracts/abi/RLPReader.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /packages/contracts/abi/ResourceSelector.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /packages/contracts/abi/SchemaLib.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "uint256", 6 | "name": "length", 7 | "type": "uint256" 8 | } 9 | ], 10 | "name": "SchemaLib_InvalidLength", 11 | "type": "error" 12 | }, 13 | { 14 | "inputs": [], 15 | "name": "SchemaLib_StaticTypeAfterDynamicType", 16 | "type": "error" 17 | } 18 | ] -------------------------------------------------------------------------------- /packages/contracts/abi/Script.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [], 4 | "name": "IS_SCRIPT", 5 | "outputs": [ 6 | { 7 | "internalType": "bool", 8 | "name": "", 9 | "type": "bool" 10 | } 11 | ], 12 | "stateMutability": "view", 13 | "type": "function" 14 | } 15 | ] -------------------------------------------------------------------------------- /packages/contracts/abi/ScriptBase.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /packages/contracts/abi/SliceInstance.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /packages/contracts/abi/SliceLib.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "bytes", 6 | "name": "data", 7 | "type": "bytes" 8 | }, 9 | { 10 | "internalType": "uint256", 11 | "name": "start", 12 | "type": "uint256" 13 | }, 14 | { 15 | "internalType": "uint256", 16 | "name": "end", 17 | "type": "uint256" 18 | } 19 | ], 20 | "name": "Slice_OutOfBounds", 21 | "type": "error" 22 | } 23 | ] -------------------------------------------------------------------------------- /packages/contracts/abi/StdChains.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /packages/contracts/abi/StdCheats.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /packages/contracts/abi/StdCheatsSafe.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /packages/contracts/abi/StdUtils.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /packages/contracts/abi/Storage.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /packages/contracts/abi/StoreCore.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "anonymous": false, 4 | "inputs": [ 5 | { 6 | "indexed": false, 7 | "internalType": "bytes32", 8 | "name": "tableId", 9 | "type": "bytes32" 10 | }, 11 | { 12 | "indexed": false, 13 | "internalType": "bytes32[]", 14 | "name": "key", 15 | "type": "bytes32[]" 16 | } 17 | ], 18 | "name": "StoreDeleteRecord", 19 | "type": "event" 20 | }, 21 | { 22 | "anonymous": false, 23 | "inputs": [ 24 | { 25 | "indexed": false, 26 | "internalType": "bytes32", 27 | "name": "table", 28 | "type": "bytes32" 29 | }, 30 | { 31 | "indexed": false, 32 | "internalType": "bytes32[]", 33 | "name": "key", 34 | "type": "bytes32[]" 35 | }, 36 | { 37 | "indexed": false, 38 | "internalType": "bytes", 39 | "name": "data", 40 | "type": "bytes" 41 | } 42 | ], 43 | "name": "StoreEphemeralRecord", 44 | "type": "event" 45 | }, 46 | { 47 | "anonymous": false, 48 | "inputs": [ 49 | { 50 | "indexed": false, 51 | "internalType": "bytes32", 52 | "name": "tableId", 53 | "type": "bytes32" 54 | }, 55 | { 56 | "indexed": false, 57 | "internalType": "bytes32[]", 58 | "name": "key", 59 | "type": "bytes32[]" 60 | }, 61 | { 62 | "indexed": false, 63 | "internalType": "uint8", 64 | "name": "schemaIndex", 65 | "type": "uint8" 66 | }, 67 | { 68 | "indexed": false, 69 | "internalType": "bytes", 70 | "name": "data", 71 | "type": "bytes" 72 | } 73 | ], 74 | "name": "StoreSetField", 75 | "type": "event" 76 | }, 77 | { 78 | "anonymous": false, 79 | "inputs": [ 80 | { 81 | "indexed": false, 82 | "internalType": "bytes32", 83 | "name": "tableId", 84 | "type": "bytes32" 85 | }, 86 | { 87 | "indexed": false, 88 | "internalType": "bytes32[]", 89 | "name": "key", 90 | "type": "bytes32[]" 91 | }, 92 | { 93 | "indexed": false, 94 | "internalType": "bytes", 95 | "name": "data", 96 | "type": "bytes" 97 | } 98 | ], 99 | "name": "StoreSetRecord", 100 | "type": "event" 101 | } 102 | ] -------------------------------------------------------------------------------- /packages/contracts/abi/StoreCoreExtended.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /packages/contracts/abi/StoreCoreInternal.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /packages/contracts/abi/StoreMetadata.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /packages/contracts/abi/StoreSwitch.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [], 4 | "name": "StoreSwitch_InvalidInsideConstructor", 5 | "type": "error" 6 | } 7 | ] -------------------------------------------------------------------------------- /packages/contracts/abi/System.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /packages/contracts/abi/TableId.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /packages/contracts/abi/TestBase.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /packages/contracts/abi/TightCoder.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /packages/contracts/abi/Utils.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /packages/contracts/abi/VRF.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /packages/contracts/abi/VRFCoordinator.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "address", 6 | "name": "_blockHashStore", 7 | "type": "address" 8 | } 9 | ], 10 | "stateMutability": "nonpayable", 11 | "type": "constructor" 12 | }, 13 | { 14 | "inputs": [], 15 | "name": "FailedToFulfillRandomness", 16 | "type": "error" 17 | }, 18 | { 19 | "inputs": [], 20 | "name": "InvalidCallbackGasLimit", 21 | "type": "error" 22 | }, 23 | { 24 | "inputs": [], 25 | "name": "InvalidCommitment", 26 | "type": "error" 27 | }, 28 | { 29 | "inputs": [], 30 | "name": "InvalidNumberOfWords", 31 | "type": "error" 32 | }, 33 | { 34 | "inputs": [], 35 | "name": "InvalidOracleId", 36 | "type": "error" 37 | }, 38 | { 39 | "inputs": [], 40 | "name": "InvalidRequestConfirmations", 41 | "type": "error" 42 | }, 43 | { 44 | "inputs": [], 45 | "name": "InvalidRequestParameters", 46 | "type": "error" 47 | }, 48 | { 49 | "anonymous": false, 50 | "inputs": [ 51 | { 52 | "indexed": false, 53 | "internalType": "bytes32", 54 | "name": "requestId", 55 | "type": "bytes32" 56 | } 57 | ], 58 | "name": "FulfillRandomWords", 59 | "type": "event" 60 | }, 61 | { 62 | "anonymous": false, 63 | "inputs": [ 64 | { 65 | "indexed": false, 66 | "internalType": "bytes32", 67 | "name": "requestId", 68 | "type": "bytes32" 69 | }, 70 | { 71 | "indexed": false, 72 | "internalType": "address", 73 | "name": "sender", 74 | "type": "address" 75 | }, 76 | { 77 | "indexed": false, 78 | "internalType": "uint256", 79 | "name": "nonce", 80 | "type": "uint256" 81 | }, 82 | { 83 | "indexed": false, 84 | "internalType": "bytes32", 85 | "name": "oracleId", 86 | "type": "bytes32" 87 | }, 88 | { 89 | "indexed": false, 90 | "internalType": "uint32", 91 | "name": "nbWords", 92 | "type": "uint32" 93 | }, 94 | { 95 | "indexed": false, 96 | "internalType": "uint16", 97 | "name": "requestConfirmations", 98 | "type": "uint16" 99 | }, 100 | { 101 | "indexed": false, 102 | "internalType": "uint32", 103 | "name": "callbackGasLimit", 104 | "type": "uint32" 105 | }, 106 | { 107 | "indexed": false, 108 | "internalType": "address", 109 | "name": "callbackAddress", 110 | "type": "address" 111 | }, 112 | { 113 | "indexed": false, 114 | "internalType": "bytes4", 115 | "name": "callbackSelector", 116 | "type": "bytes4" 117 | } 118 | ], 119 | "name": "RequestRandomWords", 120 | "type": "event" 121 | }, 122 | { 123 | "inputs": [], 124 | "name": "MAXIMUM_CALLBACK_GAS_LIMIT", 125 | "outputs": [ 126 | { 127 | "internalType": "uint64", 128 | "name": "", 129 | "type": "uint64" 130 | } 131 | ], 132 | "stateMutability": "view", 133 | "type": "function" 134 | }, 135 | { 136 | "inputs": [], 137 | "name": "MAXIMUM_NB_WORDS", 138 | "outputs": [ 139 | { 140 | "internalType": "uint64", 141 | "name": "", 142 | "type": "uint64" 143 | } 144 | ], 145 | "stateMutability": "view", 146 | "type": "function" 147 | }, 148 | { 149 | "inputs": [], 150 | "name": "MINIMUM_REQUEST_CONFIRMATIONS", 151 | "outputs": [ 152 | { 153 | "internalType": "uint16", 154 | "name": "", 155 | "type": "uint16" 156 | } 157 | ], 158 | "stateMutability": "view", 159 | "type": "function" 160 | }, 161 | { 162 | "inputs": [], 163 | "name": "ORACLE_ADDRESS", 164 | "outputs": [ 165 | { 166 | "internalType": "address", 167 | "name": "", 168 | "type": "address" 169 | } 170 | ], 171 | "stateMutability": "view", 172 | "type": "function" 173 | }, 174 | { 175 | "inputs": [], 176 | "name": "ORACLE_ID", 177 | "outputs": [ 178 | { 179 | "internalType": "bytes32", 180 | "name": "", 181 | "type": "bytes32" 182 | } 183 | ], 184 | "stateMutability": "view", 185 | "type": "function" 186 | }, 187 | { 188 | "inputs": [], 189 | "name": "blockHashStore", 190 | "outputs": [ 191 | { 192 | "internalType": "contract BlockHashStore", 193 | "name": "", 194 | "type": "address" 195 | } 196 | ], 197 | "stateMutability": "view", 198 | "type": "function" 199 | }, 200 | { 201 | "inputs": [ 202 | { 203 | "components": [ 204 | { 205 | "internalType": "uint256[2]", 206 | "name": "pk", 207 | "type": "uint256[2]" 208 | }, 209 | { 210 | "internalType": "uint256[2]", 211 | "name": "gamma", 212 | "type": "uint256[2]" 213 | }, 214 | { 215 | "internalType": "uint256", 216 | "name": "c", 217 | "type": "uint256" 218 | }, 219 | { 220 | "internalType": "uint256", 221 | "name": "s", 222 | "type": "uint256" 223 | }, 224 | { 225 | "internalType": "uint256", 226 | "name": "seed", 227 | "type": "uint256" 228 | }, 229 | { 230 | "internalType": "address", 231 | "name": "uWitness", 232 | "type": "address" 233 | }, 234 | { 235 | "internalType": "uint256[2]", 236 | "name": "cGammaWitness", 237 | "type": "uint256[2]" 238 | }, 239 | { 240 | "internalType": "uint256[2]", 241 | "name": "sHashWitness", 242 | "type": "uint256[2]" 243 | }, 244 | { 245 | "internalType": "uint256", 246 | "name": "zInv", 247 | "type": "uint256" 248 | } 249 | ], 250 | "internalType": "struct VRF.Proof", 251 | "name": "_proof", 252 | "type": "tuple" 253 | }, 254 | { 255 | "components": [ 256 | { 257 | "internalType": "address", 258 | "name": "sender", 259 | "type": "address" 260 | }, 261 | { 262 | "internalType": "uint256", 263 | "name": "nonce", 264 | "type": "uint256" 265 | }, 266 | { 267 | "internalType": "bytes32", 268 | "name": "oracleId", 269 | "type": "bytes32" 270 | }, 271 | { 272 | "internalType": "uint32", 273 | "name": "nbWords", 274 | "type": "uint32" 275 | }, 276 | { 277 | "internalType": "uint16", 278 | "name": "requestConfirmations", 279 | "type": "uint16" 280 | }, 281 | { 282 | "internalType": "uint32", 283 | "name": "callbackGasLimit", 284 | "type": "uint32" 285 | }, 286 | { 287 | "internalType": "address", 288 | "name": "callbackAddress", 289 | "type": "address" 290 | }, 291 | { 292 | "internalType": "bytes4", 293 | "name": "callbackSelector", 294 | "type": "bytes4" 295 | }, 296 | { 297 | "internalType": "uint64", 298 | "name": "blockNumber", 299 | "type": "uint64" 300 | } 301 | ], 302 | "internalType": "struct VRF.Request", 303 | "name": "_request", 304 | "type": "tuple" 305 | } 306 | ], 307 | "name": "fulfillRandomWords", 308 | "outputs": [], 309 | "stateMutability": "nonpayable", 310 | "type": "function" 311 | }, 312 | { 313 | "inputs": [], 314 | "name": "nonce", 315 | "outputs": [ 316 | { 317 | "internalType": "uint256", 318 | "name": "", 319 | "type": "uint256" 320 | } 321 | ], 322 | "stateMutability": "view", 323 | "type": "function" 324 | }, 325 | { 326 | "inputs": [ 327 | { 328 | "internalType": "bytes32", 329 | "name": "", 330 | "type": "bytes32" 331 | } 332 | ], 333 | "name": "oracles", 334 | "outputs": [ 335 | { 336 | "internalType": "address", 337 | "name": "", 338 | "type": "address" 339 | } 340 | ], 341 | "stateMutability": "view", 342 | "type": "function" 343 | }, 344 | { 345 | "inputs": [ 346 | { 347 | "internalType": "bytes32", 348 | "name": "_oracleId", 349 | "type": "bytes32" 350 | }, 351 | { 352 | "internalType": "uint32", 353 | "name": "_nbWords", 354 | "type": "uint32" 355 | }, 356 | { 357 | "internalType": "uint16", 358 | "name": "_requestConfirmations", 359 | "type": "uint16" 360 | }, 361 | { 362 | "internalType": "uint32", 363 | "name": "_callbackGasLimit", 364 | "type": "uint32" 365 | }, 366 | { 367 | "internalType": "address", 368 | "name": "_callbackAddress", 369 | "type": "address" 370 | }, 371 | { 372 | "internalType": "bytes4", 373 | "name": "_callbackSelector", 374 | "type": "bytes4" 375 | } 376 | ], 377 | "name": "requestRandomWords", 378 | "outputs": [ 379 | { 380 | "internalType": "bytes32", 381 | "name": "", 382 | "type": "bytes32" 383 | } 384 | ], 385 | "stateMutability": "nonpayable", 386 | "type": "function" 387 | }, 388 | { 389 | "inputs": [ 390 | { 391 | "internalType": "bytes32", 392 | "name": "", 393 | "type": "bytes32" 394 | } 395 | ], 396 | "name": "requests", 397 | "outputs": [ 398 | { 399 | "internalType": "bytes32", 400 | "name": "", 401 | "type": "bytes32" 402 | } 403 | ], 404 | "stateMutability": "view", 405 | "type": "function" 406 | } 407 | ] -------------------------------------------------------------------------------- /packages/contracts/abi/VRFCoordinatorAddress.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /packages/contracts/abi/VRFCoordinatorModule.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "string", 6 | "name": "resourceSelector", 7 | "type": "string" 8 | } 9 | ], 10 | "name": "RequiredModuleNotFound", 11 | "type": "error" 12 | }, 13 | { 14 | "inputs": [ 15 | { 16 | "internalType": "uint256", 17 | "name": "length", 18 | "type": "uint256" 19 | } 20 | ], 21 | "name": "SchemaLib_InvalidLength", 22 | "type": "error" 23 | }, 24 | { 25 | "inputs": [], 26 | "name": "SchemaLib_StaticTypeAfterDynamicType", 27 | "type": "error" 28 | }, 29 | { 30 | "inputs": [], 31 | "name": "getName", 32 | "outputs": [ 33 | { 34 | "internalType": "bytes16", 35 | "name": "", 36 | "type": "bytes16" 37 | } 38 | ], 39 | "stateMutability": "pure", 40 | "type": "function" 41 | }, 42 | { 43 | "inputs": [ 44 | { 45 | "internalType": "bytes", 46 | "name": "", 47 | "type": "bytes" 48 | } 49 | ], 50 | "name": "install", 51 | "outputs": [], 52 | "stateMutability": "nonpayable", 53 | "type": "function" 54 | }, 55 | { 56 | "inputs": [], 57 | "name": "vrfCoordinatorSystem", 58 | "outputs": [ 59 | { 60 | "internalType": "contract VRFCoordinatorSystem", 61 | "name": "", 62 | "type": "address" 63 | } 64 | ], 65 | "stateMutability": "view", 66 | "type": "function" 67 | } 68 | ] -------------------------------------------------------------------------------- /packages/contracts/abi/VRFCoordinatorSystem.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "bytes", 6 | "name": "data", 7 | "type": "bytes" 8 | }, 9 | { 10 | "internalType": "uint256", 11 | "name": "start", 12 | "type": "uint256" 13 | }, 14 | { 15 | "internalType": "uint256", 16 | "name": "end", 17 | "type": "uint256" 18 | } 19 | ], 20 | "name": "Slice_OutOfBounds", 21 | "type": "error" 22 | }, 23 | { 24 | "inputs": [ 25 | { 26 | "internalType": "uint256", 27 | "name": "expected", 28 | "type": "uint256" 29 | }, 30 | { 31 | "internalType": "uint256", 32 | "name": "received", 33 | "type": "uint256" 34 | } 35 | ], 36 | "name": "StoreCore_InvalidDataLength", 37 | "type": "error" 38 | }, 39 | { 40 | "inputs": [ 41 | { 42 | "internalType": "bytes32", 43 | "name": "tableId", 44 | "type": "bytes32" 45 | }, 46 | { 47 | "internalType": "string", 48 | "name": "tableIdString", 49 | "type": "string" 50 | } 51 | ], 52 | "name": "StoreCore_TableNotFound", 53 | "type": "error" 54 | }, 55 | { 56 | "inputs": [ 57 | { 58 | "internalType": "bytes32", 59 | "name": "_oracleId", 60 | "type": "bytes32" 61 | }, 62 | { 63 | "internalType": "uint32", 64 | "name": "_nbWords", 65 | "type": "uint32" 66 | }, 67 | { 68 | "internalType": "uint16", 69 | "name": "_requestConfirmations", 70 | "type": "uint16" 71 | }, 72 | { 73 | "internalType": "uint32", 74 | "name": "_callbackGasLimit", 75 | "type": "uint32" 76 | }, 77 | { 78 | "internalType": "bytes4", 79 | "name": "_callbackSelector", 80 | "type": "bytes4" 81 | } 82 | ], 83 | "name": "requestRandomWords", 84 | "outputs": [ 85 | { 86 | "internalType": "bytes32", 87 | "name": "", 88 | "type": "bytes32" 89 | } 90 | ], 91 | "stateMutability": "nonpayable", 92 | "type": "function" 93 | }, 94 | { 95 | "inputs": [ 96 | { 97 | "internalType": "address", 98 | "name": "_coordinator", 99 | "type": "address" 100 | } 101 | ], 102 | "name": "setCoordinator", 103 | "outputs": [], 104 | "stateMutability": "nonpayable", 105 | "type": "function" 106 | } 107 | ] -------------------------------------------------------------------------------- /packages/contracts/abi/Vector2.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /packages/contracts/abi/WorldContext.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /packages/contracts/abi/console.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /packages/contracts/abi/console2.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /packages/contracts/abi/stdJson.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /packages/contracts/abi/stdMath.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /packages/contracts/abi/stdStorage.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /packages/contracts/abi/stdStorageSafe.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "anonymous": false, 4 | "inputs": [ 5 | { 6 | "indexed": false, 7 | "internalType": "address", 8 | "name": "who", 9 | "type": "address" 10 | }, 11 | { 12 | "indexed": false, 13 | "internalType": "bytes4", 14 | "name": "fsig", 15 | "type": "bytes4" 16 | }, 17 | { 18 | "indexed": false, 19 | "internalType": "bytes32", 20 | "name": "keysHash", 21 | "type": "bytes32" 22 | }, 23 | { 24 | "indexed": false, 25 | "internalType": "uint256", 26 | "name": "slot", 27 | "type": "uint256" 28 | } 29 | ], 30 | "name": "SlotFound", 31 | "type": "event" 32 | }, 33 | { 34 | "anonymous": false, 35 | "inputs": [ 36 | { 37 | "indexed": false, 38 | "internalType": "address", 39 | "name": "who", 40 | "type": "address" 41 | }, 42 | { 43 | "indexed": false, 44 | "internalType": "uint256", 45 | "name": "slot", 46 | "type": "uint256" 47 | } 48 | ], 49 | "name": "WARNING_UninitedSlot", 50 | "type": "event" 51 | } 52 | ] -------------------------------------------------------------------------------- /packages/contracts/build_with_abi.sh: -------------------------------------------------------------------------------- 1 | echo "Generating ABI..." 2 | 3 | # Clean old build artifacts 4 | rm -rf abi out 5 | 6 | # forge build: outputs normal forge .json files and .abi.json files to out/ 7 | FOUNDRY_IGNORED_ERROR_CODES='[5740,1878]' forge build --extra-output-files abi 8 | 9 | # Move .abi.json files to abi/ 10 | # and change extension from .abi.json to .json so typechain doesn't generate types like 'TelepathyRouterAbi' 11 | mkdir abi 12 | cp out/**/*.abi.json abi/ 13 | for file in abi/*.abi.json; do 14 | mv -- "$file" "${file%.abi.json}.json" 15 | done 16 | 17 | echo "Generated ABI!" -------------------------------------------------------------------------------- /packages/contracts/foundry.toml: -------------------------------------------------------------------------------- 1 | [profile.default] 2 | solc_version = "0.8.13" 3 | ffi = false 4 | fuzz_runs = 256 5 | optimizer = true 6 | optimizer_runs = 3000 7 | verbosity = 1 8 | src = "src" 9 | test = "test" 10 | out = "out" 11 | allow_paths = ["../../node_modules", "../../../../packages"] 12 | extra_output_files = [ 13 | "abi", 14 | "evm.bytecode" 15 | ] 16 | fs_permissions = [{ access = "read-write", path = "./"}] 17 | 18 | [profile.lattice-testnet] 19 | eth_rpc_url = "https://follower.testnet-chain.linfra.xyz" 20 | 21 | [profile.hackathon-testnet] 22 | eth_rpc_url = "https://lattice-goerli-sequencer.optimism.io" 23 | -------------------------------------------------------------------------------- /packages/contracts/mud.config.ts: -------------------------------------------------------------------------------- 1 | import { mudConfig } from "@latticexyz/world/register"; 2 | 3 | export default mudConfig({ 4 | codegenDirectory: "", 5 | namespace: "mudvrf", 6 | tables: { 7 | VRFCoordinatorAddress: { 8 | keySchema: {}, 9 | schema: { 10 | vrfCoordinatorAddress: "address" 11 | } 12 | } 13 | }, 14 | modules: [ 15 | { 16 | name: "VRFCoordinatorModule", 17 | root: true, 18 | args: [], 19 | }, 20 | ], 21 | }); 22 | -------------------------------------------------------------------------------- /packages/contracts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@succinctlabs/mudvrf", 3 | "version": "0.0.0", 4 | "private": true, 5 | "license": "MIT", 6 | "scripts": { 7 | "build": "forge clean && bash build_with_abi.sh", 8 | "deploy": "pnpm run initialize && mud deploy", 9 | "deploy:hackathon": "pnpm run initialize && mud deploy --profile=hackathon-testnet", 10 | "deploy:testnet": "pnpm run initialize && mud deploy --profile=lattice-testnet", 11 | "dev": "pnpm mud dev-contracts --tsgenOutput ../client/src/mud", 12 | "initialize": "pnpm run tablegen && pnpm run worldgen && pnpm run build && pnpm run worldtypes && pnpm run tsgen", 13 | "lint": "pnpm run prettier && pnpm run solhint", 14 | "prettier": "prettier --write 'src/**/*.sol'", 15 | "solhint": "solhint --config ./.solhint.json 'src/**/*.sol' --fix", 16 | "tablegen": "mud tablegen", 17 | "test": "tsc --noEmit && mud test", 18 | "tsgen": "mud tsgen --configPath mud.config.ts --out ../client/src/mud", 19 | "worldgen": "mud worldgen", 20 | "worldtypes": "rimraf types && typechain --target=ethers-v5 out/IWorld.sol/IWorld.json" 21 | }, 22 | "dependencies": { 23 | "@ethersproject/abi": "^5.7.0", 24 | "@ethersproject/bytes": "^5.7.0", 25 | "@ethersproject/providers": "^5.7.2", 26 | "@latticexyz/cli": "2.0.0-alpha.1.196", 27 | "@latticexyz/schema-type": "2.0.0-alpha.1.196", 28 | "@latticexyz/std-contracts": "2.0.0-alpha.1.196", 29 | "@latticexyz/store": "2.0.0-alpha.1.196", 30 | "@latticexyz/world": "2.0.0-alpha.1.196", 31 | "@latticexyz/config": "2.0.0-alpha.1.196", 32 | "ethers": "^5.7.2" 33 | }, 34 | "devDependencies": { 35 | "@typechain/ethers-v5": "^10.2.0", 36 | "@types/node": "^18.15.11", 37 | "ds-test": "https://github.com/dapphub/ds-test.git#c9ce3f25bde29fc5eb9901842bf02850dfd2d084", 38 | "forge-std": "https://github.com/foundry-rs/forge-std.git#b4f121555729b3afb3c5ffccb62ff4b6e2818fd3", 39 | "prettier": "^2.6.2", 40 | "prettier-plugin-solidity": "^1.0.0-beta.19", 41 | "solhint": "^3.3.7", 42 | "solhint-plugin-mud": "2.0.0-alpha.1.165+21066424", 43 | "typechain": "^8.1.1" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /packages/contracts/remappings.txt: -------------------------------------------------------------------------------- 1 | ds-test/=./node_modules/ds-test/src/ 2 | forge-std/=./node_modules/forge-std/src/ 3 | @latticexyz/=./node_modules/@latticexyz/ 4 | -------------------------------------------------------------------------------- /packages/contracts/src/BlockHashStore.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0; 3 | 4 | import {RLPReader} from "./libraries/RLPReader.sol"; 5 | 6 | contract BlockHashStore { 7 | mapping(uint256 => bytes32) public blockHashes; 8 | uint256 public latestBlockNumber; 9 | 10 | /// @notice Gets a block hash at a particular block number. 11 | /// @param _n The block number; 12 | function getBlockHash(uint256 _n) external view returns (bytes32) { 13 | bytes32 h = blockHashes[_n]; 14 | require(h != 0, "block hash not available"); 15 | return h; 16 | } 17 | 18 | /// @notice Stores block hashes for a range of blocks using the blockhash opcode. 19 | /// @param _blockNumbers The block numbers to store hashes for. 20 | function storeBlockHashesViaOpCode(uint256[] memory _blockNumbers) external { 21 | for (uint256 i = 0; i < _blockNumbers.length; i++) { 22 | bytes32 h = blockhash(_blockNumbers[i]); 23 | require(h != 0, "block hash not available"); 24 | blockHashes[_blockNumbers[i]] = h; 25 | } 26 | } 27 | 28 | /// @notice Stores block hashes for a range of blocks using merkle proofs. 29 | /// @param _blockHeaders The block headers to store hashes for. 30 | function storeBlockHashesViaMerkleProofs(bytes[] memory _blockHeaders) external { 31 | for (uint256 i = 0; i < _blockHeaders.length; i++) { 32 | RLPReader.RLPItem[] memory blockHeader = RLPReader.readList(_blockHeaders[i]); 33 | 34 | uint256 blockNumber = RLPReader.readUint256(blockHeader[8]); 35 | bytes32 blockHash = keccak256(_blockHeaders[i]); 36 | require(blockHashes[blockNumber] == blockHash, "Block hash not proven"); 37 | 38 | uint256 parentNumber = blockNumber - 1; 39 | bytes32 parentHash = RLPReader.readBytes32(blockHeader[0]); 40 | blockHashes[parentNumber] = parentHash; 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /packages/contracts/src/Tables.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0; 3 | 4 | /* Autogenerated file. Do not edit manually. */ 5 | 6 | import { VRFCoordinatorAddress, VRFCoordinatorAddressTableId } from "./tables/VRFCoordinatorAddress.sol"; 7 | -------------------------------------------------------------------------------- /packages/contracts/src/VRFCoordinator.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0; 3 | 4 | import {System} from "@latticexyz/world/src/System.sol"; 5 | 6 | import {VRF} from "./VRF.sol"; 7 | import {IVRFCoordinator} from "./interfaces/IVRFCoordinator.sol"; 8 | import {BlockHashStore} from "./BlockHashStore.sol"; 9 | 10 | /// @title VRFCoordinator 11 | /// @notice This contract handles requests and fulfillments of random words from a VRF. 12 | contract VRFCoordinator is VRF, IVRFCoordinator { 13 | /// @notice The oracle identifier used for validating the VRF proof came from the oracle. 14 | bytes32 public constant ORACLE_ID = 0xc1ffd3cfee2d9e5cd67643f8f39fd6e51aad88f6f4ce6ab8827279cfffb92266; 15 | 16 | /// @notice The oracle address used for validating that the VRF proof came from the oracle. 17 | address public constant ORACLE_ADDRESS = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266; 18 | 19 | /// @notice The minimum number of request confirmatins. 20 | uint16 public constant MINIMUM_REQUEST_CONFIRMATIONS = 0; 21 | 22 | /// @notice The maximum callback gas limit. 23 | uint64 public constant MAXIMUM_CALLBACK_GAS_LIMIT = 10000000; 24 | 25 | /// @notice The maximum number of random words that can be provided in the callback. 26 | uint64 public constant MAXIMUM_NB_WORDS = 64; 27 | 28 | /// @notice The request nonce. 29 | uint256 public nonce = 0; 30 | 31 | /// @notice The storage proof oracle. 32 | BlockHashStore public blockHashStore; 33 | 34 | /// @notice The mapping of request ids to commitments to what is stored in the request. 35 | mapping(bytes32 => bytes32) public requests; 36 | 37 | /// @notice The mapping of oracle ids to oracle addresses. 38 | mapping(bytes32 => address) public oracles; 39 | 40 | constructor(address _blockHashStore) { 41 | oracles[ORACLE_ID] = ORACLE_ADDRESS; 42 | blockHashStore = BlockHashStore(_blockHashStore); 43 | } 44 | 45 | /// @notice Requests random words from the VRF. 46 | /// @param _oracleId The address of the operator to get shares for. 47 | /// @param _requestConfirmations The number of blocks to wait before posting the VRF request. 48 | /// @param _callbackGasLimit The maximum amount of gas the callback can use. 49 | /// @param _nbWords The number of random words to request. 50 | /// @param _callbackSelector The selector of the callback function. 51 | function requestRandomWords( 52 | bytes32 _oracleId, 53 | uint32 _nbWords, 54 | uint16 _requestConfirmations, 55 | uint32 _callbackGasLimit, 56 | address _callbackAddress, 57 | bytes4 _callbackSelector 58 | ) external returns (bytes32) { 59 | if (_requestConfirmations < MINIMUM_REQUEST_CONFIRMATIONS) { 60 | revert InvalidRequestConfirmations(); 61 | } else if (_callbackGasLimit > MAXIMUM_CALLBACK_GAS_LIMIT) { 62 | revert InvalidCallbackGasLimit(); 63 | } else if (_nbWords > MAXIMUM_NB_WORDS) { 64 | revert InvalidNumberOfWords(); 65 | } 66 | 67 | bytes32 seed = keccak256(abi.encode(_callbackAddress, nonce)); 68 | bytes32 requestId = keccak256(abi.encode(_oracleId, seed)); 69 | requests[requestId] = keccak256( 70 | abi.encode( 71 | requestId, 72 | msg.sender, 73 | nonce, 74 | _oracleId, 75 | _nbWords, 76 | _requestConfirmations, 77 | _callbackGasLimit, 78 | _callbackAddress, 79 | _callbackSelector 80 | ) 81 | ); 82 | 83 | emit RequestRandomWords( 84 | requestId, 85 | msg.sender, 86 | nonce, 87 | _oracleId, 88 | _nbWords, 89 | _requestConfirmations, 90 | _callbackGasLimit, 91 | _callbackAddress, 92 | _callbackSelector 93 | ); 94 | 95 | nonce += 1; 96 | return requestId; 97 | } 98 | 99 | /// @notice Fulfills the request for random words. 100 | /// @param _proof The address of the operator to get shares for. 101 | /// @param _request The number of shares for the operator. 102 | function fulfillRandomWords(VRF.Proof memory _proof, VRF.Request memory _request) external { 103 | bytes32 oracleId = keccak256(abi.encode(_proof.pk)); 104 | address oracle = oracles[oracleId]; 105 | if (oracle == address(0)) { 106 | revert("Invalid oracle id"); 107 | } 108 | 109 | bytes32 seed = keccak256(abi.encode(_request.callbackAddress, _request.nonce)); 110 | bytes32 requestId = keccak256(abi.encode(oracleId, seed)); 111 | bytes32 commitment = requests[requestId]; 112 | bytes32 expectedCommitment = keccak256( 113 | abi.encode( 114 | requestId, 115 | _request.sender, 116 | _request.nonce, 117 | _request.oracleId, 118 | _request.nbWords, 119 | _request.requestConfirmations, 120 | _request.callbackGasLimit, 121 | _request.callbackAddress, 122 | _request.callbackSelector 123 | ) 124 | ); 125 | if (commitment == bytes32(0)) { 126 | revert("Invalid commitment 1"); 127 | } else if (commitment != expectedCommitment) { 128 | revert("Invalid commitment 2"); 129 | } 130 | delete requests[requestId]; 131 | 132 | bytes32 blockHash = blockHashStore.getBlockHash(_request.blockNumber); 133 | uint256 actualSeed = uint256(keccak256(abi.encodePacked(seed, blockHash))); 134 | 135 | uint256 randomness = VRF.randomValueFromVRFProof(_proof, actualSeed); 136 | uint256[] memory randomWords = new uint256[](_request.nbWords); 137 | for (uint256 i = 0; i < _request.nbWords; i++) { 138 | randomWords[i] = uint256(keccak256(abi.encode(randomness, i))); 139 | } 140 | 141 | bytes memory fulfillRandomnessCall = abi.encodeWithSelector(_request.callbackSelector, requestId, randomWords); 142 | (bool status,) = _request.callbackAddress.call(fulfillRandomnessCall); 143 | 144 | if (!status) { 145 | revert("Failed to fulfill randomness"); 146 | } 147 | 148 | emit FulfillRandomWords(requestId); 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /packages/contracts/src/VRFCoordinatorModule.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0; 3 | 4 | import {IBaseWorld} from "@latticexyz/world/src/interfaces/IBaseWorld.sol"; 5 | import {IModule} from "@latticexyz/world/src/interfaces/IModule.sol"; 6 | import {WorldContext} from "@latticexyz/world/src/WorldContext.sol"; 7 | import { getTargetTableSelector } from "@latticexyz/world/src/modules/utils/getTargetTableSelector.sol"; 8 | 9 | import {VRFCoordinator} from "./VRFCoordinator.sol"; 10 | import {VRFCoordinatorSystem} from "./VRFCoordinatorSystem.sol"; 11 | import {VRFCoordinatorAddress} from "./tables/VRFCoordinatorAddress.sol"; 12 | import {NAMESPACE, MODULE_NAME, SYSTEM_NAME, TABLE_NAME} from "./constants.sol"; 13 | 14 | contract VRFCoordinatorModule is IModule, WorldContext { 15 | VRFCoordinatorSystem public immutable vrfCoordinatorSystem = new VRFCoordinatorSystem(); 16 | 17 | function getName() public pure returns (bytes16) { 18 | return MODULE_NAME; 19 | } 20 | 21 | function install(bytes memory) public { 22 | IBaseWorld world = IBaseWorld(_world()); 23 | 24 | // Register system 25 | world.registerSystem(NAMESPACE, SYSTEM_NAME, vrfCoordinatorSystem, true); 26 | 27 | // Register tables 28 | bytes32 resourceSelector = world.registerTable( 29 | NAMESPACE, 30 | TABLE_NAME, 31 | VRFCoordinatorAddress.getSchema(), 32 | VRFCoordinatorAddress.getKeySchema() 33 | ); 34 | 35 | // Register metadata for tables 36 | (string memory tableName, string[] memory fieldNames) = VRFCoordinatorAddress.getMetadata(); 37 | IBaseWorld(_world()).setMetadata( 38 | NAMESPACE, 39 | TABLE_NAME, 40 | tableName, 41 | fieldNames 42 | ); 43 | 44 | // Register system functions 45 | world.registerFunctionSelector( 46 | NAMESPACE, SYSTEM_NAME, "setCoordinator", "(address)" 47 | ); 48 | world.registerFunctionSelector( 49 | NAMESPACE, SYSTEM_NAME, "requestRandomWords", "(bytes32,uint32,uint16,uint32,bytes4)" 50 | ); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /packages/contracts/src/VRFCoordinatorSystem.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0; 3 | 4 | import {System} from "@latticexyz/world/src/System.sol"; 5 | 6 | import {VRF} from "./VRF.sol"; 7 | import {VRFCoordinator} from "./VRFCoordinator.sol"; 8 | import {VRFCoordinatorAddress} from "./tables/VRFCoordinatorAddress.sol"; 9 | 10 | /// @title VRFCoordinatorSystem 11 | /// @notice This contract handles requests and fulfillments of random words from a VRF. 12 | contract VRFCoordinatorSystem is System, VRF { 13 | /// @notice Can be used to set the coordinator address. 14 | /// @param _coordinator The address of the coordinator. 15 | function setCoordinator(address _coordinator) external { 16 | VRFCoordinatorAddress.set(_coordinator); 17 | } 18 | 19 | /// @notice Requests random words from the VRF. 20 | /// @param _oracleId The address of the operator to get shares for. 21 | /// @param _requestConfirmations The number of shares for the operator. 22 | /// @param _callbackGasLimit The maximum amount of gas the callback can use. 23 | /// @param _nbWords The number of random words to request. 24 | /// @param _callbackSelector The selector of the callback function. 25 | function requestRandomWords( 26 | bytes32 _oracleId, 27 | uint32 _nbWords, 28 | uint16 _requestConfirmations, 29 | uint32 _callbackGasLimit, 30 | bytes4 _callbackSelector 31 | ) external returns (bytes32) { 32 | address coordinator = VRFCoordinatorAddress.get(); 33 | bytes32 requestId = VRFCoordinator(coordinator).requestRandomWords( 34 | _oracleId, 35 | _nbWords, 36 | _requestConfirmations, 37 | _callbackGasLimit, 38 | _world(), 39 | _callbackSelector 40 | ); 41 | return requestId; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /packages/contracts/src/constants.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0; 3 | 4 | bytes16 constant NAMESPACE = bytes16("mudvrf"); 5 | bytes16 constant MODULE_NAME = bytes16("mudvrf.m"); 6 | bytes16 constant SYSTEM_NAME = bytes16("VRFCoordinatorSy"); 7 | bytes16 constant TABLE_NAME = bytes16("VRFCoordinatorAd"); 8 | -------------------------------------------------------------------------------- /packages/contracts/src/interfaces/IVRFCoordinator.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0; 3 | 4 | import {VRF} from "../VRF.sol"; 5 | 6 | interface IVRFCoordinator { 7 | event RequestRandomWords( 8 | bytes32 requestId, 9 | address sender, 10 | uint256 nonce, 11 | bytes32 oracleId, 12 | uint32 nbWords, 13 | uint16 requestConfirmations, 14 | uint32 callbackGasLimit, 15 | address callbackAddress, 16 | bytes4 callbackSelector 17 | ); 18 | event FulfillRandomWords(bytes32 requestId); 19 | 20 | error InvalidRequestConfirmations(); 21 | error InvalidCallbackGasLimit(); 22 | error InvalidNumberOfWords(); 23 | error InvalidOracleId(); 24 | error InvalidCommitment(); 25 | error InvalidRequestParameters(); 26 | error FailedToFulfillRandomness(); 27 | 28 | function requestRandomWords( 29 | bytes32 _oracleId, 30 | uint32 _nbWords, 31 | uint16 _requestConfirmations, 32 | uint32 _callbackGasLimit, 33 | address _callbackAddress, 34 | bytes4 _callbackSelector 35 | ) external returns (bytes32); 36 | 37 | function fulfillRandomWords( 38 | VRF.Proof memory _proof, 39 | VRF.Request memory _request 40 | ) external; 41 | } -------------------------------------------------------------------------------- /packages/contracts/src/mocks/MockVRFCoordinator.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0; 3 | 4 | import {System} from "@latticexyz/world/src/System.sol"; 5 | 6 | import {VRF} from "../VRF.sol"; 7 | import {IVRFCoordinator} from "../interfaces/IVRFCoordinator.sol"; 8 | import {BlockHashStore} from "../BlockHashStore.sol"; 9 | 10 | /// @title MockVRFCoordinator 11 | /// @notice This mock contract handles requests and fulfillments of random words from a VRF. 12 | contract MockVRFCoordinator is VRF, IVRFCoordinator { 13 | /// @notice The oracle identifier used for validating the VRF proof came from the oracle. 14 | bytes32 public constant ORACLE_ID = 0xc1ffd3cfee2d9e5cd67643f8f39fd6e51aad88f6f4ce6ab8827279cfffb92266; 15 | 16 | /// @notice The oracle address used for validating that the VRF proof came from the oracle. 17 | address public constant ORACLE_ADDRESS = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266; 18 | 19 | /// @notice The minimum number of request confirmatins. 20 | uint16 public constant MINIMUM_REQUEST_CONFIRMATIONS = 0; 21 | 22 | /// @notice The maximum callback gas limit. 23 | uint64 public constant MAXIMUM_CALLBACK_GAS_LIMIT = 10000000; 24 | 25 | /// @notice The maximum number of random words that can be provided in the callback. 26 | uint64 public constant MAXIMUM_NB_WORDS = 64; 27 | 28 | /// @notice The request nonce. 29 | uint256 public nonce = 0; 30 | 31 | /// @notice The storage proof oracle. 32 | BlockHashStore public blockHashStore; 33 | 34 | /// @notice The mapping of request ids to commitments to what is stored in the request. 35 | mapping(bytes32 => bytes32) public requests; 36 | 37 | /// @notice The mapping of oracle ids to oracle addresses. 38 | mapping(bytes32 => address) public oracles; 39 | 40 | constructor(address _blockHashStore) { 41 | oracles[ORACLE_ID] = ORACLE_ADDRESS; 42 | blockHashStore = BlockHashStore(_blockHashStore); 43 | } 44 | 45 | /// @notice Requests random words from the VRF. 46 | /// @param _oracleId The address of the operator to get shares for. 47 | /// @param _requestConfirmations The number of blocks to wait before posting the VRF request. 48 | /// @param _callbackGasLimit The maximum amount of gas the callback can use. 49 | /// @param _nbWords The number of random words to request. 50 | /// @param _callbackSelector The selector of the callback function. 51 | function requestRandomWords( 52 | bytes32 _oracleId, 53 | uint32 _nbWords, 54 | uint16 _requestConfirmations, 55 | uint32 _callbackGasLimit, 56 | address _callbackAddress, 57 | bytes4 _callbackSelector 58 | ) external returns (bytes32) { 59 | if (_requestConfirmations < MINIMUM_REQUEST_CONFIRMATIONS) { 60 | revert InvalidRequestConfirmations(); 61 | } else if (_callbackGasLimit > MAXIMUM_CALLBACK_GAS_LIMIT) { 62 | revert InvalidCallbackGasLimit(); 63 | } else if (_nbWords > MAXIMUM_NB_WORDS) { 64 | revert InvalidNumberOfWords(); 65 | } 66 | 67 | bytes32 seed = keccak256(abi.encode(_callbackAddress, nonce)); 68 | bytes32 requestId = keccak256(abi.encode(seed)); 69 | requests[requestId] = keccak256( 70 | abi.encode( 71 | requestId, 72 | msg.sender, 73 | nonce, 74 | _oracleId, 75 | _nbWords, 76 | _requestConfirmations, 77 | _callbackGasLimit, 78 | _callbackAddress, 79 | _callbackSelector 80 | ) 81 | ); 82 | 83 | emit RequestRandomWords( 84 | requestId, 85 | msg.sender, 86 | nonce, 87 | _oracleId, 88 | _nbWords, 89 | _requestConfirmations, 90 | _callbackGasLimit, 91 | _callbackAddress, 92 | _callbackSelector 93 | ); 94 | 95 | nonce += 1; 96 | return requestId; 97 | } 98 | 99 | /// @notice Fulfills the request for random words. 100 | /// @param _proof The address of the operator to get shares for. 101 | /// @param _request The number of shares for the operator. 102 | function fulfillRandomWords(VRF.Proof memory _proof, VRF.Request memory _request) external { 103 | bytes32 seed = keccak256(abi.encode(_request.callbackAddress, _request.nonce)); 104 | bytes32 requestId = keccak256(abi.encode(seed)); 105 | bytes32 commitment = requests[requestId]; 106 | bytes32 expectedCommitment = keccak256( 107 | abi.encode( 108 | requestId, 109 | _request.sender, 110 | _request.nonce, 111 | _request.oracleId, 112 | _request.nbWords, 113 | _request.requestConfirmations, 114 | _request.callbackGasLimit, 115 | _request.callbackAddress, 116 | _request.callbackSelector 117 | ) 118 | ); 119 | if (commitment == bytes32(0)) { 120 | revert("Invalid commitment 1"); 121 | } else if (commitment != expectedCommitment) { 122 | revert("Invalid commitment 2"); 123 | } 124 | delete requests[requestId]; 125 | 126 | uint256 randomness = uint256(keccak256(abi.encodePacked(seed))); 127 | uint256[] memory randomWords = new uint256[](_request.nbWords); 128 | for (uint256 i = 0; i < _request.nbWords; i++) { 129 | randomWords[i] = uint256(keccak256(abi.encode(randomness, i))); 130 | } 131 | 132 | bytes memory fulfillRandomnessCall = abi.encodeWithSelector(_request.callbackSelector, requestId, randomWords); 133 | (bool status,) = _request.callbackAddress.call(fulfillRandomnessCall); 134 | 135 | if (!status) { 136 | revert("Failed to fulfill randomness"); 137 | } 138 | 139 | emit FulfillRandomWords(requestId); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /packages/contracts/src/tables/VRFCoordinatorAddress.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0; 3 | 4 | /* Autogenerated file. Do not edit manually. */ 5 | 6 | // Import schema type 7 | import { SchemaType } from "@latticexyz/schema-type/src/solidity/SchemaType.sol"; 8 | 9 | // Import store internals 10 | import { IStore } from "@latticexyz/store/src/IStore.sol"; 11 | import { StoreSwitch } from "@latticexyz/store/src/StoreSwitch.sol"; 12 | import { StoreCore } from "@latticexyz/store/src/StoreCore.sol"; 13 | import { Bytes } from "@latticexyz/store/src/Bytes.sol"; 14 | import { Memory } from "@latticexyz/store/src/Memory.sol"; 15 | import { SliceLib } from "@latticexyz/store/src/Slice.sol"; 16 | import { EncodeArray } from "@latticexyz/store/src/tightcoder/EncodeArray.sol"; 17 | import { Schema, SchemaLib } from "@latticexyz/store/src/Schema.sol"; 18 | import { PackedCounter, PackedCounterLib } from "@latticexyz/store/src/PackedCounter.sol"; 19 | 20 | bytes32 constant _tableId = bytes32(abi.encodePacked(bytes16("mudvrf"), bytes16("VRFCoordinatorAd"))); 21 | bytes32 constant VRFCoordinatorAddressTableId = _tableId; 22 | 23 | library VRFCoordinatorAddress { 24 | /** Get the table's schema */ 25 | function getSchema() internal pure returns (Schema) { 26 | SchemaType[] memory _schema = new SchemaType[](1); 27 | _schema[0] = SchemaType.ADDRESS; 28 | 29 | return SchemaLib.encode(_schema); 30 | } 31 | 32 | function getKeySchema() internal pure returns (Schema) { 33 | SchemaType[] memory _schema = new SchemaType[](0); 34 | 35 | return SchemaLib.encode(_schema); 36 | } 37 | 38 | /** Get the table's metadata */ 39 | function getMetadata() internal pure returns (string memory, string[] memory) { 40 | string[] memory _fieldNames = new string[](1); 41 | _fieldNames[0] = "vrfCoordinatorAddress"; 42 | return ("VRFCoordinatorAddress", _fieldNames); 43 | } 44 | 45 | /** Register the table's schema */ 46 | function registerSchema() internal { 47 | StoreSwitch.registerSchema(_tableId, getSchema(), getKeySchema()); 48 | } 49 | 50 | /** Register the table's schema (using the specified store) */ 51 | function registerSchema(IStore _store) internal { 52 | _store.registerSchema(_tableId, getSchema(), getKeySchema()); 53 | } 54 | 55 | /** Set the table's metadata */ 56 | function setMetadata() internal { 57 | (string memory _tableName, string[] memory _fieldNames) = getMetadata(); 58 | StoreSwitch.setMetadata(_tableId, _tableName, _fieldNames); 59 | } 60 | 61 | /** Set the table's metadata (using the specified store) */ 62 | function setMetadata(IStore _store) internal { 63 | (string memory _tableName, string[] memory _fieldNames) = getMetadata(); 64 | _store.setMetadata(_tableId, _tableName, _fieldNames); 65 | } 66 | 67 | /** Get vrfCoordinatorAddress */ 68 | function get() internal view returns (address vrfCoordinatorAddress) { 69 | bytes32[] memory _keyTuple = new bytes32[](0); 70 | 71 | bytes memory _blob = StoreSwitch.getField(_tableId, _keyTuple, 0); 72 | return (address(Bytes.slice20(_blob, 0))); 73 | } 74 | 75 | /** Get vrfCoordinatorAddress (using the specified store) */ 76 | function get(IStore _store) internal view returns (address vrfCoordinatorAddress) { 77 | bytes32[] memory _keyTuple = new bytes32[](0); 78 | 79 | bytes memory _blob = _store.getField(_tableId, _keyTuple, 0); 80 | return (address(Bytes.slice20(_blob, 0))); 81 | } 82 | 83 | /** Set vrfCoordinatorAddress */ 84 | function set(address vrfCoordinatorAddress) internal { 85 | bytes32[] memory _keyTuple = new bytes32[](0); 86 | 87 | StoreSwitch.setField(_tableId, _keyTuple, 0, abi.encodePacked((vrfCoordinatorAddress))); 88 | } 89 | 90 | /** Set vrfCoordinatorAddress (using the specified store) */ 91 | function set(IStore _store, address vrfCoordinatorAddress) internal { 92 | bytes32[] memory _keyTuple = new bytes32[](0); 93 | 94 | _store.setField(_tableId, _keyTuple, 0, abi.encodePacked((vrfCoordinatorAddress))); 95 | } 96 | 97 | /** Tightly pack full data using this table's schema */ 98 | function encode(address vrfCoordinatorAddress) internal view returns (bytes memory) { 99 | return abi.encodePacked(vrfCoordinatorAddress); 100 | } 101 | 102 | /** Encode keys as a bytes32 array using this table's schema */ 103 | function encodeKeyTuple() internal pure returns (bytes32[] memory _keyTuple) { 104 | _keyTuple = new bytes32[](0); 105 | } 106 | 107 | /* Delete all data for given keys */ 108 | function deleteRecord() internal { 109 | bytes32[] memory _keyTuple = new bytes32[](0); 110 | 111 | StoreSwitch.deleteRecord(_tableId, _keyTuple); 112 | } 113 | 114 | /* Delete all data for given keys (using the specified store) */ 115 | function deleteRecord(IStore _store) internal { 116 | bytes32[] memory _keyTuple = new bytes32[](0); 117 | 118 | _store.deleteRecord(_tableId, _keyTuple); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /packages/contracts/src/world/IVRFCoordinatorSystem.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0; 3 | 4 | /* Autogenerated file. Do not edit manually. */ 5 | 6 | interface IVRFCoordinatorSystem { 7 | function mudvrf_VRFCoordinatorSy_setCoordinator(address _coordinator) external; 8 | 9 | function mudvrf_VRFCoordinatorSy_requestRandomWords( 10 | bytes32 _oracleId, 11 | uint32 _nbWords, 12 | uint16 _requestConfirmations, 13 | uint32 _callbackGasLimit, 14 | bytes4 _callbackSelector 15 | ) external returns (bytes32); 16 | } 17 | -------------------------------------------------------------------------------- /packages/contracts/src/world/IWorld.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0; 3 | 4 | /* Autogenerated file. Do not edit manually. */ 5 | 6 | import { IBaseWorld } from "@latticexyz/world/src/interfaces/IBaseWorld.sol"; 7 | 8 | import { IVRFCoordinatorSystem } from "./IVRFCoordinatorSystem.sol"; 9 | 10 | /** 11 | * The IWorld interface includes all systems dynamically added to the World 12 | * during the deploy process. 13 | */ 14 | interface IWorld is IBaseWorld, IVRFCoordinatorSystem { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /packages/contracts/tsconfig.json: -------------------------------------------------------------------------------- 1 | // Visit https://aka.ms/tsconfig.json for all config options 2 | { 3 | "compilerOptions": { 4 | "target": "ES2020", 5 | "module": "commonjs", 6 | "strict": true, 7 | "resolveJsonModule": true, 8 | "esModuleInterop": true, 9 | "skipLibCheck": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "moduleResolution": "node" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/contracts/vrf.json: -------------------------------------------------------------------------------- 1 | { 2 | "blockHashStoreAddress": "0x0B306BF915C4d645ff596e518fAf3F9669b97016", 3 | "vrfCoordinatorAddress": "0x959922bE3CAee4b8Cd9a407cc3ac1C251C2007B1" 4 | } -------------------------------------------------------------------------------- /packages/contracts/worlds.json: -------------------------------------------------------------------------------- 1 | { 2 | "31337": { 3 | "address": "0x5FbDB2315678afecb367f032d93F642f64180aa3" 4 | } 5 | } -------------------------------------------------------------------------------- /packages/example-client/.env: -------------------------------------------------------------------------------- 1 | VITE_CHAIN_ID=31337 2 | -------------------------------------------------------------------------------- /packages/example-client/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc", "plugin:react/recommended", "plugin:react-hooks/recommended"], 3 | "plugins": ["react", "react-hooks"], 4 | "rules": { 5 | "react/react-in-jsx-scope": "off" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/example-client/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /packages/example-client/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | a minimal MUD client 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/example-client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example-client", 3 | "version": "0.0.0", 4 | "private": true, 5 | "license": "MIT", 6 | "type": "module", 7 | "scripts": { 8 | "build": "vite build", 9 | "dev": "wait-port localhost:8545 && vite", 10 | "initialize": "pnpm build", 11 | "preview": "vite preview", 12 | "test": "tsc --noEmit", 13 | "typechain": "typechain --target ethers-v5 '../example-contracts/out/**/*.abi.json'" 14 | }, 15 | "dependencies": { 16 | "@ethersproject/providers": "^5.7.2", 17 | "@latticexyz/common": "2.0.0-alpha.1.196", 18 | "@latticexyz/dev-tools": "2.0.0-alpha.1.196", 19 | "@latticexyz/network": "2.0.0-alpha.1.196", 20 | "@latticexyz/react": "2.0.0-alpha.1.196", 21 | "@latticexyz/recs": "2.0.0-alpha.1.196", 22 | "@latticexyz/schema-type": "2.0.0-alpha.1.196", 23 | "@latticexyz/std-client": "2.0.0-alpha.1.196", 24 | "@latticexyz/utils": "2.0.0-alpha.1.196", 25 | "@latticexyz/world": "2.0.0-alpha.1.196", 26 | "@wagmi/chains": "^0.2.22", 27 | "@succinctlabs/mudvrf": "workspace:*", 28 | "ethers": "^5.7.2", 29 | "react": "^18.2.0", 30 | "react-dom": "^18.2.0", 31 | "@succinctlabs/mudvrf-example-contracts": "workspace:*" 32 | }, 33 | "devDependencies": { 34 | "@types/react": "^18.2.6", 35 | "@types/react-dom": "^18.2.4", 36 | "@vitejs/plugin-react": "^3.1.0", 37 | "eslint-plugin-react": "7.31.11", 38 | "eslint-plugin-react-hooks": "4.6.0", 39 | "vite": "^4.2.1", 40 | "wait-port": "^1.0.4" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /packages/example-client/src/App.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap'); 2 | 3 | body { 4 | background-color: #1d5c4e; 5 | opacity: 0.8; 6 | background-image: radial-gradient(#92c7cd 0.65px, #1d5c4e 0.65px); 7 | background-size: 13px 13px; 8 | color: white; 9 | font-family: 'Inter', sans-serif; 10 | } -------------------------------------------------------------------------------- /packages/example-client/src/App.tsx: -------------------------------------------------------------------------------- 1 | import { useComponentValue, useRow, useRows } from "@latticexyz/react"; 2 | import { useMUD } from "./MUDContext"; 3 | import { useEffect, useState } from "react"; 4 | import { world } from "./mud/world"; 5 | import './App.css' 6 | 7 | export const App = () => { 8 | const { 9 | systemCalls: { startGame, dealUser, standUser }, 10 | network: { storeCache, worldContract }, 11 | } = useMUD(); 12 | 13 | const [address, setAddress] = useState(""); 14 | 15 | useEffect(() => { 16 | async function set() { 17 | setAddress(await worldContract.signer.getAddress()); 18 | } 19 | set(); 20 | }, [worldContract.signer]); 21 | 22 | const game = useRow(storeCache, { 23 | table: "BlackJack", 24 | key: { userAddress: address as any }, 25 | }); 26 | 27 | console.log("game", address, game); 28 | 29 | // worldContract.on("StoreSetRecord", (table, key, data) => { 30 | // if ( 31 | // table !== 32 | // "0x00000000000000000000000000000000565246526571756573745461626c6556" 33 | // ) { 34 | // console.log("wrong table", table); 35 | // return; 36 | // } 37 | 38 | // const bytes: string = data.slice(2); 39 | 40 | // let offset = 0; 41 | // const msgSender = "0x" + bytes.slice(offset, offset + 40); 42 | // offset += 40; 43 | 44 | // const nonce = BigInt("0x" + bytes.slice(offset, offset + 64)); 45 | // offset += 64; 46 | 47 | // const blockNumber = BigInt("0x" + bytes.slice(offset, offset + 64)); 48 | // offset += 64; 49 | 50 | // const callbackGasLimit = BigInt("0x" + bytes.slice(offset, offset + 8)); 51 | // offset += 8; 52 | 53 | // const nbWords = BigInt("0x" + bytes.slice(offset, offset + 8)); 54 | // offset += 8; 55 | 56 | // const callbackSelector = "0x" + bytes.slice(offset, offset + 8); 57 | // offset += 8; 58 | 59 | // // console.log(msgSender, nonce, blockNumber, callbackGasLimit, nbWords, callbackSelector); 60 | // setMsgSender(msgSender); 61 | // setNonce(nonce); 62 | // setBlockNumber(blockNumber); 63 | // setCallbackGasLimit(callbackGasLimit); 64 | // setNbWords(nbWords); 65 | // setCallbackSelector(callbackSelector); 66 | // }); 67 | 68 | const CARDS = [ 69 | "A", 70 | "2", 71 | "3", 72 | "4", 73 | "5", 74 | "6", 75 | "7", 76 | "8", 77 | "9", 78 | "10", 79 | "J", 80 | "Q", 81 | "K", 82 | ]; 83 | const SUITS = ["♠", "♣", "♥", "♦"]; 84 | 85 | function getCard(card: bigint) { 86 | return CARDS[Number(card % 13n)] + SUITS[Number((card / 13n) % 4n)]; 87 | } 88 | 89 | function getHandTotal(cards: bigint[]) { 90 | let total = 0; 91 | let aces = false; 92 | for (const card of cards) { 93 | const cardValue = Number(card % 13n); 94 | if (cardValue === 0) { 95 | aces = true; 96 | total += 1; 97 | } else if (cardValue >= 9) { 98 | total += 10; 99 | } else { 100 | total += cardValue + 1; 101 | } 102 | } 103 | return [total, aces] as const; 104 | } 105 | 106 | function renderHandTotal(cards: bigint[]) { 107 | const [total, aces] = getHandTotal(cards); 108 | if (aces && total <= 11) { 109 | return total + 10; 110 | } else { 111 | return total; 112 | } 113 | } 114 | 115 | return ( 116 | <> 117 |
118 |

MUDVRF🎲

119 |

120 | 126 |

CURRENT GAME:

127 | {game === undefined || 128 | game === null || 129 | game.value.userCards === undefined ? ( 130 |
NO GAME
131 | ) : ( 132 |
133 |
134 | Dealer cards:{" "} 135 | {game.value.dealerCards.map((card: any) => getCard(card)).join(", ")} 136 | ({renderHandTotal(game.value.dealerCards)}) 137 |
138 |
139 | Your cards:{" "} 140 | {game.value.userCards.map((card: any) => getCard(card)).join(", ")} ( 141 | {renderHandTotal(game.value.userCards)}) 142 |
143 |
144 | Game Status: {game.value.userWon ? "Win" : "Lose"} 145 |
146 |
147 | Game Ended: {game.value.gameEnded ? "Yes" : "No"} 148 |
149 |

150 | 151 | 154 |
155 | )} 156 |

157 |

158 |
159 | 160 | ); 161 | }; 162 | -------------------------------------------------------------------------------- /packages/example-client/src/MUDContext.tsx: -------------------------------------------------------------------------------- 1 | import { createContext, ReactNode, useContext } from "react"; 2 | import { SetupResult } from "./mud/setup"; 3 | 4 | const MUDContext = createContext(null); 5 | 6 | type Props = { 7 | children: ReactNode; 8 | value: SetupResult; 9 | }; 10 | 11 | export const MUDProvider = ({ children, value }: Props) => { 12 | const currentValue = useContext(MUDContext); 13 | if (currentValue) throw new Error("MUDProvider can only be used once"); 14 | return {children}; 15 | }; 16 | 17 | export const useMUD = () => { 18 | const value = useContext(MUDContext); 19 | if (!value) throw new Error("Must be used within a MUDProvider"); 20 | return value; 21 | }; 22 | -------------------------------------------------------------------------------- /packages/example-client/src/index.tsx: -------------------------------------------------------------------------------- 1 | import ReactDOM from "react-dom/client"; 2 | import { mount as mountDevTools } from "@latticexyz/dev-tools"; 3 | import { App } from "./App"; 4 | import { setup } from "./mud/setup"; 5 | import { MUDProvider } from "./MUDContext"; 6 | 7 | const rootElement = document.getElementById("react-root"); 8 | if (!rootElement) throw new Error("React root not found"); 9 | const root = ReactDOM.createRoot(rootElement); 10 | 11 | // TODO: figure out if we actually want this to be async or if we should render something else in the meantime 12 | setup().then((result) => { 13 | root.render( 14 | 15 | 16 | 17 | ); 18 | mountDevTools(); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/example-client/src/mud/contractComponents.ts: -------------------------------------------------------------------------------- 1 | /* Autogenerated file. Do not edit manually. */ 2 | 3 | import { TableId } from "@latticexyz/utils"; 4 | import { defineComponent, Type as RecsType, World } from "@latticexyz/recs"; 5 | 6 | export function defineContractComponents(world: World) { 7 | return { 8 | BlackJack: (() => { 9 | const tableId = new TableId("", "BlackJack"); 10 | return defineComponent( 11 | world, 12 | { 13 | userWins: RecsType.BigInt, 14 | userLosses: RecsType.BigInt, 15 | gameEnded: RecsType.Boolean, 16 | userWon: RecsType.Boolean, 17 | userCards: RecsType.BigIntArray, 18 | dealerCards: RecsType.BigIntArray, 19 | }, 20 | { 21 | metadata: { 22 | contractId: tableId.toHexString(), 23 | tableId: tableId.toString(), 24 | }, 25 | } 26 | ); 27 | })(), 28 | RequestIdToBlackJackUser: (() => { 29 | const tableId = new TableId("", "RequestIdToBlack"); 30 | return defineComponent( 31 | world, 32 | { 33 | user: RecsType.String, 34 | }, 35 | { 36 | metadata: { 37 | contractId: tableId.toHexString(), 38 | tableId: tableId.toString(), 39 | }, 40 | } 41 | ); 42 | })(), 43 | }; 44 | } 45 | -------------------------------------------------------------------------------- /packages/example-client/src/mud/createClientComponents.ts: -------------------------------------------------------------------------------- 1 | import { SetupNetworkResult } from "./setupNetwork"; 2 | 3 | export type ClientComponents = ReturnType; 4 | 5 | export function createClientComponents({ components }: SetupNetworkResult) { 6 | return { 7 | ...components, 8 | // add your client components or overrides here 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /packages/example-client/src/mud/createSystemCalls.ts: -------------------------------------------------------------------------------- 1 | import { awaitStreamValue } from "@latticexyz/utils"; 2 | import { SetupNetworkResult } from "./setupNetwork"; 3 | 4 | export type SystemCalls = ReturnType; 5 | 6 | export function createSystemCalls( 7 | { worldSend, txReduced$ }: SetupNetworkResult 8 | ) { 9 | const startGame = async () => { 10 | const tx = await worldSend("startGame", []); 11 | await tx.wait(); 12 | await awaitStreamValue(txReduced$, (txHash) => txHash === tx.hash); 13 | } 14 | 15 | const dealUser = async () => { 16 | const tx = await worldSend("dealUser", []); 17 | await tx.wait(); 18 | await awaitStreamValue(txReduced$, (txHash) => txHash === tx.hash); 19 | } 20 | 21 | const standUser = async () => { 22 | const tx = await worldSend("standUser", []); 23 | await tx.wait(); 24 | await awaitStreamValue(txReduced$, (txHash) => txHash === tx.hash); 25 | } 26 | 27 | return { 28 | startGame, 29 | dealUser, 30 | standUser, 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /packages/example-client/src/mud/getNetworkConfig.ts: -------------------------------------------------------------------------------- 1 | import { SetupContractConfig, getBurnerWallet } from "@latticexyz/std-client"; 2 | import worldsJson from "@succinctlabs/mudvrf-example-contracts/worlds.json"; 3 | import { supportedChains } from "./supportedChains"; 4 | 5 | const worlds = worldsJson as Partial>; 6 | 7 | type NetworkConfig = SetupContractConfig & { 8 | privateKey: string; 9 | faucetServiceUrl?: string; 10 | snapSync?: boolean; 11 | }; 12 | 13 | export async function getNetworkConfig(): Promise { 14 | const params = new URLSearchParams(window.location.search); 15 | 16 | const chainId = Number(params.get("chainId") || import.meta.env.VITE_CHAIN_ID || 31337); 17 | const chainIndex = supportedChains.findIndex((c) => c.id === chainId); 18 | const chain = supportedChains[chainIndex]; 19 | if (!chain) { 20 | throw new Error(`Chain ${chainId} not found`); 21 | } 22 | 23 | const world = worlds[chain.id.toString()]; 24 | const worldAddress = params.get("worldAddress") || world?.address; 25 | if (!worldAddress) { 26 | throw new Error(`No world address found for chain ${chainId}. Did you run \`mud deploy\`?`); 27 | } 28 | 29 | const privateKey = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80'; 30 | 31 | const initialBlockNumber = params.has("initialBlockNumber") 32 | ? Number(params.get("initialBlockNumber")) 33 | : world?.blockNumber ?? -1; // -1 will attempt to find the block number from RPC 34 | 35 | return { 36 | clock: { 37 | period: 1000, 38 | initialTime: 0, 39 | syncInterval: 5000, 40 | }, 41 | provider: { 42 | chainId, 43 | jsonRpcUrl: params.get("rpc") ?? chain.rpcUrls.default.http[0], 44 | wsRpcUrl: params.get("wsRpc") ?? chain.rpcUrls.default.webSocket?.[0], 45 | }, 46 | privateKey: privateKey, 47 | chainId, 48 | modeUrl: params.get("mode") ?? chain.modeUrl, 49 | faucetServiceUrl: params.get("faucet") ?? chain.faucetUrl, 50 | worldAddress, 51 | initialBlockNumber, 52 | snapSync: params.get("snapSync") === "true", 53 | disableCache: params.get("cache") === "false", 54 | }; 55 | } 56 | -------------------------------------------------------------------------------- /packages/example-client/src/mud/setup.ts: -------------------------------------------------------------------------------- 1 | import { createClientComponents } from "./createClientComponents"; 2 | import { createSystemCalls } from "./createSystemCalls"; 3 | import { setupNetwork } from "./setupNetwork"; 4 | 5 | export type SetupResult = Awaited>; 6 | 7 | export async function setup() { 8 | const network = await setupNetwork(); 9 | const components = createClientComponents(network); 10 | const systemCalls = createSystemCalls(network, components); 11 | return { 12 | network, 13 | components, 14 | systemCalls, 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /packages/example-client/src/mud/setupNetwork.ts: -------------------------------------------------------------------------------- 1 | import { setupMUDV2Network } from "@latticexyz/std-client"; 2 | import { createFastTxExecutor, createFaucetService, getSnapSyncRecords } from "@latticexyz/network"; 3 | import { getNetworkConfig } from "./getNetworkConfig"; 4 | import { defineContractComponents } from "./contractComponents"; 5 | import { world } from "./world"; 6 | import { Contract, Signer, utils } from "ethers"; 7 | import { JsonRpcProvider } from "@ethersproject/providers"; 8 | import { IWorld__factory } from "@succinctlabs/mudvrf-example-contracts/types/ethers-contracts/factories/IWorld__factory"; 9 | import { getTableIds } from "@latticexyz/utils"; 10 | import storeConfig from "@succinctlabs/mudvrf-example-contracts/mud.config"; 11 | 12 | export type SetupNetworkResult = Awaited>; 13 | 14 | export async function setupNetwork() { 15 | const contractComponents = defineContractComponents(world); 16 | const networkConfig = await getNetworkConfig(); 17 | const result = await setupMUDV2Network({ 18 | networkConfig, 19 | world, 20 | contractComponents, 21 | syncThread: "main", 22 | storeConfig, 23 | worldAbi: IWorld__factory.abi, 24 | }); 25 | 26 | // Request drip from faucet 27 | const signer = result.network.signer.get(); 28 | if (networkConfig.faucetServiceUrl && signer) { 29 | const address = await signer.getAddress(); 30 | console.info("[Dev Faucet]: Player address -> ", address); 31 | 32 | const faucet = createFaucetService(networkConfig.faucetServiceUrl); 33 | 34 | const requestDrip = async () => { 35 | const balance = await signer.getBalance(); 36 | console.info(`[Dev Faucet]: Player balance -> ${balance}`); 37 | const lowBalance = balance?.lte(utils.parseEther("1")); 38 | if (lowBalance) { 39 | console.info("[Dev Faucet]: Balance is low, dripping funds to player"); 40 | // Double drip 41 | await faucet.dripDev({ address }); 42 | await faucet.dripDev({ address }); 43 | } 44 | }; 45 | 46 | requestDrip(); 47 | // Request a drip every 20 seconds 48 | setInterval(requestDrip, 20000); 49 | } 50 | 51 | const provider = result.network.providers.get().json; 52 | const signerOrProvider = signer ?? provider; 53 | // Create a World contract instance 54 | const worldContract = IWorld__factory.connect(networkConfig.worldAddress, signerOrProvider); 55 | 56 | if (networkConfig.snapSync) { 57 | const currentBlockNumber = await provider.getBlockNumber(); 58 | const tableRecords = await getSnapSyncRecords( 59 | networkConfig.worldAddress, 60 | getTableIds(storeConfig), 61 | currentBlockNumber, 62 | signerOrProvider 63 | ); 64 | 65 | console.log(`Syncing ${tableRecords.length} records`); 66 | result.startSync(tableRecords, currentBlockNumber); 67 | } else { 68 | result.startSync(); 69 | } 70 | 71 | // Create a fast tx executor 72 | const fastTxExecutor = 73 | signer?.provider instanceof JsonRpcProvider 74 | ? await createFastTxExecutor(signer as Signer & { provider: JsonRpcProvider }) 75 | : null; 76 | 77 | // TODO: infer this from fastTxExecute signature? 78 | type BoundFastTxExecuteFn = ( 79 | func: F, 80 | args: Parameters, 81 | options?: { 82 | retryCount?: number; 83 | } 84 | ) => Promise>; 85 | 86 | function bindFastTxExecute(contract: C): BoundFastTxExecuteFn { 87 | return async function (...args) { 88 | if (!fastTxExecutor) { 89 | throw new Error("no signer"); 90 | } 91 | const { tx } = await fastTxExecutor.fastTxExecute(contract, ...args); 92 | return await tx; 93 | }; 94 | } 95 | 96 | return { 97 | ...result, 98 | worldContract, 99 | worldSend: bindFastTxExecute(worldContract), 100 | fastTxExecutor, 101 | }; 102 | } 103 | -------------------------------------------------------------------------------- /packages/example-client/src/mud/supportedChains.ts: -------------------------------------------------------------------------------- 1 | import { MUDChain, latticeTestnet } from "@latticexyz/common/chains"; 2 | import { foundry } from "@wagmi/chains"; 3 | 4 | // If you are deploying to chains other than anvil or Lattice testnet, add them here 5 | export const supportedChains: MUDChain[] = [foundry, latticeTestnet]; 6 | -------------------------------------------------------------------------------- /packages/example-client/src/mud/world.ts: -------------------------------------------------------------------------------- 1 | import { createWorld } from "@latticexyz/recs"; 2 | 3 | export const world = createWorld(); 4 | -------------------------------------------------------------------------------- /packages/example-client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "types": ["vite/client"], 4 | "target": "ESNext", 5 | "useDefineForClassFields": true, 6 | "module": "ESNext", 7 | "lib": ["ESNext", "DOM"], 8 | "moduleResolution": "Node", 9 | "strict": true, 10 | "resolveJsonModule": true, 11 | "isolatedModules": true, 12 | "esModuleInterop": true, 13 | "noEmit": true, 14 | "skipLibCheck": true, 15 | "jsx": "react-jsx", 16 | "jsxImportSource": "react" 17 | }, 18 | "include": ["src"] 19 | } 20 | -------------------------------------------------------------------------------- /packages/example-client/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import react from "@vitejs/plugin-react"; 3 | 4 | export default defineConfig({ 5 | plugins: [react()], 6 | server: { 7 | port: 3000, 8 | fs: { 9 | strict: false, 10 | }, 11 | }, 12 | build: { 13 | target: "es2022", 14 | }, 15 | }); 16 | -------------------------------------------------------------------------------- /packages/example-contracts/.gitignore: -------------------------------------------------------------------------------- 1 | out/ 2 | cache/ 3 | node_modules/ 4 | bindings/ 5 | artifacts/ 6 | abi/ 7 | types/ 8 | broadcast/ 9 | 10 | # Ignore MUD deploy artifacts 11 | deploys/**/*.json 12 | -------------------------------------------------------------------------------- /packages/example-contracts/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["prettier-plugin-solidity"], 3 | "printWidth": 120, 4 | "semi": true, 5 | "tabWidth": 2, 6 | "useTabs": false, 7 | "bracketSpacing": true 8 | } 9 | -------------------------------------------------------------------------------- /packages/example-contracts/.solhint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "solhint:recommended", 3 | "plugins": ["mud"], 4 | "rules": { 5 | "compiler-version": ["error", ">=0.8.0"], 6 | "avoid-low-level-calls": "off", 7 | "no-inline-assembly": "off", 8 | "func-visibility": ["warn", { "ignoreConstructors": true }], 9 | "no-empty-blocks": "off", 10 | "no-complex-fallback": "off", 11 | "mud/no-msg-sender": "error" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/example-contracts/build_with_abi.sh: -------------------------------------------------------------------------------- 1 | echo "Generating ABI..." 2 | 3 | # Clean old build artifacts 4 | rm -rf abi out 5 | 6 | # forge build: outputs normal forge .json files and .abi.json files to out/ 7 | FOUNDRY_IGNORED_ERROR_CODES='[5740,1878]' forge build --extra-output-files abi 8 | 9 | # Move .abi.json files to abi/ 10 | # and change extension from .abi.json to .json so typechain doesn't generate types like 'TelepathyRouterAbi' 11 | mkdir abi 12 | cp out/**/*.abi.json abi/ 13 | for file in abi/*.abi.json; do 14 | mv -- "$file" "${file%.abi.json}.json" 15 | done 16 | 17 | echo "Generated ABI!" -------------------------------------------------------------------------------- /packages/example-contracts/foundry.toml: -------------------------------------------------------------------------------- 1 | [profile.default] 2 | solc_version = "0.8.13" 3 | ffi = false 4 | fuzz_runs = 256 5 | optimizer = true 6 | optimizer_runs = 3000 7 | verbosity = 1 8 | src = "src" 9 | test = "test" 10 | out = "out" 11 | allow_paths = ["../../node_modules", "../../packages"] 12 | extra_output_files = [ 13 | "abi", 14 | "evm.bytecode" 15 | ] 16 | fs_permissions = [{ access = "read-write", path = "./"}] 17 | 18 | [profile.lattice-testnet] 19 | eth_rpc_url = "https://follower.testnet-chain.linfra.xyz" 20 | 21 | [profile.hackathon-testnet] 22 | eth_rpc_url = "https://lattice-goerli-sequencer.optimism.io" 23 | -------------------------------------------------------------------------------- /packages/example-contracts/mud.config.ts: -------------------------------------------------------------------------------- 1 | import { mudConfig } from "@latticexyz/world/register"; 2 | 3 | export default mudConfig({ 4 | codegenDirectory: "", 5 | tables: { 6 | BlackJack: { 7 | keySchema: { 8 | userAddress: "address" 9 | }, 10 | schema: { 11 | userWins: "uint256", 12 | userLosses: "uint256", 13 | gameEnded: "bool", 14 | userWon: "bool", 15 | userCards: "uint256[]", 16 | dealerCards: "uint256[]", 17 | } 18 | }, 19 | RequestIdToBlackJackUser: { 20 | keySchema: { 21 | requestId: "bytes32" 22 | }, 23 | schema: { 24 | user: "address" 25 | } 26 | } 27 | }, 28 | modules: [ 29 | { 30 | name: "VRFCoordinatorModule", 31 | root: true, 32 | args: [], 33 | }, 34 | ], 35 | }); 36 | -------------------------------------------------------------------------------- /packages/example-contracts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@succinctlabs/mudvrf-example-contracts", 3 | "version": "0.0.0", 4 | "private": true, 5 | "license": "MIT", 6 | "scripts": { 7 | "build": "forge clean && bash build_with_abi.sh", 8 | "deploy": "pnpm run initialize && mud deploy", 9 | "deploy:hackathon": "pnpm run initialize && mud deploy --profile=hackathon-testnet", 10 | "deploy:testnet": "pnpm run initialize && mud deploy --profile=lattice-testnet", 11 | "dev": "pnpm mud dev-contracts --tsgenOutput ../example-client/src/mud", 12 | "initialize": "pnpm run tablegen && pnpm run worldgen && pnpm run build && pnpm run worldtypes && pnpm run tsgen", 13 | "lint": "pnpm run prettier && pnpm run solhint", 14 | "prettier": "prettier --write 'src/**/*.sol'", 15 | "solhint": "solhint --config ./.solhint.json 'src/**/*.sol' --fix", 16 | "tablegen": "mud tablegen", 17 | "test": "tsc --noEmit && mud test", 18 | "tsgen": "mud tsgen --configPath mud.config.ts --out ../example-client/src/mud", 19 | "worldgen": "mud worldgen", 20 | "worldtypes": "rimraf types && typechain --target=ethers-v5 out/IWorld.sol/IWorld.json" 21 | }, 22 | "dependencies": { 23 | "@ethersproject/abi": "^5.7.0", 24 | "@ethersproject/bytes": "^5.7.0", 25 | "@ethersproject/providers": "^5.7.2", 26 | "@latticexyz/cli": "2.0.0-alpha.1.196", 27 | "@latticexyz/schema-type": "2.0.0-alpha.1.196", 28 | "@latticexyz/std-contracts": "2.0.0-alpha.1.196", 29 | "@latticexyz/store": "2.0.0-alpha.1.196", 30 | "@latticexyz/world": "2.0.0-alpha.1.196", 31 | "@latticexyz/config": "2.0.0-alpha.1.196", 32 | "ethers": "^5.7.2", 33 | "@succinctlabs/mudvrf": "workspace:*" 34 | }, 35 | "devDependencies": { 36 | "@typechain/ethers-v5": "^10.2.0", 37 | "@types/node": "^18.15.11", 38 | "ds-test": "https://github.com/dapphub/ds-test.git#c9ce3f25bde29fc5eb9901842bf02850dfd2d084", 39 | "forge-std": "https://github.com/foundry-rs/forge-std.git#b4f121555729b3afb3c5ffccb62ff4b6e2818fd3", 40 | "prettier": "^2.6.2", 41 | "prettier-plugin-solidity": "^1.0.0-beta.19", 42 | "solhint": "^3.3.7", 43 | "solhint-plugin-mud": "2.0.0-alpha.1.165+21066424", 44 | "typechain": "^8.1.1" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /packages/example-contracts/remappings.txt: -------------------------------------------------------------------------------- 1 | ds-test/=./node_modules/ds-test/src/ 2 | forge-std/=./node_modules/forge-std/src/ 3 | @latticexyz/=./node_modules/@latticexyz/ 4 | @succinctlabs/=./node_modules/@succinctlabs/ 5 | -------------------------------------------------------------------------------- /packages/example-contracts/script/PostDeploy.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0; 3 | 4 | import {Script} from "forge-std/Script.sol"; 5 | import {console} from "forge-std/console.sol"; 6 | import {IVRFCoordinatorSystem} from "@succinctlabs/mudvrf/src/world/IVRFCoordinatorSystem.sol"; 7 | import {IWorld} from "../src/world/IWorld.sol"; 8 | import {BlockHashStore} from "@succinctlabs/mudvrf/src/BlockHashStore.sol"; 9 | import {VRFCoordinator} from "@succinctlabs/mudvrf/src/VRFCoordinator.sol"; 10 | import {MockVRFCoordinator} from "@succinctlabs/mudvrf/src/mocks/MockVRFCoordinator.sol"; 11 | 12 | contract PostDeploy is Script { 13 | function run(address worldAddress) external { 14 | // Load the private key from the `PRIVATE_KEY` environment variable (in .env) 15 | uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); 16 | bool useMock = vm.envBool("USE_MOCK"); 17 | 18 | // Deploy MUDVRF contracts 19 | vm.startBroadcast(deployerPrivateKey); 20 | address blockHashStore = address(new BlockHashStore()); 21 | address coordinator; 22 | if (useMock) { 23 | coordinator = address(new MockVRFCoordinator(blockHashStore)); 24 | console.log("-----MOCK COORDINATOR ADDRESS-----"); 25 | } else { 26 | console.log("-----COORDINATOR ADDRESS-----"); 27 | coordinator = address(new VRFCoordinator(blockHashStore)); 28 | } 29 | console.logAddress(coordinator); 30 | IVRFCoordinatorSystem(worldAddress).mudvrf_VRFCoordinatorSy_setCoordinator(coordinator); 31 | vm.stopBroadcast(); 32 | 33 | string memory obj1 = "vrfCoordinatorDeployment"; 34 | string memory finalJson = vm.serializeAddress(obj1, "vrfCoordinatorAddress", coordinator); 35 | finalJson = vm.serializeAddress(obj1, "blockHashStoreAddress", blockHashStore); 36 | vm.writeJson(finalJson, "./vrf.json"); 37 | } 38 | } -------------------------------------------------------------------------------- /packages/example-contracts/src/Tables.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0; 3 | 4 | /* Autogenerated file. Do not edit manually. */ 5 | 6 | import { BlackJack, BlackJackData, BlackJackTableId } from "./tables/BlackJack.sol"; 7 | import { RequestIdToBlackJackUser, RequestIdToBlackJackUserTableId } from "./tables/RequestIdToBlackJackUser.sol"; 8 | -------------------------------------------------------------------------------- /packages/example-contracts/src/VRFCoordinatorModule.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0; 3 | 4 | import {VRFCoordinatorModule} from "@succinctlabs/mudvrf/src/VRFCoordinatorModule.sol"; -------------------------------------------------------------------------------- /packages/example-contracts/src/systems/BlackJackSystem.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0; 3 | 4 | import {System} from "@latticexyz/world/src/System.sol"; 5 | 6 | import {RequestIdToBlackJackUser, BlackJack} from "../Tables.sol"; 7 | import {IBlackJackSystem} from "../world/IBlackJackSystem.sol"; 8 | import {IVRFCoordinatorSystem} from "@succinctlabs/mudvrf/src/world/IVRFCoordinatorSystem.sol"; 9 | 10 | contract BlackJackSystem is System { 11 | bytes32 public constant ORACLE_ID = bytes32(hex"c1ffd3cfee2d9e5cd67643f8f39fd6e51aad88f6f4ce6ab8827279cfffb92266"); 12 | uint16 public constant REQUEST_CONFIRMATIONS = 0; 13 | uint32 public constant CALLBACK_GAS_LIMIT = 10000000; 14 | uint32 public constant NB_WORDS = 52; 15 | 16 | error InvalidBlackJackUser(); 17 | 18 | function requestRandomness(bytes4 selector) internal returns (bytes32) { 19 | bytes32 requestId = IVRFCoordinatorSystem(_world()).mudvrf_VRFCoordinatorSy_requestRandomWords( 20 | ORACLE_ID, NB_WORDS, REQUEST_CONFIRMATIONS, CALLBACK_GAS_LIMIT, selector 21 | ); 22 | RequestIdToBlackJackUser.set(requestId, _msgSender()); 23 | return requestId; 24 | } 25 | 26 | function calculateValueOfCards(uint256[] memory cards) internal pure returns (uint256[] memory) { 27 | uint256[] memory sums = new uint256[](2); 28 | bool seenAce = false; 29 | 30 | for (uint256 i = 0; i < cards.length; i++) { 31 | uint256 value = 0; 32 | if (cards[i] % 13 > 9) { 33 | value = 10; 34 | } else { 35 | value = 1 + cards[i] % 13; 36 | } 37 | sums[0] += value; 38 | 39 | if (cards[i] % 13 == 0) { 40 | seenAce = true; 41 | } 42 | } 43 | 44 | if (seenAce) { 45 | sums[1] = sums[0] + 10; 46 | } else { 47 | sums[1] = sums[0]; 48 | } 49 | 50 | return sums; 51 | } 52 | 53 | function startGame() public { 54 | requestRandomness(IBlackJackSystem.handleStartGame.selector); 55 | } 56 | 57 | function handleStartGame(bytes32 requestId, uint256[] memory randomWords) public { 58 | address user = RequestIdToBlackJackUser.get(requestId); 59 | if (user == address(0)) { 60 | revert InvalidBlackJackUser(); 61 | } 62 | uint256[] memory userCards = new uint256[](2); 63 | userCards[0] = randomWords[0] % 52; 64 | userCards[1] = randomWords[1] % 52; 65 | 66 | uint256[] memory valueOfCards = calculateValueOfCards(userCards); 67 | if (valueOfCards[0] == 21 || valueOfCards[1] == 21) { 68 | uint256 userWins = BlackJack.getUserWins(user); 69 | BlackJack.setUserWins(user, userWins + 1); 70 | BlackJack.setGameEnded(user, true); 71 | return; 72 | } 73 | 74 | uint256[] memory dealerCards = new uint256[](1); 75 | dealerCards[0] = randomWords[2] % 52; 76 | 77 | uint256 userWins = BlackJack.getUserWins(user); 78 | uint256 userLosses = BlackJack.getUserLosses(user); 79 | BlackJack.set(user, userWins, userLosses, false, false, userCards, dealerCards); 80 | } 81 | 82 | function dealUser() public { 83 | requestRandomness(IBlackJackSystem.handleDealUser.selector); 84 | } 85 | 86 | function handleDealUser(bytes32 requestId, uint256[] memory randomWords) public { 87 | address user = RequestIdToBlackJackUser.get(requestId); 88 | uint256[] memory userCards = BlackJack.getUserCards(user); 89 | uint256[] memory newUserCards = new uint256[](userCards.length + 1); 90 | for (uint256 i = 0; i < userCards.length; i++) { 91 | newUserCards[i] = userCards[i]; 92 | } 93 | newUserCards[userCards.length] = randomWords[0] % 52; 94 | BlackJack.setUserCards(user, newUserCards); 95 | 96 | uint256[] memory valueOfCards = calculateValueOfCards(newUserCards); 97 | if (valueOfCards[0] > 21 && valueOfCards[1] > 21) { 98 | uint256 userLosses = BlackJack.getUserLosses(user); 99 | BlackJack.setUserLosses(user, userLosses + 1); 100 | BlackJack.setUserWon(user, false); 101 | BlackJack.setGameEnded(user, true); 102 | } else if (valueOfCards[0] == 21 || valueOfCards[1] == 21) { 103 | uint256 userWins = BlackJack.getUserWins(user); 104 | BlackJack.setUserWins(user, userWins + 1); 105 | BlackJack.setUserWon(user, true); 106 | BlackJack.setGameEnded(user, true); 107 | } 108 | } 109 | 110 | function standUser() public { 111 | requestRandomness(IBlackJackSystem.handleStandUser.selector); 112 | } 113 | 114 | function handleStandUser(bytes32 requestId, uint256[] memory randomWords) public { 115 | address user = RequestIdToBlackJackUser.get(requestId); 116 | uint256[] memory userCards = BlackJack.getUserCards(user); 117 | uint256[] memory dealerCards = BlackJack.getDealerCards(user); 118 | uint256[] memory newDealerCards = new uint256[](dealerCards.length + 1); 119 | 120 | for (uint256 i = 0; i < dealerCards.length; i++) { 121 | newDealerCards[i] = dealerCards[i]; 122 | } 123 | 124 | uint8 idx = 0; 125 | newDealerCards[dealerCards.length] = randomWords[idx] % 52; 126 | BlackJack.setDealerCards(user, newDealerCards); 127 | 128 | uint256[] memory valueOfDealerCards = calculateValueOfCards(newDealerCards); 129 | 130 | // Assume ace is 11. 131 | while (valueOfDealerCards[1] < 17) { 132 | idx++; 133 | dealerCards = BlackJack.getDealerCards(user); 134 | newDealerCards = new uint256[](dealerCards.length + 1); 135 | for (uint256 i = 0; i < dealerCards.length; i++) { 136 | newDealerCards[i] = dealerCards[i]; 137 | } 138 | newDealerCards[dealerCards.length] = randomWords[idx] % 52; 139 | BlackJack.setDealerCards(user, newDealerCards); 140 | valueOfDealerCards = calculateValueOfCards(newDealerCards); 141 | } 142 | 143 | uint256[] memory valueOfUserCards = calculateValueOfCards(userCards); 144 | 145 | // Tie at 21. 146 | if ( 147 | (valueOfUserCards[0] == 21 || valueOfUserCards[1] == 21) 148 | && (valueOfDealerCards[0] == 21 || valueOfDealerCards[1] == 21) 149 | ) { 150 | BlackJack.setUserWon(user, false); 151 | BlackJack.setGameEnded(user, true); 152 | return; 153 | } 154 | 155 | // Tie at greater than 21. 156 | if ( 157 | (valueOfUserCards[0] > 21 && valueOfUserCards[1] > 21) 158 | && (valueOfDealerCards[0] > 21 && valueOfDealerCards[1] > 21) 159 | ) { 160 | BlackJack.setUserWon(user, false); 161 | BlackJack.setGameEnded(user, true); 162 | return; 163 | } 164 | 165 | // User goes over 21. 166 | if (valueOfUserCards[0] > 21 && valueOfUserCards[1] > 21) { 167 | uint256 userLosses = BlackJack.getUserLosses(user); 168 | BlackJack.setUserWon(user, false); 169 | BlackJack.setUserLosses(user, userLosses + 1); 170 | BlackJack.setGameEnded(user, true); 171 | return; 172 | } 173 | 174 | // Opponent goes over 21. 175 | if (valueOfDealerCards[0] > 21 && valueOfDealerCards[1] > 21) { 176 | uint256 userWins = BlackJack.getUserWins(user); 177 | BlackJack.setUserWon(user, true); 178 | BlackJack.setUserWins(user, userWins + 1); 179 | BlackJack.setGameEnded(user, true); 180 | return; 181 | } 182 | 183 | // Find users best card under 21. 184 | uint256 userBestCard = 0; 185 | if (valueOfUserCards[0] >= valueOfUserCards[1] && valueOfUserCards[0] <= 21) { 186 | userBestCard = valueOfUserCards[0]; 187 | } else if (valueOfUserCards[1] >= valueOfUserCards[0] && valueOfUserCards[1] <= 21) { 188 | userBestCard = valueOfUserCards[1]; 189 | } 190 | 191 | // Find dealers best card under 21. 192 | uint256 dealerBestCard = 0; 193 | if (valueOfDealerCards[0] >= valueOfDealerCards[1] && valueOfDealerCards[0] <= 21) { 194 | dealerBestCard = valueOfDealerCards[0]; 195 | } else if (valueOfDealerCards[1] >= valueOfDealerCards[0] && valueOfDealerCards[1] <= 21) { 196 | dealerBestCard = valueOfDealerCards[1]; 197 | } 198 | 199 | // Evaluate result. 200 | if (userBestCard > dealerBestCard) { 201 | uint256 userWins = BlackJack.getUserWins(user); 202 | BlackJack.setUserWon(user, true); 203 | BlackJack.setUserWins(user, userWins + 1); 204 | } else if (userBestCard < dealerBestCard) { 205 | uint256 userLosses = BlackJack.getUserLosses(user); 206 | BlackJack.setUserWon(user, false); 207 | BlackJack.setUserLosses(user, userLosses + 1); 208 | } else { 209 | BlackJack.setUserWon(user, false); 210 | } 211 | BlackJack.setGameEnded(user, true); 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /packages/example-contracts/src/tables/RequestIdToBlackJackUser.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0; 3 | 4 | /* Autogenerated file. Do not edit manually. */ 5 | 6 | // Import schema type 7 | import { SchemaType } from "@latticexyz/schema-type/src/solidity/SchemaType.sol"; 8 | 9 | // Import store internals 10 | import { IStore } from "@latticexyz/store/src/IStore.sol"; 11 | import { StoreSwitch } from "@latticexyz/store/src/StoreSwitch.sol"; 12 | import { StoreCore } from "@latticexyz/store/src/StoreCore.sol"; 13 | import { Bytes } from "@latticexyz/store/src/Bytes.sol"; 14 | import { Memory } from "@latticexyz/store/src/Memory.sol"; 15 | import { SliceLib } from "@latticexyz/store/src/Slice.sol"; 16 | import { EncodeArray } from "@latticexyz/store/src/tightcoder/EncodeArray.sol"; 17 | import { Schema, SchemaLib } from "@latticexyz/store/src/Schema.sol"; 18 | import { PackedCounter, PackedCounterLib } from "@latticexyz/store/src/PackedCounter.sol"; 19 | 20 | bytes32 constant _tableId = bytes32(abi.encodePacked(bytes16(""), bytes16("RequestIdToBlack"))); 21 | bytes32 constant RequestIdToBlackJackUserTableId = _tableId; 22 | 23 | library RequestIdToBlackJackUser { 24 | /** Get the table's schema */ 25 | function getSchema() internal pure returns (Schema) { 26 | SchemaType[] memory _schema = new SchemaType[](1); 27 | _schema[0] = SchemaType.ADDRESS; 28 | 29 | return SchemaLib.encode(_schema); 30 | } 31 | 32 | function getKeySchema() internal pure returns (Schema) { 33 | SchemaType[] memory _schema = new SchemaType[](1); 34 | _schema[0] = SchemaType.BYTES32; 35 | 36 | return SchemaLib.encode(_schema); 37 | } 38 | 39 | /** Get the table's metadata */ 40 | function getMetadata() internal pure returns (string memory, string[] memory) { 41 | string[] memory _fieldNames = new string[](1); 42 | _fieldNames[0] = "user"; 43 | return ("RequestIdToBlackJackUser", _fieldNames); 44 | } 45 | 46 | /** Register the table's schema */ 47 | function registerSchema() internal { 48 | StoreSwitch.registerSchema(_tableId, getSchema(), getKeySchema()); 49 | } 50 | 51 | /** Register the table's schema (using the specified store) */ 52 | function registerSchema(IStore _store) internal { 53 | _store.registerSchema(_tableId, getSchema(), getKeySchema()); 54 | } 55 | 56 | /** Set the table's metadata */ 57 | function setMetadata() internal { 58 | (string memory _tableName, string[] memory _fieldNames) = getMetadata(); 59 | StoreSwitch.setMetadata(_tableId, _tableName, _fieldNames); 60 | } 61 | 62 | /** Set the table's metadata (using the specified store) */ 63 | function setMetadata(IStore _store) internal { 64 | (string memory _tableName, string[] memory _fieldNames) = getMetadata(); 65 | _store.setMetadata(_tableId, _tableName, _fieldNames); 66 | } 67 | 68 | /** Get user */ 69 | function get(bytes32 requestId) internal view returns (address user) { 70 | bytes32[] memory _keyTuple = new bytes32[](1); 71 | _keyTuple[0] = bytes32((requestId)); 72 | 73 | bytes memory _blob = StoreSwitch.getField(_tableId, _keyTuple, 0); 74 | return (address(Bytes.slice20(_blob, 0))); 75 | } 76 | 77 | /** Get user (using the specified store) */ 78 | function get(IStore _store, bytes32 requestId) internal view returns (address user) { 79 | bytes32[] memory _keyTuple = new bytes32[](1); 80 | _keyTuple[0] = bytes32((requestId)); 81 | 82 | bytes memory _blob = _store.getField(_tableId, _keyTuple, 0); 83 | return (address(Bytes.slice20(_blob, 0))); 84 | } 85 | 86 | /** Set user */ 87 | function set(bytes32 requestId, address user) internal { 88 | bytes32[] memory _keyTuple = new bytes32[](1); 89 | _keyTuple[0] = bytes32((requestId)); 90 | 91 | StoreSwitch.setField(_tableId, _keyTuple, 0, abi.encodePacked((user))); 92 | } 93 | 94 | /** Set user (using the specified store) */ 95 | function set(IStore _store, bytes32 requestId, address user) internal { 96 | bytes32[] memory _keyTuple = new bytes32[](1); 97 | _keyTuple[0] = bytes32((requestId)); 98 | 99 | _store.setField(_tableId, _keyTuple, 0, abi.encodePacked((user))); 100 | } 101 | 102 | /** Tightly pack full data using this table's schema */ 103 | function encode(address user) internal view returns (bytes memory) { 104 | return abi.encodePacked(user); 105 | } 106 | 107 | /** Encode keys as a bytes32 array using this table's schema */ 108 | function encodeKeyTuple(bytes32 requestId) internal pure returns (bytes32[] memory _keyTuple) { 109 | _keyTuple = new bytes32[](1); 110 | _keyTuple[0] = bytes32((requestId)); 111 | } 112 | 113 | /* Delete all data for given keys */ 114 | function deleteRecord(bytes32 requestId) internal { 115 | bytes32[] memory _keyTuple = new bytes32[](1); 116 | _keyTuple[0] = bytes32((requestId)); 117 | 118 | StoreSwitch.deleteRecord(_tableId, _keyTuple); 119 | } 120 | 121 | /* Delete all data for given keys (using the specified store) */ 122 | function deleteRecord(IStore _store, bytes32 requestId) internal { 123 | bytes32[] memory _keyTuple = new bytes32[](1); 124 | _keyTuple[0] = bytes32((requestId)); 125 | 126 | _store.deleteRecord(_tableId, _keyTuple); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /packages/example-contracts/src/world/IBlackJackSystem.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0; 3 | 4 | /* Autogenerated file. Do not edit manually. */ 5 | 6 | interface IBlackJackSystem { 7 | error InvalidBlackJackUser(); 8 | 9 | function startGame() external; 10 | 11 | function handleStartGame(bytes32 requestId, uint256[] memory randomWords) external; 12 | 13 | function dealUser() external; 14 | 15 | function handleDealUser(bytes32 requestId, uint256[] memory randomWords) external; 16 | 17 | function standUser() external; 18 | 19 | function handleStandUser(bytes32 requestId, uint256[] memory randomWords) external; 20 | } 21 | -------------------------------------------------------------------------------- /packages/example-contracts/src/world/IWorld.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0; 3 | 4 | /* Autogenerated file. Do not edit manually. */ 5 | 6 | import { IBaseWorld } from "@latticexyz/world/src/interfaces/IBaseWorld.sol"; 7 | 8 | import { IBlackJackSystem } from "./IBlackJackSystem.sol"; 9 | 10 | /** 11 | * The IWorld interface includes all systems dynamically added to the World 12 | * during the deploy process. 13 | */ 14 | interface IWorld is IBaseWorld, IBlackJackSystem { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /packages/example-contracts/tsconfig.json: -------------------------------------------------------------------------------- 1 | // Visit https://aka.ms/tsconfig.json for all config options 2 | { 3 | "compilerOptions": { 4 | "target": "ES2020", 5 | "module": "commonjs", 6 | "strict": true, 7 | "resolveJsonModule": true, 8 | "esModuleInterop": true, 9 | "skipLibCheck": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "moduleResolution": "node" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/example-contracts/vrf.json: -------------------------------------------------------------------------------- 1 | { 2 | "blockHashStoreAddress": "0x4A679253410272dd5232B3Ff7cF5dbB88f295319", 3 | "vrfCoordinatorAddress": "0x7a2088a1bFc9d81c55368AE168C2C02570cB814F" 4 | } -------------------------------------------------------------------------------- /packages/example-contracts/worlds.json: -------------------------------------------------------------------------------- 1 | { 2 | "31337": { 3 | "address": "0x5FbDB2315678afecb367f032d93F642f64180aa3" 4 | } 5 | } -------------------------------------------------------------------------------- /packages/mock-prover/.gitignore: -------------------------------------------------------------------------------- 1 | out/ 2 | cache/ 3 | node_modules/ 4 | bindings/ 5 | artifacts/ 6 | abi/ 7 | dist/ 8 | types/ 9 | broadcast/ 10 | 11 | # Ignore MUD deploy artifacts 12 | deploys/**/*.json 13 | -------------------------------------------------------------------------------- /packages/mock-prover/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lil-relayer", 3 | "version": "0.0.0", 4 | "private": true, 5 | "license": "MIT", 6 | "scripts": { 7 | "build": "npm run typechain && tsc -b", 8 | "start": "wait-port localhost:8545 && sleep 10 && node dist/index.js --vrfJsonPath $VRF_JSON_PATH --rpcUrl $RPC_URL --privateKey $PRIVATE_KEY", 9 | "dev": "npm run build && npm run start", 10 | "typechain": "typechain --target ethers-v5 --out-dir src/types '../contracts/abi/?(VRFCoordinator|MockVRFCoordinator|VRF).json'" 11 | }, 12 | "dependencies": { 13 | "@ethersproject/abi": "^5.7.0", 14 | "@ethersproject/providers": "^5.7.2", 15 | "@succinctlabs/mudvrf-example-contracts": "workspace:*", 16 | "ethers": "^5.7.2", 17 | "express": "^4.18.2", 18 | "fs": "0.0.1-security", 19 | "react": "^18.2.0", 20 | "react-dom": "^18.2.0", 21 | "typechain": "^8.1.1" 22 | }, 23 | "devDependencies": { 24 | "@types/express": "^4.17.17", 25 | "@types/react": "^18.2.6", 26 | "@types/react-dom": "^18.2.4", 27 | "@types/yargs": "^17.0.24", 28 | "@vitejs/plugin-react": "^3.1.0", 29 | "eslint-plugin-react": "7.31.11", 30 | "eslint-plugin-react-hooks": "4.6.0", 31 | "vite": "^4.2.1", 32 | "wait-port": "^1.0.4" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/mock-prover/src/index.ts: -------------------------------------------------------------------------------- 1 | import {FulfillRandomWordsEvent, RequestRandomWordsEvent, VRF} from "./types/VRFCoordinator"; 2 | import {MockVRFCoordinator__factory} from "./types/factories/MockVRFCoordinator__factory"; 3 | import { ethers, utils } from 'ethers'; 4 | import { BigNumber } from "ethers"; 5 | import fs from "fs/promises"; 6 | import yargs from "yargs"; 7 | import { hideBin } from 'yargs/helpers'; 8 | 9 | async function main() { 10 | const argv = await yargs(hideBin(process.argv)) 11 | .option('vrfJsonPath', { 12 | type: 'string', 13 | demandOption: true, 14 | describe: 'Path to the VRF JSON file' 15 | }) 16 | .option('rpcUrl', { 17 | type: 'string', 18 | demandOption: true, 19 | describe: 'RPC URL' 20 | }) 21 | .option('privateKey', { 22 | type: 'string', 23 | demandOption: true, 24 | describe: 'Private key' 25 | }) 26 | .argv; 27 | 28 | const vrfJSONPath = argv.vrfJsonPath; 29 | const rpcURL = argv.rpcUrl; 30 | const privateKey = argv.privateKey; 31 | 32 | const chainId = 31337; 33 | 34 | const provider = new ethers.providers.WebSocketProvider(rpcURL, chainId); 35 | 36 | const wallet = new ethers.Wallet('0x'+privateKey, provider); 37 | 38 | const signer = wallet.connect(provider); 39 | 40 | // Read address from vrf.json in contracts directory 41 | const vrfJSON = JSON.parse(await fs.readFile(vrfJSONPath, 'utf8')); 42 | const vrfContractAddress = vrfJSON.vrfCoordinatorAddress; 43 | 44 | console.log("VRFCoordinator Address:", vrfContractAddress) 45 | 46 | const vrfCoordinator = MockVRFCoordinator__factory.connect(vrfContractAddress, signer); 47 | 48 | console.log("\nStarting VRFRequestWatcher..."); 49 | console.log("\nListening for RequestRandomWords events...") 50 | const handleFulfilledRandomness = async (event: FulfillRandomWordsEvent) => { 51 | console.log("tx: ", event.transactionHash); 52 | }; 53 | 54 | const handleRandomnessRequest = async (event: RequestRandomWordsEvent) => { 55 | console.log("\nEvent: ", event.args.requestId); 56 | console.log("> Sender:", event.args.sender); 57 | console.log("> Nonce:", BigNumber.from(event.args.nonce).toNumber()); 58 | console.log("> OracleId:", event.args.oracleId); 59 | console.log("> NbWords:", BigNumber.from(event.args.nbWords).toNumber()); 60 | console.log("> CallbackGasLimit:", BigNumber.from(event.args.callbackGasLimit).toNumber()); 61 | console.log("> CallbackAddress:", event.args.callbackAddress); 62 | console.log("> CallbackSelector:", event.args.callbackSelector); 63 | console.log("> BlockNumber:", BigNumber.from(event.blockNumber).toNumber()) 64 | 65 | // Proof is unused in mock 66 | const proof: VRF.ProofStruct = { 67 | pk: [event.args.requestId, event.args.requestId], 68 | gamma: [event.args.requestId, event.args.requestId], 69 | c: event.args.requestId, 70 | s: event.args.requestId, 71 | seed: event.args.requestId, 72 | uWitness: event.args.sender, 73 | cGammaWitness: [event.args.requestId, event.args.requestId], 74 | sHashWitness: [event.args.requestId, event.args.requestId], 75 | zInv: event.args.requestId 76 | } 77 | 78 | const request: VRF.RequestStruct = { 79 | sender: event.args.sender, 80 | nonce: BigNumber.from(event.args.nonce), 81 | oracleId: event.args.oracleId, 82 | nbWords: BigNumber.from(event.args.nbWords), 83 | requestConfirmations: 0, 84 | callbackGasLimit: BigNumber.from(event.args.callbackGasLimit), 85 | callbackAddress: event.args.callbackAddress, 86 | callbackSelector: event.args.callbackSelector, 87 | blockNumber: BigNumber.from(event.blockNumber) 88 | } 89 | 90 | async function submitTransaction() { 91 | try { 92 | console.log("Fulfilling random words..."); 93 | const tx = await vrfCoordinator.fulfillRandomWords(proof, request, { 94 | gasLimit: 3000000, 95 | gasPrice: ethers.utils.parseUnits('200', 'gwei') 96 | }); 97 | 98 | // Handle the transaction success 99 | // ... 100 | } catch (error) { 101 | // Handle revert or exception 102 | console.error('Error:', error); 103 | return; 104 | } 105 | } 106 | 107 | submitTransaction(); 108 | 109 | }; 110 | 111 | let latestBlockChecked = await provider.getBlockNumber(); 112 | 113 | const fetchPastEvents = async () => { 114 | const requestRandomWordsFilter = vrfCoordinator.filters.RequestRandomWords(); 115 | const fulfillRandomWordsFilter = vrfCoordinator.filters.FulfillRandomWords(); 116 | const latestBlock = await provider.getBlockNumber(); 117 | const rrwEvents = await vrfCoordinator.queryFilter(requestRandomWordsFilter, latestBlockChecked, latestBlock); 118 | const frwEvents = await vrfCoordinator.queryFilter(fulfillRandomWordsFilter, latestBlockChecked, latestBlock); 119 | rrwEvents.forEach(handleRandomnessRequest); 120 | frwEvents.forEach(handleFulfilledRandomness); 121 | latestBlockChecked = latestBlock + 1; // to avoid duplicate event fetching 122 | }; 123 | 124 | fetchPastEvents(); 125 | setInterval(fetchPastEvents, 1000); // Fetch new events every second 126 | 127 | // Handle exit signals 128 | process.on('SIGINT', () => { 129 | console.log('Server shutting down...'); 130 | process.exit(); 131 | }); 132 | } 133 | main(); 134 | -------------------------------------------------------------------------------- /packages/mock-prover/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "commonjs", 5 | "strict": true, 6 | "rootDir": "src", 7 | "outDir": "dist", 8 | "resolveJsonModule": true, 9 | "esModuleInterop": true, 10 | "skipLibCheck": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "moduleResolution": "node" 13 | }, 14 | "include": [ 15 | "src/**/*.ts" 16 | ], 17 | "exclude": [ 18 | "node_modules", 19 | "src/types" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /packages/prover/.gitignore: -------------------------------------------------------------------------------- 1 | .env -------------------------------------------------------------------------------- /packages/prover/abigen.sh: -------------------------------------------------------------------------------- 1 | rm -rf bindings 2 | mkdir bindings 3 | abigen --abi ../contracts/out/VRFCoordinator.sol/VRFCoordinator.abi.json --out bindings/VRFCoordinator.go --pkg bindings --type VRFCoordinator 4 | abigen --abi ../contracts/out/BlockHashStore.sol/BlockhashStore.abi.json --out bindings/BlockHashStore.go --pkg bindings --type BlockHashStore 5 | -------------------------------------------------------------------------------- /packages/prover/main/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io/ioutil" 7 | "os" 8 | 9 | "github.com/akamensky/argparse" 10 | "github.com/ethereum/go-ethereum/common" 11 | "github.com/ethereum/go-ethereum/ethclient" 12 | "github.com/jtguibas/mudvrf/server" 13 | ) 14 | 15 | type VRFDeploymentJSON struct { 16 | VrfCoordinatorAddress string `json:"vrfCoordinatorAddress"` 17 | BlockHashStoreAddress string `json:"blockHashStoreAddress"` 18 | } 19 | 20 | type WorldDeploymentJSON struct { 21 | Foundry struct { 22 | Address string `json:"address"` 23 | } `json:"31337"` 24 | } 25 | 26 | func main() { 27 | parser := argparse.NewParser("print", "Prints provided string to stdout") 28 | vrfJSONPath := parser.String("v", "vrfJsonPath", &argparse.Options{Required: true, Help: "VRF deployment json path"}) 29 | rpcUrl := parser.String("r", "rpcUrl", &argparse.Options{Required: true, Help: "Ethereum RPC url"}) 30 | privateKey := parser.String("p", "privateKey", &argparse.Options{Required: true, Help: "Private key of the prover"}) 31 | 32 | err := parser.Parse(os.Args) 33 | if err != nil { 34 | fmt.Print(parser.Usage(err)) 35 | } 36 | 37 | vrfJson := VRFDeploymentJSON{} 38 | vrfJsonFile, err := os.Open(*vrfJSONPath) 39 | if err != nil { 40 | panic(err) 41 | } 42 | vrfJsonBytes, err := ioutil.ReadAll(vrfJsonFile) 43 | if err != nil { 44 | panic(err) 45 | } 46 | err = json.Unmarshal(vrfJsonBytes, &vrfJson) 47 | if err != nil { 48 | panic(err) 49 | } 50 | fmt.Println("VRFCoordinator Address:", vrfJson.VrfCoordinatorAddress) 51 | fmt.Println("BlockHashStore Address:", vrfJson.BlockHashStoreAddress) 52 | 53 | ethclient, err := ethclient.Dial(*rpcUrl) 54 | if err != nil { 55 | panic(err) 56 | } 57 | vrfCoordinatorAddress := common.HexToAddress(vrfJson.VrfCoordinatorAddress) 58 | blockHashStoreAddress := common.HexToAddress(vrfJson.BlockHashStoreAddress) 59 | server := server.New(*privateKey, vrfCoordinatorAddress, blockHashStoreAddress, ethclient) 60 | server.Start() 61 | } 62 | -------------------------------------------------------------------------------- /packages/prover/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "prover", 3 | "version": "0.0.0", 4 | "private": true, 5 | "license": "MIT", 6 | "scripts": { 7 | "dev": "wait-port localhost:8545 && sleep 10 && go run main/main.go --vrfJsonPath $VRF_JSON_PATH --rpcUrl $RPC_URL --privateKey $PRIVATE_KEY" 8 | }, 9 | "devDependencies": { 10 | "wait-port": "^1.0.4" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/prover/server/server.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "crypto/ecdsa" 5 | "encoding/hex" 6 | "fmt" 7 | "math/big" 8 | 9 | "github.com/ethereum/go-ethereum/accounts/abi/bind" 10 | "github.com/ethereum/go-ethereum/common" 11 | "github.com/ethereum/go-ethereum/crypto" 12 | "github.com/ethereum/go-ethereum/ethclient" 13 | "github.com/jtguibas/mudvrf/bindings" 14 | "github.com/jtguibas/mudvrf/vrf" 15 | ) 16 | 17 | type VRFRequestWatcher struct { 18 | privateKey string 19 | key *ecdsa.PrivateKey 20 | vrfkey *vrf.VRFKey 21 | vrfCoordinator *bindings.VRFCoordinator 22 | blockHashStore *bindings.BlockHashStore 23 | ethclient *ethclient.Client 24 | } 25 | 26 | // abigen --abi ../packages/contracts/out/VRFCoordinator.sol/VRFCoordinator.abi.json --out ../backend/bindings/VRFCoordinator.go --pkg bindings --type VRFCoordinator 27 | func New(privateKey string, vrfCoordinatorAddress common.Address, blockHashStoreAddress common.Address, ethclient *ethclient.Client) *VRFRequestWatcher { 28 | vrfCoordinator, err := bindings.NewVRFCoordinator(vrfCoordinatorAddress, ethclient) 29 | if err != nil { 30 | panic(err) 31 | } 32 | blockHashStore, err := bindings.NewBlockHashStore(blockHashStoreAddress, ethclient) 33 | if err != nil { 34 | panic(err) 35 | } 36 | vrfkey, err := vrf.NewSecp256k1VRFKey(privateKey) 37 | if err != nil { 38 | panic(err) 39 | } 40 | key, err := crypto.HexToECDSA(privateKey) 41 | if err != nil { 42 | panic(err) 43 | } 44 | return &VRFRequestWatcher{ 45 | privateKey: privateKey, 46 | key: key, 47 | vrfkey: vrfkey, 48 | vrfCoordinator: vrfCoordinator, 49 | blockHashStore: blockHashStore, 50 | ethclient: ethclient, 51 | } 52 | } 53 | 54 | func (s *VRFRequestWatcher) Start() { 55 | oracleId, err := s.vrfkey.OracleId() 56 | if err != nil { 57 | panic(err) 58 | } 59 | 60 | fmt.Println("\nStarting VRFRequestWatcher...") 61 | fmt.Println("Oracle:", hex.EncodeToString(oracleId)) 62 | 63 | fmt.Println("\nListening for RequestRandomWords events...") 64 | requests := make(chan *bindings.VRFCoordinatorRequestRandomWords) 65 | s.vrfCoordinator.WatchRequestRandomWords(nil, requests) 66 | 67 | for { 68 | select { 69 | case event := <-requests: 70 | fmt.Printf("Event: %+v\n", hex.EncodeToString(event.RequestId[:])) 71 | fmt.Println("> RequestId:", "0x"+hex.EncodeToString(event.RequestId[:])) 72 | fmt.Println("> Sender:", event.Sender.Hex()) 73 | fmt.Println("> Nonce:", event.Nonce) 74 | fmt.Println("> OracleId:", "0x"+hex.EncodeToString(event.OracleId[:])) 75 | fmt.Println("> NbWords:", event.NbWords) 76 | fmt.Println("> CallbackGasLimit:", event.CallbackGasLimit) 77 | fmt.Println("> CallbackAddress:", event.CallbackAddress.Hex()) 78 | fmt.Println("> CallbackSelector:", "0x"+hex.EncodeToString(event.CallbackSelector[:])) 79 | fmt.Println("> BlockNumber:", event.Raw.BlockNumber) 80 | fmt.Println("Storing block hash...") 81 | err := s.StoreBlockHash(event) 82 | if err != nil { 83 | fmt.Println("Error:", err) 84 | } 85 | fmt.Println("Fulfilling random words...") 86 | err = s.FulfillRandomWords(event) 87 | if err != nil { 88 | fmt.Println("Error:", err) 89 | } 90 | fmt.Println("") 91 | } 92 | } 93 | } 94 | 95 | func (s *VRFRequestWatcher) StoreBlockHash(event *bindings.VRFCoordinatorRequestRandomWords) error { 96 | key, err := crypto.HexToECDSA(s.privateKey) 97 | if err != nil { 98 | return fmt.Errorf("failed to parse private key: %v", err) 99 | } 100 | 101 | transactor, err := bind.NewKeyedTransactorWithChainID(key, big.NewInt(31337)) 102 | if err != nil { 103 | return fmt.Errorf("creating transactor: %w", err) 104 | } 105 | 106 | blockNumber := big.NewInt(int64(event.Raw.BlockNumber)) 107 | tx, err := s.blockHashStore.StoreBlockHashesViaOpCode(transactor, []*big.Int{blockNumber}) 108 | if err != nil { 109 | return fmt.Errorf("storing block hash: %w", err) 110 | } 111 | fmt.Printf("tx: %+v\n", tx.Hash().Hex()) 112 | 113 | return nil 114 | } 115 | 116 | func (s *VRFRequestWatcher) FulfillRandomWords(event *bindings.VRFCoordinatorRequestRandomWords) error { 117 | seedBytes := vrf.Keccak256AddressAndU256(event.CallbackAddress, event.Nonce) 118 | seed := new(big.Int).SetBytes(seedBytes) 119 | actualSeedBytes := vrf.Keccak256Pair(seed, event.Raw.BlockHash.Big()) 120 | actualSeed := new(big.Int).SetBytes(actualSeedBytes) 121 | 122 | proof, err := s.vrfkey.GenerateProof(actualSeed) 123 | if err != nil { 124 | return err 125 | } 126 | 127 | proofWithWitnesses, err := proof.CalculateWitnesses() 128 | if err != nil { 129 | return err 130 | } 131 | 132 | key, err := crypto.HexToECDSA(s.privateKey) 133 | if err != nil { 134 | return fmt.Errorf("failed to parse private key: %v", err) 135 | } 136 | 137 | transactor, err := bind.NewKeyedTransactorWithChainID(key, big.NewInt(31337)) 138 | if err != nil { 139 | return fmt.Errorf("creating transactor: %w", err) 140 | } 141 | 142 | resultProof := bindings.VRFProof{ 143 | Pk: proofWithWitnesses.PublicKey, 144 | Gamma: proofWithWitnesses.Gamma, 145 | C: proofWithWitnesses.C, 146 | S: proofWithWitnesses.S, 147 | Seed: proofWithWitnesses.Seed, 148 | UWitness: proofWithWitnesses.UWitness, 149 | CGammaWitness: proofWithWitnesses.CGammaWitness, 150 | SHashWitness: proofWithWitnesses.SHashWitness, 151 | ZInv: proofWithWitnesses.ZInv, 152 | } 153 | 154 | resultRequest := bindings.VRFRequest{ 155 | Sender: event.Sender, 156 | Nonce: event.Nonce, 157 | OracleId: event.OracleId, 158 | NbWords: event.NbWords, 159 | RequestConfirmations: event.RequestConfirmations, 160 | CallbackGasLimit: event.CallbackGasLimit, 161 | CallbackAddress: event.CallbackAddress, 162 | CallbackSelector: [4]byte(event.CallbackSelector), 163 | BlockNumber: event.Raw.BlockNumber, 164 | } 165 | 166 | tx, err := s.vrfCoordinator.FulfillRandomWords(transactor, resultProof, resultRequest) 167 | if err != nil { 168 | return fmt.Errorf("fulfilling randomness: %w", err) 169 | } 170 | fmt.Printf("> tx: %+v\n", tx.Hash().Hex()) 171 | 172 | return nil 173 | } 174 | -------------------------------------------------------------------------------- /packages/prover/vrf/utils.go: -------------------------------------------------------------------------------- 1 | package vrf 2 | 3 | import ( 4 | "math/big" 5 | 6 | "github.com/ethereum/go-ethereum/common" 7 | "github.com/ethereum/go-ethereum/crypto" 8 | "github.com/umbracle/ethgo/abi" 9 | ) 10 | 11 | func Keccak256Pair(a *big.Int, b *big.Int) []byte { 12 | type Value struct { 13 | A *big.Int 14 | B *big.Int 15 | } 16 | typ := abi.MustNewType("tuple(uint256 a, uint256 b)") 17 | value := &Value{ 18 | a, 19 | b, 20 | } 21 | encoded, err := typ.Encode(value) 22 | if err != nil { 23 | panic(err) 24 | } 25 | return crypto.Keccak256(encoded) 26 | } 27 | 28 | func Keccak256AddressAndU256(a common.Address, b *big.Int) []byte { 29 | type Value struct { 30 | A common.Address 31 | B *big.Int 32 | } 33 | typ := abi.MustNewType("tuple(address a, uint256 b)") 34 | value := &Value{ 35 | a, 36 | b, 37 | } 38 | encoded, err := typ.Encode(value) 39 | if err != nil { 40 | panic(err) 41 | } 42 | return crypto.Keccak256(encoded) 43 | } 44 | -------------------------------------------------------------------------------- /packages/prover/vrf/vrf.go: -------------------------------------------------------------------------------- 1 | package vrf 2 | 3 | import ( 4 | "fmt" 5 | "math/big" 6 | 7 | "github.com/ethereum/go-ethereum/common" 8 | "github.com/ethereum/go-ethereum/crypto" 9 | "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/vrfkey" 10 | "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" 11 | "github.com/smartcontractkit/chainlink/v2/core/services/vrf/proof" 12 | ) 13 | 14 | type VRFPublicKeyUncompressed struct { 15 | X *big.Int 16 | Y *big.Int 17 | } 18 | 19 | type VRFKey struct { 20 | vrfkey vrfkey.KeyV2 21 | } 22 | 23 | type VRFProof struct { 24 | proof vrfkey.Proof 25 | } 26 | 27 | type VRFProofWithWitnesses struct { 28 | PublicKey [2]*big.Int 29 | Gamma [2]*big.Int 30 | C *big.Int 31 | S *big.Int 32 | Seed *big.Int 33 | UWitness common.Address 34 | CGammaWitness [2]*big.Int 35 | SHashWitness [2]*big.Int 36 | ZInv *big.Int 37 | } 38 | 39 | func NewSecp256k1VRFKey(privateKey string) (*VRFKey, error) { 40 | ecdsaKey, err := crypto.HexToECDSA(privateKey) 41 | if err != nil { 42 | return nil, fmt.Errorf("failed to convert private key to ECDSA key") 43 | } 44 | secretKeyBytes := ecdsaKey.D.Bytes() 45 | vrfkey := VRFKey{ 46 | vrfkey: vrfkey.Raw(secretKeyBytes).Key(), 47 | } 48 | return &vrfkey, nil 49 | } 50 | 51 | func (k *VRFKey) GenerateProof(seed *big.Int) (VRFProof, error) { 52 | proof, err := k.vrfkey.GenerateProof(seed) 53 | return VRFProof{proof}, err 54 | } 55 | 56 | func (k *VRFKey) OracleAddress() common.Address { 57 | return k.vrfkey.PublicKey.Address() 58 | } 59 | 60 | func (k *VRFKey) OracleId() ([]byte, error) { 61 | proof, err := k.GenerateProof(big.NewInt(1)) 62 | if err != nil { 63 | return nil, err 64 | } 65 | 66 | x, y := secp256k1.Coordinates(proof.proof.PublicKey) 67 | oracleId := Keccak256Pair(x, y) 68 | 69 | return oracleId, nil 70 | } 71 | 72 | func (p *VRFProof) VerifyProof() (bool, error) { 73 | return p.proof.VerifyVRFProof() 74 | } 75 | 76 | func (p *VRFProof) CalculateWitnesses() (*VRFProofWithWitnesses, error) { 77 | solidityProof, err := proof.SolidityPrecalculations(&p.proof) 78 | if err != nil { 79 | return nil, err 80 | } 81 | 82 | pubkeyX, pubkeyY := secp256k1.Coordinates(solidityProof.P.PublicKey) 83 | gammaX, gammaY := secp256k1.Coordinates(solidityProof.P.Gamma) 84 | c := solidityProof.P.C 85 | s := solidityProof.P.S 86 | seed := solidityProof.P.Seed 87 | uWitness := solidityProof.UWitness 88 | cGammaWitnessX, cGammaWitnessY := secp256k1.Coordinates(solidityProof.CGammaWitness) 89 | sHashWitnessX, sHashWitnessY := secp256k1.Coordinates(solidityProof.SHashWitness) 90 | zInv := solidityProof.ZInv 91 | 92 | return &VRFProofWithWitnesses{ 93 | PublicKey: [2]*big.Int{pubkeyX, pubkeyY}, 94 | Gamma: [2]*big.Int{gammaX, gammaY}, 95 | C: c, 96 | S: s, 97 | Seed: seed, 98 | UWitness: uWitness, 99 | CGammaWitness: [2]*big.Int{cGammaWitnessX, cGammaWitnessY}, 100 | SHashWitness: [2]*big.Int{sHashWitnessX, sHashWitnessY}, 101 | ZInv: zInv, 102 | }, nil 103 | } 104 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - packages/* 3 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | # Load the enviroment variables. 2 | source .env 3 | 4 | # Choose what private key and whether to use the mock vrf coordinator for contract deployments. 5 | echo "" > packages/example-contracts/.env 6 | echo "PRIVATE_KEY=$PRIVATE_KEY" >> packages/example-contracts/.env 7 | echo "USE_MOCK=$USE_MOCK" >> packages/example-contracts/.env 8 | 9 | # Run the prover. 10 | if [ "$USE_MOCK" == "false" ] 11 | then 12 | pnpm concurrently -n contracts,client,prover -c cyan,magenta,blue \ 13 | "cd packages/example-contracts && pnpm run dev" \ 14 | "cd packages/example-client && pnpm run dev" \ 15 | "cd packages/prover && VRF_JSON_PATH=$VRF_JSON_PATH RPC_URL=$RPC_URL PRIVATE_KEY=$PRIVATE_KEY pnpm run dev" 16 | else 17 | pnpm concurrently -n contracts,client,mock-prover -c cyan,magenta,blue \ 18 | "cd packages/example-contracts && pnpm run dev" \ 19 | "cd packages/example-client && pnpm run dev" \ 20 | "cd packages/mock-prover && VRF_JSON_PATH=$VRF_JSON_PATH RPC_URL=$RPC_URL PRIVATE_KEY=$PRIVATE_KEY pnpm run dev" 21 | fi --------------------------------------------------------------------------------