feat: finish challenge
Some checks failed
Lint / ci (lts/*, ubuntu-latest) (push) Has been cancelled

This commit is contained in:
han
2026-01-21 20:39:51 +07:00
parent 2acc4d2eae
commit b241a84555
12 changed files with 1175 additions and 19 deletions

View File

@@ -11,6 +11,9 @@ contract RiggedRoll is Ownable {
/////////////////
// Errors go here...
error NotEnoughETH(uint256 required, uint256 available);
error NotWinningRoll(uint256 roll);
error InsufficientBalance(uint256 requested, uint256 available);
//////////////////////
/// State Variables //
@@ -31,4 +34,29 @@ contract RiggedRoll is Ownable {
///////////////////
// Functions go here...
function riggedRoll() public {
uint256 required = 0.002 ether;
uint256 balance = address(this).balance;
if (balance < required) revert NotEnoughETH(required, balance);
// calculate
bytes32 prevHash = blockhash(block.number - 1);
bytes32 hash = keccak256(abi.encodePacked(prevHash, address(diceGame), diceGame.nonce()));
uint256 roll = uint256(hash) % 16;
if (roll > 5) revert NotWinningRoll(roll);
diceGame.rollTheDice{value: required}();
}
function withdraw(address _addr, uint256 _amount) public onlyOwner {
uint256 balance = address(this).balance;
if (balance < _amount) revert InsufficientBalance(_amount, balance);
(bool sent,) = payable(_addr).call{value: _amount}("");
require(sent, "failed to transfer");
}
receive() external payable {}
}

View File

@@ -11,21 +11,21 @@ const deployRiggedRoll: DeployFunction = async function (hre: HardhatRuntimeEnvi
const diceGameAddress = await diceGame.getAddress();
// Uncomment to deploy RiggedRoll contract
// await deploy("RiggedRoll", {
// from: deployer,
// log: true,
// args: [diceGameAddress],
// autoMine: true,
// });
await deploy("RiggedRoll", {
from: deployer,
log: true,
args: [diceGameAddress],
autoMine: true,
});
// const riggedRoll: RiggedRoll = await ethers.getContract("RiggedRoll", deployer);
const riggedRoll: RiggedRoll = await ethers.getContract("RiggedRoll", deployer);
// Please replace the text "Your Address" with your own address.
// try {
// await riggedRoll.transferOwnership("Your Address");
// } catch (err) {
// console.log(err);
// }
try {
await riggedRoll.transferOwnership("0xD70D3fC875061A950d61cD5CDACb4aE4bF90608A");
} catch (err) {
console.log(err);
}
};
export default deployRiggedRoll;

View File

@@ -0,0 +1 @@
11155111

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -37,7 +37,7 @@ const config: HardhatUserConfig = {
},
],
},
defaultNetwork: "localhost",
defaultNetwork: "sepolia", //"localhost",
namedAccounts: {
deployer: {
// By default, it will take the first Hardhat account as the deployer

View File

@@ -150,7 +150,7 @@ const DiceGame: NextPage = () => {
<Amount amount={Number(riggedRollBalance?.formatted || 0)} showUsdPrice className="text-lg" />
</div>
</div>
{/* <button
<button
onClick={async () => {
if (!rolled) {
setRolled(true);
@@ -167,7 +167,7 @@ const DiceGame: NextPage = () => {
className="mt-2 btn btn-secondary btn-xl normal-case font-xl text-lg"
>
Rigged Roll!
</button> */}
</button>
<div className="flex mt-8">
{rolled ? (

View File

@@ -4,6 +4,569 @@
*/
import { GenericContractsDeclaration } from "~~/utils/scaffold-eth/contract";
const deployedContracts = {} as const;
const deployedContracts = {
31337: {
DiceGame: {
address: "0xc6e7DF5E7b4f2A278906862b61205850344D4e7d",
abi: [
{
inputs: [],
stateMutability: "payable",
type: "constructor",
},
{
inputs: [],
name: "NotEnoughEther",
type: "error",
},
{
anonymous: false,
inputs: [
{
indexed: true,
internalType: "address",
name: "player",
type: "address",
},
{
indexed: false,
internalType: "uint256",
name: "amount",
type: "uint256",
},
{
indexed: false,
internalType: "uint256",
name: "roll",
type: "uint256",
},
],
name: "Roll",
type: "event",
},
{
anonymous: false,
inputs: [
{
indexed: false,
internalType: "address",
name: "winner",
type: "address",
},
{
indexed: false,
internalType: "uint256",
name: "amount",
type: "uint256",
},
],
name: "Winner",
type: "event",
},
{
inputs: [],
name: "nonce",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "prize",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "rollTheDice",
outputs: [],
stateMutability: "payable",
type: "function",
},
{
stateMutability: "payable",
type: "receive",
},
],
inheritedFunctions: {},
deployedOnBlock: 11051,
},
RiggedRoll: {
address: "0x59b670e9fA9D0A427751Af201D676719a970857b",
abi: [
{
inputs: [
{
internalType: "address payable",
name: "diceGameAddress",
type: "address",
},
],
stateMutability: "nonpayable",
type: "constructor",
},
{
inputs: [
{
internalType: "uint256",
name: "requested",
type: "uint256",
},
{
internalType: "uint256",
name: "available",
type: "uint256",
},
],
name: "InsufficientBalance",
type: "error",
},
{
inputs: [
{
internalType: "uint256",
name: "required",
type: "uint256",
},
{
internalType: "uint256",
name: "available",
type: "uint256",
},
],
name: "NotEnoughETH",
type: "error",
},
{
inputs: [
{
internalType: "uint256",
name: "roll",
type: "uint256",
},
],
name: "NotWinningRoll",
type: "error",
},
{
inputs: [
{
internalType: "address",
name: "owner",
type: "address",
},
],
name: "OwnableInvalidOwner",
type: "error",
},
{
inputs: [
{
internalType: "address",
name: "account",
type: "address",
},
],
name: "OwnableUnauthorizedAccount",
type: "error",
},
{
anonymous: false,
inputs: [
{
indexed: true,
internalType: "address",
name: "previousOwner",
type: "address",
},
{
indexed: true,
internalType: "address",
name: "newOwner",
type: "address",
},
],
name: "OwnershipTransferred",
type: "event",
},
{
inputs: [],
name: "diceGame",
outputs: [
{
internalType: "contract DiceGame",
name: "",
type: "address",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "owner",
outputs: [
{
internalType: "address",
name: "",
type: "address",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "renounceOwnership",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [],
name: "riggedRoll",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "address",
name: "newOwner",
type: "address",
},
],
name: "transferOwnership",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "address",
name: "_addr",
type: "address",
},
{
internalType: "uint256",
name: "_amount",
type: "uint256",
},
],
name: "withdraw",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
stateMutability: "payable",
type: "receive",
},
],
inheritedFunctions: {
owner: "@openzeppelin/contracts/access/Ownable.sol",
renounceOwnership: "@openzeppelin/contracts/access/Ownable.sol",
transferOwnership: "@openzeppelin/contracts/access/Ownable.sol",
},
deployedOnBlock: 11052,
},
},
11155111: {
DiceGame: {
address: "0x6a1e81b3882dCFAef90c546d4bF6066026021E62",
abi: [
{
inputs: [],
stateMutability: "payable",
type: "constructor",
},
{
inputs: [],
name: "NotEnoughEther",
type: "error",
},
{
anonymous: false,
inputs: [
{
indexed: true,
internalType: "address",
name: "player",
type: "address",
},
{
indexed: false,
internalType: "uint256",
name: "amount",
type: "uint256",
},
{
indexed: false,
internalType: "uint256",
name: "roll",
type: "uint256",
},
],
name: "Roll",
type: "event",
},
{
anonymous: false,
inputs: [
{
indexed: false,
internalType: "address",
name: "winner",
type: "address",
},
{
indexed: false,
internalType: "uint256",
name: "amount",
type: "uint256",
},
],
name: "Winner",
type: "event",
},
{
inputs: [],
name: "nonce",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "prize",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "rollTheDice",
outputs: [],
stateMutability: "payable",
type: "function",
},
{
stateMutability: "payable",
type: "receive",
},
],
inheritedFunctions: {},
deployedOnBlock: 10090400,
},
RiggedRoll: {
address: "0x07907676103D88d238181c17342F5Da40f5c96ac",
abi: [
{
inputs: [
{
internalType: "address payable",
name: "diceGameAddress",
type: "address",
},
],
stateMutability: "nonpayable",
type: "constructor",
},
{
inputs: [
{
internalType: "uint256",
name: "requested",
type: "uint256",
},
{
internalType: "uint256",
name: "available",
type: "uint256",
},
],
name: "InsufficientBalance",
type: "error",
},
{
inputs: [
{
internalType: "uint256",
name: "required",
type: "uint256",
},
{
internalType: "uint256",
name: "available",
type: "uint256",
},
],
name: "NotEnoughETH",
type: "error",
},
{
inputs: [
{
internalType: "uint256",
name: "roll",
type: "uint256",
},
],
name: "NotWinningRoll",
type: "error",
},
{
inputs: [
{
internalType: "address",
name: "owner",
type: "address",
},
],
name: "OwnableInvalidOwner",
type: "error",
},
{
inputs: [
{
internalType: "address",
name: "account",
type: "address",
},
],
name: "OwnableUnauthorizedAccount",
type: "error",
},
{
anonymous: false,
inputs: [
{
indexed: true,
internalType: "address",
name: "previousOwner",
type: "address",
},
{
indexed: true,
internalType: "address",
name: "newOwner",
type: "address",
},
],
name: "OwnershipTransferred",
type: "event",
},
{
inputs: [],
name: "diceGame",
outputs: [
{
internalType: "contract DiceGame",
name: "",
type: "address",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "owner",
outputs: [
{
internalType: "address",
name: "",
type: "address",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "renounceOwnership",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [],
name: "riggedRoll",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "address",
name: "newOwner",
type: "address",
},
],
name: "transferOwnership",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "address",
name: "_addr",
type: "address",
},
{
internalType: "uint256",
name: "_amount",
type: "uint256",
},
],
name: "withdraw",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
stateMutability: "payable",
type: "receive",
},
],
inheritedFunctions: {
owner: "@openzeppelin/contracts/access/Ownable.sol",
renounceOwnership: "@openzeppelin/contracts/access/Ownable.sol",
transferOwnership: "@openzeppelin/contracts/access/Ownable.sol",
},
deployedOnBlock: 10090401,
},
},
} as const;
export default deployedContracts satisfies GenericContractsDeclaration;

View File

@@ -1,6 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
/// <reference path="./.next/types/routes.d.ts" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.

View File

@@ -15,7 +15,7 @@ export const DEFAULT_ALCHEMY_API_KEY = "cR4WnXePioePZ5fFrnSiR";
const scaffoldConfig = {
// The networks on which your DApp is live
targetNetworks: [chains.hardhat],
targetNetworks: [chains.sepolia], //chains.hardhat],
// The interval at which your front-end polls the RPC servers for new data (it has no effect if you only target the local network (default is 4000))
pollingInterval: 30000,
// This is ours Alchemy's default API key.
@@ -34,7 +34,7 @@ const scaffoldConfig = {
// It's recommended to store it in an env variable:
// .env.local for local testing, and in the Vercel/system env config for live apps.
walletConnectProjectId: process.env.NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID || "3a8170812b534d0ff9d794f19a901d64",
onlyLocalBurnerWallet: true,
onlyLocalBurnerWallet: false,
} as const satisfies ScaffoldConfig;
export default scaffoldConfig;