Skip to content

Commit

Permalink
[EVM] Add erc721 to loadtest (#1428)
Browse files Browse the repository at this point in the history
* test erc721

* add erc721

* Silence output from other commands that break erc721 deployment

* goimports

---------

Co-authored-by: Philip Su <[email protected]>
  • Loading branch information
stevenlanders and philipsu522 authored Mar 12, 2024
1 parent e823eb3 commit 21b0e6c
Show file tree
Hide file tree
Showing 10 changed files with 1,741 additions and 5 deletions.
188 changes: 188 additions & 0 deletions contracts/src/ERC721.sol
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);
}
}
38 changes: 38 additions & 0 deletions contracts/test/ERC721Test.js
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()
})
})
});
14 changes: 14 additions & 0 deletions loadtest/contracts/deploy_erc721.sh
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'
Loading

0 comments on commit 21b0e6c

Please sign in to comment.