Skip to content

Commit

Permalink
feat: added event emitter for user safe
Browse files Browse the repository at this point in the history
  • Loading branch information
shivam-ef committed Oct 29, 2024
1 parent bc325db commit eb9a4ad
Show file tree
Hide file tree
Showing 28 changed files with 577 additions and 284 deletions.
39 changes: 37 additions & 2 deletions script/user-safe/MockSetup.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pragma solidity ^0.8.24;

import {Script} from "forge-std/Script.sol";
import {UserSafeFactory} from "../../src/user-safe/UserSafeFactory.sol";
import {UserSafe} from "../../src/user-safe/UserSafe.sol";
import {UserSafe, UserSafeEventEmitter} from "../../src/user-safe/UserSafe.sol";
import {MockERC20} from "../../src/mocks/MockERC20.sol";
import {MockPriceProvider} from "../../src/mocks/MockPriceProvider.sol";
import {MockSwapper} from "../../src/mocks/MockSwapper.sol";
Expand All @@ -23,6 +23,7 @@ contract DeployMockUserSafeSetup is Utils {
MockPriceProvider priceProvider;
MockSwapper swapper;
UserSafe userSafeImpl;
UserSafeEventEmitter userSafeEventEmitter;
UserSafeFactory userSafeFactory;
IL2DebtManager debtManager;
CashDataProvider cashDataProvider;
Expand Down Expand Up @@ -113,6 +114,19 @@ contract DeployMockUserSafeSetup is Utils {
)
);

address eventEmitterImpl = address(new UserSafeEventEmitter());
userSafeEventEmitter = UserSafeEventEmitter(address(
new UUPSProxy(
eventEmitterImpl,
abi.encodeWithSelector(
UserSafeEventEmitter.initialize.selector,
delay,
owner,
address(cashDataProvider)
)
)
));

