Skip to content

Commit

Permalink
Merge pull request #10 from axieinfinity/feature/erc721-common-upgrad…
Browse files Browse the repository at this point in the history
…able

Feat: Implement ERC721CommonUpgradeable
  • Loading branch information
huyhuynh3103 authored Apr 17, 2024
2 parents cadc772 + 3495978 commit 456898d
Show file tree
Hide file tree
Showing 14 changed files with 532 additions and 7 deletions.
2 changes: 2 additions & 0 deletions .github/template/create-pull-request.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
### Description
PR to merge from [{{ .fromBranch }}](/axieinfinity/foundry-contract-template/tree/{{ .fromBranch }}) to [{{ .toBranch }}](/axieinfinity/foundry-contract-template/tree/{{ .toBranch }}).
54 changes: 54 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: test

on:
push:
branches:
- mainnet
- testnet
- 'feature/*'
- 'features/*'
pull_request:
branches:
- mainnet
- testnet
- 'feature/*'
- 'features/*'

env:
FOUNDRY_PROFILE: ci

jobs:
check:
strategy:
fail-fast: true

name: Foundry project
runs-on: [self-hosted, dockerize]
steps:
- id: 'gh-app'
name: 'Get Token'
uses: 'tibdex/github-app-token@3beb63f4bd073e61482598c45c71c1019b59b73a' #v1.7.0
with:
app_id: ${{ secrets.GH_APP_ID }}
private_key: ${{ secrets.GH_PRIVATE_KEY }}

- uses: actions/[email protected]
with:
submodules: recursive
token: ${{ steps.gh-app.outputs.token }}

- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
with:
version: nightly

- name: Run Forge build
run: |
forge --version
forge build --sizes
id: build

- name: Run Forge tests
run: |
forge test -vvv
id: test
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,7 @@
path = lib/openzeppelin-contracts
url = https://github.com/openzeppelin/openzeppelin-contracts
branch = v4.8.2
[submodule "lib/openzeppelin-contracts-upgradeable"]
path = lib/openzeppelin-contracts-upgradeable
url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable
branch = v4.9.5
7 changes: 0 additions & 7 deletions .husky/pre-commit

This file was deleted.

3 changes: 3 additions & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ solc = '0.8.17'
evm_version = 'istanbul'
cache_path = 'cache/foundry'

extra_output = ["devdoc", "userdoc", "storagelayout"]
fs_permissions = [{ access = "read-write", path = "./" }]

[fmt]
line_length = 120
tab_width = 2
1 change: 1 addition & 0 deletions lib/openzeppelin-contracts-upgradeable
16 changes: 16 additions & 0 deletions scripts/deploy/logic/erc721-upgradeable-logic.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { HardhatRuntimeEnvironment } from 'hardhat/types';

const deploy = async ({ getNamedAccounts, deployments, ethers }: HardhatRuntimeEnvironment) => {
const { deploy } = deployments;
const { deployer } = await getNamedAccounts();
await deploy('SampleERC721CommonUpgradeableLogic', {
contract: 'ERC721CommonUpgradeable',
from: deployer,
log: true,
});
};

deploy.tags = ['SampleERC721CommonUpgradeableLogic'];
deploy.dependencies = ['VerifyContracts'];

export default deploy;
16 changes: 16 additions & 0 deletions scripts/deploy/proxy-admin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { HardhatRuntimeEnvironment } from 'hardhat/types';

const deploy = async ({ getNamedAccounts, deployments, ethers }: HardhatRuntimeEnvironment) => {
const { deploy } = deployments;
const { deployer } = await getNamedAccounts();
await deploy('ProxyAdmin', {
contract: 'ProxyAdmin',
from: deployer,
log: true,
});
};

deploy.tags = ['ProxyAdmin'];
deploy.dependencies = ['VerifyContracts'];

export default deploy;
25 changes: 25 additions & 0 deletions scripts/deploy/proxy/erc721-upgradeable-proxy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { ERC721CommonUpgradeable__factory } from '../../typechain-types';
import { HardhatRuntimeEnvironment } from 'hardhat/types';

