Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pointers contracts: support for ERC1155 and CW1155 contracts #1755

Open
wants to merge 90 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 69 commits
Commits
Show all changes
90 commits
Select commit Hold shift + click to select a range
9eab721
wip cw1155 pointer
apolloshab May 24, 2024
33d8bfd
cleanup todos
apolloshab Jun 5, 2024
0061483
sync events with current standard
apolloshab Jun 5, 2024
9f0d299
fix query BalanceOfBatch
apolloshab Jun 5, 2024
45c654f
fix import
apolloshab Jun 5, 2024
0269627
Fix up cwerc1155 compiled files
dvli2007 Jun 15, 2024
4d706dd
Add 1155 requests into bindings
dvli2007 Jun 20, 2024
533bca6
queries
mr-meat Jun 20, 2024
792da46
follow same coding style
mr-meat Jun 20, 2024
6304c6d
Add cwerc1155.wasm binary to `/contracts`
dvli2007 Jun 21, 2024
68df425
Add go code to support new pointer contract
dvli2007 Jun 21, 2024
3502209
Fix typo
dvli2007 Jun 21, 2024
cca521c
Add updated protobuf files
dvli2007 Jun 21, 2024
f7fa05d
Fix up tests
dvli2007 Jun 21, 2024
2e6622e
Merge pull request #5 from palletexchange/add-new-pointer
dvli2007 Jun 21, 2024
aa22642
Merge branch 'main' into cw1155
dvli2007 Jun 21, 2024
ae6a095
Deprecate pointer proposals
dvli2007 Jun 21, 2024
5082b6b
queries
mr-meat Jun 20, 2024
cb2ba41
follow same coding style
mr-meat Jun 20, 2024
d260408
safetransfer functions, royalyinfo, set approval
mr-meat Jun 25, 2024
1e2ca09
add in exe queries and royaltyinfo
mr-meat Jun 25, 2024
39978bb
Merge branch 'main' into cw1155
dvli2007 Jun 25, 2024
a05cbac
Merge branch 'cw1155' into davy/cw1155
dvli2007 Jun 25, 2024
1ee0e92
adding in transfer and approval tests
mr-meat Jun 25, 2024
1d91ef5
solc and abigen
mr-meat Jun 26, 2024
b117fb2
clean up unused artifacts
mr-meat Jun 26, 2024
8b818a0
Merge pull request #6 from palletexchange/erc1155
dvli2007 Jun 27, 2024
ed38c98
Merge branch 'cw1155' into davy/cw1155
dvli2007 Jun 27, 2024
68ed5a0
Add all go bindings
dvli2007 Jun 30, 2024
3989fc3
Merge pull request #7 from palletexchange/davy/cw1155
dvli2007 Jun 30, 2024
2cce20c
return unsupported for methods not supported in erc standard
apolloshab Jul 1, 2024
7b0668e
Merge pull request #9 from palletexchange/cw1155
scottirvine Jul 1, 2024
f5858a8
fix query BalanceOfBatch response
apolloshab Jul 1, 2024
5d0750c
Add new test files
dvli2007 Jul 1, 2024
a00687b
fix Erc1155BalanceOfBatchResponse
apolloshab Jul 2, 2024
18768c1
More testing
dvli2007 Jul 2, 2024
b2b9a6c
Merge pull request #8 from palletexchange/cw1155-cleanup
dvli2007 Jul 2, 2024
ae52356
Merge pull request #10 from palletexchange/davy/test-cw1155
dvli2007 Jul 2, 2024
327d5fd
Update cwerc1155.wasm
dvli2007 Jul 2, 2024
6736609
More tests
dvli2007 Jul 3, 2024
95fc243
return true/false instead of erroring in query IsApprovedForAll
apolloshab Jul 3, 2024
219a3ca
use correct response for query BalanceOfBatch
apolloshab Jul 3, 2024
134252a
pass optional token id field to evm query TotalSupply
apolloshab Jul 3, 2024
0c429e9
remove todos
apolloshab Jul 3, 2024
f2b67b3
remove AllTokenInfo query
apolloshab Jul 3, 2024
bcfc760
Fix balances query struct
dvli2007 Jul 3, 2024
eaa110d
Update and rebuild CW1155 pointer
dvli2007 Jul 3, 2024
d9b54b3
Add new cw1155 wasms
dvli2007 Jul 3, 2024
4ae3e4b
Merge pull request #12 from palletexchange/cw1155
scottirvine Jul 3, 2024
d91e3cb
merge
mr-meat Jul 3, 2024
846f7c2
Update cwerc1155.wasm
dvli2007 Jul 3, 2024
61e2c27
Fix up ERC1155 pointer tests
dvli2007 Jul 3, 2024
2c537ed
balanceOfBatch
mr-meat Jul 3, 2024
2c0c498
adding in expect calls
mr-meat Jul 3, 2024
7c8bc90
remove unused import
mr-meat Jul 3, 2024
60cbbce
Round of updates to cw1155 contracts
dvli2007 Jul 3, 2024
487ac30
Update cw1155 pointer tests
dvli2007 Jul 3, 2024
8c1e7a4
Fix: missing ERC1155TransferPayload
dvli2007 Jul 3, 2024
0d7a6cb
removing unnecessary return
mr-meat Jul 3, 2024
8949624
Update binary
dvli2007 Jul 3, 2024
b964fd0
Merge branch 'erc1155' into cw1155-localtest
dvli2007 Jul 3, 2024
db6af24
Fix balance of batch
dvli2007 Jul 3, 2024
b3ac9de
Merge branch 'erc1155' into cw1155-localtest
dvli2007 Jul 3, 2024
bcb3b3c
Merge pull request #14 from palletexchange/cw1155-localtest
dvli2007 Jul 3, 2024
a5a1c51
Merge branch 'main' into cw1155
dvli2007 Jul 4, 2024
e372e13
add minor checks
dvli2007 Jul 4, 2024
f129599
Update integration test with latest main updates
dvli2007 Jul 4, 2024
adc2519
Fix up erc721-payload and erc1155-payload cli commands
dvli2007 Jul 4, 2024
2e2d938
Merge branch 'main' into pointers/erc1155-cw1155
dvli2007 Jul 9, 2024
7541497
Lint code
dvli2007 Jul 12, 2024
a73a8a1
Merge branch 'main' into pointers/erc1155-cw1155
dvli2007 Jul 12, 2024
4f6aa54
Merge branch 'pointers/erc1155-cw1155' of github.com:palletexchange/s…
dvli2007 Jul 12, 2024
d39f380
Update integration test with new pointer contract code id
dvli2007 Jul 12, 2024
532a24d
Merge branch 'main' into pointers/erc1155-cw1155
dvli2007 Jul 22, 2024
0fdfbe5
Map CW1155 events to EVM
dvli2007 Jul 23, 2024
86d0dd3
updates from cw1155 base
apolloshab Jul 23, 2024
1caea56
update cw1155 base
apolloshab Jul 24, 2024
fd8ef0f
Test events emissions for cw1155 events
dvli2007 Jul 24, 2024
649e610
Update wasm build for cwerc1155
dvli2007 Jul 24, 2024
4229eeb
Merge branch 'update-base-cw1155' into pointers/erc1155-cw1155
dvli2007 Jul 24, 2024
66bc71c
Fix integration test 1
dvli2007 Jul 24, 2024
6478b68
update cw1155 cargo, add optimize script to cargo
apolloshab Jul 25, 2024
89b349b
Merge branch 'update-base-cw1155' into pointers/erc1155-cw1155
dvli2007 Jul 25, 2024
21f7765
Update wasm builds
dvli2007 Jul 25, 2024
01322e9
Merge branch 'main' into pointers/erc1155-cw1155
dvli2007 Jul 25, 2024
dbdcbc0
Add migrations for 1155s
dvli2007 Jul 25, 2024
2c0db74
Code quality
dvli2007 Jul 25, 2024
b9389cb
Merge branch 'main' into pointers/erc1155-cw1155
dvli2007 Jul 25, 2024
c004c54
Remove unnecessary lines
dvli2007 Jul 26, 2024
e9ffdc3
Merge branch 'main' into pointers/erc1155-cw1155
dvli2007 Jul 26, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ coverage.out
example/cosmwasm/echo/target
example/cosmwasm/cw20/target
example/cosmwasm/cw721/target
example/cosmwasm/cw1155/target

