diff --git a/.gitmodules b/.gitmodules index 25dbf4e..04ea64a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,6 @@ [submodule "lib/forge-std"] path = lib/forge-std url = https://github.com/foundry-rs/forge-std -[submodule "lib/openzeppelin-contracts"] - path = lib/openzeppelin-contracts - url = https://github.com/OpenZeppelin/openzeppelin-contracts [submodule "lib/modular-contracts"] path = lib/modular-contracts url = https://github.com/thirdweb-dev/modular-contracts diff --git a/foundry.toml b/foundry.toml index bbc1b8d..e853876 100644 --- a/foundry.toml +++ b/foundry.toml @@ -13,7 +13,6 @@ test = 'test' out = 'artifacts_forge' libs = ["lib"] remappings = [ - '@openzeppelin/contracts=lib/openzeppelin-contracts/contracts', '@ds-test=lib/ds-test/src/', '@std=lib/forge-std/src/', ] diff --git a/lib/openzeppelin-contracts b/lib/openzeppelin-contracts deleted file mode 160000 index 01ef448..0000000 --- a/lib/openzeppelin-contracts +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 01ef448981be9d20ca85f2faf6ebdf591ce409f3 diff --git a/test/PayGateway.t.sol b/test/PayGateway.t.sol index f0e8735..7039256 100644 --- a/test/PayGateway.t.sol +++ b/test/PayGateway.t.sol @@ -226,6 +226,51 @@ contract PayGatewayTest is Test { assertEq(mockERC20.balanceOf(receiver), receiverBalanceBefore + sendValue); } + function test_initiateTokenPurchase_erc20_directTransfer() public { + uint256 sendValue = 1 ether; + uint256 sendValueWithFees = sendValue + totalFeeAmount; + bytes memory targetCalldata = abi.encodeWithSignature("transfer(address,uint256)", receiver, sendValue); + + // approve amount to gateway contract + vm.prank(sender); + mockERC20.approve(address(gateway), sendValueWithFees); + + // create pay request + PayGatewayModule.PayRequest memory req; + bytes32 _transactionId = keccak256("transaction ID"); + + req.clientId = clientId; + req.transactionId = _transactionId; + req.tokenAddress = address(mockERC20); + req.tokenAmount = sendValue; + req.forwardAddress = payable(address(mockERC20)); + req.expirationTimestamp = 1000; + req.data = targetCalldata; + req.payouts = payouts; + + // generate signature + bytes memory _signature = _prepareAndSignData( + 2, // sign with operator private key, i.e. 2 + req + ); + + // state/balances before sending transaction + uint256 ownerBalanceBefore = mockERC20.balanceOf(owner); + uint256 clientBalanceBefore = mockERC20.balanceOf(client); + uint256 senderBalanceBefore = mockERC20.balanceOf(sender); + uint256 receiverBalanceBefore = mockERC20.balanceOf(receiver); + + // send transaction + vm.prank(sender); + gateway.initiateTokenPurchase(req, _signature); + + // check balances after transaction + assertEq(mockERC20.balanceOf(owner), ownerBalanceBefore + ownerFeeAmount); + assertEq(mockERC20.balanceOf(client), clientBalanceBefore + clientFeeAmount); + assertEq(mockERC20.balanceOf(sender), senderBalanceBefore - sendValueWithFees); + assertEq(mockERC20.balanceOf(receiver), receiverBalanceBefore + sendValue); + } + function test_initiateTokenPurchase_nativeToken() public { uint256 sendValue = 1 ether; uint256 sendValueWithFees = sendValue + totalFeeAmount; @@ -279,6 +324,53 @@ contract PayGatewayTest is Test { assertEq(receiver.balance, receiverBalanceBefore + sendValue); } + function test_initiateTokenPurchase_nativeToken_directTransfer() public { + uint256 sendValue = 1 ether; + uint256 sendValueWithFees = sendValue + totalFeeAmount; + bytes memory targetCalldata = ""; + + // create pay request + PayGatewayModule.PayRequest memory req; + bytes32 _transactionId = keccak256("transaction ID"); + + req.clientId = clientId; + req.transactionId = _transactionId; + req.tokenAddress = address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE); + req.tokenAmount = sendValue; + req.forwardAddress = payable(address(receiver)); + req.expirationTimestamp = 1000; + req.data = targetCalldata; + req.payouts = payouts; + + console.logBytes32(clientId); + console.logBytes32(_transactionId); + console.log(sendValue); + console.log(address(mockTarget)); + console.logBytes(targetCalldata); + + // generate signature + bytes memory _signature = _prepareAndSignData( + 2, // sign with operator private key, i.e. 2 + req + ); + + // state/balances before sending transaction + uint256 ownerBalanceBefore = owner.balance; + uint256 clientBalanceBefore = client.balance; + uint256 senderBalanceBefore = sender.balance; + uint256 receiverBalanceBefore = receiver.balance; + + // send transaction + vm.prank(sender); + gateway.initiateTokenPurchase{ value: sendValueWithFees }(req, _signature); + + // check balances after transaction + assertEq(owner.balance, ownerBalanceBefore + ownerFeeAmount); + assertEq(client.balance, clientBalanceBefore + clientFeeAmount); + assertEq(sender.balance, senderBalanceBefore - sendValueWithFees); + assertEq(receiver.balance, receiverBalanceBefore + sendValue); + } + function test_initiateTokenPurchase_events() public { uint256 sendValue = 1 ether; uint256 sendValueWithFees = sendValue + totalFeeAmount; diff --git a/test/utils/MockERC20.sol b/test/utils/MockERC20.sol index b71b22c..8dabd48 100644 --- a/test/utils/MockERC20.sol +++ b/test/utils/MockERC20.sol @@ -1,10 +1,24 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.22; -import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "lib/solady/src/tokens/ERC20.sol"; contract MockERC20 is ERC20 { - constructor(string memory name, string memory symbol) ERC20(name, symbol) {} + string private _name; + string private _symbol; + + constructor(string memory name, string memory symbol) { + _name = name; + _symbol = symbol; + } + + function name() public view override returns (string memory) { + return _name; + } + + function symbol() public view override returns (string memory) { + return _symbol; + } function mint(address to, uint256 amount) public { _mint(to, amount); diff --git a/test/utils/MockTarget.sol b/test/utils/MockTarget.sol index 2d121bb..fccce10 100644 --- a/test/utils/MockTarget.sol +++ b/test/utils/MockTarget.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "lib/solady/src/tokens/ERC20.sol"; import "lib/forge-std/src/console.sol"; contract MockTarget { @@ -23,7 +23,7 @@ contract MockTarget { emit TargetLog(sender, receiver, tokenAddress, tokenAmount, message); console.log("Transferring %s erc20 tokens from %s to %s", tokenAmount, sender, receiver); - require(IERC20(tokenAddress).transferFrom(msg.sender, receiver, tokenAmount), "Token transfer failed"); + require(ERC20(tokenAddress).transferFrom(msg.sender, receiver, tokenAmount), "Token transfer failed"); } function performNativeTokenAction(