external messages that perform data modifications like Transfer or mintNFT can only be called after the execution of my smart contract, like after all code in my contract is finished. Is that the case?
Yes, that is correct. The CosmWasm runtime (which is the smart contract runtime model we use for secret contracts) follows the “actors” model, so only one contract has mutable access to the storage at a time, and you can trigger callbacks (i.e. send messages) between contracts, effectively handing over control between different “actors”. You can also send out multiple callbacks after your contract finishes running, including a callback to yourself. These callbacks are processed in a depth-first fashion, so a contract A can issue two callbacks to B and C. B will be processed first, and can issue more callbacks that will be processed before C. Contracts can also make callbacks to each other, e.g. A->B->C->B->A->C etc, and this already happens on mainnet quite often. (but it requires some collaborative behavior from the contracts.)
So we couldn’t, for instance, mint an NFT and then store its ID in a separate minter contract because the minter contract cannot execute code after sending an external message. We would have to make the mintNFT supply a random token id for the mint and store that?
@baedrik can comment on the best way to do this with SNIP-721 (and you can always extend it if you need to) but from what i remember to mint an NFT you have to provide its ID in the first place. So your contract can pick a new ID, save it in its own state, then issue two callbacks:
- mint an NFT with the ID
- inform some other contract that the NFT was minted.
If the ID doesn’t exist, the tx will fail at step 1, and revert the state of your contract to before the TX.
If you want to avoid the revert, you can query the NFT contract first to see if the ID is available, and if it isn’t, not send the callback in the first place (and don’t return an error so it doesn’t get reverted)