Skip to content

Add scripts, transactions and a test example on how to interact with Solidty contracts through Flow EVM #6

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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
with:
go-version: 1.20
- name: Install Flow CLI
run: bash -ci "$(curl -fsSL https://raw.githubusercontent.com/onflow/flow-cli/master/install.sh)" -- v1.12.0-cadence-v1.0.0-M8
run: bash -ci "$(curl -fsSL https://raw.githubusercontent.com/onflow/flow-cli/master/install.sh)" -- v1.12.0-cadence-v1.0.0-M8-2
- name: Run tests
run: flow test --cover --covercode="contracts" --coverprofile="coverage.lcov" tests/test_*.cdc
- name: Upload coverage reports to Codecov
Expand Down
16 changes: 16 additions & 0 deletions contracts/SolidityContractsRegistry.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
access(all) contract SolidityContractsRegistry {

access(all) let contractRegistry: {String: [UInt8; 20]}
Copy link

@sisyphusSmiling sisyphusSmiling Mar 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting idea...I wonder if something like a Cadence-native diamond pattern (ERC-2535) would be a useful example


access(all) event ContractRegistered(name: String, address: [UInt8; 20])

access(all)
fun registerContract(name: String, address: [UInt8; 20]) {
self.contractRegistry[name] = address
emit ContractRegistered(name: name, address: address)
}

init() {
self.contractRegistry = {}
}
}
9 changes: 8 additions & 1 deletion flow.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@
"aliases": {
"testing": "0x0000000000000007"
}
},
"SolidityContractsRegistry": {
"source": "contracts/SolidityContractsRegistry.cdc",
"aliases": {
"testing": "0x0000000000000007"
}
}
},
"networks": {
Expand All @@ -41,7 +47,8 @@
"FooContract",
"ArrayUtils",
"StringUtils",
"ApprovalVoting"
"ApprovalVoting",
"SolidityContractsRegistry"
]
}
}
Expand Down
6 changes: 6 additions & 0 deletions scripts/solidity_contract_address.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import "SolidityContractsRegistry"

access(all)
fun main(contractName: String): [UInt8; 20]? {
return SolidityContractsRegistry.contractRegistry[contractName]
}
63 changes: 63 additions & 0 deletions tests/test_solidity_contract.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import Test
import BlockchainHelpers

access(all) let serviceAccount = Test.serviceAccount()

access(all)
fun setup() {
let err = Test.deployContract(
name: "SolidityContractsRegistry",
path: "../contracts/SolidityContractsRegistry.cdc",
arguments: []
)
Test.expect(err, Test.beNil())
}

access(all)
fun testCreateCOA() {
let txResult = executeTransaction(
"../transactions/create_coa.cdc",
[750.0],
serviceAccount
)

Test.expect(txResult, Test.beSucceeded())
}

access(all)
fun testDeployMultiply7Contract() {
// contract Multiply7 {
// event Print(uint);
// function multiply(uint input) returns (uint) {
// Print(input * 7);
// return input * 7;
// }
// }
// ABI for the above Solidity contract
let contractCode = "6060604052341561000f57600080fd5b60eb8061001d6000396000f300606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c6888fa1146044575b600080fd5b3415604e57600080fd5b606260048080359060200190919050506078565b6040518082815260200191505060405180910390f35b60007f24abdb5865df5079dcc5ac590ff6f01d5c16edbc5fab4e195d9febd1114503da600783026040518082815260200191505060405180910390a16007820290509190505600a165627a7a7230582040383f19d9f65246752244189b02f56e8d0980ed44e7a56c0b200458caad20bb0029"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way to pull this value from a local JSON file containing Cadence JSON args?

let txResult = executeTransaction(
"../transactions/deploy_solidity_contract.cdc",
["Multiply7", contractCode],
serviceAccount
)

Test.expect(txResult, Test.beSucceeded())
}

access(all)
fun testCallMultiply7() {
let scriptResult = executeScript(
"../scripts/solidity_contract_address.cdc",
["Multiply7"]
)
Test.expect(scriptResult, Test.beSucceeded())
let contractAddress = (scriptResult.returnValue as! [UInt8; 20]?)!

let txResult = executeTransaction(
"../transactions/solidity_contract_call.cdc",
[contractAddress],
serviceAccount
)

Test.expect(txResult, Test.beSucceeded())
}
27 changes: 27 additions & 0 deletions transactions/create_coa.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import "FungibleToken"
import "FlowToken"
import "EVM"

transaction(amount: UFix64) {
let sentVault: @FlowToken.Vault
let auth: auth(Storage) &Account

prepare(signer: auth(Storage) &Account) {
let vaultRef = signer.storage.borrow<auth(FungibleToken.Withdraw) &FlowToken.Vault>(
from: /storage/flowTokenVault
) ?? panic("Could not borrow reference to the owner's Vault!")

self.sentVault <- vaultRef.withdraw(amount: amount) as! @FlowToken.Vault
self.auth = signer
}

execute {
let account <- EVM.createCadenceOwnedAccount()
account.deposit(from: <-self.sentVault)

self.auth.storage.save<@EVM.CadenceOwnedAccount>(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we'd also want to issue an un-entitled COA Capability at /public/evm so things like the COA ownership proof and public deposits are accessible

<-account,
to: StoragePath(identifier: "evm")!
)
}
}
25 changes: 25 additions & 0 deletions transactions/deploy_solidity_contract.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import "EVM"
import "SolidityContractsRegistry"

transaction(contractName: String, contractCode: String) {
let coa: auth(EVM.Deploy) &EVM.CadenceOwnedAccount

prepare(signer: auth(Storage) &Account) {
self.coa = signer.storage.borrow<auth(EVM.Deploy) &EVM.CadenceOwnedAccount>(
from: /storage/evm
) ?? panic("Could not borrow reference to the COA!")
}

execute {
let contractAddress = self.coa.deploy(
code: contractCode.decodeHex(),
gasLimit: 110000,
value: EVM.Balance(attoflow: 0)
)

SolidityContractsRegistry.registerContract(
name: contractName,
address: contractAddress.bytes
)
}
}
30 changes: 30 additions & 0 deletions transactions/solidity_contract_call.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import "EVM"

transaction(addressBytes: [UInt8; 20]) {
let coa: auth(EVM.Call) &EVM.CadenceOwnedAccount

prepare(signer: auth(Storage) &Account) {
self.coa = signer.storage.borrow<auth(EVM.Call) &EVM.CadenceOwnedAccount>(
from: /storage/evm
) ?? panic("Could not borrow reference to the COA!")
}

execute {
let data = EVM.encodeABIWithSignature("multiply(uint256)", [UInt256(6)])
let txResult = self.coa.call(
to: EVM.EVMAddress(bytes: addressBytes),
data: data,
gasLimit: 35000,
value: EVM.Balance(attoflow: 0)
)

assert(
txResult.status == EVM.Status.successful,
message: txResult.errorCode.toString()
)

let returnedValues = EVM.decodeABI(types: [Type<UInt256>()], data: txResult.data)
let value = returnedValues[0] as! UInt256
assert(value == 42) // 6 * 7 = 42
}
}
Loading