Skip to content

Commit

Permalink
Merge pull request #11 from openfort-xyz/native_currency_support
Browse files Browse the repository at this point in the history
Native currency support
  • Loading branch information
Haypierre committed Feb 5, 2025
2 parents d92362e + c76eb9a commit a4eafae
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 14 deletions.
1 change: 0 additions & 1 deletion demo/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
import {
Address,
encodeAbiParameters,
encodeFunctionData,
Hex,
parseAbi,
} from "viem";
Expand Down
1 change: 1 addition & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ src = "src"
out = "out"
libs = ["lib"]
via_ir = true
gas_reports = ["*"]
# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options
4 changes: 3 additions & 1 deletion script/deployChainAbstractionSetup.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@ contract DeployChainAbstractionSetup is Script, CheckOrDeployEntryPoint {
uint256 internal deployerPrivKey = vm.envUint("PK_DEPLOYER");
uint256 internal withdrawLockBlock = vm.envUint("WITHDRAW_LOCK_BLOCK");
address internal deployer = vm.addr(deployerPrivKey);
address internal crossL2Prover = vm.envAddress("CROSS_L2_PROVER");
address internal owner = vm.envAddress("OWNER");
address internal verifyingSigner = vm.envAddress("VERIFYING_SIGNER");
bytes32 internal versionSalt = vm.envBytes32("VERSION_SALT");

// Note: crossL2Prover is deployed by Polymer at the same address on all supported chains
address internal crossL2Prover = 0xb8AcB3FE3117A67b665Bc787c977623612f8a461;

function run(address[] calldata tokens) public {
if (tokens.length == 0) {
revert("No tokens provided");
Expand Down
1 change: 0 additions & 1 deletion src/mocks/CrossL2Prover.sol

This file was deleted.

42 changes: 31 additions & 11 deletions src/paymasters/CABPaymaster.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {IPaymasterVerifier} from "../interfaces/IPaymasterVerifier.sol";
import {ICrossL2Prover} from "@vibc-core-smart-contracts/contracts/interfaces/ICrossL2Prover.sol";
import {LibBytes} from "@solady/utils/LibBytes.sol";


/**
* @title CABPaymaster
* @dev A paymaster used in chain abstracted balance to sponsor the gas fee and tokens cross-chain.
Expand All @@ -31,6 +30,8 @@ contract CABPaymaster is IPaymasterVerifier, BasePaymaster {
uint256 private constant VALID_TIMESTAMP_OFFSET = PAYMASTER_DATA_OFFSET;
uint256 private constant SIGNATURE_OFFSET = VALID_TIMESTAMP_OFFSET + 12;

address public constant NATIVE_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;

constructor(
IEntryPoint _entryPoint,
IInvoiceManager _invoiceManager,
Expand Down Expand Up @@ -62,10 +63,7 @@ contract CABPaymaster is IPaymasterVerifier, BasePaymaster {
(uint256 logIndex, bytes memory proof) = abi.decode(_proof, (uint256, bytes));
(,, bytes[] memory topics,) = crossL2Prover.validateEvent(logIndex, proof);

return (
LibBytes.eqs(topics[0], IInvoiceManager.InvoiceCreated.selector) &&
LibBytes.eqs(topics[1], invoiceId)
);
return (LibBytes.eqs(topics[0], IInvoiceManager.InvoiceCreated.selector) && LibBytes.eqs(topics[1], invoiceId));
}

function withdraw(address token, uint256 amount) external override onlyOwner {
Expand Down Expand Up @@ -129,9 +127,21 @@ contract CABPaymaster is IPaymasterVerifier, BasePaymaster {
(uint256 sponsorTokenLength, SponsorToken[] memory sponsorTokens) = parseSponsorTokenData(sponsorTokenData);

// revoke the approval at the end of userOp
for (uint256 i = 0; i < sponsorTokenLength; i++) {
SponsorToken memory sponsorToken = sponsorTokens[i];
IERC20(sponsorToken.token).approve(sponsorToken.spender, sponsorToken.amount);
for (uint256 i = 0; i < sponsorTokenLength;) {
address token = sponsorTokens[i].token;
address spender = sponsorTokens[i].spender;
uint256 amount = sponsorTokens[i].amount;

if (token == NATIVE_TOKEN) {
(bool success,) = payable(spender).call{value: amount}("");
require(success, "Native token transfer failed");
} else {
require(IERC20(token).approve(spender, amount), "Approve failed");
}

unchecked {
i++;
}
}

bytes32 invoiceId =
Expand Down Expand Up @@ -161,12 +171,22 @@ contract CABPaymaster is IPaymasterVerifier, BasePaymaster {
bytes calldata sponsorTokenData = context[84:];

(uint8 sponsorTokenLength, SponsorToken[] memory sponsorTokens) = parseSponsorTokenData(sponsorTokenData);
for (uint8 i = 0; i < sponsorTokenLength; i++) {
SponsorToken memory sponsorToken = sponsorTokens[i];
IERC20(sponsorToken.token).approve(sponsorToken.spender, 0);
for (uint8 i = 0; i < sponsorTokenLength;) {
address token = sponsorTokens[i].token;
address spender = sponsorTokens[i].spender;
if (token != NATIVE_TOKEN) {
require(IERC20(token).approve(spender, 0), "Reset approval failed");
}
unchecked {
i++;
}
}
// TODO: Batch Proving Optimistation -> write in settlement contract on `opSucceeded`
if (mode == PostOpMode.opSucceeded) {
//emit IInvoiceManager.InvoiceCreated(bytes32(context[:32]), address(bytes20(context[32:52])), address(this));

// This add ~= 100k gas compared to only emitting the InvoiceCreated event
// Question: is storing the invoices onchain truly necessary?
bytes32 invoiceId = bytes32(context[:32]);
address account = address(bytes20(context[32:52]));
uint256 nonce = uint256(bytes32(context[52:84]));
Expand Down
6 changes: 6 additions & 0 deletions test/CABPaymater.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,9 @@ contract CABPaymasterTest is Test {
(bytes memory context, uint256 validationData) =
paymaster.validatePaymasterUserOp(userOp, userOpHash, type(uint256).max);

uint256 allowanceAfterValidation = mockERC20.allowance(address(paymaster), userOp.sender);
assertEq(allowanceAfterValidation, 500);

// validate postOp
// This is the event that we must track on dest chain and prove on source chain with Polymer proof system

Expand All @@ -225,6 +228,9 @@ contract CABPaymasterTest is Test {
vm.expectEmit(true, true, true, false);
emit IInvoiceManager.InvoiceCreated(expectedInvoiceId, rekt, address(paymaster));
paymaster.postOp(IPaymaster.PostOpMode.opSucceeded, context, 1222, 42);

uint256 allowanceAfterExecution = mockERC20.allowance(address(paymaster), userOp.sender);
assertEq(allowanceAfterExecution, 0);
}

function testGetInvoiceId() public {
Expand Down

0 comments on commit a4eafae

Please sign in to comment.