# Solidity contracts artifacts
contracts/artifacts
248 changes: 248 additions & 0 deletions contracts/src/CW1155ERC1155Pointer.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.12;

import "@openzeppelin/contracts/token/common/ERC2981.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {IWasmd} from "./precompiles/IWasmd.sol";
import {IJson} from "./precompiles/IJson.sol";
import {IAddr} from "./precompiles/IAddr.sol";

contract CW1155ERC1155Pointer is ERC1155, ERC2981 {

address constant WASMD_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000001002;
address constant JSON_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000001003;
address constant ADDR_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000001004;

string public Cw1155Address;
IWasmd public WasmdPrecompile;
IJson public JsonPrecompile;
IAddr public AddrPrecompile;
string public name;
string public symbol;

error NotImplementedOnCosmwasmContract(string method);
error NotImplemented(string method);

constructor(string memory Cw1155Address_, string memory name_, string memory symbol_) ERC1155("") {
Cw1155Address = Cw1155Address_;
WasmdPrecompile = IWasmd(WASMD_PRECOMPILE_ADDRESS);
JsonPrecompile = IJson(JSON_PRECOMPILE_ADDRESS);
AddrPrecompile = IAddr(ADDR_PRECOMPILE_ADDRESS);
name = name_;
symbol = symbol_;
}

function supportsInterface(bytes4 interfaceId) public pure override(ERC2981, ERC1155) returns (bool) {
return
interfaceId == type(IERC2981).interfaceId ||
interfaceId == type(IERC1155).interfaceId ||
interfaceId == type(IERC1155MetadataURI).interfaceId ||
interfaceId == type(IERC165).interfaceId;
}

// Queries
function balanceOf(address account, uint256 id) public view override returns (uint256) {
require(account != address(0), "ERC1155: cannot query balance of zero address");
string memory own = _formatPayload("owner", _doubleQuotes(AddrPrecompile.getSeiAddr(account)));
string memory tId = _formatPayload("token_id", _doubleQuotes(Strings.toString(id)));
string memory req = _curlyBrace(_formatPayload("balance_of",(_curlyBrace(_join(own,",",tId)))));
bytes memory response = WasmdPrecompile.query(Cw1155Address, bytes(req));
return JsonPrecompile.extractAsUint256(response, "balance");
}

function balanceOfBatch(address[] memory accounts, uint256[] memory ids) public view override returns (uint256[] memory balances){
if(accounts.length != ids.length){
revert ERC1155InvalidArrayLength(ids.length, accounts.length);
}
string memory ownerTokens = "[";
for (uint256 i = 0; i < accounts.length; i++) {
if (i > 0) {
ownerTokens = string.concat(ownerTokens, ",");
}
string memory ownerToken = string.concat("{\"owner\":\"", AddrPrecompile.getSeiAddr(accounts[i]));
ownerToken = string.concat(ownerToken, "\",\"token_id\":\"");
ownerToken = string.concat(ownerToken, Strings.toString(ids[i]));
ownerToken = string.concat(ownerToken, "\"}");
ownerTokens = string.concat(ownerTokens, ownerToken);
}
ownerTokens = string.concat(ownerTokens, "]");
string memory req = _curlyBrace(_formatPayload("balance_of_batch", ownerTokens));
bytes memory response = WasmdPrecompile.query(Cw1155Address, bytes(req));
bytes[] memory parseResponse = JsonPrecompile.extractAsBytesList(response, "balances");
require(parseResponse.length == accounts.length, "Invalid balance_of_batch response");
balances = new uint256[](parseResponse.length);
for(uint256 i = 0; i < parseResponse.length; i++){
balances[i] = JsonPrecompile.extractAsUint256(parseResponse[i], "amount");
}
}

function uri(uint256 id) public view override returns (string memory) {
string memory tId = _curlyBrace(_formatPayload("token_id", _doubleQuotes(Strings.toString(id))));
string memory req = _curlyBrace(_formatPayload("token_info",(tId)));
bytes memory response = WasmdPrecompile.query(Cw1155Address, bytes(req));
return string(JsonPrecompile.extractAsBytes(response, "token_uri"));
}

function isApprovedForAll(address owner, address operator) public view override returns (bool) {
string memory own = _formatPayload("owner", _doubleQuotes(AddrPrecompile.getSeiAddr(owner)));
string memory op = _formatPayload("operator", _doubleQuotes(AddrPrecompile.getSeiAddr(operator)));
string memory req = _curlyBrace(_formatPayload("is_approved_for_all",(_curlyBrace(_join(own,",",op)))));
bytes32 response = keccak256(WasmdPrecompile.query(Cw1155Address, bytes(req)));
bytes32 approvedMsg = keccak256("{\"approved\":true}");
bytes32 unapprovedMsg = keccak256("{\"approved\":false}");
if (response == approvedMsg) {
return true;
} else if (response == unapprovedMsg) {
return false;
}
revert NotImplementedOnCosmwasmContract("is_approved_for_all");
}

// ERC1155Supply
function totalSupply() public view virtual returns (uint256) {
bytes memory response = WasmdPrecompile.query(Cw1155Address, bytes("{\"num_tokens\":{}}"));
return JsonPrecompile.extractAsUint256(response, "count");
}

function totalSupply(uint256 id) public view virtual returns (uint256) {
string memory query = string.concat(
string.concat("{\"num_tokens\":{\"token_id\":\"", Strings.toString(id)),
"\"}}"
);
bytes memory response = WasmdPrecompile.query(Cw1155Address, bytes(query));
return JsonPrecompile.extractAsUint256(response, "count");
}

function exists(uint256 id) public view virtual returns (bool) {
return totalSupply(id) > 0;
}

// 2981
function royaltyInfo(uint256 tokenId, uint256 salePrice) public view override returns (address, uint256) {
bytes memory checkRoyaltyResponse = WasmdPrecompile.query(Cw1155Address, bytes("{\"extension\":{\"msg\":{\"check_royalties\":{}}}}"));
bytes memory isRoyaltyImplemented = JsonPrecompile.extractAsBytes(checkRoyaltyResponse, "royalty_payments");
if (keccak256(isRoyaltyImplemented) != keccak256("true")) {
revert NotImplementedOnCosmwasmContract("royalty_info");
}
string memory tId = _formatPayload("token_id", _doubleQuotes(Strings.toString(tokenId)));
string memory sPrice = _formatPayload("sale_price", _doubleQuotes(Strings.toString(salePrice)));
string memory req = _curlyBrace(_formatPayload("royalty_info", _curlyBrace(_join(tId, ",", sPrice))));
string memory fullReq = _curlyBrace(_formatPayload("extension", _curlyBrace(_formatPayload("msg", req))));
bytes memory response = WasmdPrecompile.query(Cw1155Address, bytes(fullReq));
bytes memory addr = JsonPrecompile.extractAsBytes(response, "address");
uint256 amt = JsonPrecompile.extractAsUint256(response, "royalty_amount");
if (addr.length == 0) {
return (address(0), amt);
}
return (AddrPrecompile.getEvmAddr(string(addr)), amt);
}

//transactions
function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes memory data) public override {
require(to != address(0), "ERC1155: transfer to the zero address");
require(balanceOf(from, id) >= amount, "ERC1155: insufficient balance for transfer");
require(msg.sender == from || isApprovedForAll(from, msg.sender), "ERC1155: caller is not approved to transfer");

string memory f = _formatPayload("from", _doubleQuotes(AddrPrecompile.getSeiAddr(from)));
string memory t = _formatPayload("to", _doubleQuotes(AddrPrecompile.getSeiAddr(to)));
string memory tId = _formatPayload("token_id", _doubleQuotes(Strings.toString(id)));
string memory amt = _formatPayload("amount", _doubleQuotes(Strings.toString(amount)));

string memory req = _curlyBrace(_formatPayload("send",(_curlyBrace(_join(f,",",_join(t,",",_join(tId,",",amt)))))));
_execute(bytes(req));
emit TransferSingle(msg.sender, from, to, id, amount);
if (to.code.length > 0) {
require(
IERC1155Receiver(to).onERC1155Received(
msg.sender, from, id, amount, data
) == IERC1155Receiver.onERC1155Received.selector,
"unsafe transfer"
);
}
}

