-
Notifications
You must be signed in to change notification settings - Fork 7
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 fungible token support #28
Conversation
…es only so far, untested, undeployable atm.
…es for efficiency
symbol: onboardingValues.symbol, | ||
erc721Address: onboardingValues.evmContractAddress | ||
) | ||
} else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might want to make the check explicit for fungible tokens and panic if neither NFT or FT
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since that check is done in several places, I include it in typeRequiresOnboarding()
which is validated in the pre-condition. Beyond the pre-check, we know the type is either an NFT or FT. By the point of the if
block above, we know it's either NFT or FT, and by the else
block it must be FT. Do you think I should organize these checks differently?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense.
I personally like very explicit checks because sometimes assumptions break with future code updates. Not confident it applies here tho
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can see how it would be more resilient to add the explicit checks here. Doesn't hurt to add them so I'll include an else if + else -> panic
assert(!isERC20, message: "Contract is mixed asset and is not currently supported by the bridge") | ||
// Derive the contract name from the ERC721 contract | ||
cadenceContractName = FlowEVMBridgeUtils.deriveBridgedNFTContractName(from: evmContractAddress) | ||
} else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might want an explicit check and panic here too. It stops any errors to fall through the cracks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean check isERC20
? Further up the call stack, isERC20
would've been called
onboardByEVMAddress
|_evmAddressRequiresOnboarding
|_FlowEVMBridgeUtils.isValidEVMAsset
|_isERC20
...
|_deployDefiningContract
When I was testing locally, I found the redundant EVM calls consumed a lot of gas and made a pass at minimizing them.. But if we feel the explicit checks are worth it I can add them back in.
@@ -74,14 +109,37 @@ contract FlowEVMBridge : IFlowEVMNFTBridge { | |||
let feeVault <-feeProvider.withdraw(amount: FlowEVMBridgeConfig.onboardFee) as! @FlowToken.Vault | |||
FlowEVMBridgeUtils.deposit(<-feeVault) | |||
// Deploy an EVM defining contract via the FlowBridgeFactory.sol contract | |||
let erc721Address = self.deployEVMContract(forAssetType: type) | |||
// let evmContractAddress = self.deployEVMContract(forAssetType: type) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this be removed since it is commented out?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yeah, thanks for catching that
/// Maps EVM NFT ID to Flow NFT ID, covering cross-VM project NFTs | ||
access(self) | ||
let evmIDToFlowID: {UInt256: UInt64} | ||
access(self) let evmIDToFlowID: {UInt256: UInt64} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to have a reverse mapping of Cadence ID to EVM ID?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah that could make sense. To minimize the storage usage, I check against the EVMNFT
implementation on demand in getEVMID
. It's the same mechanism I would use to assign a value in a reverse mapping but without the associated storage cost. Think it's worth the cost here?
/// Initializes the Locker for the given fungible token type if it hasn't been initialized yet | ||
/// | ||
access(account) fun initializeEscrow( | ||
with vault: @{FungibleToken.Vault}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what is the with
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
with vault: @{FungibleToken.Vault}
is the FT vault being used to initialize escrow. FT Escrow needs an empty vault to wrap in a Locker
so that future bridged funds can be escrowed. Think the parameter naming is alright?
self.deployedAddress = coa.deploy( | ||
access(all) let deployedAddresses: {String: EVM.EVMAddress} | ||
|
||
access(all) fun deploy(name: String, bytecode: String, value: UInt) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be access(all)
or something more restrictive?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This contract is a temporary test measure until I can get visibility into EVM events from within the testing framework. The problem is I need to know the EVM address of a deployed contract and can only discover that by saving the address somewhere upon deployment.
Wrapping in a resource would be the more secure practice here, but I made it a public method to reduce complexity in testing. Just added a contract-level comment at the top, lmk if you think I should move this to a resource.
Thanks for the review @joshuahannan! I pushed changes based on recent feedback. Those are largely in two commits: |
let cadenceAddress = FlowEVMBridgeUtils.getContractAddress(fromType: forTokenType) | ||
?? panic("Could not derive contract address for token type: ".concat(identifier)) | ||
// Assign a default symbol | ||
var symbol = "BRDG" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than having a default, I think it might be better to panic if neither metadata field is filled in as expected.
I don't think anyone would want to accidentally have their token bridged with a name/ticker that can't be changed on all evm consuming indexed websites which they didnt have control over
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that's a good point. One of those calls that's a balance between ensuring bridging is permissionless with respecting how projects wish to be represented tough. That said, I'd be surprised if a Cadence NFT/FT doesn't define this value so I agree, it's probably best to just revert here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at MetadataViews, there isn't a view that supports symbol. So we can make this call for fungible tokens, but we'll have to consider how to dynamically create a symbol if a project doesn't implement the EVMBridgedMetadata
view. Maybe the first n
characters of the name with special characters and spaces removed? Have any thoughts?
Update: Created #29 to track discussion
Co-authored-by: Navid TehraniFar <[email protected]>
Closes: #5 #6 #10 #15
Description
This PR adds support for fungible token bridging, largely following patterns & interfaces found in the existing NFT bridge feature set.
In addition, some optimizations were made where low-hanging fruit was found. These include
name
andsymbol
with getters. This prevents widely redundant storage at the token-level of fields that are actually contract-level values in ERC contracts.access(account
methods (such asinitializeEscrow
) to reduce redundant EVM calls made in a single bridging transactionAs mentioned in the FLIP, support for non-standard cases will be added, but is considered out of scope for the introduction of the feature and will follow in subsequent PRs.
For contributor use:
master
branchFiles changed
in the Github PR explorer