Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into fix/code-quality
Browse files Browse the repository at this point in the history
  • Loading branch information
r4reetik committed Jun 18, 2024
2 parents b81ae5d + cbdca14 commit fe99e96
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 56 deletions.
57 changes: 38 additions & 19 deletions contracts/fee/GardenFEEAccount.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ contract GardenFEEAccount is EIP712Upgradeable {

struct HTLC {
bytes32 secretHash;
uint256 timeLock;
uint256 expiry;
uint256 sendAmount;
uint256 recieveAmount;
}
Expand All @@ -37,12 +37,12 @@ contract GardenFEEAccount is EIP712Upgradeable {
keccak256(
abi.encodePacked(
"Claim(uint256 nonce,uint256 amount,HTLC[] htlcs)",
"HTLC(bytes32 secretHash,uint256 timeLock,uint256 sendAmount,uint256 recieveAmount)"
"HTLC(bytes32 secretHash,uint256 expiry,uint256 sendAmount,uint256 recieveAmount)"
)
);

bytes32 private constant HTLC_TYPEHASH =
keccak256("HTLC(bytes32 secretHash,uint256 timeLock,uint256 sendAmount,uint256 recieveAmount)");
keccak256("HTLC(bytes32 secretHash,uint256 expiry,uint256 sendAmount,uint256 recieveAmount)");

// Are set when the channel is created
IERC20Upgradeable public token;
Expand All @@ -54,10 +54,16 @@ contract GardenFEEAccount is EIP712Upgradeable {
uint256 public amount;
uint256 public nonce;
uint256 public expiration;
uint256 public secretsProvided;

mapping(bytes => uint256) public secretsClaimed;
mapping(bytes32 => bytes) public secrets;

uint256 private constant TWO_DAYS = 2 * 7200;

function initialize() initializer external {
_disableInitializers();
}

function __GardenFEEAccount_init(
IERC20Upgradeable token_,
address funder_,
Expand Down Expand Up @@ -117,47 +123,60 @@ contract GardenFEEAccount is EIP712Upgradeable {
* @param amount_ The amount of tokens to be claimed.
* @param nonce_ The nonce value for the claim message.
* @param htlcs The array of HTLCs in the claim.
* @param secrets The array of secrets corresponding to the HTLCs.
* @param secrets_ The array of secrets corresponding to the HTLCs.
* @param funderSig The signature of the funder for the claim message.
* @param recipientSig The signature of the recipient for the claim message.
*/
function claim(
uint256 amount_,
uint256 nonce_,
HTLC[] memory htlcs,
bytes[] memory secrets,
bytes[] memory secrets_,
bytes memory funderSig,
bytes memory recipientSig
) external {
require(htlcs.length == secrets.length, "GardenFEEAccount: invalid input");
require(htlcs.length == secrets_.length, "FeeAccount: invalid input");
require(!(htlcs.length > 0 && nonce_ == 0), "FeeAccount: zero nonce claim cannot contain htlcs");
bytes32 claimID = claimHash(amount_, nonce_, htlcs);

uint256 localSecretsProvided = 0;
if (nonce == nonce_ && expiration != 0) {
amount_ = amount;
}

bool secretsProcessed = false;

for (uint256 i = 0; i < htlcs.length; i++) {
if (htlcs[i].timeLock > block.number && sha256(secrets[i]) == htlcs[i].secretHash) {
localSecretsProvided++;
if (secretsClaimed[secrets[htlcs[i].secretHash]] > 0) {
if (secretsClaimed[secrets[htlcs[i].secretHash]] != nonce_) {
secretsProcessed = true;
secretsClaimed[secrets[htlcs[i].secretHash]] = nonce_;
amount_ += htlcs[i].sendAmount;
amount_ -= htlcs[i].recieveAmount;
}
continue;
}
if (htlcs[i].timeLock > block.number && sha256(secrets_[i]) == htlcs[i].secretHash) {
secretsProcessed = true;
secretsClaimed[secrets_[i]] = nonce_;
secrets[htlcs[i].secretHash] = secrets_[i];
amount_ += htlcs[i].sendAmount;
amount_ -= htlcs[i].recieveAmount;
}
}

require(amount_ <= totalAmount(), "GardenFEEAccount: invalid amount");
require(amount_ <= totalAmount(), "FeeAccount: invalid amount");
if (expiration != 0) {
// a claim exists, so should satisfy override conditions
require(
nonce_ > nonce || (nonce_ == nonce && localSecretsProvided > secretsProvided),
"GardenFEEAccount: override conditions not met"
);
require(nonce_ > nonce || (nonce_ == nonce && secretsProcessed), "FeeAccount: override conditions not met");
}

// verify funder and recipient signatures
address funderSigner = claimID.recover(funderSig);
address recipientSigner = claimID.recover(recipientSig);
require(funderSigner == funder, "GardenFEEAccount: invalid funder signature");
require(recipientSigner == recipient, "GardenFEEAccount: invalid recipient signature");
require(funderSigner == funder, "FeeAccount: invalid funder signature");
require(recipientSigner == recipient, "FeeAccount: invalid recipient signature");

// update global claim state
secretsProvided = localSecretsProvided;
expiration = block.number + TWO_DAYS;
amount = amount_;
nonce = nonce_;
Expand Down Expand Up @@ -200,7 +219,7 @@ contract GardenFEEAccount is EIP712Upgradeable {
abi.encode(
HTLC_TYPEHASH,
htlcs[i].secretHash,
htlcs[i].timeLock,
htlcs[i].expiry,
htlcs[i].sendAmount,
htlcs[i].recieveAmount
)
Expand Down
6 changes: 5 additions & 1 deletion contracts/fee/GardenFEEAccountFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,13 @@ contract GardenFEEAccountFactory {

token = token_;
feeManager = feeManager_;
template = address(new GardenFEEAccount());

feeAccountName = feeAccountName_;
feeAccountVersion = feeAccountVersion_;

GardenFEEAccount templateFeeAccount = new GardenFEEAccount();
templateFeeAccount.initialize();
template = address(templateFeeAccount);
}

/**
Expand Down
64 changes: 44 additions & 20 deletions contracts/htlc/GardenHTLC.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ contract GardenHTLC is EIP712 {
address initiator;
address redeemer;
uint256 initiatedAt;
uint256 expiry;
uint256 timelock;
uint256 amount;
}

Expand All @@ -33,7 +33,9 @@ contract GardenHTLC is EIP712 {
mapping(bytes32 => Order) public orders;

bytes32 private constant _INITIATE_TYPEHASH =
keccak256("Initiate(address redeemer,uint256 expiry,uint256 amount,bytes32 secretHash)");
keccak256("Initiate(address redeemer,uint256 timelock,uint256 amount,bytes32 secretHash)");

bytes32 private constant _REFUND_TYPEHASH = keccak256("Refund(bytes32 orderId)");

event Initiated(bytes32 indexed orderID, bytes32 indexed secretHash, uint256 amount);
event Redeemed(bytes32 indexed orderID, bytes32 indexed secretHash, bytes secret);
Expand All @@ -43,19 +45,19 @@ contract GardenHTLC is EIP712 {
* @notice .
* @dev provides checks to ensure
* 1. redeemer is not null address
* 3. expiry is greater than current block number
* 3. timelock is greater than 0
* 4. amount is not zero
* @param redeemer public address of the reedeem
* @param expiry expiry in period for the htlc order
* @param timelock timelock in period for the htlc order
* @param amount amount of tokens to trade
*/
modifier safeParams(
address redeemer,
uint256 expiry,
uint256 timelock,
uint256 amount
) {
require(redeemer != address(0), "GardenHTLC: zero address redeemer");
require(expiry > 0, "GardenHTLC: zero expiry");
require(timelock > 0, "GardenHTLC: zero timelock");
require(amount > 0, "GardenHTLC: zero amount");
_;
}
Expand All @@ -70,17 +72,17 @@ contract GardenHTLC is EIP712 {
* and sha256 hash should be used to support hashing methods on other non-evm chains.
* Signers cannot generate orders with same secret hash or override an existing order.
* @param redeemer public address of the redeemer
* @param expiry expiry in period for the htlc order
* @param timelock timelock in period for the htlc order
* @param amount amount of tokens to trade
* @param secretHash sha256 hash of the secret used for redemtion
**/
function initiate(
address redeemer,
uint256 expiry,
uint256 timelock,
uint256 amount,
bytes32 secretHash
) external safeParams(redeemer, expiry, amount) {
_initiate(msg.sender, redeemer, expiry, amount, secretHash);
) external safeParams(redeemer, timelock, amount) {
_initiate(msg.sender, redeemer, timelock, amount, secretHash);
}

/**
Expand All @@ -89,23 +91,23 @@ contract GardenHTLC is EIP712 {
* and sha256 hash should be used to support hashing methods on other non-evm chains.
* Signers cannot generate orders with same secret hash or override an existing order.
* @param redeemer public address of the redeemer
* @param expiry expiry in period for the htlc order
* @param timelock timelock in period for the htlc order
* @param amount amount of tokens to trade
* @param secretHash sha256 hash of the secret used for redemtion
* @param signature EIP712 signature provided by authorized user for iniatiation. user will be assigned as initiator
**/
function initiateWithSignature(
address redeemer,
uint256 expiry,
uint256 timelock,
uint256 amount,
bytes32 secretHash,
bytes calldata signature
) external safeParams(redeemer, expiry, amount) {
) external safeParams(redeemer, timelock, amount) {
address initiator = _hashTypedDataV4(
keccak256(abi.encode(_INITIATE_TYPEHASH, redeemer, expiry, amount, secretHash))
keccak256(abi.encode(_INITIATE_TYPEHASH, redeemer, timelock, amount, secretHash))
).recover(signature);

_initiate(initiator, redeemer, expiry, amount, secretHash);
_initiate(initiator, redeemer, timelock, amount, secretHash);
}

/**
Expand Down Expand Up @@ -134,7 +136,7 @@ contract GardenHTLC is EIP712 {
}

/**
* @notice Signers can refund the locked assets after expiry block number
* @notice Signers can refund the locked assets after timelock block number
* @dev Signers cannot refund the an order before epiry block number or refund the same order
* multiple times.
* Funds will be SafeTransferred to the initiator.
Expand All @@ -145,7 +147,7 @@ contract GardenHTLC is EIP712 {

require(order.redeemer != address(0), "GardenHTLC: order not initiated");
require(!order.isFulfilled, "GardenHTLC: order fulfilled");
require(order.initiatedAt + order.expiry < block.number, "GardenHTLC: order not expired");
require(order.initiatedAt + order.timelock < block.number, "GardenHTLC: order not expired");

order.isFulfilled = true;

Expand All @@ -164,13 +166,13 @@ contract GardenHTLC is EIP712 {
* @param initiator_ The address of the initiator of the atomic swap
* @param redeemer_ The address of the redeemer of the atomic swap
* @param secretHash_ The hash of the secret used for redemption
* @param expiry_ The expiry block number for the atomic swap
* @param timelock_ The timelock block number for the atomic swap
* @param amount_ The amount of tokens to be traded in the atomic swap
*/
function _initiate(
address initiator_,
address redeemer_,
uint256 expiry_,
uint256 timelock_,
uint256 amount_,
bytes32 secretHash_
) internal {
Expand All @@ -186,7 +188,7 @@ contract GardenHTLC is EIP712 {
initiator: initiator_,
redeemer: redeemer_,
initiatedAt: block.number,
expiry: expiry_,
timelock: timelock_,
amount: amount_
});
orders[orderID] = newOrder;
Expand All @@ -195,4 +197,26 @@ contract GardenHTLC is EIP712 {

token.safeTransferFrom(initiator_, address(this), orders[orderID].amount);
}

/**
* @notice Redeemers can let initiator refund the locked assets before expiry block number
* @dev Signers cannot refund the the same order multiple times.
* Funds will be SafeTransferred to the initiator.
*
* @param orderID orderID of the htlc order
* @param signature EIP712 signature provided by redeemer for instant refund.
*/
function instantRefund(bytes32 orderID, bytes calldata signature) external {
address redeemer = _hashTypedDataV4(keccak256(abi.encode(_REFUND_TYPEHASH, orderID))).recover(signature);
Order storage order = orders[orderID];

require(order.redeemer == redeemer, "HTLC: invalid redeemer signature");
require(!order.isFulfilled, "HTLC: order fulfilled");

order.isFulfilled = true;

emit Refunded(orderID);

token.safeTransfer(order.initiator, order.amount);
}
}
2 changes: 1 addition & 1 deletion contracts/stake/DelegateManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ abstract contract DelegateManager is BaseStaker {
require(stake.expiry < block.number, "DelegateManager: stake not expired");

uint8 multiplier = _calculateVoteMultiplier(newLockBlocks);
stake.expiry = block.number + newLockBlocks;
stake.expiry = multiplier == uint8(7) ? MAX_UINT_256 : block.number + newLockBlocks;
stake.votes = multiplier * stake.units;

stakes[stakeID] = stake;
Expand Down
4 changes: 3 additions & 1 deletion contracts/stake/FillerManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,9 @@ abstract contract FillerManager is BaseStaker {
require(filler.deregisteredAt != 0, "FillerManager: not deregistered");
require(filler.deregisteredAt + FILLER_COOL_DOWN < block.number, "FillerManager: cooldown not passed");

delete (fillers[filler_]);
fillers[filler_].feeInBips = 0;
fillers[filler_].stake = 0;
fillers[filler_].deregisteredAt = 0;

SEED.safeTransfer(filler_, FILLER_STAKE);

Expand Down
Loading

0 comments on commit fe99e96

Please sign in to comment.