CashDataProvider(address(cashDataProvider)).initialize(
owner,
uint64(delay),
Expand All @@ -122,7 +136,8 @@ contract DeployMockUserSafeSetup is Utils {
address(priceProvider),
address(swapper),
address(aaveAdapter),
address(userSafeFactory)
address(userSafeFactory),
address(userSafeEventEmitter)
);

DebtManagerInitializer(address(debtManager)).initialize(
Expand Down Expand Up @@ -169,6 +184,26 @@ contract DeployMockUserSafeSetup is Utils {
"userSafeFactoryProxy",
address(userSafeFactory)
);
vm.serializeAddress(
deployedAddresses,
"userSafeEventEmitterImpl",
address(eventEmitterImpl)
);
vm.serializeAddress(
deployedAddresses,
"userSafeEventEmitterProxy",
address(userSafeEventEmitter)
);
vm.serializeAddress(
deployedAddresses,
"userSafeFactoryImpl",
address(factoryImpl)
);
vm.serializeAddress(
deployedAddresses,
"userSafeFactoryProxy",
address(userSafeFactory)
);
vm.serializeAddress(
deployedAddresses,
"wrapperTokenFactory",
Expand Down
32 changes: 29 additions & 3 deletions script/user-safe/Setup.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pragma solidity ^0.8.24;

import {Script} from "forge-std/Script.sol";
import {UserSafeFactory} from "../../src/user-safe/UserSafeFactory.sol";
import {UserSafe} from "../../src/user-safe/UserSafe.sol";
import {UserSafe, UserSafeEventEmitter} from "../../src/user-safe/UserSafe.sol";
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {PriceProvider} from "../../src/oracle/PriceProvider.sol";
import {SwapperOpenOcean} from "../../src/utils/SwapperOpenOcean.sol";
Expand All @@ -26,6 +26,7 @@ contract DeployUserSafeSetup is Utils {
PriceProvider priceProvider;
SwapperOpenOcean swapper;
UserSafe userSafeImpl;
UserSafeEventEmitter userSafeEventEmitter;
UserSafeFactory userSafeFactory;
IL2DebtManager debtManager;
CashDataProvider cashDataProvider;
Expand Down Expand Up @@ -59,6 +60,7 @@ contract DeployUserSafeSetup is Utils {
address debtManagerInitializer;
address cashDataProviderImpl;
address settlementDispatcherImpl;
address eventEmitterImpl;

function run() public {
// Pulling deployer info from the environment
Expand Down Expand Up @@ -196,6 +198,19 @@ contract DeployUserSafeSetup is Utils {
)
);

eventEmitterImpl = address(new UserSafeEventEmitter());
userSafeEventEmitter = UserSafeEventEmitter(address(
new UUPSProxy(
eventEmitterImpl,
abi.encodeWithSelector(
UserSafeEventEmitter.initialize.selector,
delay,
owner,
address(cashDataProvider)
)
)
));

initializeCashDataProvider();
initializeDebtManager(debtManagerProxy, collateralTokenConfig);
saveDeployments();
Expand All @@ -213,7 +228,8 @@ contract DeployUserSafeSetup is Utils {
address(priceProvider),
address(swapper),
address(aaveV3Adapter),
address(userSafeFactory)
address(userSafeFactory),
address(userSafeEventEmitter)
);
}

Expand Down Expand Up @@ -270,9 +286,19 @@ contract DeployUserSafeSetup is Utils {
);
vm.serializeAddress(
deployedAddresses,
"userSafeFactory",
"userSafeFactoryProxy",
address(userSafeFactory)
);
vm.serializeAddress(
deployedAddresses,
"userSafeEventEmitterImpl",
address(eventEmitterImpl)
);
vm.serializeAddress(
deployedAddresses,
"userSafeEventEmitterProxy",
address(userSafeEventEmitter)
);
vm.serializeAddress(
deployedAddresses,
"wrapperTokenFactory",
Expand Down
13 changes: 13 additions & 0 deletions src/interfaces/ICashDataProvider.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ interface ICashDataProvider {
event EtherFiRecoverySafeUpdated(address oldSafe, address newSafe);
event AaveAdapterUpdated(address oldAdapter, address newAdapter);
event UserSafeFactoryUpdated(address oldFactory, address newFactory);
event UserSafeEventEmitterUpdated(address oldEventEmitter, address newEventEmitter);
event UserSafeWhitelisted(address userSafe);
event EtherFiWalletAdded(address wallet);
event EtherFiWalletRemoved(address wallet);
Expand Down Expand Up @@ -74,6 +75,12 @@ interface ICashDataProvider {
*/
function userSafeFactory() external view returns (address);

/**
* @notice Function to fetch the address of the user safe event emitter
* @return Address of the user safe event emitter
*/
function userSafeEventEmitter() external view returns (address);

/**
* @notice Function to check if an account is a user safe
* @param account Address of the account
Expand Down Expand Up @@ -143,6 +150,12 @@ interface ICashDataProvider {
* @param factory Address of the new factory
*/
function setUserSafeFactory(address factory) external;

/**
* @notice Function to set the addrss of the user safe event emitter.
* @param eventEmitter Address of the new event emitter
*/
function setUserSafeEventEmitter(address eventEmitter) external;

/**
* @notice Function to whitelist user safes
Expand Down
49 changes: 0 additions & 49 deletions src/interfaces/IUserSafe.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,55 +22,6 @@ interface IUserSafe {
uint96 finalizeTime;
}

event DepositFunds(address indexed token, uint256 amount);
event WithdrawalRequested(
address[] tokens,
uint256[] amounts,
address indexed recipient,
uint256 finalizeTimestamp
);
event WithdrawalAmountUpdated(address indexed token, uint256 amount);
event WithdrawalCancelled(
address[] tokens,
uint256[] amounts,
address indexed recipient
);
event WithdrawalProcessed(
address[] tokens,
uint256[] amounts,
address indexed recipient
);
event TransferForSpending(address indexed token, uint256 amount);
event SwapTransferForSpending(
address indexed inputToken,
uint256 inputAmount,
address indexed outputToken,
uint256 outputTokenSent
);
event AddCollateralToDebtManager(address token, uint256 amount);
event BorrowFromDebtManager(address token, uint256 amount);
event RepayDebtManager(address token, uint256 debtAmount);
event WithdrawCollateralFromDebtManager(address token, uint256 amount);
event CloseAccountWithDebtManager();
event SetCollateralLimit(
uint256 oldLimitInUsd,
uint256 newLimitInUsd,
uint256 startTime
);
event IsRecoveryActiveSet(bool isActive);
event SetOwner(
OwnerLib.OwnerObject oldOwner,
OwnerLib.OwnerObject newOwner
);
event SetIncomingOwner(
OwnerLib.OwnerObject incomingOwner,
uint256 incomingOwnerStartTime
);
event UserRecoverySignerSet(
address oldRecoverySigner,
address newRecoverySigner
);

error InsufficientBalance();
error ArrayLengthMismatch();
error CannotWithdrawYet();
Expand Down
11 changes: 2 additions & 9 deletions src/libraries/EIP1271SignatureUtils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,12 @@ pragma solidity ^0.8.24;

import {IERC1271} from "@openzeppelin/contracts/interfaces/IERC1271.sol";
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";

/**
* @title Library of utilities for making EIP1271-compliant signature checks.
* @author Layr Labs, Inc.
*/
library EIP1271SignatureUtils {
using MessageHashUtils for bytes32;

// bytes4(keccak256("isValidSignature(bytes32,bytes)")
bytes4 internal constant EIP1271_MAGICVALUE = 0x1626ba7e;

Expand All @@ -24,12 +21,10 @@ library EIP1271SignatureUtils {
* Otherwise, passes on the signature to the signer to verify the signature and checks that it returns the `EIP1271_MAGICVALUE`.
*/
function checkSignature_EIP1271(
bytes32 msgHash,
bytes32 digestHash,
address signer,
bytes memory signature
) internal view {
bytes32 digestHash = msgHash.toEthSignedMessageHash();

/**
* check validity of signature:
* 1) if `signer` is an EOA, then `signature` must be a valid ECDSA signature from `signer`,
Expand All @@ -48,12 +43,10 @@ library EIP1271SignatureUtils {
}

function isValidSignature_EIP1271(
bytes32 msgHash,
bytes32 digestHash,
address signer,
bytes memory signature
) internal view returns (bool) {
bytes32 digestHash = msgHash.toEthSignedMessageHash();

/**
* check validity of signature:
* 1) if `signer` is an EOA, then `signature` must be a valid ECDSA signature from `signer`,
Expand Down
2 changes: 1 addition & 1 deletion src/libraries/OwnerLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ library OwnerLib {

function getOwnerObject(
bytes memory _ownerBytes
) internal pure returns (OwnerObject memory) {
) internal pure returns (OwnerObject memory) {
if (_ownerBytes.length == 32) {
address addr;
assembly ("memory-safe") {
Expand Down
4 changes: 3 additions & 1 deletion src/libraries/SignatureUtils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
pragma solidity ^0.8.24;

import {EIP1271SignatureUtils} from "./EIP1271SignatureUtils.sol";
import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";
import {OwnerLib} from "./OwnerLib.sol";
import {WebAuthn} from "./WebAuthn.sol";

Expand All @@ -10,6 +11,7 @@ import {WebAuthn} from "./WebAuthn.sol";
*/
library SignatureUtils {
using EIP1271SignatureUtils for bytes32;
using MessageHashUtils for bytes32;

error InvalidWebAuthSignature();

Expand All @@ -19,7 +21,7 @@ library SignatureUtils {
bytes calldata signature
) internal view {
if (owner.ethAddr != address(0))
hash.checkSignature_EIP1271(owner.ethAddr, signature);
hash.toEthSignedMessageHash().checkSignature_EIP1271(owner.ethAddr, signature);
else {
WebAuthn.WebAuthnAuth memory auth = abi.decode(
signature,
Expand Down
14 changes: 7 additions & 7 deletions src/libraries/SpendingLimitLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@ struct SpendingLimit {
library SpendingLimitLib {
using TimeLib for uint256;

event SpendingLimitSet(address indexed user, uint256 dailyLimit, uint256 monthlyLimit);
event SpendingLimitChanged(SpendingLimit oldLimit, SpendingLimit newLimit);

error ExceededDailySpendingLimit();
error ExceededMonthlySpendingLimit();
error DailyLimitCannotBeGreaterThanMonthlyLimit();
Expand All @@ -32,14 +29,15 @@ library SpendingLimitLib {
uint256 dailyLimit,
uint256 monthlyLimit,
int256 timezoneOffset
) external sanity(dailyLimit, monthlyLimit) {
) external sanity(dailyLimit, monthlyLimit) returns (SpendingLimit memory, SpendingLimit memory) {
SpendingLimit memory dummyLimit;
limit.dailyLimit = dailyLimit;
limit.monthlyLimit = monthlyLimit;
limit.timezoneOffset = timezoneOffset;
limit.dailyRenewalTimestamp = block.timestamp.getStartOfNextDay(limit.timezoneOffset);
limit.monthlyRenewalTimestamp = block.timestamp.getStartOfNextMonth(limit.timezoneOffset);

emit SpendingLimitSet(msg.sender, dailyLimit, monthlyLimit);
return (dummyLimit, limit);
}

function currentLimit(SpendingLimit storage limit) internal {
Expand Down Expand Up @@ -73,7 +71,7 @@ library SpendingLimitLib {
uint256 newDailyLimit,
uint256 newMonthlyLimit,
uint64 delay
) external sanity(newDailyLimit, newMonthlyLimit) {
) external sanity(newDailyLimit, newMonthlyLimit) returns (SpendingLimit memory, SpendingLimit memory) {
currentLimit(limit);
SpendingLimit memory oldLimit = limit;

Expand All @@ -82,6 +80,7 @@ library SpendingLimitLib {
limit.dailyLimitChangeActivationTime = uint64(block.timestamp) + delay;
} else {
limit.dailyLimit = newDailyLimit;
limit.dailyRenewalTimestamp = uint256(block.timestamp).getStartOfNextDay(limit.timezoneOffset);
limit.newDailyLimit = 0;
limit.dailyLimitChangeActivationTime = 0;
}
Expand All @@ -91,11 +90,12 @@ library SpendingLimitLib {
limit.monthlyLimitChangeActivationTime = uint64(block.timestamp) + delay;
} else {
limit.monthlyLimit = newMonthlyLimit;
limit.monthlyRenewalTimestamp = uint256(block.timestamp).getStartOfNextMonth(limit.timezoneOffset);
limit.newMonthlyLimit = 0;
limit.monthlyLimitChangeActivationTime = 0;
}

emit SpendingLimitChanged(oldLimit, limit);
return (oldLimit, limit);
}

function canSpend(SpendingLimit memory limit, uint256 amount) external view returns (bool, string memory) {
Expand Down
Loading

0 comments on commit eb9a4ad

Please sign in to comment.