function safeBatchTransferFrom(address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) public override {
require(to != address(0), "ERC1155: transfer to the zero address");
require(msg.sender == from || isApprovedForAll(from, msg.sender), "ERC1155: caller is not approved to transfer");
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
address[] memory batchFrom = new address[](ids.length);
for(uint256 i = 0; i < ids.length; i++){
batchFrom[i] = from;
}
uint256[] memory balances = balanceOfBatch(batchFrom, ids);
for(uint256 i = 0; i < balances.length; i++){
require(balances[i] >= amounts[i], "ERC1155: insufficient balance for transfer");
}

string memory payload = string.concat("{\"send_batch\":{\"from\":\"", AddrPrecompile.getSeiAddr(from));
payload = string.concat(payload, "\",\"to\":\"");
payload = string.concat(payload, AddrPrecompile.getSeiAddr(to));
payload = string.concat(payload, "\",\"batch\":[");
for(uint256 i = 0; i < ids.length; i++){
string memory batch = string.concat("{\"token_id\":\"", Strings.toString(ids[i]));
batch = string.concat(batch, "\",\"amount\":\"");
batch = string.concat(batch, Strings.toString(amounts[i]));
if (i < ids.length - 1) {
batch = string.concat(batch, "\"},");
} else {
batch = string.concat(batch, "\"}");
}
payload = string.concat(payload, batch);
}
payload = string.concat(payload, "]}}");
_execute(bytes(payload));
emit TransferBatch(msg.sender, from, to, ids, amounts);
if (to.code.length > 0) {
require(
IERC1155Receiver(to).onERC1155BatchReceived(
msg.sender, from, ids, amounts, data
) == IERC1155Receiver.onERC1155Received.selector,
"unsafe transfer"
);
}
}

