Created
August 16, 2023 07:11
-
-
Save KcPele/378ef1af3e45c39eb6a953bfbe16bb8c to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.8.18+commit.87f61d96.js&optimize=false&runs=200&gist=
This file contains hidden or 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
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.17; | |
interface IERC20 { | |
function transfer(address, uint) external; | |
} | |
contract AbiEncode { | |
function test(address _contract, bytes calldata data) external { | |
(bool ok, ) = _contract.call(data); | |
require(ok, "call failed"); | |
} | |
function encodeWithSignature( | |
address to, | |
uint amount | |
) external pure returns (bytes memory) { | |
// Typo is not checked - "transfer(address, uint)" | |
return abi.encodeWithSignature("transfer(address,uint256)", to, amount); | |
} | |
function encodeWithSelector( | |
address to, | |
uint amount | |
) external pure returns (bytes memory) { | |
// Type is not checked - (IERC20.transfer.selector, true, amount) | |
return abi.encodeWithSelector(IERC20.transfer.selector, to, amount); | |
} | |
function encodeCall(address to, uint amount) external pure returns (bytes memory) { | |
// Typo and type errors will not compile | |
return abi.encodeCall(IERC20.transfer, (to, amount)); | |
} | |
} |
This file contains hidden or 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
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.13; | |
import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; | |
import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; | |
import "@openzeppelin/contracts/interfaces/IERC1271.sol"; | |
import "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol"; | |
import "./lib/Bytecode.sol"; | |
import "./interface/IERC6551Account.sol"; | |
contract ERC6551Account is IERC165, IERC1271, IERC6551Account { | |
uint256 private _nonce; | |
receive() external payable {} | |
function executeCall( | |
address to, | |
uint256 value, | |
bytes calldata data | |
) external payable returns (bytes memory result) { | |
require(msg.sender == owner(), "Not token owner"); | |
bool success; | |
(success, result) = to.call{value: value}(data); | |
if (!success) { | |
assembly { | |
revert(add(result, 32), mload(result)) | |
} | |
} | |
_nonce++; | |
} | |
function token() | |
public | |
view | |
returns (uint256 chainId, address tokenContract, uint256 tokenId) | |
{ | |
uint256 length = address(this).code.length; | |
return | |
abi.decode( | |
Bytecode.codeAt(address(this), length - 0x60, length), | |
(uint256, address, uint256) | |
); | |
} | |
function owner() public view returns (address) { | |
(uint256 chainId, address tokenContract, uint256 tokenId) = this | |
.token(); | |
if (chainId != block.chainid) return address(0); | |
return IERC721(tokenContract).ownerOf(tokenId); | |
} | |
function nonce() external view returns (uint256) { | |
return _nonce; | |
} | |
function supportsInterface(bytes4 interfaceId) public pure returns (bool) { | |
return (interfaceId == type(IERC165).interfaceId || | |
interfaceId == type(IERC6551Account).interfaceId); | |
} | |
function isValidSignature( | |
bytes32 hash, | |
bytes memory signature | |
) external view returns (bytes4 magicValue) { | |
bool isValid = SignatureChecker.isValidSignatureNow( | |
owner(), | |
hash, | |
signature | |
); | |
if (isValid) { | |
return IERC1271.isValidSignature.selector; | |
} | |
return ""; | |
} | |
} |
This file contains hidden or 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
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.13; | |
import "@openzeppelin/contracts/utils/Create2.sol"; | |
import "./interface/IERC6551Registry.sol"; | |
contract ERC6551Registry is IERC6551Registry { | |
error InitializationFailed(); | |
function createAccount( | |
address implementation, | |
uint256 chainId, | |
address tokenContract, | |
uint256 tokenId, | |
uint256 salt, | |
bytes calldata initData | |
) external returns (address) { | |
bytes memory code = _creationCode( | |
implementation, | |
chainId, | |
tokenContract, | |
tokenId, | |
salt | |
); | |
address _account = Create2.computeAddress( | |
bytes32(salt), | |
keccak256(code) | |
); | |
if (_account.code.length != 0) return _account; | |
_account = Create2.deploy(0, bytes32(salt), code); | |
if (initData.length != 0) { | |
(bool success, ) = _account.call(initData); | |
if (!success) revert InitializationFailed(); | |
} | |
emit AccountCreated( | |
_account, | |
implementation, | |
chainId, | |
tokenContract, | |
tokenId, | |
salt | |
); | |
return _account; | |
} | |
function account( | |
address implementation, | |
uint256 chainId, | |
address tokenContract, | |
uint256 tokenId, | |
uint256 salt | |
) external view returns (address) { | |
bytes32 bytecodeHash = keccak256( | |
_creationCode(implementation, chainId, tokenContract, tokenId, salt) | |
); | |
return Create2.computeAddress(bytes32(salt), bytecodeHash); | |
} | |
function _creationCode( | |
address implementation_, | |
uint256 chainId_, | |
address tokenContract_, | |
uint256 tokenId_, | |
uint256 salt_ | |
) internal pure returns (bytes memory) { | |
return | |
abi.encodePacked( | |
hex"3d60ad80600a3d3981f3363d3d373d3d3d363d73", | |
implementation_, | |
hex"5af43d82803e903d91602b57fd5bf3", | |
abi.encode(salt_, chainId_, tokenContract_, tokenId_) | |
); | |
} | |
} |
This file contains hidden or 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
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.13; | |
/// @dev the ERC-165 identifier for this interface is `0x400a0398` | |
interface IERC6551Account { | |
/// @dev Token bound accounts MUST implement a `receive` function. | |
/// | |
/// Token bound accounts MAY perform arbitrary logic to restrict conditions | |
/// under which Ether can be received. | |
receive() external payable; | |
/// @dev Executes `call` on address `to`, with value `value` and calldata | |
/// `data`. | |
/// | |
/// MUST revert and bubble up errors if call fails. | |
/// | |
/// By default, token bound accounts MUST allow the owner of the ERC-721 token | |
/// which owns the account to execute arbitrary calls using `executeCall`. | |
/// | |
/// Token bound accounts MAY implement additional authorization mechanisms | |
/// which limit the ability of the ERC-721 token holder to execute calls. | |
/// | |
/// Token bound accounts MAY implement additional execution functions which | |
/// grant execution permissions to other non-owner accounts. | |
/// | |
/// @return The result of the call | |
function executeCall( | |
address to, | |
uint256 value, | |
bytes calldata data | |
) external payable returns (bytes memory); | |
/// @dev Returns identifier of the ERC-721 token which owns the | |
/// account | |
/// | |
/// The return value of this function MUST be constant - it MUST NOT change | |
/// over time. | |
/// | |
/// @return chainId The EIP-155 ID of the chain the ERC-721 token exists on | |
/// @return tokenContract The contract address of the ERC-721 token | |
/// @return tokenId The ID of the ERC-721 token | |
function token() | |
external | |
view | |
returns (uint256 chainId, address tokenContract, uint256 tokenId); | |
/// @dev Returns the owner of the ERC-721 token which controls the account | |
/// if the token exists. | |
/// | |
/// This is value is obtained by calling `ownerOf` on the ERC-721 contract. | |
/// | |
/// @return Address of the owner of the ERC-721 token which owns the account | |
function owner() external view returns (address); | |
/// @dev Returns a nonce value that is updated on every successful transaction | |
/// | |
/// @return The current account nonce | |
function nonce() external view returns (uint256); | |
} |
This file contains hidden or 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
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.13; | |
/// @dev the ERC-165 identifier for this interface is `0x74420f4c` | |
interface IERC6551Executable { | |
/** | |
* @dev Executes a low-level operation if the caller is a valid signer on the account | |
* | |
* Reverts and bubbles up error if operation fails | |
* | |
* @param to The target address of the operation | |
* @param value The Ether value to be sent to the target | |
* @param data The encoded operation calldata | |
* @param operation A value indicating the type of operation to perform | |
* | |
* Accounts implementing this interface MUST accept the following operation parameter values: | |
* - 0 = CALL | |
* - 1 = DELEGATECALL | |
* - 2 = CREATE | |
* - 3 = CREATE2 | |
* | |
* Accounts implementing this interface MAY support additional operations or restrict a signer's | |
* ability to execute certain operations | |
* | |
* @return The result of the operation | |
*/ | |
function execute( | |
address to, | |
uint256 value, | |
bytes calldata data, | |
uint256 operation | |
) external payable returns (bytes memory); | |
} |
This file contains hidden or 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
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.13; | |
interface IERC6551Registry { | |
/// @dev The registry SHALL emit the AccountCreated event upon successful account creation | |
event AccountCreated( | |
address account, | |
address implementation, | |
uint256 chainId, | |
address tokenContract, | |
uint256 tokenId, | |
uint256 salt | |
); | |
/// @dev Creates a token bound account for an ERC-721 token. | |
/// | |
/// If account has already been created, returns the account address without calling create2. | |
/// | |
/// If initData is not empty and account has not yet been created, calls account with | |
/// provided initData after creation. | |
/// | |
/// Emits AccountCreated event. | |
/// | |
/// @return the address of the account | |
function createAccount( | |
address implementation, | |
uint256 chainId, | |
address tokenContract, | |
uint256 tokenId, | |
uint256 salt, | |
bytes calldata initData | |
) external returns (address); | |
/// @dev Returns the computed address of a token bound account | |
/// | |
/// @return The computed address of the account | |
function account( | |
address implementation, | |
uint256 chainId, | |
address tokenContract, | |
uint256 tokenId, | |
uint256 salt | |
) external view returns (address); | |
} |
This file contains hidden or 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
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.0; | |
library Bytecode { | |
error InvalidCodeAtRange(uint256 _size, uint256 _start, uint256 _end); | |
/** | |
@notice Generate a creation code that results on a contract with `_code` as bytecode | |
@param _code The returning value of the resulting `creationCode` | |
@return creationCode (constructor) for new contract | |
*/ | |
function creationCodeFor( | |
bytes memory _code | |
) internal pure returns (bytes memory) { | |
/* | |
0x00 0x63 0x63XXXXXX PUSH4 _code.length size | |
0x01 0x80 0x80 DUP1 size size | |
0x02 0x60 0x600e PUSH1 14 14 size size | |
0x03 0x60 0x6000 PUSH1 00 0 14 size size | |
0x04 0x39 0x39 CODECOPY size | |
0x05 0x60 0x6000 PUSH1 00 0 size | |
0x06 0xf3 0xf3 RETURN | |
<CODE> | |
*/ | |
return | |
abi.encodePacked( | |
hex"63", | |
uint32(_code.length), | |
hex"80_60_0E_60_00_39_60_00_F3", | |
_code | |
); | |
} | |
/** | |
@notice Returns the size of the code on a given address | |
@param _addr Address that may or may not contain code | |
@return size of the code on the given `_addr` | |
*/ | |
function codeSize(address _addr) internal view returns (uint256 size) { | |
assembly { | |
size := extcodesize(_addr) | |
} | |
} | |
/** | |
@notice Returns the code of a given address | |
@dev It will fail if `_end < _start` | |
@param _addr Address that may or may not contain code | |
@param _start number of bytes of code to skip on read | |
@param _end index before which to end extraction | |
@return oCode read from `_addr` deployed bytecode | |
Forked from: https://gist.github.com/KardanovIR/fe98661df9338c842b4a30306d507fbd | |
*/ | |
function codeAt( | |
address _addr, | |
uint256 _start, | |
uint256 _end | |
) internal view returns (bytes memory oCode) { | |
uint256 csize = codeSize(_addr); | |
if (csize == 0) return bytes(""); | |
if (_start > csize) return bytes(""); | |
if (_end < _start) revert InvalidCodeAtRange(csize, _start, _end); | |
unchecked { | |
uint256 reqSize = _end - _start; | |
uint256 maxSize = csize - _start; | |
uint256 size = maxSize < reqSize ? maxSize : reqSize; | |
assembly { | |
// allocate output byte array - this could also be done without assembly | |
// by using o_code = new bytes(size) | |
oCode := mload(0x40) | |
// new "memory end" including padding | |
mstore( | |
0x40, | |
add(oCode, and(add(add(size, 0x20), 0x1f), not(0x1f))) | |
) | |
// store length in memory | |
mstore(oCode, size) | |
// actually retrieve the code, this needs assembly | |
extcodecopy(_addr, add(oCode, 0x20), _start, size) | |
} | |
} | |
} | |
} |
This file contains hidden or 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
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.13; | |
import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; | |
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; | |
import "@openzeppelin/contracts/access/Ownable.sol"; | |
contract NFT is ERC721, ERC721URIStorage, Ownable { | |
uint256 private _tokenId; | |
constructor() ERC721("TestNFT", "TNFT") {} | |
function totalSupply() public view returns (uint256) { | |
return _tokenId; | |
} | |
function _burn( | |
uint256 tokenId | |
) internal override(ERC721, ERC721URIStorage) { | |
super._burn(tokenId); | |
} | |
function tokenURI( | |
uint256 tokenId | |
) public view override(ERC721, ERC721URIStorage) returns (string memory) { | |
return super.tokenURI(tokenId); | |
} | |
function supportsInterface( | |
bytes4 interfaceId | |
) public view override(ERC721, ERC721URIStorage) returns (bool) { | |
return super.supportsInterface(interfaceId); | |
} | |
function safeMint(address to, string memory uri) public onlyOwner { | |
_tokenId++; | |
_safeMint(to, _tokenId); | |
_setTokenURI(_tokenId, uri); | |
} | |
} |
This file contains hidden or 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
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.13; | |
import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; | |
contract Token is ERC20 { | |
constructor() ERC20("TestToken", "TT") { | |
_mint(msg.sender, 1000 * 10 ** decimals()); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment