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

Add CrossVM views #243

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
.vscode
node_modules
coverage.json
*.pkey
*.pkey
imports/
63 changes: 63 additions & 0 deletions contracts/CrossVMMetadataViews.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import "EVM"

/// This contract implements views originally proposed in FLIP-318 supporting NFT collections
/// with project-defined implementations across both Cadence & EVM.
///
access(all) contract CrossVMMetadataViews {

/// An enum denoting a VM. For now, there are only two VMs on Flow, but this enum could be
/// expanded in the event other VMs are supported on the network.
///
access(all) enum VM : UInt8 {
access(all) case Cadence
access(all) case EVM
}

/// View resolved at contract & resource level pointing to the associated EVM implementation.
/// NOTE: This view alone is not sufficient to validate an association across Cadence & EVM!
/// Both the Cadence Type/contract *and* the EVM contract should point to each other, with the
/// EVM pointer being facilitated by ICrossVM.sol contract interface methods. For more
/// information and context, see FLIP-318: https://github.com/onflow/flips/issues/318
///
access(all) struct EVMPointer {
/// The associated Cadence Type
access(all) let cadenceType: Type
/// The defining Cadence contract address
access(all) let cadenceContractAddress: Address
/// The associated EVM contract address
access(all) let evmContractAddress: EVM.EVMAddress
/// Whether the asset is Cadence- or EVM-native. Native here meaning the VM in which the
/// asset is distributed.
access(all) let nativeVM: VM

init(
cadenceType: Type,
cadenceContractAddress: Address,
evmContractAddress: EVM.EVMAddress,
nativeVM: VM
) {
self.cadenceType = cadenceType
self.cadenceContractAddress = cadenceContractAddress
self.evmContractAddress = evmContractAddress
self.nativeVM = nativeVM
}
}

/// View resolved at resource level denoting any metadata to be passed to the associated EVM
/// contract at the time of / bridging. This optional view would allow EVM side metadata to be
/// updated based on current Cadence state. If the / view is not supported, no bytes will be
/// passed into EVM when bridging.
///
access(all) struct EVMBytesMetadata {
/// Returns the bytes to be passed to the EVM contract on `fulfillToEVM` call, allowing the
/// EVM contract to update / the metadata associated with the NFT. The corresponding Solidity
/// `bytes` type allows the implementer greater / flexibility by enabling them to pass
/// arbitrary data between VMs.
access(all) let bytes: EVM.EVMBytes?

init(bytes: EVM.EVMBytes?) {
self.bytes = bytes
}
}

}
94 changes: 66 additions & 28 deletions flow.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,9 @@
{
"contracts": {
"BasicNFT": {
"source": "./contracts/BasicNFT.cdc",
"CrossVMMetadataViews": {
"source": "contracts/CrossVMMetadataViews.cdc",
"aliases": {
"testing": "0000000000000007"
}
},
"Burner": {
"source": "./contracts/utility/Burner.cdc",
"aliases": {
"emulator": "f8d6e0586b0a20c7",
"testing": "0000000000000001",
"testnet": "9a0766d93b6608b7"
"emulator": "f8d6e0586b0a20c7"
}
},
"ExampleNFT": {
Expand All @@ -20,15 +12,6 @@
"testing": "0000000000000007"
}
},
"FungibleToken": {
"source": "./contracts/utility/FungibleToken.cdc",
"aliases": {
"emulator": "ee82856bf20e2aa6",
"mainnet": "f233dcee88fe0abe",
"testing": "0000000000000002",
"testnet": "9a0766d93b6608b7"
}
},
"MaliciousNFT": {
"source": "./contracts/MaliciousNFT.cdc",
"aliases": {
Expand Down Expand Up @@ -57,12 +40,6 @@
"testnet": "631e88ae7f1d7c20"
}
},
"UniversalCollection": {
"source": "./contracts/UniversalCollection.cdc",
"aliases": {
"testing": "0000000000000007"
}
},
"ViewResolver": {
"source": "./contracts/ViewResolver.cdc",
"aliases": {
Expand All @@ -72,6 +49,68 @@
}
}
},
"dependencies": {
"Burner": {
"source": "mainnet://f233dcee88fe0abe.Burner",
"hash": "71af18e227984cd434a3ad00bb2f3618b76482842bae920ee55662c37c8bf331",
"aliases": {
"emulator": "f8d6e0586b0a20c7",
"mainnet": "f233dcee88fe0abe",
"testnet": "9a0766d93b6608b7"
}
},
"EVM": {
"source": "mainnet://e467b9dd11fa00df.EVM",
"hash": "5c69921fa06088b477e2758e122636b39d3d3eb5316807c206c5680d9ac74c7e",
"aliases": {
"emulator": "f8d6e0586b0a20c7",
"mainnet": "e467b9dd11fa00df",
"testnet": "8c5303eaa26202d6"
}
},
"FlowToken": {
"source": "mainnet://1654653399040a61.FlowToken",
"hash": "cefb25fd19d9fc80ce02896267eb6157a6b0df7b1935caa8641421fe34c0e67a",
"aliases": {
"emulator": "0ae53cb6e3f42a79",
"mainnet": "1654653399040a61",
"testnet": "7e60df042a9c0868"
}
},
"FungibleToken": {
"source": "mainnet://f233dcee88fe0abe.FungibleToken",
"hash": "050328d01c6cde307fbe14960632666848d9b7ea4fef03ca8c0bbfb0f2884068",
"aliases": {
"emulator": "ee82856bf20e2aa6",
"mainnet": "f233dcee88fe0abe",
"testnet": "9a0766d93b6608b7"
}
},
"FungibleTokenMetadataViews": {
"source": "mainnet://f233dcee88fe0abe.FungibleTokenMetadataViews",
"hash": "dff704a6e3da83997ed48bcd244aaa3eac0733156759a37c76a58ab08863016a",
"aliases": {
"emulator": "ee82856bf20e2aa6",
"mainnet": "f233dcee88fe0abe",
"testnet": "9a0766d93b6608b7"
}
},
"MetadataViews": {
"source": "mainnet://1d7e57aa55817448.MetadataViews",
"hash": "10a239cc26e825077de6c8b424409ae173e78e8391df62750b6ba19ffd048f51",
"aliases": {}
},
"NonFungibleToken": {
"source": "mainnet://1d7e57aa55817448.NonFungibleToken",
"hash": "b63f10e00d1a814492822652dac7c0574428a200e4c26cb3c832c4829e2778f0",
"aliases": {}
},
"ViewResolver": {
"source": "mainnet://1d7e57aa55817448.ViewResolver",
"hash": "374a1994046bac9f6228b4843cb32393ef40554df9bd9907a702d098a2987bde",
"aliases": {}
}
},
"networks": {
"emulator": "127.0.0.1:3569",
"mainnet": "access.mainnet.nodes.onflow.org:9000",
Expand Down Expand Up @@ -101,8 +140,7 @@
"MetadataViews",
"ExampleNFT",
"NFTForwarding",
"UniversalCollection",
"BasicNFT"
"CrossVMMetadataViews"
]
},
"mainnet": {
Expand Down
47 changes: 29 additions & 18 deletions lib/go/contracts/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,27 +14,30 @@ import (
)

var (
placeholderNonFungibleToken = regexp.MustCompile(`"NonFungibleToken"`)
nonFungibleTokenImport = "NonFungibleToken from "
placeholderMetadataViews = regexp.MustCompile(`"MetadataViews"`)
metadataViewsImport = "MetadataViews from "
placeholderFungibleToken = regexp.MustCompile(`"FungibleToken"`)
fungibleTokenImport = "FungibleToken from "
placeholderResolver = regexp.MustCompile(`"ViewResolver"`)
viewResolverImport = "ViewResolver from "
placeholderUniversalCollection = regexp.MustCompile(`"UniversalCollection"`)
universalCollectionImport = "UniversalCollection from "
placeholderNonFungibleToken = regexp.MustCompile(`"NonFungibleToken"`)
nonFungibleTokenImport = "NonFungibleToken from "
placeholderMetadataViews = regexp.MustCompile(`"MetadataViews"`)
metadataViewsImport = "MetadataViews from "
placeholderFungibleToken = regexp.MustCompile(`"FungibleToken"`)
fungibleTokenImport = "FungibleToken from "
placeholderResolver = regexp.MustCompile(`"ViewResolver"`)
viewResolverImport = "ViewResolver from "
placeholderUniversalCollection = regexp.MustCompile(`"UniversalCollection"`)
universalCollectionImport = "UniversalCollection from "
placeholderCrossVMMetadataViews = regexp.MustCompile(`"CrossVMMetadataViews"`)
crossVMMetadataViewsImport = "CrossVMMetadataViews from "
)

const (
filenameNonFungibleToken = "NonFungibleToken.cdc"
filenameExampleNFT = "ExampleNFT.cdc"
filenameMetadataViews = "MetadataViews.cdc"
filenameNFTMetadataViews = "NFTMetadataViews.cdc"
filenameViewResolver = "ViewResolver.cdc"
filenameUniversalCollection = "UniversalCollection.cdc"
filenameBasicNFT = "BasicNFT.cdc"
filenameFungibleToken = "utility/FungibleToken.cdc"
filenameNonFungibleToken = "NonFungibleToken.cdc"
filenameExampleNFT = "ExampleNFT.cdc"
filenameMetadataViews = "MetadataViews.cdc"
filenameCrossVMMetadataViews = "CrossVMMetadataViews.cdc"
filenameNFTMetadataViews = "NFTMetadataViews.cdc"
filenameViewResolver = "ViewResolver.cdc"
filenameUniversalCollection = "UniversalCollection.cdc"
filenameBasicNFT = "BasicNFT.cdc"
filenameFungibleToken = "utility/FungibleToken.cdc"
)

func withHexPrefix(address string) string {
Expand Down Expand Up @@ -84,6 +87,14 @@ func ViewResolver() []byte {
return []byte(code)
}

func CrossVMMetadataViews(evmAddress string) []byte {
code := assets.MustAssetString(filenameCrossVMMetadataViews)

code = placeholderFungibleToken.ReplaceAllString(code, fungibleTokenImport+withHexPrefix(evmAddress))

return []byte(code)
}

func UniversalCollection(nftAddress, resolverAddress, metadataAddress flow.Address) []byte {
code := assets.MustAssetString(filenameUniversalCollection)
code = placeholderMetadataViews.ReplaceAllString(code, metadataViewsImport+withHexPrefix(metadataAddress.String()))
Expand Down
5 changes: 5 additions & 0 deletions lib/go/contracts/contracts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,8 @@ func TestMetadataViewsContract(t *testing.T) {
contract := contracts.MetadataViews(addrA, addrA, addrA)
assert.NotNil(t, contract)
}

func TestCrossVMMetadataViewsContract(t *testing.T) {
contract := contracts.CrossVMMetadataViews(addrA)
assert.NotNil(t, contract)
}
31 changes: 27 additions & 4 deletions lib/go/contracts/internal/assets/assets.go

Large diffs are not rendered by default.

Loading