function setApprovalForAll(address operator, bool approved) public override {
string memory op = _curlyBrace(_formatPayload("operator", _doubleQuotes(AddrPrecompile.getSeiAddr(operator))));
if (approved) {
_execute(bytes(_curlyBrace(_formatPayload("approve_all", op))));
} else {
_execute(bytes(_curlyBrace(_formatPayload("revoke_all", op))));
}
emit ApprovalForAll(msg.sender, operator, approved);
}

function _execute(bytes memory req) internal returns (bytes memory) {
(bool success, bytes memory ret) = WASMD_PRECOMPILE_ADDRESS.delegatecall(
abi.encodeWithSignature(
"execute(string,bytes,bytes)",
Cw1155Address,
bytes(req),
bytes("[]")
)
);
require(success, "CosmWasm execute failed");
return ret;
}

function _formatPayload(string memory key, string memory value) internal pure returns (string memory) {
return _join(_doubleQuotes(key), ":", value);
}

function _curlyBrace(string memory s) internal pure returns (string memory) {
return string.concat("{", string.concat(s, "}"));
}

function _doubleQuotes(string memory s) internal pure returns (string memory) {
return string.concat("\"", string.concat(s, "\""));
}

function _join(string memory a, string memory separator, string memory b) internal pure returns (string memory) {
return string.concat(a, string.concat(separator, b));
}
}
49 changes: 49 additions & 0 deletions contracts/src/ERC1155.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/common/ERC2981.sol";
import "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Supply.sol";

