Skip to content

Commit

Permalink
streamlined the execution environment - removed the protocol control …
Browse files Browse the repository at this point in the history
…calls (all will be delegatecalled and can just call inside the delegatecall). Added a new ERC20 allowance system that allows easy transfer initializations from inside a CREATE2 execution environment as long as the user has approved the atlas contract. Added persistence to the ExecutionEnvironment (mimic) for each protocol/user combo and removed the userCallData (hash) as a seed - replaced it with the protocolcontrol.codehash to better detect tomfoolery (its far from perfect though). Tweaked some minor bugs in the lock system.
  • Loading branch information
thogard785 committed Aug 1, 2023
1 parent 60fdc7a commit 67b153f
Show file tree
Hide file tree
Showing 26 changed files with 788 additions and 667 deletions.
44 changes: 26 additions & 18 deletions src/contracts/atlas/Atlas.sol
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ contract Atlas is Test, Factory {
return;
}

// TODO: Make sure all searcher nonces are incremented on fail.

// Check that the value of the tx is greater than or equal to the value specified
// NOTE: a msg.value *higher* than user value could be used by the staging call.
// There is a further check in the handler before the usercall to verify.
Expand All @@ -49,7 +51,7 @@ contract Atlas is Test, Factory {
gasMarker = gasleft();

// Get the execution environment
address environment = _prepEnvironment(protocolCall, keccak256(abi.encodePacked(userCall.to, userCall.data)));
address environment = _setExecutionEnvironment(protocolCall, userCall.from, verification.proof.controlCodeHash);

console.log("contract creation gas cost", gasMarker - gasleft());

Expand All @@ -61,21 +63,18 @@ contract Atlas is Test, Factory {
// Begin execution
bytes32 callChainHashHead = _execute(protocolCall, userCall, searcherCalls, environment);

// Verify that the meta transactions were executed in the correct sequence
require(callChainHashHead == verification.proof.callChainHash, "ERR-F05 InvalidCallChain");

// Gas Refund to sender
_executeGasRefund(msg.sender);

// Release the lock
_releaseEscrowLocks();

console.log("ex contract creation gas cost", gasMarker - gasleft());
}

function _prepEnvironment(ProtocolCall calldata protocolCall, bytes32 userCallHash)
internal
returns (address environment)
{
environment = _deployExecutionEnvironment(protocolCall, userCallHash);
}

function _execute(
ProtocolCall calldata protocolCall,
UserCall calldata userCall,
Expand All @@ -85,42 +84,51 @@ contract Atlas is Test, Factory {
// Build the CallChainProof. The penultimate hash will be used
// to verify against the hash supplied by ProtocolControl
CallChainProof memory proof = CallVerification.initializeProof(protocolCall, userCall);
bytes32 userCallHash = keccak256(abi.encodePacked(userCall.to, userCall.data));

bytes memory stagingReturnData = _executeStagingCall(protocolCall, userCall, proof, environment);
bytes memory stagingReturnData = _executeStagingCall(protocolCall, userCall, environment);

proof = proof.next(userCall.from, userCall.data);

bytes memory userReturnData = _executeUserCall(userCall, environment);

uint256 i;
bool auctionAlreadyWon;

for (; i < searcherCalls.length;) {

proof = proof.next(searcherCalls[i].metaTx.from, searcherCalls[i].metaTx.data);

auctionAlreadyWon = auctionAlreadyWon
|| _searcherExecutionIteration(
protocolCall, searcherCalls[i], proof, auctionAlreadyWon, environment
);
// Only execute searcher meta tx if userCallHash matches
if (userCallHash == searcherCalls[i].metaTx.userCallHash) {
auctionAlreadyWon = auctionAlreadyWon
|| _searcherExecutionIteration(
protocolCall, searcherCalls[i], auctionAlreadyWon, environment
);
}

unchecked {
++i;
}
}

_executeUserRefund(userCall.from);

_executeVerificationCall(protocolCall, proof, stagingReturnData, userReturnData, environment);
// If no searcher was successful, manually transition the lock
if (!auctionAlreadyWon) {
_notMadJustDisappointed();
}

_executeVerificationCall(protocolCall, stagingReturnData, userReturnData, environment);

return proof.targetHash;
}

function _searcherExecutionIteration(
ProtocolCall calldata protocolCall,
SearcherCall calldata searcherCall,
CallChainProof memory proof,
bool auctionAlreadyWon,
address environment
) internal returns (bool) {
if (_executeSearcherCall(searcherCall, proof, auctionAlreadyWon, environment)) {
if (_executeSearcherCall(searcherCall, auctionAlreadyWon, environment)) {
if (!auctionAlreadyWon) {
auctionAlreadyWon = true;
_executePayments(protocolCall, searcherCall.bids, environment);
Expand Down
21 changes: 7 additions & 14 deletions src/contracts/atlas/Escrow.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,12 @@ import "../types/LockTypes.sol";
import "../types/VerificationTypes.sol";

import {EscrowBits} from "../libraries/EscrowBits.sol";
import {CallChainProof} from "../libraries/CallVerification.sol";
import {CallVerification} from "../libraries/CallVerification.sol";

// import "forge-std/Test.sol";

contract Escrow is ProtocolVerifier, SafetyLocks, SearcherWrapper {
using ECDSA for bytes32;
using CallVerification for CallChainProof;

uint32 public immutable escrowDuration;

Expand Down Expand Up @@ -68,10 +66,9 @@ contract Escrow is ProtocolVerifier, SafetyLocks, SearcherWrapper {
function _executeStagingCall(
ProtocolCall calldata protocolCall,
UserCall calldata userCall,
CallChainProof memory proof,
address environment
) internal stagingLock(protocolCall, environment) returns (bytes memory stagingReturnData) {
stagingReturnData = IExecutionEnvironment(environment).stagingWrapper{value: msg.value}(proof, userCall);
stagingReturnData = IExecutionEnvironment(environment).stagingWrapper{value: msg.value}(userCall);
}

function _executeUserCall(UserCall calldata userCall, address environment)
Expand All @@ -84,7 +81,6 @@ contract Escrow is ProtocolVerifier, SafetyLocks, SearcherWrapper {

function _executeSearcherCall(
SearcherCall calldata searcherCall,
CallChainProof memory proof,
bool isAuctionAlreadyComplete,
address environment
) internal returns (bool) {
Expand All @@ -104,7 +100,7 @@ contract Escrow is ProtocolVerifier, SafetyLocks, SearcherWrapper {
_openSearcherLock(searcherCall.metaTx.to, environment);

// Execute the searcher call
(outcome, escrowSurplus) = _searcherCallWrapper(searcherCall, proof, gasLimit, environment);
(outcome, escrowSurplus) = _searcherCallWrapper(searcherCall, gasLimit, environment);

unchecked {
searcherEscrow.total += uint128(escrowSurplus);
Expand All @@ -120,7 +116,6 @@ contract Escrow is ProtocolVerifier, SafetyLocks, SearcherWrapper {
result |= 1 << uint256(SearcherOutcome.ExecutionCompleted);
}


uint256 gasRebate; // TODO: can reuse gasWaterMark here for gas efficiency if it really matters

// Update the searcher's escrow balances
Expand Down Expand Up @@ -175,17 +170,14 @@ contract Escrow is ProtocolVerifier, SafetyLocks, SearcherWrapper {

function _executeVerificationCall(
ProtocolCall calldata protocolCall,
CallChainProof memory proof,
bytes memory stagingReturnData,
bytes memory userReturnData,
address environment
) internal verificationLock(protocolCall.callConfig, environment) {
proof = proof.addVerificationCallProof(protocolCall.to, stagingReturnData, userReturnData);

IExecutionEnvironment(environment).verificationWrapper(proof, stagingReturnData, userReturnData);
IExecutionEnvironment(environment).verificationWrapper(stagingReturnData, userReturnData);
}

function _executeUserRefund(address userCallFrom) internal {
function _executeGasRefund(address gasPayor) internal {
uint256 gasRebate = uint256(_escrowKey.gasRefund) * tx.gasprice;

/*
Expand All @@ -196,7 +188,7 @@ contract Escrow is ProtocolVerifier, SafetyLocks, SearcherWrapper {
);
*/

SafeTransferLib.safeTransferETH(userCallFrom, gasRebate);
SafeTransferLib.safeTransferETH(gasPayor, gasRebate);
}

function _update(
Expand Down Expand Up @@ -267,8 +259,9 @@ contract Escrow is ProtocolVerifier, SafetyLocks, SearcherWrapper {
metaTx.value,
metaTx.gas,
metaTx.nonce,
metaTx.userCallHash,
metaTx.maxFeePerGas,
metaTx.userCallHash,
metaTx.controlCodeHash,
metaTx.bidsHash,
keccak256(metaTx.data)
)
Expand Down
Loading

0 comments on commit 67b153f

Please sign in to comment.