Skip to content
Merged
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
19 changes: 12 additions & 7 deletions src/CelerLedger.sol
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
pragma solidity ^0.8.26;

import "./lib/ledgerlib/LedgerStruct.sol";
import "./lib/ledgerlib/LedgerOperation.sol";
import "./lib/ledgerlib/LedgerMigrate.sol";
import "./lib/ledgerlib/LedgerChannel.sol";
import "./lib/AgentPayErrors.sol";
import "./interfaces/ICelerWallet.sol";
import "./interfaces/INativeWrap.sol";
import "./interfaces/IPayRegistry.sol";
Expand Down Expand Up @@ -43,8 +44,8 @@ contract CelerLedger is ICelerLedger, Ownable {
* later become its operator (during channel opening or via wallet creation).
*/
constructor(address _nativeWrap, address _payRegistry, address _celerWallet) Ownable(msg.sender) {
require(_nativeWrap != address(0), "nativeWrap address required");
require(_nativeWrap.code.length > 0, "nativeWrap code required");
require(_nativeWrap != address(0), AgentPayErrors.ZeroAddress());
require(_nativeWrap.code.length > 0, AgentPayErrors.NativeWrapNotContract());
Comment thread
hhl42 marked this conversation as resolved.
ledger.nativeWrap = INativeWrap(_nativeWrap);
ledger.payRegistry = IPayRegistry(_payRegistry);
ledger.celerWallet = ICelerWallet(_celerWallet);
Expand All @@ -59,7 +60,7 @@ contract CelerLedger is ICelerLedger, Ownable {
* native-drain path).
*/
receive() external payable {
require(msg.sender == address(ledger.nativeWrap), "Only nativeWrap");
require(msg.sender == address(ledger.nativeWrap), AgentPayErrors.CallerNotNativeWrap());
Comment thread
hhl42 marked this conversation as resolved.
}

/**
Expand All @@ -68,7 +69,7 @@ contract CelerLedger is ICelerLedger, Ownable {
* @param _limits balance limits of the tokens
*/
function setBalanceLimits(address[] calldata _tokenAddrs, uint256[] calldata _limits) external onlyOwner {
require(_tokenAddrs.length == _limits.length, "Lengths do not match");
require(_tokenAddrs.length == _limits.length, AgentPayErrors.LengthMismatch(_tokenAddrs.length, _limits.length));
Comment thread
hhl42 marked this conversation as resolved.
for (uint256 i = 0; i < _tokenAddrs.length; i++) {
ledger.balanceLimits[_tokenAddrs[i]] = _limits[i];
}
Expand Down Expand Up @@ -126,8 +127,12 @@ contract CelerLedger is ICelerLedger, Ownable {
uint256[] calldata _transferFromAmounts
) external {
require(
_channelIds.length == _receivers.length && _receivers.length == _transferFromAmounts.length,
"Lengths do not match"
_channelIds.length == _receivers.length,
AgentPayErrors.LengthMismatch(_channelIds.length, _receivers.length)
);
require(
_receivers.length == _transferFromAmounts.length,
AgentPayErrors.LengthMismatch(_receivers.length, _transferFromAmounts.length)
);
for (uint256 i = 0; i < _channelIds.length; i++) {
ledger.deposit(_channelIds[i], _receivers[i], _transferFromAmounts[i]);
Expand Down
2 changes: 1 addition & 1 deletion src/CelerLedgerMock.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
pragma solidity ^0.8.26;

import "./lib/ledgerlib/LedgerStruct.sol";
import "./lib/ledgerlib/LedgerOperation.sol";
Expand Down
17 changes: 9 additions & 8 deletions src/CelerWallet.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
pragma solidity ^0.8.26;

import "./interfaces/ICelerWallet.sol";
import "./lib/AgentPayErrors.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/utils/Pausable.sol";
Expand Down Expand Up @@ -45,7 +46,7 @@ contract CelerWallet is ICelerWallet, Pausable, Ownable {
* @param _walletId id of the wallet to be operated
*/
modifier onlyOperator(bytes32 _walletId) {
require(msg.sender == wallets[_walletId].operator, "msg.sender is not operator");
require(msg.sender == wallets[_walletId].operator, AgentPayErrors.NotOperator());
_;
}

Expand All @@ -55,7 +56,7 @@ contract CelerWallet is ICelerWallet, Pausable, Ownable {
* @param _addr address to be checked
*/
modifier onlyWalletOwner(bytes32 _walletId, address _addr) {
require(_isWalletOwner(_walletId, _addr), "Given address is not wallet owner");
require(_isWalletOwner(_walletId, _addr), AgentPayErrors.NotWalletOwner());
_;
}

Expand All @@ -73,12 +74,12 @@ contract CelerWallet is ICelerWallet, Pausable, Ownable {
whenNotPaused
returns (bytes32)
{
require(_operator != address(0), "New operator is address(0)");
require(_operator != address(0), AgentPayErrors.ZeroAddress());

bytes32 walletId = keccak256(abi.encodePacked(block.chainid, address(this), msg.sender, _nonce));
Wallet storage w = wallets[walletId];
// wallet must be uninitialized
require(w.operator == address(0), "Occupied wallet id");
require(w.operator == address(0), AgentPayErrors.WalletIdOccupied());
w.owners = _owners;
w.operator = _operator;
walletNum++;
Expand Down Expand Up @@ -182,7 +183,7 @@ contract CelerWallet is ICelerWallet, Pausable, Ownable {
* @param _newOperator the new operator proposal
*/
function proposeNewOperator(bytes32 _walletId, address _newOperator) public onlyWalletOwner(_walletId, msg.sender) {
require(_newOperator != address(0), "New operator is address(0)");
require(_newOperator != address(0), AgentPayErrors.ZeroAddress());

Wallet storage w = wallets[_walletId];
if (_newOperator != w.proposedNewOperator) {
Expand Down Expand Up @@ -273,7 +274,7 @@ contract CelerWallet is ICelerWallet, Pausable, Ownable {
function _withdrawToken(address _tokenAddress, address _receiver, uint256 _amount) internal {
if (_tokenAddress == address(0)) {
(bool success,) = payable(_receiver).call{value: _amount}("");
require(success, "Native transfer failed");
require(success, AgentPayErrors.NativeTransferFailed());
} else {
IERC20(_tokenAddress).safeTransfer(_receiver, _amount);
}
Expand Down Expand Up @@ -313,7 +314,7 @@ contract CelerWallet is ICelerWallet, Pausable, Ownable {
* @param _newOperator the new operator
*/
function _changeOperator(bytes32 _walletId, address _newOperator) internal {
require(_newOperator != address(0), "New operator is address(0)");
require(_newOperator != address(0), AgentPayErrors.ZeroAddress());

Wallet storage w = wallets[_walletId];
address oldOperator = w.operator;
Expand Down
18 changes: 12 additions & 6 deletions src/PayRegistry.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
pragma solidity ^0.8.26;

import "./interfaces/IPayRegistry.sol";
import "./lib/AgentPayErrors.sol";

/**
* @title PayRegistry
Expand Down Expand Up @@ -56,7 +57,7 @@ contract PayRegistry is IPayRegistry {

/// @inheritdoc IPayRegistry
function setPayAmounts(bytes32[] calldata _payHashes, uint256[] calldata _amts) external {
require(_payHashes.length == _amts.length, "Lengths do not match");
require(_payHashes.length == _amts.length, AgentPayErrors.LengthMismatch(_payHashes.length, _amts.length));

bytes32 payId;
address msgSender = msg.sender;
Expand All @@ -71,7 +72,9 @@ contract PayRegistry is IPayRegistry {

/// @inheritdoc IPayRegistry
function setPayDeadlines(bytes32[] calldata _payHashes, uint256[] calldata _deadlines) external {
require(_payHashes.length == _deadlines.length, "Lengths do not match");
require(
_payHashes.length == _deadlines.length, AgentPayErrors.LengthMismatch(_payHashes.length, _deadlines.length)
);

bytes32 payId;
address msgSender = msg.sender;
Expand All @@ -88,7 +91,10 @@ contract PayRegistry is IPayRegistry {
function setPayInfos(bytes32[] calldata _payHashes, uint256[] calldata _amts, uint256[] calldata _deadlines)
external
{
require(_payHashes.length == _amts.length && _payHashes.length == _deadlines.length, "Lengths do not match");
require(_payHashes.length == _amts.length, AgentPayErrors.LengthMismatch(_payHashes.length, _amts.length));
require(
_payHashes.length == _deadlines.length, AgentPayErrors.LengthMismatch(_payHashes.length, _deadlines.length)
);

bytes32 payId;
address msgSender = msg.sender;
Expand All @@ -112,10 +118,10 @@ contract PayRegistry is IPayRegistry {
for (uint256 i = 0; i < _payIds.length; i++) {
if (payInfoMap[_payIds[i]].resolveDeadline == 0) {
// unresolved pays are gated by the caller-supplied upper-bound deadline
require(block.timestamp > _maxResolveDeadline, "Payment is not finalized");
require(block.timestamp > _maxResolveDeadline, AgentPayErrors.PaymentNotFinalized());
} else {
// resolved pays are gated by their per-pay resolve deadline
require(block.timestamp > payInfoMap[_payIds[i]].resolveDeadline, "Payment is not finalized");
require(block.timestamp > payInfoMap[_payIds[i]].resolveDeadline, AgentPayErrors.PaymentNotFinalized());
}
amounts[i] = payInfoMap[_payIds[i]].amount;
}
Expand Down
47 changes: 29 additions & 18 deletions src/PayResolver.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
pragma solidity ^0.8.26;

import "./lib/data/PbChain.sol";
import "./lib/data/PbEntity.sol";
Expand All @@ -8,6 +8,7 @@ import "./interfaces/IPayResolver.sol";
import "./interfaces/IBooleanCond.sol";
import "./interfaces/INumericCond.sol";
import "./interfaces/IVirtContractResolver.sol";
import "./lib/AgentPayErrors.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";
Expand Down Expand Up @@ -73,12 +74,17 @@ contract PayResolver is IPayResolver {
PbEntity.CondPayResult memory payResult = PbEntity.decCondPayResult(vouchedPayResult.condPayResult);
PbEntity.ConditionalPay memory pay = PbEntity.decConditionalPay(payResult.condPay);

require(payResult.amount <= pay.transferFunc.maxTransfer.receiver.amt, "Exceed max transfer amount");
require(
payResult.amount <= pay.transferFunc.maxTransfer.receiver.amt,
AgentPayErrors.MaxTransferExceeded(payResult.amount, pay.transferFunc.maxTransfer.receiver.amt)
);
Comment thread
hhl42 marked this conversation as resolved.
// check signatures
bytes32 hash = keccak256(vouchedPayResult.condPayResult).toEthSignedMessageHash();
address recoveredSrc = hash.recover(vouchedPayResult.sigOfSrc);
address recoveredDest = hash.recover(vouchedPayResult.sigOfDest);
require(recoveredSrc == address(pay.src) && recoveredDest == address(pay.dest), "Check sigs failed");
require(
recoveredSrc == address(pay.src) && recoveredDest == address(pay.dest), AgentPayErrors.InvalidCoSignatures()
);
Comment thread
hhl42 marked this conversation as resolved.

bytes32 payHash = keccak256(payResult.condPay);
_resolvePayment(pay, payHash, payResult.amount);
Expand All @@ -92,21 +98,23 @@ contract PayResolver is IPayResolver {
*/
function _resolvePayment(PbEntity.ConditionalPay memory _pay, bytes32 _payHash, uint256 _amount) internal {
// bind the signed pay to its intended (chain, resolver) target
require(_pay.chainId == block.chainid, "Wrong chain id for pay");
require(_pay.payResolver == address(this), "Wrong resolver for pay");
require(_pay.chainId == block.chainid, AgentPayErrors.ChainIdMismatch(block.chainid, _pay.chainId));
require(_pay.payResolver == address(this), AgentPayErrors.ResolverAddressMismatch());
uint256 nowTs = block.timestamp;
require(nowTs <= _pay.resolveDeadline, "Passed pay resolve deadline in condPay msg");
require(nowTs <= _pay.resolveDeadline, AgentPayErrors.DeadlinePassed());
Comment thread
hhl42 marked this conversation as resolved.

bytes32 payId = _calculatePayId(_payHash, address(this));
(uint256 currentAmt, uint256 currentDeadline) = payRegistry.getPayInfo(payId);

// should never resolve a pay before or not reaching onchain resolve deadline
require(currentDeadline == 0 || nowTs <= currentDeadline, "Passed onchain resolve pay deadline");
// If a prior on-chain resolution exists (`currentDeadline > 0`), updates
// are only accepted while the registry's stored deadline has not yet
// passed. First-time resolution (`currentDeadline == 0`) always passes.
require(currentDeadline == 0 || nowTs <= currentDeadline, AgentPayErrors.ResolveUpdateWindowClosed());

if (currentDeadline > 0) {
// currentDeadline > 0 implies that this pay has been updated
// payment amount must be monotone increasing
require(_amount > currentAmt, "New amount is not larger");
require(_amount > currentAmt, AgentPayErrors.AmountNotGreater());

if (_amount == _pay.transferFunc.maxTransfer.receiver.amt) {
// set resolve deadline = current timestamp if amount = max
Expand All @@ -124,7 +132,7 @@ contract PayResolver is IPayResolver {
} else {
newDeadline = Math.min(nowTs + _pay.resolveTimeout, _pay.resolveDeadline);
// 0 is reserved for unresolved status of a payment
require(newDeadline > 0, "New resolve deadline is 0");
require(newDeadline > 0, AgentPayErrors.ZeroDeadline());
}

payRegistry.setPayInfo(_payHash, _amount, newDeadline);
Expand All @@ -148,15 +156,15 @@ contract PayResolver is IPayResolver {
for (uint256 i = 0; i < _pay.conditions.length; i++) {
PbEntity.Condition memory cond = _pay.conditions[i];
if (cond.conditionType == PbEntity.ConditionType.HASH_LOCK) {
require(keccak256(_preimages[j]) == cond.hashLock, "Wrong preimage");
require(keccak256(_preimages[j]) == cond.hashLock, AgentPayErrors.PreimageMismatch());
j++;
} else if (
cond.conditionType == PbEntity.ConditionType.DEPLOYED_CONTRACT
|| cond.conditionType == PbEntity.ConditionType.VIRTUAL_CONTRACT
) {
address addr = _getCondAddress(cond);
IBooleanCond dependent = IBooleanCond(addr);
require(dependent.isFinalized(cond.argsQueryFinalization), "Condition is not finalized");
require(dependent.isFinalized(cond.argsQueryFinalization), AgentPayErrors.ConditionNotFinalized());

if (!dependent.getOutcome(cond.argsQueryOutcome)) {
hasFalseContractCond = true;
Expand Down Expand Up @@ -191,15 +199,15 @@ contract PayResolver is IPayResolver {
for (uint256 i = 0; i < _pay.conditions.length; i++) {
PbEntity.Condition memory cond = _pay.conditions[i];
if (cond.conditionType == PbEntity.ConditionType.HASH_LOCK) {
require(keccak256(_preimages[j]) == cond.hashLock, "Wrong preimage");
require(keccak256(_preimages[j]) == cond.hashLock, AgentPayErrors.PreimageMismatch());
j++;
} else if (
cond.conditionType == PbEntity.ConditionType.DEPLOYED_CONTRACT
|| cond.conditionType == PbEntity.ConditionType.VIRTUAL_CONTRACT
) {
address addr = _getCondAddress(cond);
IBooleanCond dependent = IBooleanCond(addr);
require(dependent.isFinalized(cond.argsQueryFinalization), "Condition is not finalized");
require(dependent.isFinalized(cond.argsQueryFinalization), AgentPayErrors.ConditionNotFinalized());

hasContractCond = true;
if (dependent.getOutcome(cond.argsQueryOutcome)) {
Expand Down Expand Up @@ -236,15 +244,15 @@ contract PayResolver is IPayResolver {
for (uint256 i = 0; i < _pay.conditions.length; i++) {
PbEntity.Condition memory cond = _pay.conditions[i];
if (cond.conditionType == PbEntity.ConditionType.HASH_LOCK) {
require(keccak256(_preimages[j]) == cond.hashLock, "Wrong preimage");
require(keccak256(_preimages[j]) == cond.hashLock, AgentPayErrors.PreimageMismatch());
j++;
} else if (
cond.conditionType == PbEntity.ConditionType.DEPLOYED_CONTRACT
|| cond.conditionType == PbEntity.ConditionType.VIRTUAL_CONTRACT
) {
address addr = _getCondAddress(cond);
INumericCond dependent = INumericCond(addr);
require(dependent.isFinalized(cond.argsQueryFinalization), "Condition is not finalized");
require(dependent.isFinalized(cond.argsQueryFinalization), AgentPayErrors.ConditionNotFinalized());

if (_funcType == PbEntity.TransferFunctionType.NUMERIC_ADD) {
amount = amount + dependent.getOutcome(cond.argsQueryOutcome);
Expand All @@ -267,7 +275,10 @@ contract PayResolver is IPayResolver {
}

if (hasContractCond) {
require(amount <= _pay.transferFunc.maxTransfer.receiver.amt, "Exceed max transfer amount");
require(
amount <= _pay.transferFunc.maxTransfer.receiver.amt,
AgentPayErrors.MaxTransferExceeded(amount, _pay.transferFunc.maxTransfer.receiver.amt)
);
return amount;
} else {
return _pay.transferFunc.maxTransfer.receiver.amt;
Expand All @@ -288,7 +299,7 @@ contract PayResolver is IPayResolver {
} else if (_cond.conditionType == PbEntity.ConditionType.VIRTUAL_CONTRACT) {
return virtResolver.resolve(_cond.virtualContractAddress);
} else {
revert("Invalid condition type");
revert AgentPayErrors.InvalidConditionType();
}
}

Expand Down
9 changes: 5 additions & 4 deletions src/RouterRegistry.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
pragma solidity ^0.8.26;

import "./interfaces/IRouterRegistry.sol";
import "./lib/AgentPayErrors.sol";

/**
* @title RouterRegistry
Expand All @@ -19,7 +20,7 @@ contract RouterRegistry is IRouterRegistry {
* @notice An external router could register to join the Celer Network
*/
function registerRouter() external {
require(routerInfo[msg.sender] == 0, "Router address already exists");
require(routerInfo[msg.sender] == 0, AgentPayErrors.RouterAlreadyRegistered());

routerInfo[msg.sender] = block.timestamp;

Expand All @@ -30,7 +31,7 @@ contract RouterRegistry is IRouterRegistry {
* @notice An in-network router could deregister to leave the network
*/
function deregisterRouter() external {
require(routerInfo[msg.sender] != 0, "Router address does not exist");
require(routerInfo[msg.sender] != 0, AgentPayErrors.RouterNotRegistered());

delete routerInfo[msg.sender];

Expand All @@ -41,7 +42,7 @@ contract RouterRegistry is IRouterRegistry {
* @notice Refresh the existed router's stored timestamp
*/
function refreshRouter() external {
require(routerInfo[msg.sender] != 0, "Router address does not exist");
require(routerInfo[msg.sender] != 0, AgentPayErrors.RouterNotRegistered());

routerInfo[msg.sender] = block.timestamp;

Expand Down
Loading
Loading