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
6 changes: 4 additions & 2 deletions interface/IEscrow.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ interface IEscrow {
uint256 indexed instanceId,
address indexed token,
address sender,
uint256 amount,
uint256 netAmount,
uint256 feeAmount,
bytes data
);

Expand Down Expand Up @@ -109,7 +110,8 @@ interface IEscrow {
event AddedDistributor(uint256 indexed repoId, uint256 indexed instanceId, address indexed distributor);
event RemovedDistributor(uint256 indexed repoId, uint256 indexed instanceId, address indexed distributor);
event BatchLimitSet(uint256 newBatchLimit);
event FeeSet(uint256 oldFee, uint256 newFee);
event FeeOnClaimSet(uint256 oldFee, uint256 newFee);
event FeeOnFundSet(uint256 oldFee, uint256 newFee);
event FeeRecipientSet(address indexed oldRecipient, address indexed newRecipient);
event SignerSet(address indexed oldSigner, address indexed newSigner);
}
9 changes: 6 additions & 3 deletions libraries/Params.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ library Params {
address constant BASE_OWNER = 0x7163a6C74a3caB2A364F9aDD054bf83E50A1d8Bc;
address constant BASE_SIGNER = 0x7F26a8d1A94bD7c1Db651306f503430dF37E9037;
address constant BASE_USDC = 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913;
uint constant BASE_FEE_BPS = 250;
uint constant BASE_FEE_ON_FUND_BPS = 0;
uint constant BASE_FEE_ON_CLAIM_BPS = 250;

/*//////////////////////////////////////////////////////////////
SEPOLIA
Expand All @@ -23,7 +24,8 @@ library Params {
address constant SEPOLIA_TESTER = 0x99ecA80b4Ebf8fDACe6627BEcb75EF1e620E6956;
address constant SEPOLIA_TESTER_JSON = 0x5C87eA705eE49a96532F45f5db606A5f5fEF9780;
address constant SEPOLIA_TESTER_SHAFU = 0x39053B170bBD9580d0b86e8317c685aEFB65f1ec;
uint constant SEPOLIA_FEE_BPS = 250;
uint constant SEPOLIA_FEE_ON_FUND_BPS = 0;
uint constant SEPOLIA_FEE_ON_CLAIM_BPS = 250;

/*//////////////////////////////////////////////////////////////
BASE SEPOLIA
Expand All @@ -35,5 +37,6 @@ library Params {
address constant BASESEPOLIA_TESTER = 0x5C87eA705eE49a96532F45f5db606A5f5fEF9780;
address constant BASESEPOLIA_TESTER_SHAFU = 0x39053B170bBD9580d0b86e8317c685aEFB65f1ec;
address constant BASESEPOLIA_TESTER_JSON = 0x5C87eA705eE49a96532F45f5db606A5f5fEF9780;
uint constant BASESEPOLIA_FEE_BPS = 250;
uint constant BASESEPOLIA_FEE_ON_FUND_BPS = 0;
uint constant BASESEPOLIA_FEE_ON_CLAIM_BPS = 250;
}
11 changes: 7 additions & 4 deletions script/Deploy.Anvil.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,11 @@ contract DeployAnvil is Script {
MockERC20 token3 = new MockERC20("Test Token 3", "TKN3", 18);
escrow.whitelistToken(address(token3));

// Test FeeSet event
escrow.setFee(300); // 3%
// Test FeeOnClaimSet event
escrow.setFeeOnClaim(300); // 3%

// Test FeeOnFundSet event
escrow.setFeeOnFund(100); // 1%

// Test FeeRecipientSet event
escrow.setFeeRecipient(USER1);
Expand Down Expand Up @@ -1103,7 +1106,7 @@ contract DeployAnvil is Script {
feeRates[4] = 250; // Back to 2.5%

for (uint i = 0; i < feeRates.length; i++) {
escrow.setFee(feeRates[i]);
escrow.setFeeOnClaim(feeRates[i]);
}

// Test different fee recipients
Expand Down Expand Up @@ -1461,7 +1464,7 @@ contract DeployAnvil is Script {
extremeFees[7] = 250; // Back to 2.5%

for (uint i = 0; i < extremeFees.length; i++) {
escrow.setFee(extremeFees[i]);
escrow.setFeeOnClaim(extremeFees[i]);
}

// Test rotating fee recipients
Expand Down
2 changes: 1 addition & 1 deletion script/Deploy.Base.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ contract DeployBase is Deploy {
Params.BASE_OWNER,
Params.BASE_SIGNER,
initialWhitelistedTokens,
Params.BASE_FEE_BPS,
Params.BASE_FEE_ON_CLAIM_BPS,
Params.BATCH_LIMIT
);

Expand Down
2 changes: 1 addition & 1 deletion script/Deploy.BaseSepolia.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ contract DeployBaseSepolia is Deploy {
Params.BASESEPOLIA_OWNER,
Params.BASESEPOLIA_SIGNER,
initialWhitelistedTokens,
Params.BASESEPOLIA_FEE_BPS,
Params.BASESEPOLIA_FEE_ON_CLAIM_BPS,
Params.BATCH_LIMIT
);

Expand Down
6 changes: 3 additions & 3 deletions script/Deploy.Core.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ contract Deploy is Script {
address owner,
address signer,
address[] memory initialWhitelistedTokens,
uint feeBps,
uint feeOnClaimBps,
uint batchLimit
)
public
Expand All @@ -26,7 +26,7 @@ contract Deploy is Script {
owner,
signer,
initialWhitelistedTokens,
feeBps,
feeOnClaimBps,
batchLimit
);

Expand All @@ -42,7 +42,7 @@ contract Deploy is Script {
owner,
signer,
initialWhitelistedTokens,
feeBps,
feeOnClaimBps,
batchLimit
);

Expand Down
45 changes: 31 additions & 14 deletions src/Escrow.sol
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ contract Escrow is Owned, IEscrow {
mapping(uint => mapping(uint => uint)) public repoSetAdminNonce; // repoId → instanceId → nonce
mapping(address => uint) public recipientClaimNonce; // recipient → nonce

uint public fee;
uint public feeOnFund;
uint public feeOnClaim;
address public feeRecipient;
uint public batchLimit;

Expand Down Expand Up @@ -125,14 +126,14 @@ contract Escrow is Owned, IEscrow {
address _owner,
address _signer,
address[] memory _whitelistedTokens,
uint _fee,
uint _feeOnClaim,
uint _batchLimit
) Owned(_owner) {
require(_fee <= MAX_FEE, Errors.INVALID_FEE);
require(_feeOnClaim <= MAX_FEE, Errors.INVALID_FEE);

signer = _signer;
feeRecipient = _owner;
fee = _fee;
feeOnClaim = _feeOnClaim;
batchLimit = _batchLimit;
INITIAL_CHAIN_ID = block.chainid;
INITIAL_DOMAIN_SEPARATOR = _domainSeparator();
Expand Down Expand Up @@ -205,10 +206,17 @@ contract Escrow is Owned, IEscrow {

token.safeTransferFrom(msg.sender, address(this), amount);

accounts[repoId][instanceId].balance[address(token)] += amount;
fundings[repoId][instanceId][address(token)][msg.sender] += amount;
uint feeAmount = amount.mulDivUp(feeOnFund, 10_000);
require(amount > feeAmount, Errors.INVALID_AMOUNT);

emit FundedRepo(repoId, instanceId, address(token), msg.sender, amount, data);
if (feeAmount > 0) token.safeTransfer(feeRecipient, feeAmount);

uint netAmount = amount - feeAmount;

accounts[repoId][instanceId].balance[address(token)] += netAmount;
fundings[repoId][instanceId][address(token)][msg.sender] += netAmount;

emit FundedRepo(repoId, instanceId, address(token), msg.sender, netAmount, feeAmount, data);
}

/* -------------------------------------------------------------------------- */
Expand Down Expand Up @@ -305,8 +313,7 @@ contract Escrow is Owned, IEscrow {
require(distribution.amount > 0, Errors.INVALID_AMOUNT);
require(whitelistedTokens.contains(address(distribution.token)), Errors.INVALID_TOKEN);

// Validate that after fees, recipient will receive at least 1 wei
uint feeAmount = distribution.amount.mulDivUp(fee, 10_000);
uint feeAmount = distribution.amount.mulDivUp(feeOnClaim, 10_000);
require(distribution.amount > feeAmount, Errors.INVALID_AMOUNT);

distributionId = distributionCount++;
Expand All @@ -320,7 +327,7 @@ contract Escrow is Owned, IEscrow {
exists: true,
_type: _type,
payer: _type == DistributionType.Solo ? msg.sender : address(0),
fee: fee
fee: feeOnClaim
});
}

Expand Down Expand Up @@ -486,14 +493,24 @@ contract Escrow is Owned, IEscrow {
emit WhitelistedToken(token);
}

function setFee(uint newFee)
function setFeeOnFund(uint newFee)
external
onlyOwner
{
require(newFee <= MAX_FEE, Errors.INVALID_FEE);
uint oldFee = feeOnFund;
feeOnFund = newFee;
emit FeeOnFundSet(oldFee, newFee);
}

function setFeeOnClaim(uint newFee)
external
onlyOwner
{
require(newFee <= MAX_FEE, Errors.INVALID_FEE);
uint oldFee = fee;
fee = newFee;
emit FeeSet(oldFee, newFee);
uint oldFee = feeOnClaim;
feeOnClaim = newFee;
emit FeeOnClaimSet(oldFee, newFee);
}

function setFeeRecipient(address newRec)
Expand Down
10 changes: 6 additions & 4 deletions test/01_Deploy.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ contract Deploy_Test is Base_Test {
assertEq(deployedEscrow.owner(), Params.BASE_OWNER);
assertEq(deployedEscrow.signer(), Params.BASE_SIGNER);
assertEq(deployedEscrow.feeRecipient(), Params.BASE_OWNER);
assertEq(deployedEscrow.fee(), Params.BASE_FEE_BPS);
assertEq(deployedEscrow.feeOnClaim(), Params.BASE_FEE_ON_CLAIM_BPS);
assertEq(deployedEscrow.feeOnFund(), Params.BASE_FEE_ON_FUND_BPS);
assertEq(deployedEscrow.batchLimit(), Params.BATCH_LIMIT);
assertEq(deployedEscrow.repoSetAdminNonce(0, 0), 0);
assertEq(deployedEscrow.batchCount(), 0);
Expand Down Expand Up @@ -83,7 +84,8 @@ contract Deploy_Test is Base_Test {
assertEq(deployedEscrow.owner(), testOwner);
assertEq(deployedEscrow.signer(), testSigner);
assertEq(deployedEscrow.feeRecipient(), testOwner);
assertEq(deployedEscrow.fee(), feeBps);
assertEq(deployedEscrow.feeOnClaim(), feeBps);
assertEq(deployedEscrow.feeOnFund(), Params.BASE_FEE_ON_FUND_BPS);
assertEq(deployedEscrow.batchLimit(), batchLimit);
assertEq(deployedEscrow.repoSetAdminNonce(0, 0), 0);
assertEq(deployedEscrow.batchCount(), 0);
Expand Down Expand Up @@ -131,7 +133,7 @@ contract Deploy_Test is Base_Test {
batchLimit
);

assertEq(deployedEscrow.fee(), maxFeeBps);
assertEq(deployedEscrow.feeOnClaim(), maxFeeBps);
}

function test_deploy_revert_invalidFeeBps() public {
Expand Down Expand Up @@ -312,7 +314,7 @@ contract Deploy_Test is Base_Test {
assertEq(deployedEscrow.owner(), _owner);
assertEq(deployedEscrow.signer(), _signer);
assertEq(deployedEscrow.feeRecipient(), _owner);
assertEq(deployedEscrow.fee(), _feeBps);
assertEq(deployedEscrow.feeOnClaim(), _feeBps);
assertEq(deployedEscrow.batchLimit(), _batchLimit);
}

Expand Down
Loading