Skip to content

Commit

Permalink
Merge pull request #39 from onflow/evm-updates
Browse files Browse the repository at this point in the history
Updates to EVM interface
  • Loading branch information
sisyphusSmiling authored Apr 24, 2024
2 parents 8dce25e + b69b907 commit 2e0ae6a
Show file tree
Hide file tree
Showing 10 changed files with 144 additions and 31 deletions.
15 changes: 15 additions & 0 deletions .codecov.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
ignore:
- "./cadence/contracts/example-assets/*"
- "./cadence/contracts/utils/ArrayUtils.cdc"
- "./cadence/contracts/utils/StringUtils.cdc"
- "./cadence/contracts/utils/ScopedFTProvider.cdc"
- "./cadence/contracts/standards/Burner.cdc"
- "./cadence/contracts/standards/FlowStorageFees.cdc"
- "./cadence/contracts/standards/FlowToken.cdc"
- "./cadence/contracts/standards/FungibleToken.cdc"
- "./cadence/contracts/standards/FungibleTokenMetadataViews.cdc"
- "./cadence/contracts/standards/NonFungibleToken.cdc"
- "./cadence/contracts/standards/ViewResolver.cdc"
- "./cadence/contracts/templates/emulator/*"
- "./cadence/contracts/templates/previewnet/*"
- "./cadence/contracts/test/*"
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,7 @@ coverage.lcov

# Keys
*.pkey
*.pem
*.pem

# Local configs
local.flow.json
14 changes: 5 additions & 9 deletions cadence/contracts/bridge/FlowEVMBridgeAccessor.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -160,21 +160,17 @@ contract FlowEVMBridgeAccessor {
self.bridgeAccessorCap = nil
}

/// Sets the BridgeAccessor capability on the BridgeRouter
///
access(EVM.Bridge) fun setBridgeAccessorCap(_ cap: Capability<auth(EVM.Bridge) &{EVM.BridgeAccessor}>) {
pre {
cap.check(): "BridgeAccessor capability already set"
}
self.bridgeAccessorCap = cap
}

/// Returns an EVM.Bridge entitled reference to the underlying BridgeAccessor resource
///
access(EVM.Bridge) view fun borrowBridgeAccessor(): auth(EVM.Bridge) &{EVM.BridgeAccessor} {
let cap = self.bridgeAccessorCap ?? panic("BridgeAccessor Capabaility is not yet set")
return cap.borrow() ?? panic("Problem retrieving BridgeAccessor reference")
}

/// Sets the BridgeAccessor Capability in the BridgeRouter
access(EVM.Bridge) fun setBridgeAccessor(_ accessorCap: Capability<auth(EVM.Bridge) &{EVM.BridgeAccessor}>) {
self.bridgeAccessorCap = accessorCap
}
}

