@@ -44,21 +44,59 @@ contract Orchestrator is Ownable {
44
44
function rebase ()
45
45
external
46
46
{
47
+ // only callable by EOA to prevent flashloan attacks
47
48
require (msg .sender == tx .origin ); // solhint-disable-line avoid-tx-origin
48
49
50
+ // call monetary policy rebase, always revert on failure
49
51
policy.rebase ();
50
52
51
- for (uint i = 0 ; i < transactions.length ; i++ ) {
52
- Transaction storage t = transactions[i];
53
- if (t.enabled) {
54
- bool result =
55
- externalCall (t.destination, t.data);
56
- if (! result) {
57
- emit TransactionFailed (t.destination, i, t.data);
58
- revert ("Transaction Failed " );
59
- }
53
+ // call peripheral contracts, revert batch if out-of-gas or silent revert
54
+ for (uint256 index = 0 ; index < transactions.length ; index++ ) {
55
+ _executePeripheralTransaction (index);
56
+ }
57
+ }
58
+
59
+ /**
60
+ * @notice Get the revert message and code from a call.
61
+ * @param index uint256 Index of the transaction.
62
+ * @return success bool True if peripheral transaction was successful.
63
+ * @return returnData bytes Return data.
64
+ */
65
+ function _executePeripheralTransaction (uint256 index )
66
+ internal
67
+ returns (bool success , bytes memory returnData )
68
+ {
69
+ // declare storage reference
70
+ Transaction memory transaction = transactions[index];
71
+
72
+ // return early if disabled
73
+ if (! transaction.enabled) {
74
+ return (success, returnData);
75
+ }
76
+
77
+ // perform low level external call and forward 63/64 remaining gas
78
+ (success) = address (transaction.destination).call (transaction.data);
79
+
80
+ // Check if any of the atomic transactions failed, if not, decode return data
81
+ if (! success) {
82
+ assembly {
83
+ returndatacopy (returnData, 0 , returndatasize)
84
+ }
85
+ if (returnData.length == 0 ) {
86
+ // If revert reason is empty, it is either OOG error or silent revert so we revert the batch
87
+ revert ("Transaction reverted silently " );
88
+ } else {
89
+ // Log any other revert and continue rebase execution
90
+ emit TransactionFailed (
91
+ transaction.destination,
92
+ index,
93
+ transaction.data
94
+ );
60
95
}
61
96
}
97
+
98
+ // explicit return
99
+ return (success, returnData);
62
100
}
63
101
64
102
/**
@@ -116,42 +154,3 @@ contract Orchestrator is Ownable {
116
154
{
117
155
return transactions.length ;
118
156
}
119
-
120
- /**
121
- * @dev wrapper to call the encoded transactions on downstream consumers.
122
- * @param destination Address of destination contract.
123
- * @param data The encoded data payload.
124
- * @return True on success
125
- */
126
- function externalCall (address destination , bytes data )
127
- internal
128
- returns (bool )
129
- {
130
- bool result;
131
- assembly { // solhint-disable-line no-inline-assembly
132
- // "Allocate" memory for output
133
- // (0x40 is where "free memory" pointer is stored by convention)
134
- let outputAddress := mload (0x40 )
135
-
136
- // First 32 bytes are the padded length of data, so exclude that
137
- let dataAddress := add (data, 32 )
138
-
139
- result := call (
140
- // 34710 is the value that solidity is currently emitting
141
- // It includes callGas (700) + callVeryLow (3, to pay for SUB)
142
- // + callValueTransferGas (9000) + callNewAccountGas
143
- // (25000, in case the destination address does not exist and needs creating)
144
- sub (gas, 34710 ),
145
-
146
-
147
- destination,
148
- 0 , // transfer value in wei
149
- dataAddress,
150
- mload (data), // Size of the input, in bytes. Stored in position 0 of the array.
151
- outputAddress,
152
- 0 // Output is ignored, therefore the output size is zero
153
- )
154
- }
155
- return result;
156
- }
157
- }
0 commit comments