dexorder
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {ERC20} from "../../token/ERC20/ERC20.sol";
|
||||
|
||||
contract ERC20WithAutoMinerReward is ERC20 {
|
||||
constructor() ERC20("Reward", "RWD") {
|
||||
_mintMinerReward();
|
||||
}
|
||||
|
||||
function _mintMinerReward() internal {
|
||||
_mint(block.coinbase, 1000);
|
||||
}
|
||||
|
||||
function _update(address from, address to, uint256 value) internal virtual override {
|
||||
if (!(from == address(0) && to == block.coinbase)) {
|
||||
_mintMinerReward();
|
||||
}
|
||||
super._update(from, to, value);
|
||||
}
|
||||
}
|
||||
103
lib_openzeppelin_contracts/contracts/mocks/docs/ERC4626Fees.sol
Normal file
103
lib_openzeppelin_contracts/contracts/mocks/docs/ERC4626Fees.sol
Normal file
@@ -0,0 +1,103 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {IERC20} from "../../token/ERC20/IERC20.sol";
|
||||
import {ERC4626} from "../../token/ERC20/extensions/ERC4626.sol";
|
||||
import {SafeERC20} from "../../token/ERC20/utils/SafeERC20.sol";
|
||||
import {Math} from "../../utils/math/Math.sol";
|
||||
|
||||
/// @dev ERC-4626 vault with entry/exit fees expressed in https://en.wikipedia.org/wiki/Basis_point[basis point (bp)].
|
||||
abstract contract ERC4626Fees is ERC4626 {
|
||||
using Math for uint256;
|
||||
|
||||
uint256 private constant _BASIS_POINT_SCALE = 1e4;
|
||||
|
||||
// === Overrides ===
|
||||
|
||||
/// @dev Preview taking an entry fee on deposit. See {IERC4626-previewDeposit}.
|
||||
function previewDeposit(uint256 assets) public view virtual override returns (uint256) {
|
||||
uint256 fee = _feeOnTotal(assets, _entryFeeBasisPoints());
|
||||
return super.previewDeposit(assets - fee);
|
||||
}
|
||||
|
||||
/// @dev Preview adding an entry fee on mint. See {IERC4626-previewMint}.
|
||||
function previewMint(uint256 shares) public view virtual override returns (uint256) {
|
||||
uint256 assets = super.previewMint(shares);
|
||||
return assets + _feeOnRaw(assets, _entryFeeBasisPoints());
|
||||
}
|
||||
|
||||
/// @dev Preview adding an exit fee on withdraw. See {IERC4626-previewWithdraw}.
|
||||
function previewWithdraw(uint256 assets) public view virtual override returns (uint256) {
|
||||
uint256 fee = _feeOnRaw(assets, _exitFeeBasisPoints());
|
||||
return super.previewWithdraw(assets + fee);
|
||||
}
|
||||
|
||||
/// @dev Preview taking an exit fee on redeem. See {IERC4626-previewRedeem}.
|
||||
function previewRedeem(uint256 shares) public view virtual override returns (uint256) {
|
||||
uint256 assets = super.previewRedeem(shares);
|
||||
return assets - _feeOnTotal(assets, _exitFeeBasisPoints());
|
||||
}
|
||||
|
||||
/// @dev Send entry fee to {_entryFeeRecipient}. See {IERC4626-_deposit}.
|
||||
function _deposit(address caller, address receiver, uint256 assets, uint256 shares) internal virtual override {
|
||||
uint256 fee = _feeOnTotal(assets, _entryFeeBasisPoints());
|
||||
address recipient = _entryFeeRecipient();
|
||||
|
||||
super._deposit(caller, receiver, assets, shares);
|
||||
|
||||
if (fee > 0 && recipient != address(this)) {
|
||||
SafeERC20.safeTransfer(IERC20(asset()), recipient, fee);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Send exit fee to {_exitFeeRecipient}. See {IERC4626-_deposit}.
|
||||
function _withdraw(
|
||||
address caller,
|
||||
address receiver,
|
||||
address owner,
|
||||
uint256 assets,
|
||||
uint256 shares
|
||||
) internal virtual override {
|
||||
uint256 fee = _feeOnRaw(assets, _exitFeeBasisPoints());
|
||||
address recipient = _exitFeeRecipient();
|
||||
|
||||
super._withdraw(caller, receiver, owner, assets, shares);
|
||||
|
||||
if (fee > 0 && recipient != address(this)) {
|
||||
SafeERC20.safeTransfer(IERC20(asset()), recipient, fee);
|
||||
}
|
||||
}
|
||||
|
||||
// === Fee configuration ===
|
||||
|
||||
function _entryFeeBasisPoints() internal view virtual returns (uint256) {
|
||||
return 0; // replace with e.g. 100 for 1%
|
||||
}
|
||||
|
||||
function _exitFeeBasisPoints() internal view virtual returns (uint256) {
|
||||
return 0; // replace with e.g. 100 for 1%
|
||||
}
|
||||
|
||||
function _entryFeeRecipient() internal view virtual returns (address) {
|
||||
return address(0); // replace with e.g. a treasury address
|
||||
}
|
||||
|
||||
function _exitFeeRecipient() internal view virtual returns (address) {
|
||||
return address(0); // replace with e.g. a treasury address
|
||||
}
|
||||
|
||||
// === Fee operations ===
|
||||
|
||||
/// @dev Calculates the fees that should be added to an amount `assets` that does not already include fees.
|
||||
/// Used in {IERC4626-mint} and {IERC4626-withdraw} operations.
|
||||
function _feeOnRaw(uint256 assets, uint256 feeBasisPoints) private pure returns (uint256) {
|
||||
return assets.mulDiv(feeBasisPoints, _BASIS_POINT_SCALE, Math.Rounding.Ceil);
|
||||
}
|
||||
|
||||
/// @dev Calculates the fee part of an amount `assets` that already includes fees.
|
||||
/// Used in {IERC4626-deposit} and {IERC4626-redeem} operations.
|
||||
function _feeOnTotal(uint256 assets, uint256 feeBasisPoints) private pure returns (uint256) {
|
||||
return assets.mulDiv(feeBasisPoints, feeBasisPoints + _BASIS_POINT_SCALE, Math.Rounding.Ceil);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// contracts/MyNFT.sol
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {ERC721} from "../../token/ERC721/ERC721.sol";
|
||||
|
||||
contract MyNFT is ERC721 {
|
||||
constructor() ERC721("MyNFT", "MNFT") {}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {AccessControl} from "../../../access/AccessControl.sol";
|
||||
import {ERC20} from "../../../token/ERC20/ERC20.sol";
|
||||
|
||||
contract AccessControlERC20MintBase is ERC20, AccessControl {
|
||||
// Create a new role identifier for the minter role
|
||||
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
|
||||
|
||||
error CallerNotMinter(address caller);
|
||||
|
||||
constructor(address minter) ERC20("MyToken", "TKN") {
|
||||
// Grant the minter role to a specified account
|
||||
_grantRole(MINTER_ROLE, minter);
|
||||
}
|
||||
|
||||
function mint(address to, uint256 amount) public {
|
||||
// Check that the calling account has the minter role
|
||||
if (!hasRole(MINTER_ROLE, msg.sender)) {
|
||||
revert CallerNotMinter(msg.sender);
|
||||
}
|
||||
_mint(to, amount);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {AccessControl} from "../../../access/AccessControl.sol";
|
||||
import {ERC20} from "../../../token/ERC20/ERC20.sol";
|
||||
|
||||
contract AccessControlERC20MintMissing is ERC20, AccessControl {
|
||||
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
|
||||
bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE");
|
||||
|
||||
constructor() ERC20("MyToken", "TKN") {
|
||||
// Grant the contract deployer the default admin role: it will be able
|
||||
// to grant and revoke any roles
|
||||
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
|
||||
}
|
||||
|
||||
function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) {
|
||||
_mint(to, amount);
|
||||
}
|
||||
|
||||
function burn(address from, uint256 amount) public onlyRole(BURNER_ROLE) {
|
||||
_burn(from, amount);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {AccessControl} from "../../../access/AccessControl.sol";
|
||||
import {ERC20} from "../../../token/ERC20/ERC20.sol";
|
||||
|
||||
contract AccessControlERC20Mint is ERC20, AccessControl {
|
||||
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
|
||||
bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE");
|
||||
|
||||
constructor(address minter, address burner) ERC20("MyToken", "TKN") {
|
||||
_grantRole(MINTER_ROLE, minter);
|
||||
_grantRole(BURNER_ROLE, burner);
|
||||
}
|
||||
|
||||
function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) {
|
||||
_mint(to, amount);
|
||||
}
|
||||
|
||||
function burn(address from, uint256 amount) public onlyRole(BURNER_ROLE) {
|
||||
_burn(from, amount);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// contracts/AccessControlModified.sol
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {AccessControl} from "../../../access/AccessControl.sol";
|
||||
|
||||
contract AccessControlModified is AccessControl {
|
||||
error AccessControlNonRevokable();
|
||||
|
||||
// Override the revokeRole function
|
||||
function revokeRole(bytes32, address) public pure override {
|
||||
revert AccessControlNonRevokable();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// contracts/AccessControlNonRevokableAdmin.sol
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {AccessControl} from "../../../access/AccessControl.sol";
|
||||
|
||||
contract AccessControlNonRevokableAdmin is AccessControl {
|
||||
error AccessControlNonRevokable();
|
||||
|
||||
function revokeRole(bytes32 role, address account) public override {
|
||||
if (role == DEFAULT_ADMIN_ROLE) {
|
||||
revert AccessControlNonRevokable();
|
||||
}
|
||||
|
||||
super.revokeRole(role, account);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {AccessManaged} from "../../../access/manager/AccessManaged.sol";
|
||||
import {ERC20} from "../../../token/ERC20/ERC20.sol";
|
||||
|
||||
contract AccessManagedERC20Mint is ERC20, AccessManaged {
|
||||
constructor(address manager) ERC20("MyToken", "TKN") AccessManaged(manager) {}
|
||||
|
||||
// Minting is restricted according to the manager rules for this function.
|
||||
// The function is identified by its selector: 0x40c10f19.
|
||||
// Calculated with bytes4(keccak256('mint(address,uint256)'))
|
||||
function mint(address to, uint256 amount) public restricted {
|
||||
_mint(to, amount);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {Ownable} from "../../../access/Ownable.sol";
|
||||
|
||||
contract MyContract is Ownable {
|
||||
constructor(address initialOwner) Ownable(initialOwner) {}
|
||||
|
||||
function normalThing() public {
|
||||
// anyone can call this normalThing()
|
||||
}
|
||||
|
||||
function specialThing() public onlyOwner {
|
||||
// only the owner can call specialThing()!
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {IGovernor, Governor} from "../../../governance/Governor.sol";
|
||||
import {GovernorCountingSimple} from "../../../governance/extensions/GovernorCountingSimple.sol";
|
||||
import {GovernorVotes} from "../../../governance/extensions/GovernorVotes.sol";
|
||||
import {GovernorVotesQuorumFraction} from "../../../governance/extensions/GovernorVotesQuorumFraction.sol";
|
||||
import {GovernorTimelockControl} from "../../../governance/extensions/GovernorTimelockControl.sol";
|
||||
import {TimelockController} from "../../../governance/TimelockController.sol";
|
||||
import {IVotes} from "../../../governance/utils/IVotes.sol";
|
||||
import {IERC165} from "../../../interfaces/IERC165.sol";
|
||||
|
||||
contract MyGovernor is
|
||||
Governor,
|
||||
GovernorCountingSimple,
|
||||
GovernorVotes,
|
||||
GovernorVotesQuorumFraction,
|
||||
GovernorTimelockControl
|
||||
{
|
||||
constructor(
|
||||
IVotes _token,
|
||||
TimelockController _timelock
|
||||
) Governor("MyGovernor") GovernorVotes(_token) GovernorVotesQuorumFraction(4) GovernorTimelockControl(_timelock) {}
|
||||
|
||||
function votingDelay() public pure override returns (uint256) {
|
||||
return 7200; // 1 day
|
||||
}
|
||||
|
||||
function votingPeriod() public pure override returns (uint256) {
|
||||
return 50400; // 1 week
|
||||
}
|
||||
|
||||
function proposalThreshold() public pure override returns (uint256) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The functions below are overrides required by Solidity.
|
||||
|
||||
function state(uint256 proposalId) public view override(Governor, GovernorTimelockControl) returns (ProposalState) {
|
||||
return super.state(proposalId);
|
||||
}
|
||||
|
||||
function proposalNeedsQueuing(
|
||||
uint256 proposalId
|
||||
) public view virtual override(Governor, GovernorTimelockControl) returns (bool) {
|
||||
return super.proposalNeedsQueuing(proposalId);
|
||||
}
|
||||
|
||||
function _queueOperations(
|
||||
uint256 proposalId,
|
||||
address[] memory targets,
|
||||
uint256[] memory values,
|
||||
bytes[] memory calldatas,
|
||||
bytes32 descriptionHash
|
||||
) internal override(Governor, GovernorTimelockControl) returns (uint48) {
|
||||
return super._queueOperations(proposalId, targets, values, calldatas, descriptionHash);
|
||||
}
|
||||
|
||||
function _executeOperations(
|
||||
uint256 proposalId,
|
||||
address[] memory targets,
|
||||
uint256[] memory values,
|
||||
bytes[] memory calldatas,
|
||||
bytes32 descriptionHash
|
||||
) internal override(Governor, GovernorTimelockControl) {
|
||||
super._executeOperations(proposalId, targets, values, calldatas, descriptionHash);
|
||||
}
|
||||
|
||||
function _cancel(
|
||||
address[] memory targets,
|
||||
uint256[] memory values,
|
||||
bytes[] memory calldatas,
|
||||
bytes32 descriptionHash
|
||||
) internal override(Governor, GovernorTimelockControl) returns (uint256) {
|
||||
return super._cancel(targets, values, calldatas, descriptionHash);
|
||||
}
|
||||
|
||||
function _executor() internal view override(Governor, GovernorTimelockControl) returns (address) {
|
||||
return super._executor();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {ERC20} from "../../../token/ERC20/ERC20.sol";
|
||||
import {ERC20Permit} from "../../../token/ERC20/extensions/ERC20Permit.sol";
|
||||
import {ERC20Votes} from "../../../token/ERC20/extensions/ERC20Votes.sol";
|
||||
import {Nonces} from "../../../utils/Nonces.sol";
|
||||
|
||||
contract MyToken is ERC20, ERC20Permit, ERC20Votes {
|
||||
constructor() ERC20("MyToken", "MTK") ERC20Permit("MyToken") {}
|
||||
|
||||
// The functions below are overrides required by Solidity.
|
||||
|
||||
function _update(address from, address to, uint256 amount) internal override(ERC20, ERC20Votes) {
|
||||
super._update(from, to, amount);
|
||||
}
|
||||
|
||||
function nonces(address owner) public view virtual override(ERC20Permit, Nonces) returns (uint256) {
|
||||
return super.nonces(owner);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {ERC20} from "../../../token/ERC20/ERC20.sol";
|
||||
import {ERC20Permit} from "../../../token/ERC20/extensions/ERC20Permit.sol";
|
||||
import {ERC20Votes} from "../../../token/ERC20/extensions/ERC20Votes.sol";
|
||||
import {Nonces} from "../../../utils/Nonces.sol";
|
||||
|
||||
contract MyTokenTimestampBased is ERC20, ERC20Permit, ERC20Votes {
|
||||
constructor() ERC20("MyTokenTimestampBased", "MTK") ERC20Permit("MyTokenTimestampBased") {}
|
||||
|
||||
// Overrides IERC6372 functions to make the token & governor timestamp-based
|
||||
|
||||
function clock() public view override returns (uint48) {
|
||||
return uint48(block.timestamp);
|
||||
}
|
||||
|
||||
// solhint-disable-next-line func-name-mixedcase
|
||||
function CLOCK_MODE() public pure override returns (string memory) {
|
||||
return "mode=timestamp";
|
||||
}
|
||||
|
||||
// The functions below are overrides required by Solidity.
|
||||
|
||||
function _update(address from, address to, uint256 amount) internal override(ERC20, ERC20Votes) {
|
||||
super._update(from, to, amount);
|
||||
}
|
||||
|
||||
function nonces(address owner) public view virtual override(ERC20Permit, Nonces) returns (uint256) {
|
||||
return super.nonces(owner);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {IERC20, ERC20} from "../../../token/ERC20/ERC20.sol";
|
||||
import {ERC20Permit} from "../../../token/ERC20/extensions/ERC20Permit.sol";
|
||||
import {ERC20Votes} from "../../../token/ERC20/extensions/ERC20Votes.sol";
|
||||
import {ERC20Wrapper} from "../../../token/ERC20/extensions/ERC20Wrapper.sol";
|
||||
import {Nonces} from "../../../utils/Nonces.sol";
|
||||
|
||||
contract MyTokenWrapped is ERC20, ERC20Permit, ERC20Votes, ERC20Wrapper {
|
||||
constructor(
|
||||
IERC20 wrappedToken
|
||||
) ERC20("MyTokenWrapped", "MTK") ERC20Permit("MyTokenWrapped") ERC20Wrapper(wrappedToken) {}
|
||||
|
||||
// The functions below are overrides required by Solidity.
|
||||
|
||||
function decimals() public view override(ERC20, ERC20Wrapper) returns (uint8) {
|
||||
return super.decimals();
|
||||
}
|
||||
|
||||
function _update(address from, address to, uint256 amount) internal override(ERC20, ERC20Votes) {
|
||||
super._update(from, to, amount);
|
||||
}
|
||||
|
||||
function nonces(address owner) public view virtual override(ERC20Permit, Nonces) returns (uint256) {
|
||||
return super.nonces(owner);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// contracts/GameItems.sol
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {ERC1155} from "../../../../token/ERC1155/ERC1155.sol";
|
||||
|
||||
contract GameItems is ERC1155 {
|
||||
uint256 public constant GOLD = 0;
|
||||
uint256 public constant SILVER = 1;
|
||||
uint256 public constant THORS_HAMMER = 2;
|
||||
uint256 public constant SWORD = 3;
|
||||
uint256 public constant SHIELD = 4;
|
||||
|
||||
constructor() ERC1155("https://game.example/api/item/{id}.json") {
|
||||
_mint(msg.sender, GOLD, 10 ** 18, "");
|
||||
_mint(msg.sender, SILVER, 10 ** 27, "");
|
||||
_mint(msg.sender, THORS_HAMMER, 1, "");
|
||||
_mint(msg.sender, SWORD, 10 ** 9, "");
|
||||
_mint(msg.sender, SHIELD, 10 ** 9, "");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// contracts/MyERC115HolderContract.sol
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {ERC1155Holder} from "../../../../token/ERC1155/utils/ERC1155Holder.sol";
|
||||
|
||||
contract MyERC115HolderContract is ERC1155Holder {}
|
||||
@@ -0,0 +1,11 @@
|
||||
// contracts/GLDToken.sol
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {ERC20} from "../../../../token/ERC20/ERC20.sol";
|
||||
|
||||
contract GLDToken is ERC20 {
|
||||
constructor(uint256 initialSupply) ERC20("Gold", "GLD") {
|
||||
_mint(msg.sender, initialSupply);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// contracts/GameItem.sol
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {ERC721URIStorage, ERC721} from "../../../../token/ERC721/extensions/ERC721URIStorage.sol";
|
||||
|
||||
contract GameItem is ERC721URIStorage {
|
||||
uint256 private _nextTokenId;
|
||||
|
||||
constructor() ERC721("GameItem", "ITM") {}
|
||||
|
||||
function awardItem(address player, string memory tokenURI) public returns (uint256) {
|
||||
uint256 tokenId = _nextTokenId++;
|
||||
_mint(player, tokenId);
|
||||
_setTokenURI(tokenId, tokenURI);
|
||||
|
||||
return tokenId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {ERC721} from "../../../token/ERC721/ERC721.sol";
|
||||
import {Strings} from "../../../utils/Strings.sol";
|
||||
import {Base64} from "../../../utils/Base64.sol";
|
||||
|
||||
contract Base64NFT is ERC721 {
|
||||
using Strings for uint256;
|
||||
|
||||
constructor() ERC721("Base64NFT", "MTK") {}
|
||||
|
||||
// ...
|
||||
|
||||
function tokenURI(uint256 tokenId) public pure override returns (string memory) {
|
||||
// Equivalent to:
|
||||
// {
|
||||
// "name": "Base64NFT #1",
|
||||
// // Replace with extra ERC-721 Metadata properties
|
||||
// }
|
||||
// prettier-ignore
|
||||
string memory dataURI = string.concat("{\"name\": \"Base64NFT #", tokenId.toString(), "\"}");
|
||||
|
||||
return string.concat("data:application/json;base64,", Base64.encode(bytes(dataURI)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// contracts/Box.sol
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {Multicall} from "../../../utils/Multicall.sol";
|
||||
|
||||
contract Box is Multicall {
|
||||
function foo() public {
|
||||
// ...
|
||||
}
|
||||
|
||||
function bar() public {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user