// SPDX-License-Identifier: CC0-1.0 pragma solidity ^0.8.0; import {ERC5050, Action} from "./ERC5050.sol"; contract Spells is ERC5050, ERC721 { bytes4 constant CAST_SELECTOR = bytes4(keccak256("cast")); bytes4 constant ATTUNE_SELECTOR = bytes4(keccak256("attune")); mapping(uint256 => uint256) spellDust; mapping(uint256 => string) attunement; constructor() ERC721("Spells", unicode"🔮") { _registerSendable("cast"); _registerReceivable("attune"); } function sendAction(Action memory action) external payable override onlySendableAction(action) { require( msg.sender == ownerOf(action.from._tokenId), "Spells: invalid sender" ); _sendAction(action); } function onActionReceived(Action calldata action, uint256 _nonce) external payable override onlyReceivableAction(action, _nonce) { if (action.selector == ATTUNE_SELECTOR) { string memory unicodeChar; bytes memory _data = action.data; assembly { // Read unicode character from first 6 bytes (\u5050) unicodeChar := shr(208, _data) } attunement[action.to._tokenId] = unicodeChar; } // Pass action to state receiver if specified _onActionReceived(action, _nonce); } string[12] private dust = [ unicode"․", unicode"∴", unicode"`" ]; string[5] private spells = [ "Conjuring", "Divining", "Transforming", "Hexing", "Banishing" ]; function tokenURI(uint256 tokenId) public view override returns (string memory) { string memory out = ''; out = string.concat( out, string.concat(spells[_spellType(tokenId)], " Spell"), '', attunement[tokenId] ); out = string.concat(out, ""); string memory json = Base64.encode( bytes( string( abi.encodePacked( '{"name": "Spell #', Strings.toString(tokenId), '", "description": "Cast spells, attune spells.", "image": "data:image/svg+xml;base64,', Base64.encode(bytes(out)), '"}' ) ) ) ); return string(abi.encodePacked("data:application/json;base64,", json)); } function _spellType(uint256 tokenId) internal pure returns (uint256) { uint256 rand = _random(Strings.toString(tokenId)); return rand % 6; } function _random(string memory input) internal pure returns (uint256) { return uint256(keccak256(abi.encodePacked(input))); } }