Skip to content

Commit 0d4d7bb

Browse files
committed
execute multiple evm txs and revert on failure
1 parent 5a10e2b commit 0d4d7bb

File tree

4 files changed

+60
-49
lines changed

4 files changed

+60
-49
lines changed

contracts/FlowTransactionSchedulerUtils.cdc

Lines changed: 51 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -613,44 +613,46 @@ access(all) contract FlowTransactionSchedulerUtils {
613613
return
614614
}
615615

616-
if let params = data as? COAHandlerParams {
617-
switch params.txType {
618-
case COAHandlerTxType.DepositFLOW:
619-
if params.amount == nil {
620-
emit COAHandlerExecutionError(id: id, owner: self.owner?.address, coaAddress: coa!.address().toString(),
621-
errorMessage: "Amount is required for deposit for scheduled transaction with ID \(id)")
622-
return
623-
}
624-
let vault = self.flowTokenVaultCapability.borrow()
625-
if vault == nil {
626-
emit COAHandlerExecutionError(id: id, owner: self.owner?.address, coaAddress: coa!.address().toString(), errorMessage: "FlowToken vault capability is invalid or expired for scheduled transaction with ID \(id)")
627-
return
628-
}
629-
coa!.deposit(from: <-vault!.withdraw(amount: params.amount!) as! @FlowToken.Vault)
630-
case COAHandlerTxType.WithdrawFLOW:
631-
if params.amount == nil {
632-
emit COAHandlerExecutionError(id: id, owner: self.owner?.address, coaAddress: coa!.address().toString(),
633-
errorMessage: "Amount is required for withdrawal from COA for scheduled transaction with ID \(id)")
634-
}
635-
636-
let vault = self.flowTokenVaultCapability.borrow()
637-
if vault == nil {
638-
emit COAHandlerExecutionError(id: id, owner: self.owner?.address, coaAddress: coa!.address().toString(),
639-
errorMessage: "FlowToken vault capability is invalid or expired for scheduled transaction with ID \(id)")
640-
return
641-
}
642-
643-
let amount = EVM.Balance(attoflow: 0)
644-
amount.setFLOW(flow: params.amount!)
645-
646-
vault!.deposit(from: <-coa!.withdraw(balance: amount))
647-
case COAHandlerTxType.Call:
648-
if params.callToEVMAddress == nil || params.data == nil || params.gasLimit == nil || params.value == nil {
649-
emit COAHandlerExecutionError(id: id, owner: self.owner?.address, coaAddress: coa!.address().toString(),
650-
errorMessage: "Call to EVM address, data, gas limit, and value are required for EVM call for scheduled transaction with ID \(id)")
651-
return
652-
}
653-
let result = coa!.call(to: params.callToEVMAddress!, data: params.data!, gasLimit: params.gasLimit!, value: params.value!)
616+
if let transactions = data as? [COAHandlerParams] {
617+
for txParams in transactions {
618+
switch txParams.txType {
619+
case COAHandlerTxType.DepositFLOW:
620+
if txParams.amount == nil {
621+
emit COAHandlerExecutionError(id: id, owner: self.owner?.address, coaAddress: coa!.address().toString(),
622+
errorMessage: "Amount is required for deposit for scheduled transaction with ID \(id)")
623+
return
624+
}
625+
let vault = self.flowTokenVaultCapability.borrow()
626+
if vault == nil {
627+
emit COAHandlerExecutionError(id: id, owner: self.owner?.address, coaAddress: coa!.address().toString(), errorMessage: "FlowToken vault capability is invalid or expired for scheduled transaction with ID \(id)")
628+
return
629+
}
630+
coa!.deposit(from: <-vault!.withdraw(amount: txParams.amount!) as! @FlowToken.Vault)
631+
case COAHandlerTxType.WithdrawFLOW:
632+
if txParams.amount == nil {
633+
emit COAHandlerExecutionError(id: id, owner: self.owner?.address, coaAddress: coa!.address().toString(),
634+
errorMessage: "Amount is required for withdrawal from COA for scheduled transaction with ID \(id)")
635+
}
636+
637+
let vault = self.flowTokenVaultCapability.borrow()
638+
if vault == nil {
639+
emit COAHandlerExecutionError(id: id, owner: self.owner?.address, coaAddress: coa!.address().toString(),
640+
errorMessage: "FlowToken vault capability is invalid or expired for scheduled transaction with ID \(id)")
641+
return
642+
}
643+
644+
let amount = EVM.Balance(attoflow: 0)
645+
amount.setFLOW(flow: txParams.amount!)
646+
647+
vault!.deposit(from: <-coa!.withdraw(balance: amount))
648+
case COAHandlerTxType.Call:
649+
if txParams.callToEVMAddress == nil || txParams.data == nil || txParams.gasLimit == nil || txParams.value == nil {
650+
emit COAHandlerExecutionError(id: id, owner: self.owner?.address, coaAddress: coa!.address().toString(),
651+
errorMessage: "Call to EVM address, data, gas limit, and value are required for EVM call for scheduled transaction with ID \(id)")
652+
return
653+
}
654+
let result = coa!.call(to: txParams.callToEVMAddress!, data: txParams.data!, gasLimit: txParams.gasLimit!, value: txParams.value!)
655+
}
654656
}
655657
} else {
656658
emit COAHandlerExecutionError(id: id, owner: self.owner?.address, coaAddress: coa!.address().toString(),
@@ -708,8 +710,13 @@ access(all) contract FlowTransactionSchedulerUtils {
708710

709711
access(all) struct COAHandlerParams {
710712

713+
/// The type of transaction to execute
711714
access(all) let txType: COAHandlerTxType
712715

716+
/// Indicates if the whole set of scheduled transactions should be reverted
717+
/// if this one transaction fails to execute in EVM
718+
access(all) let revertOnFailure: Bool
719+
713720
/// The amount of FLOW to deposit or withdraw
714721
/// Not required for the Call transaction type
715722
access(all) let amount: UFix64?
@@ -718,30 +725,30 @@ access(all) contract FlowTransactionSchedulerUtils {
718725
access(all) let callToEVMAddress: EVM.EVMAddress?
719726
access(all) let data: [UInt8]?
720727
access(all) let gasLimit: UInt64?
721-
access(all) let value: EVM.Balance?
728+
access(all) let value: EVM.Balance?
722729

723-
init(txType: UInt8, amount: UFix64?, callToEVMAddress: [UInt8; 20]?, data: [UInt8]?, gasLimit: UInt64?, value: UFix64?) {
730+
init(txType: UInt8, revertOnFailure: Bool, amount: UFix64?, callToEVMAddress: String?, data: [UInt8]?, gasLimit: UInt64?, value: UInt?) {
724731
self.txType = COAHandlerTxType(rawValue: txType)
725732
?? panic("Invalid COA transaction type enum")
733+
self.revertOnFailure = revertOnFailure
726734
if self.txType == COAHandlerTxType.DepositFLOW {
727735
assert(amount != nil, message: "Amount is required for deposit but was not provided")
728736
}
729737
if self.txType == COAHandlerTxType.WithdrawFLOW {
730738
assert(amount != nil, message: "Amount is required for withdrawal but was not provided")
731739
}
732740
if self.txType == COAHandlerTxType.Call {
733-
assert(callToEVMAddress != nil, message: "Call to EVM address is required for EVM call but was not provided")
741+
assert(callToEVMAddress != nil && callToEVMAddress!.length == 20, message: "Call to EVM address is required for EVM call but was not provided or is invalid")
734742
assert(data != nil, message: "Data is required for EVM call but was not provided")
735743
assert(gasLimit != nil, message: "Gas limit is required for EVM call but was not provided")
736744
assert(value != nil, message: "Value is required for EVM call but was not provided")
737745
}
738746
self.amount = amount
739-
self.callToEVMAddress = callToEVMAddress != nil ? EVM.EVMAddress(bytes: callToEVMAddress!) : nil
747+
self.callToEVMAddress = callToEVMAddress != nil ? EVM.EVMAddress(bytes: callToEVMAddress!.decodeHex() as! [UInt8; 20]) : nil
740748
self.data = data
741749
self.gasLimit = gasLimit
742750
if let unwrappedValue = value {
743-
self.value = EVM.Balance(attoflow: 0)
744-
self.value!.setFLOW(flow: unwrappedValue)
751+
self.value = EVM.Balance(attoflow: unwrappedValue)
745752
} else {
746753
self.value = nil
747754
}

tests/evm_test_helpers.cdc

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,20 @@ access(all) fun scheduleCOATransaction(
2828
effort: UInt64,
2929
priority: UInt8,
3030
coaTXTypeEnum: UInt8,
31+
revertOnFailure: Bool,
3132
amount: UFix64?,
32-
callToEVMAddress: [UInt8; 20]?,
33+
callToEVMAddress: String?,
3334
data: [UInt8]?,
3435
gasLimit: UInt64?,
35-
value: UFix64?,
36+
value: UInt?,
3637
testName: String,
3738
failWithErr: String?
3839
) {
3940
var tx = Test.Transaction(
4041
code: Test.readFile("../transactions/transactionScheduler/schedule_coa_transaction.cdc"),
4142
authorizers: [adminAcct.address],
4243
signers: [adminAcct],
43-
arguments: [timestamp, fee, effort, priority, coaTXTypeEnum, amount, callToEVMAddress, data, gasLimit, value],
44+
arguments: [timestamp, fee, effort, priority, coaTXTypeEnum, revertOnFailure, amount, callToEVMAddress, data, gasLimit, value],
4445
)
4546
var result = Test.executeTransaction(tx)
4647

tests/transactionScheduler_coa_test.cdc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ access(all) fun testCOAScheduledTransactions() {
5454
effort: basicEffort,
5555
priority: highPriority,
5656
coaTXTypeEnum: depositFLOWEnum,
57+
revertOnFailure: false,
5758
amount: 100.0,
5859
callToEVMAddress: nil,
5960
data: nil,

transactions/transactionScheduler/schedule_coa_transaction.cdc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@ transaction(
1010
effort: UInt64,
1111
priority: UInt8,
1212
coaTXTypeEnum: UInt8,
13+
revertOnFailure: Bool,
1314
amount: UFix64?,
14-
callToEVMAddress: [UInt8; 20]?,
15+
callToEVMAddress: String?,
1516
data: [UInt8]?,
1617
gasLimit: UInt64?,
17-
value: UFix64?
18+
value: UInt?
1819
) {
1920

2021
prepare(account: auth(BorrowValue, SaveValue, IssueStorageCapabilityController, PublishCapability, GetStorageCapabilityController) &Account) {
@@ -98,6 +99,7 @@ transaction(
9899

99100
let coaHandlerParams = FlowTransactionSchedulerUtils.COAHandlerParams(
100101
txType: coaTXTypeEnum,
102+
revertOnFailure: revertOnFailure,
101103
amount: amount,
102104
callToEVMAddress: callToEVMAddress,
103105
data: data,

0 commit comments

Comments
 (0)