const erc721Interface = ERC721CommonUpgradeable__factory.createInterface();

const deploy = async ({ getNamedAccounts, deployments, network }: HardhatRuntimeEnvironment) => {
const { deploy } = deployments;
const { deployer } = await getNamedAccounts();
const proxyAdmin = await deployments.get('ProxyAdmin');
const logicContract = await deployments.get('SampleERC721CommonUpgradeableLogic');

const data = erc721Interface.encodeFunctionData('initialize', ['SampleERC721', 'NFT', 'http://example.com/']);

await deploy('SampleERC721CommonUpgradeableProxy', {
contract: 'TransparentUpgradeableProxy',
from: deployer,
log: true,
args: [logicContract.address, proxyAdmin, data],
});
};

deploy.tags = ['SampleERC721CommonUpgradeableProxy'];
deploy.dependencies = ['VerifyContracts', 'ProxyAdmin', 'SampleERC721CommonUpgradeableLogic'];

export default deploy;
6 changes: 6 additions & 0 deletions src/mock/SampleERC721Upgradeable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import "../upgradeable/ERC721CommonUpgradeable.sol";

contract SampleERC721Upgradeable is ERC721CommonUpgradeable {}
89 changes: 89 additions & 0 deletions src/upgradeable/ERC721CommonUpgradeable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import "../refs/IERC721State.sol";
import "./refs/ERC721NonceUpgradeable.sol";
import "./ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol";

abstract contract ERC721CommonUpgradeable is
ERC721NonceUpgradeable,
ERC721PresetMinterPauserAutoIdCustomizedUpgradeable,
IERC721State
{
error ErrInvalidArrayLength();
error ErrNonExistentToken();

constructor() {
_disableInitializers();
}

/**
* @inheritdoc IERC721State
*/
function stateOf(uint256 _tokenId) external view virtual override returns (bytes memory) {
if (!_exists(_tokenId)) revert ErrNonExistentToken();
return abi.encodePacked(ownerOf(_tokenId), nonces[_tokenId], _tokenId);
}

/**
* @dev Override `ERC721Upgradeable-_baseURI`.
*/
function _baseURI()
internal
view
virtual
override(ERC721Upgradeable, ERC721PresetMinterPauserAutoIdCustomizedUpgradeable)
returns (string memory)
{
return super._baseURI();
}

/**
* @dev Override `IERC165-supportsInterface`.
*/
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(ERC721Upgradeable, ERC721PresetMinterPauserAutoIdCustomizedUpgradeable)
returns (bool)
{
return super.supportsInterface(interfaceId);
}

/**
* @dev Override `ERC721PresetMinterPauserAutoIdCustomizedUpgradeable-_beforeTokenTransfer`.
*/
function _beforeTokenTransfer(address _from, address _to, uint256 _firstTokenId, uint256 _batchSize)
internal
virtual
override(ERC721NonceUpgradeable, ERC721PresetMinterPauserAutoIdCustomizedUpgradeable)
{
super._beforeTokenTransfer(_from, _to, _firstTokenId, _batchSize);
}

/**
* @dev Bulk create new tokens for `_recipients`. Tokens ID will be automatically
* assigned (and available on the emitted {IERC721Upgradeable-Transfer} event), and the token
* URI autogenerated based on the base URI passed at construction.
*
* See {ERC721Upgradeable-_mint}.
*
* Requirements:
*
* - the caller must have the `MINTER_ROLE`.
*/
function bulkMint(address[] calldata _recipients)
external
virtual
onlyRole(MINTER_ROLE)
returns (uint256[] memory _tokenIds)
{
if (_recipients.length == 0) revert ErrInvalidArrayLength();
_tokenIds = new uint256[](_recipients.length);

for (uint256 _i = 0; _i < _recipients.length; _i++) {
_tokenIds[_i] = _mintFor(_recipients[_i]);
}
}
}
Loading

0 comments on commit 456898d

Please sign in to comment.