Skip to content

Commit

Permalink
Merge pull request #3462 from jorgemmsilva/feat/evm-event-l1-nft-mint
Browse files Browse the repository at this point in the history
Feat: issue evm event on L1 nft mint
  • Loading branch information
jorgemmsilva authored Jul 10, 2024
2 parents 0a11da7 + 0f06829 commit 52dc844
Show file tree
Hide file tree
Showing 22 changed files with 257 additions and 44 deletions.
3 changes: 3 additions & 0 deletions packages/chain/mempool/mempool.go
Original file line number Diff line number Diff line change
Expand Up @@ -764,11 +764,13 @@ func (mpi *mempoolImpl) handleReceiveOnLedgerRequest(request isc.OnLedgerRequest
}
if request.SenderAccount() == nil {
// do not process requests without the sender feature
mpi.log.Warnf("dropping request, because it has no sender feature, ID=%v", requestID)
return
}
//
// Check, maybe mempool already has it.
if mpi.onLedgerPool.Has(requestRef) || mpi.timePool.Has(requestRef) {
mpi.log.Warnf("request already in the mempool, ID=%v", requestID)
return
}
//
Expand All @@ -779,6 +781,7 @@ func (mpi *mempoolImpl) handleReceiveOnLedgerRequest(request isc.OnLedgerRequest
panic(fmt.Errorf("cannot check if request was processed: %w", err))
}
if processed {
mpi.log.Warnf("dropping request, because it was already processed, ID=%v", requestID)
return
}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/evm/evmtest/ISCTest.abi
Original file line number Diff line number Diff line change
@@ -1 +1 @@
[{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"CustomError","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"s","type":"string"}],"name":"DummyEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"entropy","type":"bytes32"}],"name":"EntropyEvent","type":"event"},{"anonymous":false,"inputs":[],"name":"LoopEvent","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"bytes","name":"data","type":"bytes"}],"indexed":false,"internalType":"struct ISCRequestID","name":"reqID","type":"tuple"}],"name":"RequestIDEvent","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"bytes","name":"data","type":"bytes"}],"indexed":false,"internalType":"struct ISCAgentID","name":"sender","type":"tuple"}],"name":"SenderAccountEvent","type":"event"},{"anonymous":false,"inputs":[],"name":"SomeEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"","type":"address"}],"name":"TestSelfDestruct6780ContractCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"id","type":"bytes"}],"name":"nftMint","type":"event"},{"inputs":[],"name":"TokensForGas","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"callInccounter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emitDummyEvent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emitEntropy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emitEventAndRevert","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emitRequestID","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emitSenderAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getChainID","outputs":[{"internalType":"ISCChainID","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"loopWithGasLeft","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"makeISCPanic","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"foundrySN","type":"uint32"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint64","name":"storageDeposit","type":"uint64"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mintNFT","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"l1addr","type":"bytes"}],"name":"mintNFTToL1","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct ISCAgentID","name":"targetAgentID","type":"tuple"},{"components":[{"internalType":"uint64","name":"baseTokens","type":"uint64"},{"components":[{"components":[{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct NativeTokenID","name":"ID","type":"tuple"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct NativeToken[]","name":"nativeTokens","type":"tuple[]"},{"internalType":"NFTID[]","name":"nfts","type":"bytes32[]"}],"internalType":"struct ISCAssets","name":"allowance","type":"tuple"}],"name":"moveToAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"revertWithCustomError","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct L1Address","name":"receiver","type":"tuple"},{"internalType":"uint64","name":"baseTokens","type":"uint64"}],"name":"sendBaseTokens","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct L1Address","name":"receiver","type":"tuple"},{"internalType":"NFTID","name":"id","type":"bytes32"},{"internalType":"uint64","name":"storageDeposit","type":"uint64"}],"name":"sendNFT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"sendTo","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"testCallViewCaller","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"testRevertReason","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address payable","name":"beneficiary","type":"address"}],"name":"testSelfDestruct","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"testSelfDestruct6780","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"testStackOverflow","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[],"name":"testStaticCall","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"s","type":"string"}],"name":"triggerEvent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"s","type":"string"}],"name":"triggerEventFail","outputs":[],"stateMutability":"nonpayable","type":"function"}]
[{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"CustomError","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"s","type":"string"}],"name":"DummyEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"entropy","type":"bytes32"}],"name":"EntropyEvent","type":"event"},{"anonymous":false,"inputs":[],"name":"LoopEvent","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"bytes","name":"data","type":"bytes"}],"indexed":false,"internalType":"struct ISCRequestID","name":"reqID","type":"tuple"}],"name":"RequestIDEvent","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"bytes","name":"data","type":"bytes"}],"indexed":false,"internalType":"struct ISCAgentID","name":"sender","type":"tuple"}],"name":"SenderAccountEvent","type":"event"},{"anonymous":false,"inputs":[],"name":"SomeEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"","type":"address"}],"name":"TestSelfDestruct6780ContractCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"id","type":"bytes"}],"name":"nftMint","type":"event"},{"inputs":[],"name":"TokensForGas","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"callInccounter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emitDummyEvent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emitEntropy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emitEventAndRevert","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emitRequestID","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emitSenderAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getChainID","outputs":[{"internalType":"ISCChainID","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"loopWithGasLeft","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"makeISCPanic","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"foundrySN","type":"uint32"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint64","name":"storageDeposit","type":"uint64"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mintNFT","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"NFTID","name":"collectionID","type":"bytes32"}],"name":"mintNFTForCollection","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"l1addr","type":"bytes"}],"name":"mintNFTToL1","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct ISCAgentID","name":"targetAgentID","type":"tuple"},{"components":[{"internalType":"uint64","name":"baseTokens","type":"uint64"},{"components":[{"components":[{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct NativeTokenID","name":"ID","type":"tuple"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct NativeToken[]","name":"nativeTokens","type":"tuple[]"},{"internalType":"NFTID[]","name":"nfts","type":"bytes32[]"}],"internalType":"struct ISCAssets","name":"allowance","type":"tuple"}],"name":"moveToAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"revertWithCustomError","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct L1Address","name":"receiver","type":"tuple"},{"internalType":"uint64","name":"baseTokens","type":"uint64"}],"name":"sendBaseTokens","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct L1Address","name":"receiver","type":"tuple"},{"internalType":"NFTID","name":"id","type":"bytes32"},{"internalType":"uint64","name":"storageDeposit","type":"uint64"}],"name":"sendNFT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"sendTo","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"testCallViewCaller","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"testRevertReason","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address payable","name":"beneficiary","type":"address"}],"name":"testSelfDestruct","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"testSelfDestruct6780","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"testStackOverflow","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[],"name":"testStaticCall","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"s","type":"string"}],"name":"triggerEvent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"s","type":"string"}],"name":"triggerEventFail","outputs":[],"stateMutability":"nonpayable","type":"function"}]
2 changes: 1 addition & 1 deletion packages/evm/evmtest/ISCTest.bin

