-
Notifications
You must be signed in to change notification settings - Fork 828
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[EVM] Add erc721 to loadtest (#1428)
* test erc721 * add erc721 * Silence output from other commands that break erc721 deployment * goimports --------- Co-authored-by: Philip Su <philip.su.522@gmail.com>
- Loading branch information
Showing
10 changed files
with
1,741 additions
and
5 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,188 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.20; | ||
|
||
interface IERC165 { | ||
function supportsInterface(bytes4 interfaceID) external view returns (bool); | ||
} | ||
|
||
interface IERC721 is IERC165 { | ||
function balanceOf(address owner) external view returns (uint balance); | ||
|
||
function ownerOf(uint tokenId) external view returns (address owner); | ||
|
||
function safeTransferFrom(address from, address to, uint tokenId) external; | ||
|
||
function safeTransferFrom( | ||
address from, | ||
address to, | ||
uint tokenId, | ||
bytes calldata data | ||
) external; | ||
|
||
function transferFrom(address from, address to, uint tokenId) external; | ||
|
||
function approve(address to, uint tokenId) external; | ||
|
||
function getApproved(uint tokenId) external view returns (address operator); | ||
|
||
function setApprovalForAll(address operator, bool _approved) external; | ||
|
||
function isApprovedForAll( | ||
address owner, | ||
address operator | ||
) external view returns (bool); | ||
} | ||
|
||
interface IERC721Receiver { | ||
function onERC721Received( | ||
address operator, | ||
address from, | ||
uint tokenId, | ||
bytes calldata data | ||
) external returns (bytes4); | ||
} | ||
|
||
contract ERC721 is IERC721 { | ||
event Transfer(address indexed from, address indexed to, uint indexed id); | ||
event Approval(address indexed owner, address indexed spender, uint indexed id); | ||
event ApprovalForAll( | ||
address indexed owner, | ||
address indexed operator, | ||
bool approved | ||
); | ||
|
||
// Mapping from token ID to owner address | ||
mapping(uint => address) internal _ownerOf; | ||
|
||
// Mapping owner address to token count | ||
mapping(address => uint) internal _balanceOf; | ||
|
||
// Mapping from token ID to approved address | ||
mapping(uint => address) internal _approvals; | ||
|
||
// Mapping from owner to operator approvals | ||
mapping(address => mapping(address => bool)) public isApprovedForAll; | ||
|
||
function supportsInterface(bytes4 interfaceId) external pure returns (bool) { | ||
return | ||
interfaceId == type(IERC721).interfaceId || | ||
interfaceId == type(IERC165).interfaceId; | ||
} | ||
|
||
function ownerOf(uint id) external view returns (address owner) { | ||
owner = _ownerOf[id]; | ||
require(owner != address(0), "token doesn't exist"); | ||
} | ||
|
||
function balanceOf(address owner) external view returns (uint) { | ||
require(owner != address(0), "owner = zero address"); | ||
return _balanceOf[owner]; | ||
} | ||
|
||
function setApprovalForAll(address operator, bool approved) external { | ||
isApprovedForAll[msg.sender][operator] = approved; | ||
emit ApprovalForAll(msg.sender, operator, approved); | ||
} | ||
|
||
function approve(address spender, uint id) external { | ||
address owner = _ownerOf[id]; | ||
require( | ||
msg.sender == owner || isApprovedForAll[owner][msg.sender], | ||
"not authorized" | ||
); | ||
|
||
_approvals[id] = spender; | ||
|
||
emit Approval(owner, spender, id); | ||
} | ||
|
||
function getApproved(uint id) external view returns (address) { | ||
require(_ownerOf[id] != address(0), "token doesn't exist"); | ||
return _approvals[id]; | ||
} | ||
|
||
function _isApprovedOrOwner( | ||
address owner, | ||
address spender, | ||
uint id | ||
) internal view returns (bool) { | ||
return (spender == owner || | ||
isApprovedForAll[owner][spender] || | ||
spender == _approvals[id]); | ||
} | ||
|
||
function transferFrom(address from, address to, uint id) public { | ||
require(from == _ownerOf[id], "from != owner"); | ||
require(to != address(0), "transfer to zero address"); | ||
|
||
require(_isApprovedOrOwner(from, msg.sender, id), "not authorized"); | ||
|
||
_balanceOf[from]--; | ||
_balanceOf[to]++; | ||
_ownerOf[id] = to; | ||
|
||
delete _approvals[id]; | ||
|
||
emit Transfer(from, to, id); | ||
} | ||
|
||
function safeTransferFrom(address from, address to, uint id) external { | ||
transferFrom(from, to, id); | ||
|
||
require( | ||
to.code.length == 0 || | ||
IERC721Receiver(to).onERC721Received(msg.sender, from, id, "") == | ||
IERC721Receiver.onERC721Received.selector, | ||
"unsafe recipient" | ||
); | ||
} | ||
|
||
function safeTransferFrom( | ||
address from, | ||
address to, | ||
uint id, | ||
bytes calldata data | ||
) external { | ||
transferFrom(from, to, id); | ||
|
||
require( | ||
to.code.length == 0 || | ||
IERC721Receiver(to).onERC721Received(msg.sender, from, id, data) == | ||
IERC721Receiver.onERC721Received.selector, | ||
"unsafe recipient" | ||
); | ||
} | ||
|
||
function _mint(address to, uint id) internal { | ||
require(to != address(0), "mint to zero address"); | ||
require(_ownerOf[id] == address(0), "already minted"); | ||
|
||
_balanceOf[to]++; | ||
_ownerOf[id] = to; | ||
|
||
emit Transfer(address(0), to, id); | ||
} | ||
|
||
function _burn(uint id) internal { | ||
address owner = _ownerOf[id]; | ||
require(owner != address(0), "not minted"); | ||
|
||
_balanceOf[owner] -= 1; | ||
|
||
delete _ownerOf[id]; | ||
delete _approvals[id]; | ||
|
||
emit Transfer(owner, address(0), id); | ||
} | ||
} | ||
|
||
contract MyNFT is ERC721 { | ||
function mint(address to, uint id) external { | ||
_mint(to, id); | ||
} | ||
|
||
function burn(uint id) external { | ||
require(msg.sender == _ownerOf[id], "not owner"); | ||
_burn(id); | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
const { ethers, upgrades } = require('hardhat'); | ||
|
||
describe("ERC721 test", function () { | ||
|
||
describe("ERC721 Throughput", function () { | ||
let erc721; | ||
let owner; | ||
let receiver; | ||
|
||
// This function deploys a new instance of the contract before each test | ||
beforeEach(async function () { | ||
let signers = await ethers.getSigners(); | ||
owner = signers[0]; | ||
receiver = signers[1]; | ||
const ERC721 = await ethers.getContractFactory("MyNFT") | ||
erc721 = await ERC721.deploy(); | ||
|
||
await Promise.all([erc721.waitForDeployment()]) | ||
}); | ||
|
||
it("should send 10000", async function(){ | ||
this.timeout(100000); // Increase timeout for this test | ||
|
||
let nonce = await ethers.provider.getTransactionCount(owner.address); | ||
const sends = [] | ||
|
||
const count = 10000 | ||
// start of all the rpc calls | ||
for(let i=0; i<count-1; i++){ | ||
sends.push(erc721.mint(receiver, i, {nonce: nonce})) | ||
nonce++ | ||
} | ||
await Promise.all(sends) | ||
const receipt = await erc721.mint(receiver, count-1, {nonce: nonce}) | ||
await receipt.wait() | ||
}) | ||
}) | ||
}); |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
#!/bin/bash | ||
|
||
# This script is used to deploy the NoopToken contract to the target network | ||
# This avoids trying to predict what address it might be deployed to | ||
|
||
evm_endpoint=$1 | ||
|
||
cd loadtest/contracts/evm || exit 1 | ||
|
||
./setup.sh > /dev/null | ||
|
||
git submodule update --init --recursive > /dev/null | ||
|
||
/root/.foundry/bin/forge create -r "$evm_endpoint" --private-key 57acb95d82739866a5c29e40b0aa2590742ae50425b7dd5b5d279a986370189e src/ERC721.sol:MyNFT --json | jq -r '.deployedTo' |
Oops, something went wrong.