Skip to content

Commit

Permalink
Merge pull request #77 from onflow/add-flow-transfer-txn
Browse files Browse the repository at this point in the history
Add EVM serialization updates & FLOW transfer txn
  • Loading branch information
sisyphusSmiling authored May 22, 2024
2 parents 6e5d9c2 + 36d7acb commit 7cbab5c
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 0 deletions.
26 changes: 26 additions & 0 deletions cadence/contracts/standards/EVM.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,32 @@ contract EVM {
)
emit FLOWTokensDeposited(addressBytes: self.bytes, amount: amount)
}

/// Serializes the address to a hex string without the 0x prefix
/// Future implementations should pass data to InternalEVM for native serialization
access(all)
view fun toString(): String {
return String.encodeHex(self.bytes.toVariableSized())
}

/// Compares the address with another address
access(all)
view fun equals(_ other: EVMAddress): Bool {
return self.bytes == other.bytes
}
}

/// Converts a hex string to an EVM address if the string is a valid hex string
/// Future implementations should pass data to InternalEVM for native deserialization
access(all)
fun addressFromString(_ asHex: String): EVMAddress {
pre {
asHex.length == 40 || asHex.length == 42: "Invalid hex string length for an EVM address"
}
// Strip the 0x prefix if it exists
var withoutPrefix = (asHex[1] == "x" ? asHex.slice(from: 2, upTo: asHex.length) : asHex).toLower()
let bytes = withoutPrefix.decodeHex().toConstantSized<[UInt8;20]>()!
return EVMAddress(bytes: bytes)
}

access(all)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import "FungibleToken"
import "FlowToken"

import "EVM"

// Transfers $FLOW from the signer's account to the recipient's address, determining the target VM based on the format
// of the recipient's hex address.
///
/// @param addressString: The recipient's address in hex format - this should be either an EVM address or a Flow address
/// @param amount: The amount of $FLOW to transfer as a UFix64 value
///
transaction(addressString: String, amount: UFix64) {

let sentVault: @FlowToken.Vault
let evmRecipient: EVM.EVMAddress?
var receiver: &{FungibleToken.Receiver}?

prepare(signer: auth(BorrowValue, SaveValue) &Account) {
// Reference signer's FlowToken Vault
let sourceVault = signer.storage.borrow<auth(FungibleToken.Withdraw) &FlowToken.Vault>(from: /storage/flowTokenVault)
?? panic("Could not borrow signer's FlowToken.Vault")

// Init receiver as nil
self.receiver = nil
// Ensure address is prefixed with '0x'
let withPrefix = addressString.slice(from: 0, upTo: 2) == "0x" ? addressString : "0x".concat(addressString)
// Attempt to parse address as Cadence or EVM address
let cadenceRecipient = withPrefix.length < 40 ? Address.fromString(withPrefix) : nil
self.evmRecipient = cadenceRecipient == nil ? EVM.addressFromString(withPrefix) : nil

// Validate exactly one target address is assigned
if cadenceRecipient != nil && self.evmRecipient != nil {
panic("Malformed recipient address - assignable as both Cadence and EVM addresses")
} else if cadenceRecipient == nil && self.evmRecipient == nil {
panic("Malformed recipient address - not assignable as either Cadence or EVM address")
}

if cadenceRecipient != nil {
// Assign FungibleToken Receiver if recipient is a Cadence address
self.receiver = getAccount(cadenceRecipient!).capabilities.borrow<&{FungibleToken.Receiver}>(/public/flowTokenReceiver)
?? panic("Could not borrow FungibleToken Receiver from recipient")
}

// Create empty FLOW vault to capture funds
self.sentVault <- sourceVault.withdraw(amount: amount) as! @FlowToken.Vault
}

pre {
self.receiver != nil || self.evmRecipient != nil: "Could not assign a recipient for the transfer"
self.sentVault.balance == amount: "Attempting to send an incorrect amount of $FLOW"
}

execute {
// Complete Cadence transfer if the FungibleToken Receiver is assigned
if self.receiver != nil {
self.receiver!.deposit(from: <-self.sentVault)
} else {
// Otherwise, complete EVM transfer
self.evmRecipient!.deposit(from: <-self.sentVault)
}
}
}

0 comments on commit 7cbab5c

Please sign in to comment.