fixed TBA
4fae5c79
11 file(s) · +317 −26
| 1 | + | // SPDX-License-Identifier: MIT |
|
| 2 | + | pragma solidity ^0.8.20; |
|
| 3 | + | ||
| 4 | + | import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; |
|
| 5 | + | import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; |
|
| 6 | + | import "@openzeppelin/contracts/interfaces/IERC1271.sol"; |
|
| 7 | + | import "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol"; |
|
| 8 | + | ||
| 9 | + | import "./interfaces/IERC6551Account.sol"; |
|
| 10 | + | import "./interfaces/IERC6551Executable.sol"; |
|
| 11 | + | ||
| 12 | + | contract ERC6551Account is |
|
| 13 | + | IERC165, |
|
| 14 | + | IERC1271, |
|
| 15 | + | IERC6551Account, |
|
| 16 | + | IERC6551Executable |
|
| 17 | + | { |
|
| 18 | + | uint256 public state; |
|
| 19 | + | ||
| 20 | + | receive() external payable {} |
|
| 21 | + | ||
| 22 | + | function execute( |
|
| 23 | + | address to, |
|
| 24 | + | uint256 value, |
|
| 25 | + | bytes calldata data, |
|
| 26 | + | uint256 operation |
|
| 27 | + | ) public payable virtual returns (bytes memory result) { |
|
| 28 | + | require(_isValidSigner(msg.sender), "Invalid signer"); |
|
| 29 | + | require(operation == 0, "Only call operations are supported"); |
|
| 30 | + | ||
| 31 | + | ++state; |
|
| 32 | + | ||
| 33 | + | bool success; |
|
| 34 | + | (success, result) = to.call{value: value}(data); |
|
| 35 | + | ||
| 36 | + | if (!success) { |
|
| 37 | + | assembly { |
|
| 38 | + | revert(add(result, 32), mload(result)) |
|
| 39 | + | } |
|
| 40 | + | } |
|
| 41 | + | } |
|
| 42 | + | ||
| 43 | + | function isValidSigner( |
|
| 44 | + | address signer, |
|
| 45 | + | bytes calldata |
|
| 46 | + | ) public view virtual returns (bytes4) { |
|
| 47 | + | if (_isValidSigner(signer)) { |
|
| 48 | + | return IERC6551Account.isValidSigner.selector; |
|
| 49 | + | } |
|
| 50 | + | ||
| 51 | + | return bytes4(0); |
|
| 52 | + | } |
|
| 53 | + | ||
| 54 | + | function isValidSignature( |
|
| 55 | + | bytes32 hash, |
|
| 56 | + | bytes memory signature |
|
| 57 | + | ) public view virtual returns (bytes4 magicValue) { |
|
| 58 | + | bool isValid = SignatureChecker.isValidSignatureNow( |
|
| 59 | + | owner(), |
|
| 60 | + | hash, |
|
| 61 | + | signature |
|
| 62 | + | ); |
|
| 63 | + | ||
| 64 | + | if (isValid) { |
|
| 65 | + | return IERC1271.isValidSignature.selector; |
|
| 66 | + | } |
|
| 67 | + | ||
| 68 | + | return ""; |
|
| 69 | + | } |
|
| 70 | + | ||
| 71 | + | function supportsInterface( |
|
| 72 | + | bytes4 interfaceId |
|
| 73 | + | ) public pure virtual returns (bool) { |
|
| 74 | + | return (interfaceId == type(IERC165).interfaceId || |
|
| 75 | + | interfaceId == type(IERC6551Account).interfaceId || |
|
| 76 | + | interfaceId == type(IERC6551Executable).interfaceId); |
|
| 77 | + | } |
|
| 78 | + | ||
| 79 | + | function token() public view virtual returns (uint256, address, uint256) { |
|
| 80 | + | bytes memory footer = new bytes(0x60); |
|
| 81 | + | ||
| 82 | + | assembly { |
|
| 83 | + | extcodecopy(address(), add(footer, 0x20), 0x4d, 0x60) |
|
| 84 | + | } |
|
| 85 | + | ||
| 86 | + | return abi.decode(footer, (uint256, address, uint256)); |
|
| 87 | + | } |
|
| 88 | + | ||
| 89 | + | function owner() public view virtual returns (address) { |
|
| 90 | + | (uint256 chainId, address tokenContract, uint256 tokenId) = token(); |
|
| 91 | + | if (chainId != block.chainid) return address(0); |
|
| 92 | + | ||
| 93 | + | return IERC721(tokenContract).ownerOf(tokenId); |
|
| 94 | + | } |
|
| 95 | + | ||
| 96 | + | function _isValidSigner( |
|
| 97 | + | address signer |
|
| 98 | + | ) internal view virtual returns (bool) { |
|
| 99 | + | return signer == owner(); |
|
| 100 | + | } |
|
| 101 | + | } |
| 1 | + | // SPDX-License-Identifier: MIT |
|
| 2 | + | pragma solidity ^0.8.20; |
|
| 3 | + | ||
| 4 | + | import "@openzeppelin/contracts/utils/Create2.sol"; |
|
| 5 | + | ||
| 6 | + | import "./interfaces/IERC6551Registry.sol"; |
|
| 7 | + | import "./lib/ERC6551BytecodeLib.sol"; |
|
| 8 | + | ||
| 9 | + | contract ERC6551Registry is IERC6551Registry { |
|
| 10 | + | error AccountCreationFailed(); |
|
| 11 | + | ||
| 12 | + | function createAccount( |
|
| 13 | + | address implementation, |
|
| 14 | + | uint256 chainId, |
|
| 15 | + | address tokenContract, |
|
| 16 | + | uint256 tokenId, |
|
| 17 | + | uint256 salt, |
|
| 18 | + | bytes calldata initData |
|
| 19 | + | ) external returns (address) { |
|
| 20 | + | bytes memory code = ERC6551BytecodeLib.getCreationCode( |
|
| 21 | + | implementation, |
|
| 22 | + | chainId, |
|
| 23 | + | tokenContract, |
|
| 24 | + | tokenId, |
|
| 25 | + | salt |
|
| 26 | + | ); |
|
| 27 | + | ||
| 28 | + | address _account = Create2.computeAddress( |
|
| 29 | + | bytes32(salt), |
|
| 30 | + | keccak256(code) |
|
| 31 | + | ); |
|
| 32 | + | ||
| 33 | + | if (_account.code.length != 0) return _account; |
|
| 34 | + | ||
| 35 | + | emit AccountCreated( |
|
| 36 | + | _account, |
|
| 37 | + | implementation, |
|
| 38 | + | chainId, |
|
| 39 | + | tokenContract, |
|
| 40 | + | tokenId, |
|
| 41 | + | salt |
|
| 42 | + | ); |
|
| 43 | + | ||
| 44 | + | assembly { |
|
| 45 | + | _account := create2(0, add(code, 0x20), mload(code), salt) |
|
| 46 | + | } |
|
| 47 | + | ||
| 48 | + | if (_account == address(0)) revert AccountCreationFailed(); |
|
| 49 | + | ||
| 50 | + | if (initData.length != 0) { |
|
| 51 | + | (bool success, bytes memory result) = _account.call(initData); |
|
| 52 | + | ||
| 53 | + | if (!success) { |
|
| 54 | + | assembly { |
|
| 55 | + | revert(add(result, 32), mload(result)) |
|
| 56 | + | } |
|
| 57 | + | } |
|
| 58 | + | } |
|
| 59 | + | ||
| 60 | + | return _account; |
|
| 61 | + | } |
|
| 62 | + | ||
| 63 | + | function account( |
|
| 64 | + | address implementation, |
|
| 65 | + | uint256 chainId, |
|
| 66 | + | address tokenContract, |
|
| 67 | + | uint256 tokenId, |
|
| 68 | + | uint256 salt |
|
| 69 | + | ) external view returns (address) { |
|
| 70 | + | bytes32 bytecodeHash = keccak256( |
|
| 71 | + | ERC6551BytecodeLib.getCreationCode( |
|
| 72 | + | implementation, |
|
| 73 | + | chainId, |
|
| 74 | + | tokenContract, |
|
| 75 | + | tokenId, |
|
| 76 | + | salt |
|
| 77 | + | ) |
|
| 78 | + | ); |
|
| 79 | + | ||
| 80 | + | return Create2.computeAddress(bytes32(salt), bytecodeHash); |
|
| 81 | + | } |
|
| 82 | + | } |
| 1 | + | // SPDX-License-Identifier: MIT |
|
| 2 | + | pragma solidity ^0.8.20; |
|
| 3 | + | ||
| 4 | + | import "./CosmicCowboy.sol"; |
|
| 5 | + | import "./SpaceGrub.sol"; |
|
| 6 | + | import "./RocketFuel.sol"; |
|
| 7 | + | import "./GoldenCorn.sol"; |
| 1 | + | // SPDX-License-Identifier: MIT |
|
| 2 | + | pragma solidity ^0.8.20; |
|
| 3 | + | ||
| 4 | + | import "@openzeppelin/contracts/utils/Create2.sol"; |
|
| 5 | + | import "./ERC6551BytecodeLib.sol"; |
|
| 6 | + | ||
| 7 | + | library ERC6551AccountLib { |
|
| 8 | + | function computeAddress( |
|
| 9 | + | address registry, |
|
| 10 | + | address implementation, |
|
| 11 | + | uint256 chainId, |
|
| 12 | + | address tokenContract, |
|
| 13 | + | uint256 tokenId, |
|
| 14 | + | uint256 _salt |
|
| 15 | + | ) internal pure returns (address) { |
|
| 16 | + | bytes32 bytecodeHash = keccak256( |
|
| 17 | + | ERC6551BytecodeLib.getCreationCode( |
|
| 18 | + | implementation, |
|
| 19 | + | chainId, |
|
| 20 | + | tokenContract, |
|
| 21 | + | tokenId, |
|
| 22 | + | _salt |
|
| 23 | + | ) |
|
| 24 | + | ); |
|
| 25 | + | ||
| 26 | + | return Create2.computeAddress(bytes32(_salt), bytecodeHash, registry); |
|
| 27 | + | } |
|
| 28 | + | ||
| 29 | + | function token() internal view returns (uint256, address, uint256) { |
|
| 30 | + | bytes memory footer = new bytes(0x60); |
|
| 31 | + | ||
| 32 | + | assembly { |
|
| 33 | + | // copy 0x60 bytes from end of footer |
|
| 34 | + | extcodecopy(address(), add(footer, 0x20), 0x4d, 0x60) |
|
| 35 | + | } |
|
| 36 | + | ||
| 37 | + | return abi.decode(footer, (uint256, address, uint256)); |
|
| 38 | + | } |
|
| 39 | + | ||
| 40 | + | function salt() internal view returns (uint256) { |
|
| 41 | + | bytes memory footer = new bytes(0x20); |
|
| 42 | + | ||
| 43 | + | assembly { |
|
| 44 | + | // copy 0x20 bytes from beginning of footer |
|
| 45 | + | extcodecopy(address(), add(footer, 0x20), 0x2d, 0x20) |
|
| 46 | + | } |
|
| 47 | + | ||
| 48 | + | return abi.decode(footer, (uint256)); |
|
| 49 | + | } |
|
| 50 | + | } |
| 1 | + | // SPDX-License-Identifier: MIT |
|
| 2 | + | pragma solidity ^0.8.20; |
|
| 3 | + | ||
| 4 | + | library ERC6551BytecodeLib { |
|
| 5 | + | function getCreationCode( |
|
| 6 | + | address implementation_, |
|
| 7 | + | uint256 chainId_, |
|
| 8 | + | address tokenContract_, |
|
| 9 | + | uint256 tokenId_, |
|
| 10 | + | uint256 salt_ |
|
| 11 | + | ) internal pure returns (bytes memory) { |
|
| 12 | + | return |
|
| 13 | + | abi.encodePacked( |
|
| 14 | + | hex"3d60ad80600a3d3981f3363d3d373d3d3d363d73", |
|
| 15 | + | implementation_, |
|
| 16 | + | hex"5af43d82803e903d91602b57fd5bf3", |
|
| 17 | + | abi.encode(salt_, chainId_, tokenContract_, tokenId_) |
|
| 18 | + | ); |
|
| 19 | + | } |
|
| 20 | + | } |
| 6 | 6 | "": { |
|
| 7 | 7 | "name": "hardhat-project", |
|
| 8 | 8 | "dependencies": { |
|
| 9 | - | "@openzeppelin/contracts": "^5.0.0" |
|
| 9 | + | "@openzeppelin/contracts": "^5.0.0", |
|
| 10 | + | "ethers": "^6.7.1" |
|
| 10 | 11 | }, |
|
| 11 | 12 | "devDependencies": { |
|
| 12 | 13 | "@nomicfoundation/hardhat-toolbox": "^3.0.0", |
|
| 17 | 18 | "node_modules/@adraffy/ens-normalize": { |
|
| 18 | 19 | "version": "1.9.2", |
|
| 19 | 20 | "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.9.2.tgz", |
|
| 20 | - | "integrity": "sha512-0h+FrQDqe2Wn+IIGFkTCd4aAwTJ+7834Ek1COohCyV26AXhwQ7WQaz+4F/nLOeVl/3BtWHOHLPsq46V8YB46Eg==", |
|
| 21 | - | "dev": true, |
|
| 22 | - | "peer": true |
|
| 21 | + | "integrity": "sha512-0h+FrQDqe2Wn+IIGFkTCd4aAwTJ+7834Ek1COohCyV26AXhwQ7WQaz+4F/nLOeVl/3BtWHOHLPsq46V8YB46Eg==" |
|
| 23 | 22 | }, |
|
| 24 | 23 | "node_modules/@chainsafe/as-sha256": { |
|
| 25 | 24 | "version": "0.3.1", |
|
| 955 | 954 | "version": "1.1.2", |
|
| 956 | 955 | "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.1.2.tgz", |
|
| 957 | 956 | "integrity": "sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA==", |
|
| 958 | - | "dev": true, |
|
| 959 | 957 | "funding": [ |
|
| 960 | 958 | { |
|
| 961 | 959 | "type": "individual", |
|
| 962 | 960 | "url": "https://paulmillr.com/funding/" |
|
| 963 | 961 | } |
|
| 964 | - | ], |
|
| 965 | - | "peer": true |
|
| 962 | + | ] |
|
| 966 | 963 | }, |
|
| 967 | 964 | "node_modules/@noble/secp256k1": { |
|
| 968 | 965 | "version": "1.7.1", |
|
| 969 | 966 | "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", |
|
| 970 | 967 | "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==", |
|
| 971 | - | "dev": true, |
|
| 972 | 968 | "funding": [ |
|
| 973 | 969 | { |
|
| 974 | 970 | "type": "individual", |
|
| 2066 | 2062 | "node_modules/aes-js": { |
|
| 2067 | 2063 | "version": "4.0.0-beta.5", |
|
| 2068 | 2064 | "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz", |
|
| 2069 | - | "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==", |
|
| 2070 | - | "dev": true, |
|
| 2071 | - | "peer": true |
|
| 2065 | + | "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==" |
|
| 2072 | 2066 | }, |
|
| 2073 | 2067 | "node_modules/agent-base": { |
|
| 2074 | 2068 | "version": "6.0.2", |
|
| 3466 | 3460 | "version": "6.7.1", |
|
| 3467 | 3461 | "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.7.1.tgz", |
|
| 3468 | 3462 | "integrity": "sha512-qX5kxIFMfg1i+epfgb0xF4WM7IqapIIu50pOJ17aebkxxa4BacW5jFrQRmCJpDEg2ZK2oNtR5QjrQ1WDBF29dA==", |
|
| 3469 | - | "dev": true, |
|
| 3470 | 3463 | "funding": [ |
|
| 3471 | 3464 | { |
|
| 3472 | 3465 | "type": "individual", |
|
| 3477 | 3470 | "url": "https://www.buymeacoffee.com/ricmoo" |
|
| 3478 | 3471 | } |
|
| 3479 | 3472 | ], |
|
| 3480 | - | "peer": true, |
|
| 3481 | 3473 | "dependencies": { |
|
| 3482 | 3474 | "@adraffy/ens-normalize": "1.9.2", |
|
| 3483 | 3475 | "@noble/hashes": "1.1.2", |
|
| 3494 | 3486 | "node_modules/ethers/node_modules/@types/node": { |
|
| 3495 | 3487 | "version": "18.15.13", |
|
| 3496 | 3488 | "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.13.tgz", |
|
| 3497 | - | "integrity": "sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==", |
|
| 3498 | - | "dev": true, |
|
| 3499 | - | "peer": true |
|
| 3489 | + | "integrity": "sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==" |
|
| 3500 | 3490 | }, |
|
| 3501 | 3491 | "node_modules/ethjs-unit": { |
|
| 3502 | 3492 | "version": "0.1.6", |
|
| 6807 | 6797 | "node_modules/tslib": { |
|
| 6808 | 6798 | "version": "2.4.0", |
|
| 6809 | 6799 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", |
|
| 6810 | - | "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", |
|
| 6811 | - | "dev": true, |
|
| 6812 | - | "peer": true |
|
| 6800 | + | "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" |
|
| 6813 | 6801 | }, |
|
| 6814 | 6802 | "node_modules/tsort": { |
|
| 6815 | 6803 | "version": "0.0.1", |
|
| 7262 | 7250 | "version": "8.5.0", |
|
| 7263 | 7251 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", |
|
| 7264 | 7252 | "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", |
|
| 7265 | - | "dev": true, |
|
| 7266 | - | "peer": true, |
|
| 7267 | 7253 | "engines": { |
|
| 7268 | 7254 | "node": ">=10.0.0" |
|
| 7269 | 7255 | }, |
|
| 6 | 6 | "mocha": "^10.2.0" |
|
| 7 | 7 | }, |
|
| 8 | 8 | "dependencies": { |
|
| 9 | - | "@openzeppelin/contracts": "^5.0.0" |
|
| 9 | + | "@openzeppelin/contracts": "^5.0.0", |
|
| 10 | + | "ethers": "^6.7.1" |
|
| 10 | 11 | } |
|
| 11 | 12 | } |
| 1 | - | const { expect } = require("chai"); |
|
| 2 | - | ||
| 3 | 1 | // Import the ethers library |
|
| 4 | 2 | const { ethers } = require("hardhat"); |
|
| 5 | 3 | ||
| 6 | - | async function runTests() { |
|
| 4 | + | async function CosmicCoyboys() { |
|
| 7 | 5 | let contract; |
|
| 8 | 6 | let owner; |
|
| 9 | 7 | let addr1; |
|
| 28 | 26 | console.log(tokenURI); |
|
| 29 | 27 | }; |
|
| 30 | 28 | ||
| 31 | - | runTests() |
|
| 29 | + | async function GoldenCorn() { |
|
| 30 | + | let contract; |
|
| 31 | + | let owner; |
|
| 32 | + | let addr1; |
|
| 33 | + | let addr2; |
|
| 34 | + | ||
| 35 | + | // Get the signers from ethers |
|
| 36 | + | [owner, addr1, addr2] = await ethers.getSigners(); |
|
| 37 | + | ||
| 38 | + | // Deploy the contract |
|
| 39 | + | const Contract = await ethers.getContractFactory("GoldenCorn"); |
|
| 40 | + | contract = await Contract.deploy(owner.address); |
|
| 41 | + | const contractAddress = await contract.getAddress() |
|
| 42 | + | console.log("Contract deployed to address:", contractAddress); |
|
| 43 | + | ||
| 44 | + | // Mint tokens |
|
| 45 | + | await contract.mint(addr1.address, 100); |
|
| 46 | + | console.log("Minted token 1"); |
|
| 47 | + | ||
| 48 | + | const balance = await contract.balanceOf(addr1.address); |
|
| 49 | + | console.log(balance) |
|
| 50 | + | ||
| 51 | + | } |
|
| 52 | + | ||
| 53 | + | async function TBA() { |
|
| 54 | + | let contract; |
|
| 55 | + | let owner; |
|
| 56 | + | let addr1; |
|
| 57 | + | let addr2; |
|
| 58 | + | ||
| 59 | + | // Get the signers from ethers |
|
| 60 | + | [owner, addr1, addr2] = await ethers.getSigners(); |
|
| 61 | + | ||
| 62 | + | // Deploy the contract |
|
| 63 | + | const RegistryContract = await ethers.getContractFactory("ERC6551Registry"); |
|
| 64 | + | const regristryContract = await RegistryContract.deploy(); |
|
| 65 | + | const registryContractAddress = await regristryContract.getAddress() |
|
| 66 | + | console.log("Registry Contract deployed to address:", registryContractAddress); |
|
| 67 | + | ||
| 68 | + | const AccountContract = await ethers.getContractFactory("ERC6551Account"); |
|
| 69 | + | const accountContract = await AccountContract.deploy(); |
|
| 70 | + | const accountContractAddress = await accountContract.getAddress() |
|
| 71 | + | console.log("Account Contract deployed to address:", accountContractAddress); |
|
| 72 | + | ||
| 73 | + | } |
|
| 74 | + | ||
| 75 | + | TBA() |
|