Skip to content

Commit

Permalink
➕ Add MagicAnimalCarousel level
Browse files Browse the repository at this point in the history
  • Loading branch information
GianfrancoBazzani committed Nov 6, 2024
1 parent fecc2e5 commit 55a7c8e
Show file tree
Hide file tree
Showing 5 changed files with 201 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"abi":[{"type":"constructor","inputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"MAX_CAPACITY","inputs":[],"outputs":[{"name":"","type":"uint16","internalType":"uint16"}],"stateMutability":"view"},{"type":"function","name":"carousel","inputs":[{"name":"crateId","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"animalInside","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"changeAnimal","inputs":[{"name":"animal","type":"string","internalType":"string"},{"name":"crateId","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"currentCrateId","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"encodeAnimalName","inputs":[{"name":"animalName","type":"string","internalType":"string"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"pure"},{"type":"function","name":"setAnimalAndSpin","inputs":[{"name":"animal","type":"string","internalType":"string"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"error","name":"AnimalNameTooLong","inputs":[]},{"type":"error","name":"InvalidCarouselId","inputs":[]}],"bytecode":{"object":"0x6080604052348015600e575f5ffd5b505f805260016020527fa6eef7e35abe7026729641147f7915573c7e97b47efa546f5f6e3230263bcb498054600160a01b1890556104768061004f5f395ff3fe608060405234801561000f575f5ffd5b506004361061006f575f3560e01c8063932289cc1161004d578063932289cc146100bd57806393684bd4146100d2578063ab3b9224146100f1575f5ffd5b806326bad99e146100735780633a5ddf301461008e57806376997b75146100aa575b5f5ffd5b61007b5f5481565b6040519081526020015b60405180910390f35b61009761ffff81565b60405161ffff9091168152602001610085565b61007b6100b836600461032f565b610104565b6100d06100cb36600461036e565b61015f565b005b61007b6100e03660046103b6565b60016020525f908152604090205481565b6100d06100ff36600461032f565b610230565b5f600c82111561012757604051630b3d107360e01b815260040160405180910390fd5b60a0838360405160200161013c9291906103cd565b604051602081830303815290604052610154906103dc565b901c90505b92915050565b5f8181526001602052604090205473ffffffffffffffffffffffffffffffffffffffff1680156101aa573373ffffffffffffffffffffffffffffffffffffffff8216146101aa575f5ffd5b5f6101b58585610104565b905080156101f5575f83815260016020526040902080543375ffff000000000000000000000000000000000000000090911660a084901b17179055610229565b5f83815260016020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001690555b5050505050565b5f601061023d8484610104565b5f8054815260016020526040902054911c915060a01c61ffff1669ffffffffffffffffffff82111561028257604051630b3d107360e01b815260040160405180910390fd5b3360a061ffff610293846001610402565b61029d9190610421565b5f84815260016020526040812080547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff1660b09790971b969096189190921b179190911790925590555050565b5f5f83601f8401126102fa575f5ffd5b50813567ffffffffffffffff811115610311575f5ffd5b602083019150836020828501011115610328575f5ffd5b9250929050565b5f5f60208385031215610340575f5ffd5b823567ffffffffffffffff811115610356575f5ffd5b610362858286016102ea565b90969095509350505050565b5f5f5f60408486031215610380575f5ffd5b833567ffffffffffffffff811115610396575f5ffd5b6103a2868287016102ea565b909790965060209590950135949350505050565b5f602082840312156103c6575f5ffd5b5035919050565b818382375f9101908152919050565b805160208083015191908110156103fc575f198160200360031b1b821691505b50919050565b8082018082111561015957634e487b7160e01b5f52601160045260245ffd5b5f8261043b57634e487b7160e01b5f52601260045260245ffd5b50069056fea26469706673582212202b77bb2d0bcfdd47de499a5624f573379292b0c12cc5d6659d8fe015ef0e534164736f6c634300081c0033","sourceMap":"58:1969:2:-:0;;;529:54;;;;;;;;;-1:-1:-1;553:11:2;;;:8;:11;;;:23;;-1:-1:-1;;;553:23:2;;;58:1969;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x608060405234801561000f575f5ffd5b506004361061006f575f3560e01c8063932289cc1161004d578063932289cc146100bd57806393684bd4146100d2578063ab3b9224146100f1575f5ffd5b806326bad99e146100735780633a5ddf301461008e57806376997b75146100aa575b5f5ffd5b61007b5f5481565b6040519081526020015b60405180910390f35b61009761ffff81565b60405161ffff9091168152602001610085565b61007b6100b836600461032f565b610104565b6100d06100cb36600461036e565b61015f565b005b61007b6100e03660046103b6565b60016020525f908152604090205481565b6100d06100ff36600461032f565b610230565b5f600c82111561012757604051630b3d107360e01b815260040160405180910390fd5b60a0838360405160200161013c9291906103cd565b604051602081830303815290604052610154906103dc565b901c90505b92915050565b5f8181526001602052604090205473ffffffffffffffffffffffffffffffffffffffff1680156101aa573373ffffffffffffffffffffffffffffffffffffffff8216146101aa575f5ffd5b5f6101b58585610104565b905080156101f5575f83815260016020526040902080543375ffff000000000000000000000000000000000000000090911660a084901b17179055610229565b5f83815260016020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001690555b5050505050565b5f601061023d8484610104565b5f8054815260016020526040902054911c915060a01c61ffff1669ffffffffffffffffffff82111561028257604051630b3d107360e01b815260040160405180910390fd5b3360a061ffff610293846001610402565b61029d9190610421565b5f84815260016020526040812080547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff1660b09790971b969096189190921b179190911790925590555050565b5f5f83601f8401126102fa575f5ffd5b50813567ffffffffffffffff811115610311575f5ffd5b602083019150836020828501011115610328575f5ffd5b9250929050565b5f5f60208385031215610340575f5ffd5b823567ffffffffffffffff811115610356575f5ffd5b610362858286016102ea565b90969095509350505050565b5f5f5f60408486031215610380575f5ffd5b833567ffffffffffffffff811115610396575f5ffd5b6103a2868287016102ea565b909790965060209590950135949350505050565b5f602082840312156103c6575f5ffd5b5035919050565b818382375f9101908152919050565b805160208083015191908110156103fc575f198160200360031b1b821691505b50919050565b8082018082111561015957634e487b7160e01b5f52601160045260245ffd5b5f8261043b57634e487b7160e01b5f52601260045260245ffd5b50069056fea26469706673582212202b77bb2d0bcfdd47de499a5624f573379292b0c12cc5d6659d8fe015ef0e534164736f6c634300081c0033","sourceMap":"58:1969:2:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;360:29;;;;;;;;;160:25:5;;;148:2;133:18;360:29:2;;;;;;;;93:54;;131:16;93:54;;;;;370:6:5;358:19;;;340:38;;328:2;313:18;93:54:2;196:188:5;1794:231:2;;;;;;:::i;:::-;;:::i;1108:680::-;;;;;;:::i;:::-;;:::i;:::-;;395:64;;;;;;:::i;:::-;;;;;;;;;;;;;;589:513;;;;;;:::i;:::-;;:::i;1794:231::-;1869:7;1924:2;1896:30;;;1888:60;;;;-1:-1:-1;;;1888:60:2;;;;;;;;;;;;2014:3;1998:10;;1981:28;;;;;;;;;:::i;:::-;;;;;;;;;;;;;1973:37;;;:::i;:::-;:44;;;-1:-1:-1;1794:231:2;;;;;:::o;1108:680::-;1190:13;1222:17;;;:8;:17;;;;;;335;1222:30;1268:19;;1264:78;;1311:10;:19;;;;1303:28;;;;;;1351:21;1375:24;1392:6;;1375:16;:24::i;:::-;1351:48;-1:-1:-1;1413:18:2;;1409:373;;1539:17;;;;:8;:17;;;;;;;1583:10;259:32;1539;;;288:3;1514:20;;;1513:59;:81;1477:117;;1409:373;;;1722:17;;;;:8;:17;;;;;;;1743:26;1722:48;1702:69;;1409:373;1180:608;;1108:680;;;:::o;589:513::-;658:21;710:2;682:24;699:6;;682:16;:24::i;:::-;722:19;754:14;;745:24;;:8;:24;;;;;;682:30;;;-1:-1:-1;789:3:2;744:48;267:16;744:48;836:16;811:42;;;803:72;;;;-1:-1:-1;;;803:72:2;;;;;;;;;;;;1045:10;1031:3;131:16;995:15;:11;1009:1;995:15;:::i;:::-;994:32;;;;:::i;:::-;910:21;;;;:8;:21;;;;;;;934:13;910:37;969:8;952:25;;;;909:69;;;;993:41;;;;909:125;:147;;;;885:171;;;1067:28;;-1:-1:-1;;589:513:2:o;389:348:5:-;441:8;451:6;505:3;498:4;490:6;486:17;482:27;472:55;;523:1;520;513:12;472:55;-1:-1:-1;546:20:5;;589:18;578:30;;575:50;;;621:1;618;611:12;575:50;658:4;650:6;646:17;634:29;;710:3;703:4;694:6;686;682:19;678:30;675:39;672:59;;;727:1;724;717:12;672:59;389:348;;;;;:::o;742:411::-;813:6;821;874:2;862:9;853:7;849:23;845:32;842:52;;;890:1;887;880:12;842:52;930:9;917:23;963:18;955:6;952:30;949:50;;;995:1;992;985:12;949:50;1034:59;1085:7;1076:6;1065:9;1061:22;1034:59;:::i;:::-;1112:8;;1008:85;;-1:-1:-1;742:411:5;-1:-1:-1;;;;742:411:5:o;1158:525::-;1238:6;1246;1254;1307:2;1295:9;1286:7;1282:23;1278:32;1275:52;;;1323:1;1320;1313:12;1275:52;1363:9;1350:23;1396:18;1388:6;1385:30;1382:50;;;1428:1;1425;1418:12;1382:50;1467:59;1518:7;1509:6;1498:9;1494:22;1467:59;:::i;:::-;1545:8;;1441:85;;-1:-1:-1;1649:2:5;1634:18;;;;1621:32;;1158:525;-1:-1:-1;;;;1158:525:5:o;1688:226::-;1747:6;1800:2;1788:9;1779:7;1775:23;1771:32;1768:52;;;1816:1;1813;1806:12;1768:52;-1:-1:-1;1861:23:5;;1688:226;-1:-1:-1;1688:226:5:o;1919:273::-;2104:6;2096;2091:3;2078:33;2060:3;2130:16;;2155:13;;;2130:16;1919:273;-1:-1:-1;1919:273:5:o;2197:297::-;2315:12;;2362:4;2351:16;;;2345:23;;2315:12;2380:16;;2377:111;;;2474:1;2470:6;2460;2454:4;2450:17;2447:1;2443:25;2439:38;2432:5;2428:50;2419:59;;2377:111;;2197:297;;;:::o;2499:279::-;2564:9;;;2585:10;;;2582:190;;;-1:-1:-1;;;2625:1:5;2618:88;2729:4;2726:1;2719:15;2757:4;2754:1;2747:15;2783:266;2815:1;2841;2831:189;;-1:-1:-1;;;2873:1:5;2866:88;2977:4;2974:1;2967:15;3005:4;3002:1;2995:15;2831:189;-1:-1:-1;3034:9:5;;2783:266::o","linkReferences":{}},"methodIdentifiers":{"MAX_CAPACITY()":"3a5ddf30","carousel(uint256)":"93684bd4","changeAnimal(string,uint256)":"932289cc","currentCrateId()":"26bad99e","encodeAnimalName(string)":"76997b75","setAnimalAndSpin(string)":"ab3b9224"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.28+commit.7893614a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AnimalNameTooLong\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCarouselId\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MAX_CAPACITY\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"crateId\",\"type\":\"uint256\"}],\"name\":\"carousel\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"animalInside\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"animal\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"crateId\",\"type\":\"uint256\"}],\"name\":\"changeAnimal\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"currentCrateId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"animalName\",\"type\":\"string\"}],\"name\":\"encodeAnimalName\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"animal\",\"type\":\"string\"}],\"name\":\"setAnimalAndSpin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/levels/MagicAnimalCarousel.sol\":\"MagicAnimalCarousel\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":1000},\"remappings\":[\":ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/\",\":erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/\",\":forge-std/=lib/forge-std/src/\",\":openzeppelin-contracts-06/=lib/openzeppelin-contracts-06/contracts/\",\":openzeppelin-contracts-08/=lib/openzeppelin-contracts-08/contracts/\",\":openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/\",\":openzeppelin-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/\",\":openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/\"]},\"sources\":{\"src/levels/MagicAnimalCarousel.sol\":{\"keccak256\":\"0xa6d06a3605347ff0aa528e9a4199a69d9beb9dd040455047eccd185c27971f87\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://9604bd65b2ebf3d09fa81a2f83740b25fdc2d142c0185026e3daafe53bb0f18d\",\"dweb:/ipfs/Qmd6kt3opASsMgFLxm8eRR7sdKQTDuknM18CFZH6pWtwfd\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.28+commit.7893614a"},"language":"Solidity","output":{"abi":[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"type":"error","name":"AnimalNameTooLong"},{"inputs":[],"type":"error","name":"InvalidCarouselId"},{"inputs":[],"stateMutability":"view","type":"function","name":"MAX_CAPACITY","outputs":[{"internalType":"uint16","name":"","type":"uint16"}]},{"inputs":[{"internalType":"uint256","name":"crateId","type":"uint256"}],"stateMutability":"view","type":"function","name":"carousel","outputs":[{"internalType":"uint256","name":"animalInside","type":"uint256"}]},{"inputs":[{"internalType":"string","name":"animal","type":"string"},{"internalType":"uint256","name":"crateId","type":"uint256"}],"stateMutability":"nonpayable","type":"function","name":"changeAnimal"},{"inputs":[],"stateMutability":"view","type":"function","name":"currentCrateId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}]},{"inputs":[{"internalType":"string","name":"animalName","type":"string"}],"stateMutability":"pure","type":"function","name":"encodeAnimalName","outputs":[{"internalType":"uint256","name":"","type":"uint256"}]},{"inputs":[{"internalType":"string","name":"animal","type":"string"}],"stateMutability":"nonpayable","type":"function","name":"setAnimalAndSpin"}],"devdoc":{"kind":"dev","methods":{},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"remappings":["ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/","erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/","forge-std/=lib/forge-std/src/","openzeppelin-contracts-06/=lib/openzeppelin-contracts-06/contracts/","openzeppelin-contracts-08/=lib/openzeppelin-contracts-08/contracts/","openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/","openzeppelin-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/","openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/"],"optimizer":{"enabled":true,"runs":1000},"metadata":{"bytecodeHash":"ipfs"},"compilationTarget":{"src/levels/MagicAnimalCarousel.sol":"MagicAnimalCarousel"},"evmVersion":"shanghai","libraries":{}},"sources":{"src/levels/MagicAnimalCarousel.sol":{"keccak256":"0xa6d06a3605347ff0aa528e9a4199a69d9beb9dd040455047eccd185c27971f87","urls":["bzz-raw://9604bd65b2ebf3d09fa81a2f83740b25fdc2d142c0185026e3daafe53bb0f18d","dweb:/ipfs/Qmd6kt3opASsMgFLxm8eRR7sdKQTDuknM18CFZH6pWtwfd"],"license":"MIT"}},"version":1},"id":2}

Large diffs are not rendered by default.

51 changes: 51 additions & 0 deletions contracts/src/levels/MagicAnimalCarousel.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

contract MagicAnimalCarousel {
uint16 constant public MAX_CAPACITY = type(uint16).max;
uint256 constant ANIMAL_MASK = uint256(type(uint80).max) << 160 + 16;
uint256 constant NEXT_ID_MASK = uint256(type(uint16).max) << 160;
uint256 constant OWNER_MASK = uint256(type(uint160).max);

uint256 public currentCrateId;
mapping(uint256 crateId => uint256 animalInside) public carousel;

error InvalidCarouselId();
error AnimalNameTooLong();

constructor() {
carousel[0] ^= 1 << 160;
}

function setAnimalAndSpin(string calldata animal) external {
uint256 encodedAnimal = encodeAnimalName(animal) >> 16;
uint256 nextCrateId = (carousel[currentCrateId] & NEXT_ID_MASK) >> 160;

require(encodedAnimal <= uint256(type(uint80).max), AnimalNameTooLong());
carousel[nextCrateId] = (carousel[nextCrateId] & ~NEXT_ID_MASK) ^ (encodedAnimal << 160 + 16)
| ((nextCrateId + 1) % MAX_CAPACITY) << 160 | uint160(msg.sender);

currentCrateId = nextCrateId;
}

function changeAnimal(string calldata animal, uint256 crateId) external {
address owner = address(uint160(carousel[crateId] & OWNER_MASK));
if (owner != address(0)) {
require(msg.sender == owner);
}
uint256 encodedAnimal = encodeAnimalName(animal);
if (encodedAnimal != 0) {
// Replace animal
carousel[crateId] =
(encodedAnimal << 160) | (carousel[crateId] & NEXT_ID_MASK) | uint160(msg.sender);
} else {
// If no animal specified keep same animal but clear owner slot
carousel[crateId]= (carousel[crateId] & (ANIMAL_MASK | NEXT_ID_MASK));
}
}

function encodeAnimalName(string calldata animalName) public pure returns (uint256) {
require(bytes(animalName).length <= 12, AnimalNameTooLong());
return uint256(bytes32(abi.encodePacked(animalName)) >> 160);
}
}
28 changes: 28 additions & 0 deletions contracts/src/levels/MagicAnimalCarouselFactory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./base/Level.sol";
import "./MagicAnimalCarousel.sol";

contract MagicAnimalCarouselFactory is Level {
function createInstance(address _player) public payable override returns (address) {
_player;
MagicAnimalCarousel magicAnimalCarousel = new MagicAnimalCarousel();
return address(magicAnimalCarousel);
}

function validateInstance(address payable _instance, address _player) public override returns (bool) {
_player;
MagicAnimalCarousel instance = MagicAnimalCarousel(_instance);
// Store a goat in the box
string memory goat = "Goat";
instance.setAnimalAndSpin(goat);

// Goat should be mutated
uint256 currentCrateId = instance.currentCrateId();
uint256 animalInBox = instance.carousel(currentCrateId) >> 176;
uint256 goatEnc = uint256(bytes32(abi.encodePacked(goat))) >> 176;
return animalInBox != goatEnc;
}
}
Loading

0 comments on commit 55a7c8e

Please sign in to comment.