Skip to content

Commit

Permalink
πŸ€–πŸ”¬ ↝ Building out multitool helper contract for planet (#6 #18 #1)
Browse files Browse the repository at this point in the history
Also working on building out the frontend for #16 -> see Signal-K/Silfur#28 &
Signal-K/Silfur#26 & Signal-K/Silfur#24 &
Signal-K/Silfur#25 & Signal-K/Silfur#21 &
Signal-K/Silfur#22

Frontend components are being built out on the signal-k/client repo:
Signal-K/client#12

Contract: https://thirdweb.com/0xCdc5929e1158F7f0B320e3B942528E6998D8b25c/PlanetHelper, https://www.notion.so/skinetics/Sample-Planets-Contract-4c3bdcbca4b9450382f9cc4e72e081f7#73801895fc5a421bbf57801a33a775c7

Claiming mints:
```sol
function verifyClaim(
    address _claimer,
    uint256 _tokenId,
    uint256 _quantity
) public view override {
    require (_tokenId == 0, 'Only first NFT is claimable');
    require (_quantity == 1, 'Only 1 NFT can be claimed at a time');
}
```

Multitool base documentation: https://skinetics.notion.site/Planet-Mining-multitool-8310fa1cd188440688bbcc19692b3b67

Contract README:
> # Planets
>
>
> ## Confirmed Planets Contract
>
> Documentation: [https://skinetics.notion.site/Sample-Planets-Contract-4c3bdcbca4b9450382f9cc4e72e081f7](https://www.notion.so/Sample-Planets-Contract-4c3bdcbca4b9450382f9cc4e72e081f7)
>
> - User mints an anomaly that has appeared in their UI (for now, the webapp, later it will be the game as well)
> - API searches for a token that has already been lazy minted with the TIC id of the anomaly (or the identifier of the candidate)
>     - If there is a token id that has the TIC Id, then claim a copy of that to the `msg.sender` (player’s address) so they can manipulate it in-game
>     - If the TIC ID has never been minted before, lazy mint a new one with parameters fetched from the data source and send it to `msg.sender`
>     - Return the IPFS metadata
> - Add some buttons that allow manipulations for the NFT (e.g. viewing (reading) metadata (e.g. image/video files, graphs).
>     - Graphs should be generated in a Jupyter notebook and returned in the Next app.
> - User creates post (proposal [Proposal Board β†’ Migration from Vite](https://www.notion.so/Proposal-Board-Migration-from-Vite-2e3ef95e384d4ac1875e0dbbe9a59337)) with the NFT ID for their anomaly and some extra metadata for their discoveries and proposal, and then users can vote
>
> ## Planet/Node candidates
>
> (Where node refers to any type/class/collection of object that is part of the classification process. E.g. the TESS planets collection, mining/seismic data collection, etc)
> Simple flow: Contract for unconfirmed planet β†’ created via Deepnote flask
> Once confirmed β†’ lazy mint on existing goerli contract
> Mining multitool helper
>
> # PlanetContractAddress
>
> Address for the collection of planets/node candidates that have been confirmed and lazy-minted.
> The process for this in the Star Sailors wrapper is as follows:
>
> 1. Player mints an anomaly, which is an ERC1155 drop that is lazy-minted. The player requests a new planet, a random TIC id is assigned, our Flask API on Deepnote searches for an NFT in the first drop with that TIC ID. If none is found, a new NFT is lazy minted on that collection with data from the Lightkurve python module.
> 2. User/Player then has a candidate (unconfirmed node object) in their wallet and on the web application frontend, they're redirected to a special planet `{...id}` page where they can interact with and view the candidate.
> 3. Once the user has made a decision as to the status of the node candidate, they then create a Proposal (first on the [threaded comments via Supabase](https://www.notion.so/Threaded-Comments-8374255ed9314473b044db150fb13c36) and then on [Lens](https://github.com/signal-k/client)). The contents of this proposal are [outlined here](https://www.notion.so/Threaded-Comments-8374255ed9314473b044db150fb13c36).
> 4. An NFT of this proposal is minted and then a new NFT is lazy minted from [this collection](notion://www.notion.so/skinetics/0xdf35Bb26d9AAD05EeC5183c6288f13c0136A7b43) (**note -> this is a demo. Will be updated). This new lazy-minted NFT will contain a link to the candidate node the proposal was created from, the proposal, and all the traits the user has filled in for the node once they have been cross-referenced with the proposal, voters and the python module that has the dataset (in this case, Lightkurve on Deepnote). This collection is the one referenced to in this contract (`planetNftCollectionAddress`). This planet can then have actions performed on it and rewards/items generated via [the minerals contract](notion://www.notion.so/skinetics/0xE938775F4ee4913470905885c9744C7FAD482991).

Threads docs: https://skinetics.notion.site/Threaded-Comments-8374255ed9314473b044db150fb13c36
  • Loading branch information
Gizmotronn committed Jan 14, 2023
1 parent c77311e commit e94b60e
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 11 deletions.
Binary file added Classify/contracts/.PlanetHelper.sol.swp
Binary file not shown.
83 changes: 83 additions & 0 deletions Classify/contracts/PlanetHelper.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.11;

// Import thirdweb contracts
import "@thirdweb-dev/contracts/drop/DropERC1155.sol"; // For my collection of Pickaxes
import "@thirdweb-dev/contracts/token/TokenERC20.sol"; // For my ERC-20 Token contract
import "@thirdweb-dev/contracts/openzeppelin-presets/utils/ERC1155/ERC1155Holder.sol"; // For my ERC-1155 Receiver contract
/* Extra metadata/tags contracts (no function)
import "@thirdweb-dev/contracts/drop/ERC721.sol";
import "@thirdweb-dev/contracts/drop/ERC20.sol";
import "@thirdweb-dev/contracts/token/Token721.sol";*/


// OpenZeppelin (ReentrancyGuard)
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

contract PlanetHelper is ReentrancyGuard, ERC1155Holder {
DropERC1155 public immutable planetNFTCollection; // Edition drop for the planets (terminology & game item may change around...e.g. PlanetHelper or planetNFTCollection may become a pickaxe/mining bot)
TokenERC20 public immutable rewardsToken; // Starting off with rewarding Minerals to the user - more resource types will be added

// Metadata deeplinks (taken out of constructor)
string public classificationContractArchive = 'goerli/0xed6e837Fda815FBf78E8E7266482c5Be80bC4bF9'; // Archived version of the classification proposal contract on the Mumbai testnet. Used for archival purposes
string public jupyterNotebook = 'https://deepnote.com/workspace/star-sailors-49d2efda-376f-4329-9618-7f871ba16007/project/Star-Sailors-Light-Curve-Plot-b4c251b4-c11a-481e-8206-c29934eb75da/notebook/Light%20Curve%20Demo-0c60a045940145ba950f2c0e51cac7c1'; // Deeplink to a copy of the Deepnote notebook
string public jupyterNftTagId = 'goerli/0xdf35Bb26d9AAD05EeC5183c6288f13c0136A7b43/1'; // Deep link to a goerli NFT with some metadata relevant to the jupyterNotebook
// This contract is a 'helper', aka multitool provider for your planets in the Star Sailors game. Using this contract, you'll be able to perform different actions on the planets in your inventory, such as mining, building & customising the terrain and life. More documentation is available on Notion at https://skinetics.notion.site/421c898e3583496bb9dc950e3150b8d0?v=db85a572b6c5409e998451318d6b5187 and on our Github -> https://github.com/signal-k/sytizen

constructor(DropERC1155 planetNFTCollectionAddress, TokenERC20 mineralsTokenAddress) {
planetNFTCollection = planetNFTCollectionAddress;
rewardsToken = mineralsTokenAddress; // For this helper function, minerals will be the primary resource (later this trait on the planet nft will determine whcib of the Helpers is called (each helper will have different rewards))
}

struct MapValue {
bool isData; // Is being staked?
uint256 value; // Token id being staked
}

// Map the player address to their current "helper" item
mapping (address => MapValue) public playerHelper; // TokenID of helper (type of mining/gathering tool) is the reward multiplier. This here lists the type of tool the user is using
mapping (address => MapValue) public playerLastUpdate; // Map the address to the time they last claimed/staked/withdrew. Default state is null -> not in the mapping. { is there a value, timestamp of last action}

function stake (uint256 _tokenId) external nonReentrant {
require (planetNFTCollection.balanceOf(msg.sender, _tokenId) >= 1, "You must have at least one planet to stake");
if (playerHelper[msg.sender].isData) { // If the user has a helper that is already staked : send it back to address (unstake)
planetNFTCollection.safeTransferFrom(address(this), msg.sender, playerHelper[msg.sender].value, 1, "Returning your old helper item");
}

uint256 reward = calculateRewards(msg.sender); // Calculate the rewards owed to the address
rewardsToken.transfer(msg.sender, reward);

planetNFTCollection.safeTransferFrom(msg.sender, address(this), _tokenId, 1, "Staking your planet"); // Actual statement that transfers the nft from the user to this staking contract to begin staking
playerHelper[msg.sender].value = _tokenId; // Update the mapping for the helper NFT once it's been staked
playerHelper[msg.sender].isData = true;
playerLastUpdate[msg.sender].value = block.timestamp; // Update the mapping for the playerLastUpdate tag. It's set to the current time (and we can use that and the state of the nft to calculate rewards)
playerLastUpdate[msg.sender].isData = true;
}

function withdraw () external nonReentrant {
require(playerHelper[msg.sender].isData, "You do not have a helper staked to withdraw"); // The user can't execute this function if they aren't staking anything
uint256 reward = calculateRewards(msg.sender);
rewardsToken.transfer(msg.sender, reward);
planetNFTCollection.safeTransferFrom(address(this), msg.sender, playerHelper[msg.sender].value, 1, "Transferring your previously staked nft to your wallet");
playerHelper[msg.sender].isData = false; // Update the helper mapping
playerLastUpdate[msg.sender].isData = true; // There's been a new update -> so update the mapping
playerLastUpdate[msg.sender].value = block.timestamp;
}

function claim () external nonReentrant {
uint256 reward = calculateRewards(msg.sender);
rewardsToken.transfer(msg.sender, reward);
playerLastUpdate[msg.sender].isData = true; // Update mappings for last event for player
playerLastUpdate[msg.sender].value = block.timestamp;
}

function calculateRewards (address _player) public view returns (uint256 _rewards) { // 20,000,000 rewards/minerals per block. Uses block.timestamp & playerLastUpdate. Requires the player to have staked a helper item
if (!playerLastUpdate[_player].isData || !playerHelper[_player].isData) { // Either nothing is being staked, or the player hasn't ever staked/edited their stake items
return 0; // No rewards are owed to the player/address
}

uint256 timeDifference = block.timestamp - playerLastUpdate[_player].value; // Time difference between now and when the last action on their helper occured
uint256 rewards = timeDifference * 10_000_000_000_000 * (playerHelper[_player].value + 1); // If there is a higher level helper (see the evolution stage), the reward is greater
return rewards;
}
}
2 changes: 1 addition & 1 deletion Classify/hardhat.config.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/** @type import('hardhat/config').HardhatUserConfig */
module.exports = {
solidity: {
version: '0.8.9',
version: '0.8.11',
defaultNetwork: 'goerli',
networks: {
hardhat: {},
Expand Down
3 changes: 2 additions & 1 deletion Classify/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
"release": "npx thirdweb@latest release"
},
"devDependencies": {
"hardhat": "^2.10.1"
"hardhat": "^2.12.6"
},
"dependencies": {
"@openzeppelin/contracts-upgradeable": "^4.8.1",
"@thirdweb-dev/contracts": "^3",
"dotenv": "^16.0.3"
}
Expand Down
23 changes: 14 additions & 9 deletions Classify/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,11 @@
"@nomicfoundation/solidity-analyzer-win32-ia32-msvc" "0.1.0"
"@nomicfoundation/solidity-analyzer-win32-x64-msvc" "0.1.0"

"@openzeppelin/contracts-upgradeable@^4.8.1":
version "4.8.1"
resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-4.8.1.tgz#363f7dd08f25f8f77e16d374350c3d6b43340a7a"
integrity sha512-1wTv+20lNiC0R07jyIAbHU7TNHKRwGiTGRfiNnA8jOWjKT98g5OgLpYWOi40Vgpk8SPLA9EvfJAbAeIyVn+7Bw==

"@scure/base@~1.1.0":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.1.tgz#ebb651ee52ff84f420097055f4bf46cfba403938"
Expand Down Expand Up @@ -1230,10 +1235,10 @@ graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9:
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c"
integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==

hardhat@^2.10.1:
version "2.12.4"
resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.12.4.tgz#e539ba58bee9ba1a1ced823bfdcec0b3c5a3e70f"
integrity sha512-rc9S2U/4M+77LxW1Kg7oqMMmjl81tzn5rNFARhbXKUA1am/nhfMJEujOjuKvt+ZGMiZ11PYSe8gyIpB/aRNDgw==
hardhat@^2.12.6:
version "2.12.6"
resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.12.6.tgz#ea3c058bbd81850867389d10f76037cfa52a0019"
integrity sha512-0Ent1O5DsPgvaVb5sxEgsQ3bJRt/Ex92tsoO+xjoNH2Qc4bFmhI5/CHVlFikulalxOPjNmw5XQ2vJFuVQFESAA==
dependencies:
"@ethersproject/abi" "^5.1.2"
"@metamask/eth-sig-util" "^4.0.0"
Expand Down Expand Up @@ -1282,7 +1287,7 @@ hardhat@^2.10.1:
source-map-support "^0.5.13"
stacktrace-parser "^0.1.10"
tsort "0.0.1"
undici "^5.4.0"
undici "^5.14.0"
uuid "^8.3.2"
ws "^7.4.6"

Expand Down Expand Up @@ -2090,10 +2095,10 @@ type-fest@^0.7.1:
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.7.1.tgz#8dda65feaf03ed78f0a3f9678f1869147f7c5c48"
integrity sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==

undici@^5.4.0:
version "5.14.0"
resolved "https://registry.yarnpkg.com/undici/-/undici-5.14.0.tgz#1169d0cdee06a4ffdd30810f6228d57998884d00"
integrity sha512-yJlHYw6yXPPsuOH0x2Ib1Km61vu4hLiRRQoafs+WUgX1vO64vgnxiCEN9dpIrhZyHFsai3F0AEj4P9zy19enEQ==
undici@^5.14.0:
version "5.15.0"
resolved "https://registry.yarnpkg.com/undici/-/undici-5.15.0.tgz#cb8437c43718673a8be59df0fdd4856ff6689283"
integrity sha512-wCAZJDyjw9Myv+Ay62LAoB+hZLPW9SmKbQkbHIhMw/acKSlpn7WohdMUc/Vd4j1iSMBO0hWwU8mjB7a5p5bl8g==
dependencies:
busboy "^1.6.0"

Expand Down

0 comments on commit e94b60e

Please sign in to comment.