Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(contracts): Implement a default withdraw function #801

Merged
merged 2 commits into from
Nov 14, 2024
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
3 changes: 0 additions & 3 deletions contracts/src/DefaultPortal.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,4 @@ contract DefaultPortal is AbstractPortal {
* @dev This sets the addresses for the AttestationRegistry, ModuleRegistry and PortalRegistry
*/
constructor(address[] memory modules, address router) AbstractPortal(modules, router) {}

/// @inheritdoc AbstractPortal
function withdraw(address payable to, uint256 amount) external override {}
}
13 changes: 10 additions & 3 deletions contracts/src/abstracts/AbstractPortal.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ abstract contract AbstractPortal is IPortal {
/// @notice Error thrown when someone else than the portal's owner is trying to revoke
error OnlyPortalOwner();

/// @notice Error thrown when withdrawing funds fails
error WithdrawFail();

/**
* @notice Contract constructor
* @param _modules list of modules to use for the portal (can be empty)
Expand All @@ -42,12 +45,16 @@ abstract contract AbstractPortal is IPortal {
}

/**
* @notice Optional method to withdraw funds from the Portal
* @notice Withdraw funds from the Portal
* @param to the address to send the funds to
* @param amount the amount to withdraw
* @dev DISCLAIMER: by default, this method is not implemented and should be overridden if funds are to be withdrawn
* @dev Only the Portal owner can withdraw funds
*/
function withdraw(address payable to, uint256 amount) external virtual;
function withdraw(address payable to, uint256 amount) external virtual {
if (msg.sender != portalRegistry.getPortalByAddress(address(this)).ownerAddress) revert OnlyPortalOwner();
(bool s, ) = to.call{ value: amount }("");
if (!s) revert WithdrawFail();
}

/**
* @notice Attest the schema with given attestationPayload and validationPayload
Expand Down
38 changes: 38 additions & 0 deletions contracts/test/DefaultPortal.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ contract DefaultPortalTest is Test {
AttestationRegistryMock public attestationRegistryMock = new AttestationRegistryMock();
Router public router = new Router();
address public portalOwner = makeAddr("portalOwner");
address public recipient = makeAddr("recipient");

event Initialized(uint8 version);
event PortalRegistered(string name, string description, address portalAddress);
Expand Down Expand Up @@ -328,4 +329,41 @@ contract DefaultPortalTest is Test {
bool isAbstractPortalSupported = defaultPortal.supportsInterface(type(AbstractPortal).interfaceId);
assertEq(isAbstractPortalSupported, true);
}

function test_withdraw_byOwner() public {
// Fund the portal contract with 1 ether
vm.deal(address(defaultPortal), 1 ether);

// Set the amount to withdraw
uint256 withdrawAmount = 0.5 ether;
uint256 recipientInitialBalance = recipient.balance;

// Attempt withdrawal by the owner
vm.prank(portalOwner);
defaultPortal.withdraw(payable(recipient), withdrawAmount);

// Verify the recipient's balance has increased by the withdrawal amount
assertEq(recipient.balance, recipientInitialBalance + withdrawAmount);
}

function test_withdrawFail_OnlyPortalOwner() public {
// Attempt withdrawal by a non-owner address
uint256 withdrawAmount = 0.5 ether;
vm.prank(makeAddr("nonOwner"));
vm.expectRevert(AbstractPortal.OnlyPortalOwner.selector);

defaultPortal.withdraw(payable(recipient), withdrawAmount);
}

function test_withdrawFail_InsufficientBalance() public {
// Fund the portal contract with less than the requested amount
vm.deal(address(defaultPortal), 0.25 ether);

// Attempt withdrawal of 0.5 ether
uint256 withdrawAmount = 0.5 ether;
vm.prank(portalOwner);
vm.expectRevert(AbstractPortal.WithdrawFail.selector);

defaultPortal.withdraw(payable(recipient), withdrawAmount);
}
}
Loading