Skip to content
Draft
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
2 changes: 1 addition & 1 deletion docs/content/developers/evm/intent-gateway/simplex.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ Create an API keypair in the Turnkey Dashboard under user details. The <code>sig

Solver selection requires each solver's EOA to be delegated to the `SolverAccount` contract. Simplex performs this automatically at startup via EIP-7702:

- **Primary path** — builds a no-op UserOperation with an attached EIP-7702 authorization and submits it through the configured bundler. When a paymaster is deployed on the chain — Circle Paymaster (USDC) preferred, then the `SimplexPaymaster` (USDC or USDT) — and the solver holds at least one whole token of a supported stablecoin, the paymaster pays gas in that stablecoin (via EIP-2612 permit, or a small capped approval for tokens without permit support such as BSC stables) so the solver never needs native gas for delegation.
- **Primary path** — builds a no-op UserOperation with an attached EIP-7702 authorization and submits it through the configured bundler. When a paymaster is deployed on the chain — Circle Paymaster (USDC) preferred, then the `SimplexPaymaster` (USDC or USDT) — and the solver holds at least one whole token of a supported stablecoin, the paymaster pays gas in that stablecoin so the solver never needs native gas for delegation. Tokens with EIP-2612 are authorized by permit; tokens without it (such as BSC stables) need a one-time funded `approve(Permit2, max)` from the solver EOA, after which every operation carries a per-op Permit2 signature and no native gas is needed again.
- **Fallback** — if the bundler path fails or the chain has no paymaster, Simplex sends a direct type-0x04 delegation tx using the solver's native balance. On paymaster-less chains it also keeps the ERC-4337 EntryPoint deposit topped up to cover `targetGasUnits` (default 3,000,000) at the current gas price.

No manual steps are required — delegation is idempotent and skipped if the EOA is already delegated to the correct contract.
Expand Down
79 changes: 79 additions & 0 deletions evm/script/SimplexPaymasterPermit2Probe.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;

import "forge-std/Script.sol";
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import {ERC4337Utils} from "@openzeppelin/contracts/account/utils/draft-ERC4337Utils.sol";

import {SimplexPaymaster, AggregatorV3Interface} from "../src/utils/SimplexPaymaster.sol";
import {SolverAccount} from "../src/apps/intentsv2/SolverAccount.sol";

/// @dev Freely mintable stand-in for a stablecoin without EIP-2612.
contract ProbeToken is ERC20 {
constructor() ERC20("Probe USD", "pUSD") {}

function decimals() public pure override returns (uint8) {
return 6;
}

function mint(address to, uint256 amount) external {
_mint(to, amount);
}
}

/// @notice Base Sepolia side deployment for probing PERMIT2 mode through live bundlers:
/// a mintable no-permit token priced off the USDC/USD feed, a SolverAccount to
/// delegate to, and a fully configured, deposited and staked SimplexPaymaster.
/// Usage: PRIVATE_KEY=... forge script script/SimplexPaymasterPermit2Probe.s.sol \
/// --rpc-url <base-sepolia> --broadcast
contract SimplexPaymasterPermit2ProbeScript is Script {
address constant HOST = 0x9AA003594d59C62EE17A73A569Fd7B1DbdBd71E1;
address constant INTENT_GATEWAY_V2 = 0x6CF42FA9BecbC5b6a26884964956b113530f7cFA;
address constant ETH_USD = 0x4aDC67696bA383F43DD60A9e78F2C97Fbbfc7cb1;
address constant USDC_USD = 0xd30e2101a97dcbAeBCBC04F14C3f624E67A35165;

function run() external {
uint256 pk = vm.envUint("PRIVATE_KEY");
address deployer = vm.addr(pk);
vm.startBroadcast(pk);

ProbeToken token = new ProbeToken();
token.mint(deployer, 1_000e6);

SolverAccount solverAccount = new SolverAccount(INTENT_GATEWAY_V2);

address[] memory tokens = new address[](1);
tokens[0] = address(token);
AggregatorV3Interface[] memory oracles = new AggregatorV3Interface[](1);
oracles[0] = AggregatorV3Interface(USDC_USD);

SimplexPaymaster implementation = new SimplexPaymaster();
bytes memory initData = abi.encodeCall(
SimplexPaymaster.initialize,
(
HOST,
SimplexPaymaster.Params({
nativeOracle: AggregatorV3Interface(ETH_USD),
markupBps: 200,
treasury: deployer,
maxOracleAge: 90_000,
swapSlippageBps: 200
}),
tokens,
oracles
)
);
SimplexPaymaster paymaster = SimplexPaymaster(payable(address(new ERC1967Proxy(address(implementation), initData))));

ERC4337Utils.ENTRYPOINT_V08.depositTo{value: 0.05 ether}(address(paymaster));
paymaster.addStake{value: 0.1 ether}(86_400);

vm.stopBroadcast();

console.log("token:", address(token));
console.log("solverAccount:", address(solverAccount));
console.log("paymaster implementation:", address(implementation));
console.log("paymaster proxy:", address(paymaster));
}
}
Loading
Loading