generated from ethereum-optimism/scaffold-op
-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
34b754c
commit aa89bab
Showing
11 changed files
with
2,065 additions
and
196 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity >=0.8.0 <0.9.0; | ||
|
||
/** | ||
* @title World | ||
* @dev World struct | ||
*/ | ||
struct World { | ||
string vibe; | ||
string gameMasterName; | ||
string gameMasterTwitterHandle; | ||
string description; | ||
uint256 time; | ||
address gameMasterAddress; | ||
} | ||
|
||
/** | ||
* @title BuyMeACeptorWorld | ||
* @dev BuyMeACeptorWorld contract to accept donations and for our users to create a world for us | ||
*/ | ||
contract BuyMeACeptor{ | ||
address payable public owner; | ||
uint256 public price; | ||
World[] public worlds; | ||
|
||
error InsufficientFunds(); | ||
error InvalidArguments(string message); | ||
error OnlyOwner(); | ||
|
||
event BuyMeACeptorWorldEvent(address indexed buyer, uint256 price); | ||
event NewWorld(address indexed gameMasterAddress, uint256 time, string vibe, string gameMasterName, string gameMasterTwitterHandle, string description); | ||
|
||
constructor() { | ||
owner = payable(msg.sender); | ||
price = 0.0001 ether; | ||
} | ||
|
||
/** | ||
* WRITE FUNCTIONS ************* | ||
*/ | ||
|
||
/** | ||
* @dev Function to buy a world | ||
* @param gameMasterName The name of the game master | ||
* @param gameMasterTwitterHandle The Twitter handle of the game master | ||
* @param description The description of the world | ||
* (Note: Using calldata for gas efficiency) | ||
*/ | ||
function buyWorld(string calldata vibe, string calldata gameMasterName, string calldata gameMasterTwitterHandle, string calldata description) public payable { | ||
if (msg.value < price) { | ||
revert InsufficientFunds(); | ||
} | ||
|
||
emit BuyMeACeptorWorldEvent(msg.sender, msg.value); | ||
|
||
if (bytes(gameMasterName).length == 0 && bytes(description).length == 0) { | ||
revert InvalidArguments("Invalid gameMasterName or description"); | ||
} | ||
|
||
worlds.push(World(vibe, gameMasterName, gameMasterTwitterHandle, description, block.timestamp, msg.sender)); | ||
|
||
emit NewWorld(msg.sender, block.timestamp, vibe, gameMasterName, gameMasterTwitterHandle, description); | ||
} | ||
|
||
/** | ||
* @dev Function to remove a world | ||
* @param index The index of the world | ||
*/ | ||
function removeWorld(uint256 index) public { | ||
if (index >= worlds.length) { | ||
revert InvalidArguments("Invalid index"); | ||
} | ||
|
||
World memory world = worlds[index]; | ||
|
||
// if operation isnt sent from the same game master or the owner, then not allowed | ||
if (world.gameMasterAddress != msg.sender && msg.sender != owner) { | ||
revert InvalidArguments("Operation not allowed"); | ||
} | ||
|
||
World memory indexWorld = worlds[index]; | ||
worlds[index] = worlds[worlds.length - 1]; | ||
worlds[worlds.length - 1] = indexWorld; | ||
worlds.pop(); | ||
} | ||
|
||
/** | ||
* @dev Function to modify a world description | ||
* @param index The index of the world | ||
* @param description The description of the world | ||
*/ | ||
function modifyWorldDescription(uint256 index, string memory description) public { | ||
if (index >= worlds.length) { | ||
revert InvalidArguments("Invalid index"); | ||
} | ||
|
||
World memory world = worlds[index]; | ||
|
||
if (world.gameMasterAddress != msg.sender || msg.sender != owner) { | ||
revert InvalidArguments("Operation not allowed"); | ||
} | ||
|
||
worlds[index].description = description; | ||
} | ||
|
||
/** | ||
* @dev Function to withdraw the balance | ||
*/ | ||
function withdrawTips() public { | ||
if (msg.sender != owner) { | ||
revert OnlyOwner(); | ||
} | ||
|
||
if (address(this).balance == 0) { | ||
revert InsufficientFunds(); | ||
} | ||
|
||
(bool sent,) = owner.call{value: address(this).balance}(""); | ||
require(sent, "Failed to send Ether"); | ||
} | ||
|
||
/** | ||
* READ FUNCTIONS ************* | ||
*/ | ||
|
||
/** | ||
* @dev Function to get the worlds | ||
*/ | ||
function getWorlds() public view returns (World[] memory) { | ||
return worlds; | ||
} | ||
|
||
/** | ||
* @dev Recieve function to accept ether | ||
*/ | ||
receive() external payable {} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.19; | ||
|
||
import "@openzeppelin/contracts/access/Ownable.sol"; | ||
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; | ||
import "@chainlink/contracts/src/v0.8/vrf/VRFConsumerBaseV2.sol"; | ||
|
||
contract CeptorCharacterSheets is ERC721URIStorage, VRFConsumerBaseV2, Ownable { | ||
struct Stats { | ||
uint8 strength; | ||
uint8 dexterity; | ||
uint8 constitution; | ||
uint8 intelligence; | ||
uint8 wisdom; | ||
uint8 charisma; | ||
uint8 luck; | ||
} | ||
|
||
struct Character { | ||
Stats stats; | ||
string name; | ||
uint swapsLeft; | ||
} | ||
|
||
mapping(address => uint256) public ownerToTokenId; | ||
mapping(uint256 => Character) public tokenIdToCharacter; | ||
|
||
uint256 public tokenIdCounter; | ||
bytes32 public keyHash; | ||
uint256 public fee; | ||
uint64 public subscriptionId; | ||
|
||
event CharacterCreated(uint256 indexed tokenId, address owner); | ||
event StatsSwapped(uint256 indexed tokenId, address owner); | ||
|
||
constructor( | ||
address vrfCoordinator, | ||
address linkToken, | ||
bytes32 _keyHash, | ||
uint64 _subscriptionId | ||
) | ||
VRFConsumerBaseV2(vrfCoordinator) | ||
ERC721("CeptorCharacterSheets", "CCS") | ||
{ | ||
keyHash = _keyHash; | ||
fee = 0.1 * 10**18; // Chainlink VRF fee | ||
subscriptionId = _subscriptionId; | ||
tokenIdCounter = 1; | ||
} | ||
|
||
function createCharacter(string memory name) external { | ||
require(ownerToTokenId[msg.sender] == 0, "Owner already has a character"); | ||
uint256 tokenId = tokenIdCounter++; | ||
ownerToTokenId[msg.sender] = tokenId; | ||
tokenIdToCharacter[tokenId] = Character({ | ||
name: name, | ||
stats: Stats(0, 0, 0, 0, 0, 0, 0), | ||
swapsLeft: 3 | ||
}); | ||
_safeMint(msg.sender, tokenId); | ||
emit CharacterCreated(tokenId, msg.sender); | ||
requestStats(tokenId); | ||
} | ||
|
||
function requestStats(uint256 tokenId) internal { | ||
require(LINK.balanceOf(address(this)) >= fee, "Not enough LINK"); | ||
requestRandomWords(keyHash, subscriptionId, 3, fee, 1); | ||
} | ||
|
||
function fulfillRandomWords(uint256, uint256[] memory randomWords) internal override { | ||
uint256 tokenId = ownerToTokenId[msg.sender]; | ||
Character storage character = tokenIdToCharacter[tokenId]; | ||
character.stats.strength = uint8(randomWords[0] % 16 + 3); | ||
character.stats.dexterity = uint8(randomWords[1] % 16 + 3); | ||
character.stats.constitution = uint8(randomWords[2] % 16 + 3); | ||
character.stats.intelligence = uint8(randomWords[3] % 16 + 3); | ||
character.stats.wisdom = uint8(randomWords[4] % 16 + 3); | ||
character.stats.charisma = uint8(randomWords[5] % 16 + 3); | ||
character.stats.luck = uint8(randomWords[6] % 16 + 3); | ||
} | ||
|
||
function swapStats(uint256 tokenId) external { | ||
require(ownerOf(tokenId) == msg.sender, "Not the owner"); | ||
Character storage character = tokenIdToCharacter[tokenId]; | ||
require(character.swapsLeft > 0, "No swaps left"); | ||
character.swapsLeft--; | ||
requestStats(tokenId); | ||
emit StatsSwapped(tokenId, msg.sender); | ||
} | ||
} |
Oops, something went wrong.