Skip to content

Commit

Permalink
Gas optimization: minor erc721 pointer (#1680)
Browse files Browse the repository at this point in the history
* Make `balanceOf` more gas efficient (~20% gas savings)

* Make `tokenSupply` more gas efficient

* Update CW721ERC721Pointer bin and bump version
  • Loading branch information
dvli2007 authored May 17, 2024
1 parent 96ec672 commit 16a2b18
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 17 deletions.
31 changes: 19 additions & 12 deletions contracts/src/CW721ERC721Pointer.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
pragma solidity ^0.8.12;

import "@openzeppelin/contracts/token/common/ERC2981.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
Expand Down Expand Up @@ -46,18 +46,26 @@ contract CW721ERC721Pointer is ERC721,ERC2981 {
}
uint256 numTokens = 0;
string memory startAfter;
string memory ownerAddr = _formatPayload("owner", _doubleQuotes(AddrPrecompile.getSeiAddr(owner)));
string memory req = _curlyBrace(_formatPayload("tokens", _curlyBrace(ownerAddr)));
string memory qb = string.concat(
string.concat("\"limit\":1000,\"owner\":\"", AddrPrecompile.getSeiAddr(owner)),
"\""
);
bytes32 terminator = keccak256("{\"tokens\":[]}");

bytes[] memory tokens;
uint256 tokensLength;
string memory req = string.concat(string.concat("{\"tokens\":{", qb), "}}");
bytes memory response = WasmdPrecompile.query(Cw721Address, bytes(req));
bytes[] memory tokens = JsonPrecompile.extractAsBytesList(response, "tokens");
uint256 tokensLength = tokens.length;
while (tokensLength > 0) {
numTokens += tokensLength;
startAfter = _formatPayload("start_after", string(tokens[tokensLength-1]));
req = _curlyBrace(_formatPayload("tokens", _curlyBrace(_join(ownerAddr, startAfter, ","))));
response = WasmdPrecompile.query(Cw721Address, bytes(req));
while (keccak256(response) != terminator) {
tokens = JsonPrecompile.extractAsBytesList(response, "tokens");
tokensLength = tokens.length;
numTokens += tokensLength;
startAfter = string.concat(",\"start_after\":", string(tokens[tokensLength-1]));
req = string.concat(
string.concat("{\"tokens\":{", string.concat(qb, startAfter)),
"}}"
);
response = WasmdPrecompile.query(Cw721Address, bytes(req));
}
return numTokens;
}
Expand Down Expand Up @@ -128,8 +136,7 @@ contract CW721ERC721Pointer is ERC721,ERC2981 {

// 721-Enumerable
function totalSupply() public view virtual returns (uint256) {
string memory req = _curlyBrace(_formatPayload("num_tokens", "{}"));
bytes memory response = WasmdPrecompile.query(Cw721Address, bytes(req));
bytes memory response = WasmdPrecompile.query(Cw721Address, bytes("{\"num_tokens\":{}}"));
return JsonPrecompile.extractAsUint256(response, "count");
}

Expand Down
20 changes: 17 additions & 3 deletions contracts/test/CW721ERC721PointerTest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -106,17 +106,17 @@ contract CW721ERC721PointerTest is Test {
function testBalanceOf() public {
vm.mockCall(
WASMD_PRECOMPILE_ADDRESS,
abi.encodeWithSignature("query(string,bytes)", MockCWContractAddress, bytes("{\"tokens\":{\"owner\":\"sei19zhelek4q5lt4zam8mcarmgv92vzgqd3ux32jw\"}}")),
abi.encodeWithSignature("query(string,bytes)", MockCWContractAddress, bytes("{\"tokens\":{\"limit\":1000,\"owner\":\"sei19zhelek4q5lt4zam8mcarmgv92vzgqd3ux32jw\"}}")),
abi.encode("{\"tokens\":[\"a\",\"b\"]}")
);
vm.mockCall(
WASMD_PRECOMPILE_ADDRESS,
abi.encodeWithSignature("query(string,bytes)", MockCWContractAddress, bytes("{\"tokens\":{\"owner\":\"sei19zhelek4q5lt4zam8mcarmgv92vzgqd3ux32jw\",\"start_after\":\"b\"}}")),
abi.encodeWithSignature("query(string,bytes)", MockCWContractAddress, bytes("{\"tokens\":{\"limit\":1000,\"owner\":\"sei19zhelek4q5lt4zam8mcarmgv92vzgqd3ux32jw\",\"start_after\":\"b\"}}")),
abi.encode("{\"tokens\":[\"c\",\"d\"]}")
);
vm.mockCall(
WASMD_PRECOMPILE_ADDRESS,
abi.encodeWithSignature("query(string,bytes)", MockCWContractAddress, bytes("{\"tokens\":{\"owner\":\"sei19zhelek4q5lt4zam8mcarmgv92vzgqd3ux32jw\",\"start_after\":\"d\"}}")),
abi.encodeWithSignature("query(string,bytes)", MockCWContractAddress, bytes("{\"tokens\":{\"limit\":1000,\"owner\":\"sei19zhelek4q5lt4zam8mcarmgv92vzgqd3ux32jw\",\"start_after\":\"d\"}}")),
abi.encode("{\"tokens\":[]}")
);
bytes[] memory resp1 = new bytes[](2);
Expand Down Expand Up @@ -158,6 +158,20 @@ contract CW721ERC721PointerTest is Test {
assertEq(pointer.ownerOf(1), 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266);
}

function testTotalSupply() public {
vm.mockCall(
WASMD_PRECOMPILE_ADDRESS,
abi.encodeWithSignature("query(string,bytes)", MockCWContractAddress, bytes("{\"num_tokens\":{}}")),
abi.encode("{\"count\":100}")
);
vm.mockCall(
JSON_PRECOMPILE_ADDRESS,
abi.encodeWithSignature("extractAsUint256(bytes,string)", bytes("{\"count\":100}"), "count"),
abi.encode(100)
);
assertEq(pointer.totalSupply(), 100);
}

function testGetApproved() public {
vm.mockCall(
WASMD_PRECOMPILE_ADDRESS,
Expand Down
2 changes: 1 addition & 1 deletion x/evm/artifacts/cw721/CW721ERC721Pointer.bin

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion x/evm/artifacts/cw721/artifacts.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"github.com/ethereum/go-ethereum/accounts/abi"
)

const CurrentVersion uint16 = 3
const CurrentVersion uint16 = 4

//go:embed CW721ERC721Pointer.abi
//go:embed CW721ERC721Pointer.bin
Expand Down

0 comments on commit 16a2b18

Please sign in to comment.