init(publishToEVMAccount: Address) {
Expand Down
4 changes: 2 additions & 2 deletions cadence/contracts/example-assets/ExampleNFT.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ access(all) contract ExampleNFT: NonFungibleToken {
access(all) resource Collection: NonFungibleToken.Collection {
/// dictionary of NFT conforming tokens
/// NFT is a resource type with an `UInt64` ID field
access(contract) var ownedNFTs: @{UInt64: ExampleNFT.NFT}
access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}}

access(all) var storagePath: StoragePath
access(all) var publicPath: PublicPath
Expand Down Expand Up @@ -187,7 +187,7 @@ access(all) contract ExampleNFT: NonFungibleToken {

/// Borrow the view resolver for the specified NFT ID
access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver}? {
if let nft = &self.ownedNFTs[id] as &ExampleNFT.NFT? {
if let nft = &self.ownedNFTs[id] as &{NonFungibleToken.NFT}? {
return nft as &{ViewResolver.Resolver}
}
return nil
Expand Down
28 changes: 28 additions & 0 deletions cadence/contracts/standards/EVM.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,19 @@ contract EVM {
access(all)
event FLOWTokensWithdrawn(addressBytes: [UInt8; 20], amount: UFix64)

/// BridgeAccessorUpdated is emitted when the BridgeAccessor Capability
/// is updated in the stored BridgeRouter along with identifying
/// information about both.
access(all)
event BridgeAccessorUpdated(
routerType: Type,
routerUUID: UInt64,
routerAddress: Address,
accessorType: Type,
accessorUUID: UInt64,
accessorAddress: Address
)

/// EVMAddress is an EVM-compatible address
access(all)
struct EVMAddress {
Expand Down Expand Up @@ -602,6 +615,21 @@ contract EVM {

/// Returns a reference to the BridgeAccessor designated for internal bridge requests
access(Bridge) view fun borrowBridgeAccessor(): auth(Bridge) &{BridgeAccessor}

/// Sets the BridgeAccessor Capability in the BridgeRouter
access(Bridge) fun setBridgeAccessor(_ accessor: Capability<auth(Bridge) &{BridgeAccessor}>) {
pre {
accessor.check(): "Invalid BridgeAccessor Capability provided"
emit BridgeAccessorUpdated(
routerType: self.getType(),
routerUUID: self.uuid,
routerAddress: self.owner?.address ?? panic("Router must have an owner to be identified"),
accessorType: accessor.borrow()!.getType(),
accessorUUID: accessor.borrow()!.uuid,
accessorAddress: accessor.address
)
}
}
}

/// Returns a reference to the BridgeAccessor designated for internal bridge requests
Expand Down
26 changes: 19 additions & 7 deletions cadence/contracts/standards/NonFungibleToken.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Collection to complete the transfer.
*/

import ViewResolver from "ViewResolver"
import "ViewResolver"

/// The main NFT contract. Other NFT contracts will
/// import and implement the interfaces defined in this contract
Expand All @@ -63,7 +63,7 @@ access(all) contract interface NonFungibleToken: ViewResolver {
/// and query the updated metadata from the owners' collections.
///
access(all) event Updated(type: String, id: UInt64, uuid: UInt64, owner: Address?)
access(contract) view fun emitNFTUpdated(_ nftRef: auth(Update | Owner) &{NonFungibleToken.NFT})
access(all) view fun emitNFTUpdated(_ nftRef: auth(Update | Owner) &{NonFungibleToken.NFT})
{
emit Updated(type: nftRef.getType().identifier, id: nftRef.id, uuid: nftRef.uuid, owner: nftRef.owner?.address)
}
Expand All @@ -85,9 +85,6 @@ access(all) contract interface NonFungibleToken: ViewResolver {
///
access(all) event Deposited(type: String, id: UInt64, uuid: UInt64, to: Address?, collectionUUID: UInt64)

/// Included for backwards-compatibility
access(all) resource interface INFT: NFT {}

/// Interface that the NFTs must conform to
///
access(all) resource interface NFT: ViewResolver.Resolver {
Expand All @@ -105,6 +102,7 @@ access(all) contract interface NonFungibleToken: ViewResolver {
access(all) fun createEmptyCollection(): @{Collection} {
post {
result.getLength() == 0: "The created collection must be empty!"
result.isSupportedNFTType(type: self.getType()): "The created collection must support this NFT type"
}
}

Expand Down Expand Up @@ -174,6 +172,7 @@ access(all) contract interface NonFungibleToken: ViewResolver {
access(all) fun deposit(token: @{NFT})
access(all) view fun getLength(): Int
access(all) view fun getIDs(): [UInt64]
access(all) fun forEachID(_ f: fun (UInt64): Bool): Void
access(all) view fun borrowNFT(_ id: UInt64): &{NFT}?
}

Expand All @@ -182,6 +181,10 @@ access(all) contract interface NonFungibleToken: ViewResolver {
///
access(all) resource interface Collection: Provider, Receiver, CollectionPublic, ViewResolver.ResolverCollection {

/// Cadence allows implementing types to specify less restrictive access
/// so implementing contracts can have this as `access(all)` with no problem
access(contract) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}}

/// deposit takes a NFT as an argument and stores it in the collection
/// @param token: The NFT to deposit into the collection
access(all) fun deposit(token: @{NonFungibleToken.NFT}) {
Expand All @@ -196,7 +199,16 @@ access(all) contract interface NonFungibleToken: ViewResolver {

/// Gets the amount of NFTs stored in the collection
/// @return An integer indicating the size of the collection
access(all) view fun getLength(): Int
access(all) view fun getLength(): Int {
return self.ownedNFTs.length
}

/// Allows a given function to iterate through the list
/// of owned NFT IDs in a collection without first
/// having to load the entire list into memory
access(all) fun forEachID(_ f: fun (UInt64): Bool): Void {
self.ownedNFTs.forEachKey(f)
}

/// Borrows a reference to an NFT stored in the collection
/// If the NFT with the specified ID is not in the collection,
Expand Down Expand Up @@ -231,4 +243,4 @@ access(all) contract interface NonFungibleToken: ViewResolver {
result.getIDs().length == 0: "The created collection must be empty!"
}
}
}
}
2 changes: 1 addition & 1 deletion cadence/tests/test_helpers.cdc

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,34 @@ import "FlowEVMBridgeAccessor"
///
transaction(name: String, provider: Address) {

prepare(signer: auth(Inbox, SaveValue) &Account) {
let accessorCap: Capability<auth(EVM.Bridge) &FlowEVMBridgeAccessor.BridgeAccessor>
let routerRef: auth(EVM.Bridge) &{EVM.BridgeRouter}

prepare(signer: auth(BorrowValue, ClaimInboxCapability, SaveValue) &Account) {
let routerStoragePath = /storage/evmBridgeRouter

// Claim the BridgeAccessor Capability
let accessorCap = signer.inbox.claim<auth(EVM.Bridge) &FlowEVMBridgeAccessor.BridgeAccessor>(name, provider: provider)
?? panic("BridgeAccessor Capability not found")
self.accessorCap = signer.inbox.claim<auth(EVM.Bridge) &FlowEVMBridgeAccessor.BridgeAccessor>(
name,
provider: provider
) ?? panic("BridgeAccessor Capability not found")

// Ensure the Capability is valid and nothing is stored where the BridgeRouter should be stored
assert(self.accessorCap.check() == true, message: "Invalid BridgeAccessor Capability")
assert(
signer.storage.type(at: routerStoragePath) == nil,
message: "Collision where BridgeRouter will be stored"
)

// Ensure the Capability is valid
assert(accessorCap.check() == true, message: "Invalid BridgeAccessor Capability")
let router <-self.accessorCap.borrow()!.createBridgeRouter()
signer.storage.save(<-router, to: routerStoragePath)

// Create a Router to store the Capability and set the BridgeAccessor Capability in the Router
let router <- accessorCap.borrow()!.createBridgeRouter()
router.setBridgeAccessorCap(accessorCap)
// Borrow the router from storage and set the BridgeAccessor Capability
self.routerRef = signer.storage.borrow<auth(EVM.Bridge) &{EVM.BridgeRouter}>(from: routerStoragePath)
?? panic("BridgeRouter not found in storage")
}

// Save the Router in storage
signer.storage.save(<-router, to: /storage/evmBridgeRouter)
execute {
self.routerRef.setBridgeAccessor(self.accessorCap)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import "EVM"

import "FlowEVMBridgeAccessor"

/// This transaction is intended to be run by the EVM contract account after FlowEVMBridgeAccessor.BridgeAccessor in the
/// event the BridgeAccessor Capability needs to be reset within the store BridgeRouter. Within this transacion, the
/// prepare block assumes a BridgeRouter is already stored at /storage/evmBridgeRouter.
///
/// @param name: The name of the BridgeAccessor Capability to claim
/// @param provider: The address of the account that published the BridgeAccessor Capability
///
transaction(name: String, provider: Address) {

let accessorCap: Capability<auth(EVM.Bridge) &FlowEVMBridgeAccessor.BridgeAccessor>
let router: auth(EVM.Bridge) &{EVM.BridgeRouter}

prepare(signer: auth(BorrowValue, ClaimInboxCapability, SaveValue) &Account) {
// Claim the BridgeAccessor Capability
self.accessorCap = signer.inbox.claim<auth(EVM.Bridge) &FlowEVMBridgeAccessor.BridgeAccessor>(
name,
provider: provider
) ?? panic("BridgeAccessor Capability not found")

// Ensure the Capability is valid
assert(self.accessorCap.check() == true, message: "Invalid BridgeAccessor Capability")

// Borrow the router from storage and set the BridgeAccessor Capability
self.router = signer.storage.borrow<auth(EVM.Bridge) &{EVM.BridgeRouter}>(from: /storage/evmBridgeRouter)
?? panic("BridgeRouter not found in storage")
}

execute {
self.router.setBridgeAccessor(self.accessorCap)
}
}
11 changes: 10 additions & 1 deletion flow.json
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,16 @@
"IEVMBridgeTokenMinter",
"IFlowEVMNFTBridge",
"IFlowEVMTokenBridge",
"FlowEVMBridge"
"FlowEVMBridge",
{
"name": "FlowEVMBridgeAccessor",
"args": [
{
"type": "Address",
"value": "0xb6763b4399a888c8"
}
]
}
]
}
}
Expand Down

0 comments on commit 2e0ae6a

Please sign in to comment.