contract ERC1155Example is ERC1155Supply,ERC2981 {
string public name = "DummyERC1155";

string public symbol = "DUMMY";

string private _uri = "https://example.com/{id}";

address private _randomAddress1 = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266;
address private _randomAddress2 = 0xF39fD6e51Aad88F6f4CE6AB8827279CFffb92267;

constructor() ERC1155(_uri) {
setDefaultRoyalty(_randomAddress1);

mintForTest(_randomAddress1, 0);
mintForTest(_randomAddress2, 4);
}

function mintForTest(address recipient, uint256 startId) public virtual {
uint256[] memory tids = new uint256[](6);
tids[0] = startId;
tids[1] = startId + 1;
tids[2] = startId + 2;
tids[3] = startId + 3;
tids[4] = startId + 4;
tids[5] = startId + 5;
uint256[] memory values = new uint256[](6);
values[0] = 10;
values[1] = 11;
values[2] = 12;
values[3] = 13;
values[4] = 14;
values[5] = 15;
_mintBatch(recipient, tids, values, '0x0');
}

function supportsInterface(bytes4 interfaceId) public view override(ERC1155, ERC2981) returns (bool) {
return super.supportsInterface(interfaceId);
}

function setDefaultRoyalty(address receiver) public {
_setDefaultRoyalty(receiver, 500);
}
}
Loading
Loading