Large diffs are not rendered by default.

31 changes: 27 additions & 4 deletions packages/evm/evmtest/ISCTest.sol
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,8 @@ contract ISCTest {
ISCAgentID memory agentID = ISC.sandbox.getSenderAccount();

ISCDict memory params = ISCDict(new ISCDictItem[](2));
params.items[0] = ISCDictItem("I", "{\"name\": \"test\"}");
params.items[1] = ISCDictItem("a", agentID.data);
params.items[0] = ISCDictItem("I", "{\"name\": \"test\"}"); // immutable metadata
params.items[1] = ISCDictItem("a", agentID.data); // agentID

ISCDict memory ret = ISC.sandbox.call(
ISC.util.hn("accounts"),
Expand All @@ -243,15 +243,38 @@ contract ISCTest {
}


// mints an NFT as part of collectionID (requires the collection NFT to be owned by this contract)
function mintNFTForCollection(NFTID collectionID) public payable {
ISCAssets memory allowance;
allowance.baseTokens = 100000;

ISCAgentID memory agentID = ISC.sandbox.getSenderAccount();

ISCDict memory params = ISCDict(new ISCDictItem[](3));
params.items[0] = ISCDictItem("I", "{\"name\": \"test\"}"); // immutable metadata
params.items[1] = ISCDictItem("a", agentID.data); // agentID
params.items[2] = ISCDictItem("C", abi.encodePacked(collectionID)); // collectionID

ISCDict memory ret = ISC.sandbox.call(
ISC.util.hn("accounts"),
ISC.util.hn("mintNFT"),
params,
allowance
);
emit nftMint(ret.items[0].value);
}



function mintNFTToL1(bytes memory l1addr ) public payable {
ISCAssets memory allowance;
allowance.baseTokens = 100000;

ISCAgentID memory agentID = ISCTypes.newL1AgentID(l1addr);

ISCDict memory params = ISCDict(new ISCDictItem[](3));
params.items[0] = ISCDictItem("I", "{\"name\": \"test\"}");
params.items[1] = ISCDictItem("a", agentID.data);
params.items[0] = ISCDictItem("I", "{\"name\": \"test\"}"); // immutable metadata
params.items[1] = ISCDictItem("a", agentID.data); // agentID
bytes memory withdrawParam = new bytes(1);
withdrawParam[0] = 0x01;
params.items[2] = ISCDictItem("w", withdrawParam);
Expand Down
2 changes: 1 addition & 1 deletion packages/evm/evmtest/SelfDestruct6780.bin
Original file line number Diff line number Diff line change
@@ -1 +1 @@
6080604052348015600e575f80fd5b5061010e8061001c5f395ff3fe6080604052348015600e575f80fd5b50600436106026575f3560e01c8063bcfb195914602a575b5f80fd5b60406004803603810190603c919060b2565b6042565b005b8073ffffffffffffffffffffffffffffffffffffffff16ff5b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f608682605f565b9050919050565b609481607e565b8114609d575f80fd5b50565b5f8135905060ac81608d565b92915050565b5f6020828403121560c45760c3605b565b5b5f60cf8482850160a0565b9150509291505056fea2646970667358221220a41c7a6e911baa9745960580bdd0fdc6823695ec3789fe87a5f8726a09b5b30a64736f6c634300081a0033
6080604052348015600e575f80fd5b5061010e8061001c5f395ff3fe6080604052348015600e575f80fd5b50600436106026575f3560e01c8063bcfb195914602a575b5f80fd5b60406004803603810190603c919060b2565b6042565b005b8073ffffffffffffffffffffffffffffffffffffffff16ff5b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f608682605f565b9050919050565b609481607e565b8114609d575f80fd5b50565b5f8135905060ac81608d565b92915050565b5f6020828403121560c45760c3605b565b5b5f60cf8482850160a0565b9150509291505056fea2646970667358221220c545e030768d61daa0411c6fc386c0dafc130882b06268fed99feec06c2aa12064736f6c634300081a0033
4 changes: 4 additions & 0 deletions packages/kv/codec/encodego.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"math/big"
"time"

"github.com/ethereum/go-ethereum/common"

iotago "github.com/iotaledger/iota.go/v3"
"github.com/iotaledger/wasp/packages/hashing"
"github.com/iotaledger/wasp/packages/isc"
Expand Down Expand Up @@ -68,6 +70,8 @@ func Encode(v interface{}) []byte {
return EncodeRatio32(vt)
case *util.Ratio32:
return EncodeRatio32(*vt)
case common.Address:
return vt.Bytes()
default:
panic(fmt.Sprintf("Can't encode value %v", v))
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0xf48358eea8a78e3ea311ee6b8c67cf664fa1df7411c2dbb7d86875dd9ed40d2b
0x054bc728d6fc6392983981c78cc7f1e37947c378fcd7bb687f633251d7101fc5
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0x6e3f35b3f5a6b14f9001d42c1b8dd78c676a238af8202b3fb2c9b3fdecbefd01
0x93ae0b29d133ce13d27fae2ea08257f2258fe5fab8cb89f9bff0d1592b7d89a6
2 changes: 1 addition & 1 deletion packages/testutil/testdbhash/TestSelfDestruct-evm.hex
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0x6ff8ffff5befa3c4cf2bd6f14b492611a977c2abc83f8e5ba2088de7c2e16d12
0x890a1dad1110c96878fd4d91dba3fafccf7bcbd6339aa64a750eda41a284700a
2 changes: 1 addition & 1 deletion packages/testutil/testdbhash/TestSendBaseTokens-evm.hex
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0x29f7a125c10e0d3a49c7b697c54627910235b826b55c8cb3706167b94757a315
0x9ca6247f0595c26d1525ce260d1d1fe686793f1ae2ab79dbff8473be702d22d9
2 changes: 1 addition & 1 deletion packages/vm/core/accounts/internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ func debitBaseTokensFromAllowance(ctx isc.Sandbox, amount uint64, chainID isc.Ch
DebitFromAccount(ctx.SchemaVersion(), ctx.State(), CommonAccount(), storageDepositAssets, chainID)
}

func UpdateLatestOutputID(state kv.KVStore, anchorTxID iotago.TransactionID, blockIndex uint32) []iotago.NFTID {
func UpdateLatestOutputID(state kv.KVStore, anchorTxID iotago.TransactionID, blockIndex uint32) map[iotago.NFTID]isc.AgentID {
updateNativeTokenOutputIDs(state, anchorTxID)
updateFoundryOutputIDs(state, anchorTxID)
updateNFTOutputIDs(state, anchorTxID)
Expand Down
33 changes: 29 additions & 4 deletions packages/vm/core/accounts/nftmint.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/iotaledger/wasp/packages/kv/dict"
"github.com/iotaledger/wasp/packages/util/rwutil"
"github.com/iotaledger/wasp/packages/vm/core/errors/coreerrors"
"github.com/iotaledger/wasp/packages/vm/core/evm"
)

type mintedNFTRecord struct {
Expand Down Expand Up @@ -80,6 +81,7 @@ type mintParameters struct {
issuerAddress iotago.Address
ownerAgentID isc.AgentID
withdrawOnMint bool
collectionID iotago.NFTID
}

func mintParams(ctx isc.Sandbox) mintParameters {
Expand All @@ -98,9 +100,10 @@ func mintParams(ctx isc.Sandbox) mintParameters {
issuerAddress: chainAddress,
ownerAgentID: targetAgentID,
withdrawOnMint: withdrawOnMint,
collectionID: collectionID,
}

if collectionID != emptyNFTID {
if !collectionID.Empty() {
// assert the NFT of collectionID is on-chain and owned by the caller
if !hasNFT(ctx.State(), ctx.Caller(), collectionID) {
panic(errCollectionNotAllowed)
Expand Down Expand Up @@ -163,6 +166,26 @@ func mintNFT(ctx isc.Sandbox) dict.Dict {
// save the info required to credit the NFT on next block
newlyMintedNFTsMap(ctx.State()).SetAt(codec.Encode(positionInMintedList), rec.Bytes())

// register the collection in the EVM
if !params.collectionID.Empty() {
res := ctx.CallView(
evm.Contract.Hname(),
evm.FuncGetERC721CollectionAddress.Hname(),
dict.Dict{evm.FieldNFTCollectionID: codec.Encode(params.collectionID)},
)
exists := codec.MustDecodeBool(res.Get(evm.FieldResult))

if !exists {
// NOTE must not call `RegisterERC721NFTCollection` if already registered, otherwise it will panic
ctx.Call(
evm.Contract.Hname(),
evm.FuncRegisterERC721NFTCollection.Hname(),
dict.Dict{evm.FieldNFTCollectionID: codec.Encode(params.collectionID)},
nil,
)
}
}

return dict.Dict{
ParamMintID: mintID(ctx.StateAnchor().StateIndex+1, positionInMintedList),
}
Expand Down Expand Up @@ -190,11 +213,12 @@ func SaveMintedNFTOutput(state kv.KVStore, positionInMintedList, outputIndex uin
mintMap.SetAt(key, rec.Bytes())
}

func updateNewlyMintedNFTOutputIDs(state kv.KVStore, anchorTxID iotago.TransactionID, blockIndex uint32) []iotago.NFTID {
func updateNewlyMintedNFTOutputIDs(state kv.KVStore, anchorTxID iotago.TransactionID, blockIndex uint32) map[iotago.NFTID]isc.AgentID {
mintMap := newlyMintedNFTsMap(state)
nftMap := NFTOutputMap(state)
newNFTIDs := make([]iotago.NFTID, 0)
newNFTIDs := make(map[iotago.NFTID]isc.AgentID, 0)

// iterate the minted collection of NFT's that we're looking to co-relate with their NFTIDs
mintMap.Iterate(func(_, recBytes []byte) bool {
mintedRec := mintedNFTRecordFromBytes(recBytes)
// calculate the NFTID from the anchor txID + outputIndex
Expand All @@ -213,10 +237,11 @@ func updateNewlyMintedNFTOutputIDs(state kv.KVStore, anchorTxID iotago.Transacti
}
// save the mapping of [mintID => NFTID]
mintIDMap(state).SetAt(mintID(blockIndex, mintedRec.positionInMintedList), nftID[:])
newNFTIDs = append(newNFTIDs, nftID)
newNFTIDs[nftID] = mintedRec.owner

return true
})
// clear the minted collection
mintMap.Erase()

return newNFTIDs
Expand Down
Loading

0 comments on commit 52dc844

Please sign in to comment.