NFTs
Aztec Connect
Solidity
This bridge allows users to deposit and withdraw NFTs to/from Aztec Connect as well as send their NFTs to other bridge contracts. A user may want to send their NFT to another bridge contract because it may have additional functionality (swapping, minting, etc).
ERC-721 contracts on Etheruem.
ERC-721 contracts are the most widely used NFT standard. A bridge that supports 721 contracts should be able to handle most NFTs.
What is the flow of the bridge?
Please list any edge cases that may restrict the usefulness of the bridge or that the bridge prevents explicit.
As written, this bridge has very little functionality. We will think about how to extend this functionality in future NFT specs.
Providing privacy for NFTs is also tricky because each NFT is unique. Aztec users typically get privacy by hiding a crowd of users, but with NFTs the size of the crowd is 1.
How can the accounting of the bridge be impacted by interactions performed by other parties than the bridge? Example, if borrowing, how does it handle liquidations etc.
What functions are available in /src/client? How should they be used?
getAuxData
getExpectedOutput
getInteractionPresentValue
No
Yes. The bridge stores a few things in state
Nft data is stored in a NftAsset struct
struct NftAsset {
address collection;
uint256 tokenId;
}
// virtual asset id => NftAsset
mapping(uint256 => NftAsset) public nftAssets;
Cases:
// DEPOSIT
// return virutal asset id, will not actually match to NFT until matchDeposit is called from ethereum
if(
_inputAssetA.assetType == AztecTypes.AztecAssetType.ETH &&
_outputAssetA.assetType == AztecTypes.AztecAssetType.VIRTUAL
) {
require(_totalInputValue == 1, "send only 1 wei");
tokens[_interactionNonce] = NftAsset({
collection: address(0x0),
id: 0
});
return (1, 0, false);
}
// WITHDRAW
else if (
_inputAssetA.assetType == AztecTypes.AztecAssetType.VIRTUAL &&
_outputAssetA.assetType == AztecTypes.AztecAssetType.ETH
) {
NftAsset token = tokens[inputAssetA.id];
require(token.collection != address(0x0), "NFT doesn't exist");
address _to = registry.addresses(_auxData);
require(_to != address(0x0), "unregistered withdraw address");
NFT(token.collection).transferFrom(this, _to, token.id);
delete tokens[inputAssetA.id];
return (0, 0, false);
}
// TRANSFER TO OTHER BRIDGE CONTRACT
else if (
_inputAssetA.assetType == AztecTypes.AztecAssetType.VIRTUAL &&
_outputAssetA.assetType == AztecTypes.AztecAssetType.VIRTUAL
) {
NftAsset token = tokens[inputAssetA.id];
require(token.collection != address(0x0), "NFT doesn't exist");
address to = AddressRegistry.addresses(auxData);
delete tokens[inputAssetA.id];
Nft(token.collection).approve(to, token.id);
NftVault(to).matchDeposit(_interactionNonce, token.collection, token.id);
return (1, 0, false);
}
User Flow:
matchDeposit
, which takes the NFT and holds it, matching the owner to the virtual asset idfunction matchDeposit(uint256 _virtualAssetId, address _collection, uint256 _tokenId) external {
if (nftAssets[_virtualAssetId].collection != address(0x0)) {
revert InvalidVirtualAssetId();
}
nftAssets[_virtualAssetId] = NftAsset({collection: _collection, tokenId: _tokenId});
IERC721(_collection).transferFrom(msg.sender, address(this), _tokenId);
emit NftDeposit(_virtualAssetId, _collection, _tokenId);
}