Skip to content
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,5 @@ Find more information at [docs](https://docs.socket.tech)
- update version after every change
- never remove code
- inherited contracts should have gaps at the end to avoid storage collision
- write tests for migration checking slots after the change
-
2 changes: 1 addition & 1 deletion contracts/interfaces/IDeliveryHelper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ interface IDeliveryHelper {
Bid winningBid // Replaced winningTransmitter and winningBid with Bid struct
);

function bidTimeout() external view returns (uint256);
function bidTimeout() external view returns (uint128);

function payloadBatches(bytes32) external view returns (PayloadBatch memory);

Expand Down
38 changes: 30 additions & 8 deletions contracts/protocol/AddressResolver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,32 +9,54 @@ import "../interfaces/IAddressResolver.sol";
import {Forwarder} from "./Forwarder.sol";
import {AsyncPromise} from "./AsyncPromise.sol";

/// @title AddressResolver Contract
/// @notice This contract is responsible for fetching latest core addresses and deploying Forwarder and AsyncPromise contracts.
/// @dev Inherits the Ownable contract and implements the IAddressResolver interface.
contract AddressResolver is Ownable, IAddressResolver, Initializable {
abstract contract AddressResolverStorage is IAddressResolver {
// slots [0-49] reserved for gap
uint256[50] _gap_before;

// slot 50
IWatcherPrecompile public override watcherPrecompile__;

// slot 51
address public override deliveryHelper;

// slot 52
address public override feesManager;

// Beacons for managing upgrades
// slot 53
UpgradeableBeacon public forwarderBeacon;

// slot 54
UpgradeableBeacon public asyncPromiseBeacon;

// slot 55
address public forwarderImplementation;

// slot 56
address public asyncPromiseImplementation;

// Array to store promises
// slot 57
address[] internal _promises;

// slot 58
uint256 public asyncPromiseCounter;

// slot 59
uint64 public version;

// contracts to gateway map
// slot 60
mapping(address => address) public override contractsToGateways;
// gateway to contract map

// slot 61
mapping(address => address) public override gatewaysToContracts;

// slots [62-111] reserved for gap
uint256[50] _gap_after;
}

/// @title AddressResolver Contract
/// @notice This contract is responsible for fetching latest core addresses and deploying Forwarder and AsyncPromise contracts.
/// @dev Inherits the Ownable contract and implements the IAddressResolver interface.
contract AddressResolver is AddressResolverStorage, Initializable, Ownable {
/// @notice Error thrown if AppGateway contract was already set by a different address
error InvalidAppGateway(address contractAddress_);

Expand Down
28 changes: 21 additions & 7 deletions contracts/protocol/AsyncPromise.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,43 @@ enum AsyncPromiseState {
RESOLVED
}

/// @title AsyncPromise
/// @notice this contract stores the callback address and data to be executed once the previous call is executed
/// This promise expires once the callback is executed
contract AsyncPromise is IPromise, Initializable, AddressResolverUtil {
abstract contract AsyncPromiseStorage is IPromise {
// slots [0-49] reserved for gap
uint256[50] _gap_before;

// slot 50
// bytes1
/// @notice The callback selector to be called on the invoker.
bytes4 public callbackSelector;

// bytes4
/// @notice Indicates whether the promise has been resolved.
bool public override resolved;

// bytes8
/// @notice The current state of the async promise.
AsyncPromiseState public state;

// bytes20
/// @notice The local contract which initiated the async call.
/// @dev The callback will be executed on this address
address public localInvoker;

// slot 51
/// @notice The forwarder address which can call the callback
address public forwarder;

// slot 52
/// @notice The callback data to be used when the promise is resolved.
bytes public callbackData;

// slots [53-102] reserved for gap
uint256[50] _gap_after;

// slots 103-154 reserved for addr resolver util
}

/// @title AsyncPromise
/// @notice this contract stores the callback address and data to be executed once the previous call is executed
/// This promise expires once the callback is executed
contract AsyncPromise is AsyncPromiseStorage, Initializable, AddressResolverUtil {
/// @notice Error thrown when attempting to resolve an already resolved promise.
error PromiseAlreadyResolved();
/// @notice Only the forwarder or local invoker can set then's promise callback
Expand Down
19 changes: 15 additions & 4 deletions contracts/protocol/Forwarder.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,36 @@ import "../interfaces/IAddressResolver.sol";
import "../interfaces/IDeliveryHelper.sol";
import "../interfaces/IAppGateway.sol";
import "../interfaces/IPromise.sol";
import "./AsyncPromise.sol";
import "../interfaces/IForwarder.sol";
import "solady/utils/Initializable.sol";

/// @title Forwarder Contract
/// @notice This contract acts as a forwarder for async calls to the on-chain contracts.
contract Forwarder is IForwarder, Initializable {
abstract contract ForwarderStorage is IForwarder {
// slots [0-49] reserved for gap
uint256[50] _gap_before;

// slot 50
/// @notice chain id
uint32 public chainSlug;

// slot 51
/// @notice on-chain address associated with this forwarder
address public onChainAddress;

// slot 52
/// @notice address resolver contract address for imp addresses
address public addressResolver;

// slot 53
/// @notice caches the latest async promise address for the last call
address public latestAsyncPromise;

// slots [54-103] reserved for gap
uint256[50] _gap_after;
}

/// @title Forwarder Contract
/// @notice This contract acts as a forwarder for async calls to the on-chain contracts.
contract Forwarder is ForwarderStorage, Initializable {
error AsyncModifierNotUsed();

constructor() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,38 +1,51 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {Ownable} from "solady/auth/Ownable.sol";
import {ECDSA} from "solady/utils/ECDSA.sol";
import {AddressResolverUtil} from "../../utils/AddressResolverUtil.sol";
import {Fees, Bid, PayloadBatch} from "../../utils/common/Structs.sol";
import {IDeliveryHelper} from "../../../interfaces/IDeliveryHelper.sol";
import {IFeesManager} from "../../../interfaces/IFeesManager.sol";
import {IAuctionManager} from "../../../interfaces/IAuctionManager.sol";
import "solady/utils/Initializable.sol";
import {Ownable} from "solady/auth/Ownable.sol";

/// @title AuctionManager
/// @notice Contract for managing auctions and placing bids
contract AuctionManager is AddressResolverUtil, Ownable, IAuctionManager, Initializable {
import {IDeliveryHelper} from "../../interfaces/IDeliveryHelper.sol";
import {IFeesManager} from "../../interfaces/IFeesManager.sol";
import {IAuctionManager} from "../../interfaces/IAuctionManager.sol";

import {AddressResolverUtil} from "../utils/AddressResolverUtil.sol";
import {Fees, Bid, PayloadBatch} from "../utils/common/Structs.sol";
import {AuctionClosed, AuctionAlreadyStarted, BidExceedsMaxFees, LowerBidAlreadyExists, InvalidTransmitter} from "../utils/common/Errors.sol";

abstract contract AuctionManagerStorage is IAuctionManager {
// slots [0-49] reserved for gap
uint256[50] _gap_before;

// slot 50
uint32 public evmxSlug;

// slot 51
mapping(bytes32 => Bid) public winningBids;

// slot 52
// asyncId => auction status
mapping(bytes32 => bool) public override auctionClosed;

// slot 53
mapping(bytes32 => bool) public override auctionStarted;

// slot 54
uint256 public auctionEndDelaySeconds;

/// @notice Error thrown when trying to start or bid a closed auction
error AuctionClosed();
/// @notice Error thrown when trying to start an ongoing auction
error AuctionAlreadyStarted();
/// @notice Error thrown if fees exceed the maximum set fees
error BidExceedsMaxFees();
/// @notice Error thrown if winning bid is assigned to an invalid transmitter
error InvalidTransmitter();
/// @notice Error thrown if a lower bid already exists
error LowerBidAlreadyExists();
// slots [55-104] reserved for gap
uint256[50] _gap_after;

// slots 105-155 reserved for addr resolver util
}

/// @title AuctionManager
/// @notice Contract for managing auctions and placing bids
contract AuctionManager is AuctionManagerStorage, Initializable, Ownable, AddressResolverUtil {
event AuctionRestarted(bytes32 asyncId);
event AuctionStarted(bytes32 asyncId);
event AuctionEnded(bytes32 asyncId, Bid winningBid);
event BidPlaced(bytes32 asyncId, Bid bid);

constructor() {
_disableInitializers(); // disable for implementation
Expand All @@ -55,10 +68,6 @@ contract AuctionManager is AddressResolverUtil, Ownable, IAuctionManager, Initia
auctionEndDelaySeconds = auctionEndDelaySeconds_;
}

event AuctionStarted(bytes32 asyncId);
event AuctionEnded(bytes32 asyncId, Bid winningBid);
event BidPlaced(bytes32 asyncId, Bid bid);

function setAuctionEndDelaySeconds(uint256 auctionEndDelaySeconds_) external onlyOwner {
auctionEndDelaySeconds = auctionEndDelaySeconds_;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,23 @@ pragma solidity ^0.8.0;
import {Ownable} from "solady/auth/Ownable.sol";
import "solady/utils/Initializable.sol";
import "solady/utils/ECDSA.sol";
import {AddressResolverUtil} from "../../../protocol/utils/AddressResolverUtil.sol";
import {Bid, Fees, PayloadDetails, CallType, FinalizeParams, PayloadBatch, Parallel} from "../../../protocol/utils/common/Structs.sol";
import {IDeliveryHelper} from "../../../interfaces/IDeliveryHelper.sol";
import {FORWARD_CALL, DISTRIBUTE_FEE, DEPLOY, WITHDRAW} from "../../../protocol/utils/common/Constants.sol";
import {IFeesPlug} from "../../../interfaces/IFeesPlug.sol";
import {IFeesManager} from "../../../interfaces/IFeesManager.sol";

import {NotAuctionManager} from "../../../protocol/utils/common/Errors.sol";
import {IFeesPlug} from "../../interfaces/IFeesPlug.sol";
import {IFeesManager} from "../../interfaces/IFeesManager.sol";

/// @title FeesManager
/// @notice Contract for managing fees
contract FeesManager is IFeesManager, AddressResolverUtil, Ownable, Initializable {
import {AddressResolverUtil} from "../utils/AddressResolverUtil.sol";
import {WITHDRAW} from "../utils/common/Constants.sol";
import {NotAuctionManager} from "../utils/common/Errors.sol";
import {Bid, Fees, PayloadDetails, CallType, FinalizeParams, Parallel} from "../utils/common/Structs.sol";

abstract contract FeesManagerStorage is IFeesManager {
// slots [0-49] reserved for gap
uint256[50] _gap_before;

// slot 50
uint256 public feesCounter;

// slot 51
uint32 public evmxSlug;

/// @notice Struct containing fee amounts and status
Expand All @@ -25,23 +29,36 @@ contract FeesManager is IFeesManager, AddressResolverUtil, Ownable, Initializabl
uint256 blocked; // Amount blocked
}

// slot 52
/// @notice Master mapping tracking all fee information
/// @dev appGateway => chainSlug => token => TokenBalance
mapping(address => mapping(uint32 => mapping(address => TokenBalance)))
public appGatewayFeeBalances;

// slot 53
/// @notice Mapping to track blocked fees for each async id
/// @dev asyncId => Fees
mapping(bytes32 => Fees) public asyncIdBlockedFees;

// slot 54
/// @notice Mapping to track fees to be distributed to transmitters
/// @dev transmitter => chainSlug => token => amount
mapping(address => mapping(uint32 => mapping(address => uint256))) public transmitterFees;

// slot 55
/// @notice Mapping to track nonce to whether it has been used
/// @dev signatureNonce => isValid
/// @dev signatureNonce => isNonceUsed
mapping(uint256 => bool) public isNonceUsed;

// slots [56-105] reserved for gap
uint256[50] _gap_after;

// slots 106-156 reserved for addr resolver util
}

/// @title FeesManager
/// @notice Contract for managing fees
contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResolverUtil {
/// @notice Emitted when fees are blocked for a batch
/// @param asyncId The batch identifier
/// @param chainSlug The chain identifier
Expand Down
12 changes: 3 additions & 9 deletions contracts/protocol/payload-delivery/app-gateway/BatchAsync.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,12 @@ pragma solidity ^0.8.21;

import "./QueueAsync.sol";

import {IDeliveryHelper} from "../../../interfaces/IDeliveryHelper.sol";
import {IAppGateway} from "../../../interfaces/IAppGateway.sol";
import {IAddressResolver} from "../../../interfaces/IAddressResolver.sol";
import {IAuctionManager} from "../../../interfaces/IAuctionManager.sol";
import {IFeesManager} from "../../../interfaces/IFeesManager.sol";

import {Bid, PayloadBatch, Fees, PayloadDetails} from "../../../protocol/utils/common/Structs.sol";
import {FORWARD_CALL, DISTRIBUTE_FEE, DEPLOY, WITHDRAW, QUERY, FINALIZE} from "../../../protocol/utils/common/Constants.sol";

/// @title BatchAsync
/// @notice Abstract contract for managing asynchronous payload batches
abstract contract BatchAsync is QueueAsync {
// slots [210-259] reserved for gap
uint256[50] _gap_batch_async;

/// @notice Error thrown when attempting to executed payloads after all have been executed
error AllPayloadsExecuted();
/// @notice Error thrown request did not come from Forwarder address
Expand Down
16 changes: 3 additions & 13 deletions contracts/protocol/payload-delivery/app-gateway/DeliveryHelper.sol
Original file line number Diff line number Diff line change
@@ -1,19 +1,10 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "solady/utils/Initializable.sol";

import {IAppGateway} from "../../../interfaces/IAppGateway.sol";
import {Bid, PayloadBatch, Fees, PayloadDetails, FinalizeParams} from "../../../protocol/utils/common/Structs.sol";
import {DISTRIBUTE_FEE, DEPLOY} from "../../../protocol/utils/common/Constants.sol";
import {PromisesNotResolved, InvalidTransmitter} from "../../../protocol/utils/common/Errors.sol";
import "./BatchAsync.sol";

contract DeliveryHelper is BatchAsync, Initializable {
contract DeliveryHelper is BatchAsync {
event CallBackReverted(bytes32 asyncId_, bytes32 payloadId_);
uint64 public version;

bytes32[] public tempPayloadIds;

constructor() {
_disableInitializers(); // disable for implementation
Expand All @@ -25,10 +16,9 @@ contract DeliveryHelper is BatchAsync, Initializable {
function initialize(
address addressResolver_,
address owner_,
uint256 bidTimeout_
uint128 bidTimeout_
) public reinitializer(1) {
_setAddressResolver(addressResolver_);
version = 1;
bidTimeout = bidTimeout_;
_initializeOwner(owner_);
}
Expand All @@ -44,7 +34,7 @@ contract DeliveryHelper is BatchAsync, Initializable {

if (!isRestarted) return _process(asyncId_, false);

// Refinalize all payloads in the batch if a new transmitter is assigned
// Re-finalize all payloads in the batch if a new transmitter is assigned
bytes32[] memory payloadIds = _payloadBatches[asyncId_].lastBatchOfPayloads;
for (uint256 i = 0; i < payloadIds.length; i++) {
watcherPrecompile__().refinalize(
Expand Down
Loading
Loading