QuiverV4Gate
0x220a377e0ea1085bb5d2723b724269b8a6240db1
Verification
Verified
v0.8.26+commit.8a97fa7a
Type
Contract
12,916 bytes
ABI entries
65
19 read · 10 write
License
none
Contract information
- Address
- 0x220a377e0ea1085bb5d2723b724269b8a6240db1
- Chain
- Robinhood Chain (4663)
- Compiler
- v0.8.26+commit.8a97fa7a
- Optimization
- Enabled
- Creator
- 0x288BA0FDe7…DED6B5c829
- Creation tx
- 0x57f0b1961c…23a373d21a
Token
Not a token
This contract does not expose ERC-20 metadata.
Read contract (19)
BUY_TYPEHASH() → bytes32
MAX_VIEW_PAGE() → uint256
creatorOfPool(bytes32) → address
customSignerOfPool(bytes32) → address
effectiveSigner(bytes32) → address
eip712Domain() → bytes1, string, string, uint256, address, bytes32, uint256[]
hashVoucher(tuple) → bytes32
hook() → address
isAuthorized(address, bytes32, uint256) → bool
launcher() → address
owner() → address
pendingOwner() → address
poolSignerStatesBatch(bytes32[]) → tuple[]
signer() → address
signerRotationLocked(bytes32) → bool
tokenOfPool(bytes32) → address
universalRouter() → address
usedNonces(address, uint256) → bool
weth() → address
Events (10)
BuyExecutedEIP712DomainChangedHookSetLauncherSetOwnershipTransferStartedOwnershipTransferredPoolRegisteredPoolSignerChangedPoolSignerLockedSignerChanged
ABI
[
{
"inputs": [
{
"internalType": "address",
"name": "universalRouter_",
"type": "address"
},
{
"internalType": "address",
"name": "weth_",
"type": "address"
},
{
"internalType": "address",
"name": "signer_",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [
{
"internalType": "address",
"name": "target",
"type": "address"
}
],
"name": "AddressEmptyCode",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "AddressInsufficientBalance",
"type": "error"
},
{
"inputs": [],
"name": "ECDSAInvalidSignature",
"type": "error"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "length",
"type": "uint256"
}
],
"name": "ECDSAInvalidSignatureLength",
"type": "error"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"name": "ECDSAInvalidSignatureS",
"type": "error"
},
{
"inputs": [],
"name": "FailedInnerCall",
"type": "error"
},
{
"inputs": [],
"name": "HookAlreadySet",
"type": "error"
},
{
"inputs": [],
"name": "InvalidPool",
"type": "error"
},
{
"inputs": [],
"name": "InvalidShortString",
"type": "error"
},
{
"inputs": [],
"name": "InvalidVoucher",
"type": "error"
},
{
"inputs": [],
"name": "LauncherAlreadySet",
"type": "error"
},
{
"inputs": [],
"name": "OnlyCreator",
"type": "error"
},
{
"inputs": [],
"name": "OnlyHook",
"type": "error"
},
{
"inputs": [],
"name": "OnlyLauncher",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
}
],
"name": "OwnableInvalidOwner",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "OwnableUnauthorizedAccount",
"type": "error"
},
{
"inputs": [],
"name": "PageTooLarge",
"type": "error"
},
{
"inputs": [],
"name": "Reentrancy",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
}
],
"name": "SafeERC20FailedOperation",
"type": "error"
},
{
"inputs": [],
"name": "SignerRotationLocked",
"type": "error"
},
{
"inputs": [
{
"internalType": "string",
"name": "str",
"type": "string"
}
],
"name": "StringTooLong",
"type": "error"
},
{
"inputs": [],
"name": "TransferFailed",
"type": "error"
},
{
"inputs": [],
"name": "VoucherExpired",
"type": "error"
},
{
"inputs": [],
"name": "VoucherUsed",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "buyer",
"type": "address"
},
{
"indexed": true,
"internalType": "PoolId",
"name": "poolId",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "wethSpent",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "tokenOut",
"type": "uint256"
}
],
"name": "BuyExecuted",
"type": "event"
},
{
"anonymous": false,
"inputs": [],
"name": "EIP712DomainChanged",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "hook",
"type": "address"
}
],
"name": "HookSet",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "launcher",
"type": "address"
}
],
"name": "LauncherSet",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "previousOwner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "OwnershipTransferStarted",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "previousOwner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "OwnershipTransferred",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "PoolId",
"name": "poolId",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "creator",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "customSigner",
"type": "address"
},
{
"indexed": false,
"internalType": "bool",
"name": "rotationLocked",
"type": "bool"
}
],
"name": "PoolRegistered",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "PoolId",
"name": "poolId",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "address",
"name": "previousSigner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "newSigner",
"type": "address"
}
],
"name": "PoolSignerChanged",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "PoolId",
"name": "poolId",
"type": "bytes32"
}
],
"name": "PoolSignerLocked",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "previousSigner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "newSigner",
"type": "address"
}
],
"name": "SignerChanged",
"type": "event"
},
{
"inputs": [],
"name": "BUY_TYPEHASH",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "MAX_VIEW_PAGE",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "acceptOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "Currency",
"name": "currency0",
"type": "address"
},
{
"internalType": "Currency",
"name": "currency1",
"type": "address"
},
{
"internalType": "uint24",
"name": "fee",
"type": "uint24"
},
{
"internalType": "int24",
"name": "tickSpacing",
"type": "int24"
},
{
"internalType": "contract IHooks",
"name": "hooks",
"type": "address"
}
],
"internalType": "struct PoolKey",
"name": "key",
"type": "tuple"
},
{
"components": [
{
"internalType": "address",
"name": "buyer",
"type": "address"
},
{
"internalType": "PoolId",
"name": "poolId",
"type": "bytes32"
},
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "uint128",
"name": "tokenOut",
"type": "uint128"
},
{
"internalType": "uint128",
"name": "maxWethIn",
"type": "uint128"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "deadline",
"type": "uint256"
}
],
"internalType": "struct QuiverV4Gate.BuyVoucher",
"name": "voucher",
"type": "tuple"
},
{
"internalType": "bytes",
"name": "signature",
"type": "bytes"
}
],
"name": "buy",
"outputs": [
{
"internalType": "uint256",
"name": "tokenOut",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "wethSpent",
"type": "uint256"
}
],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "PoolId",
"name": "",
"type": "bytes32"
}
],
"name": "creatorOfPool",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "PoolId",
"name": "",
"type": "bytes32"
}
],
"name": "customSignerOfPool",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "PoolId",
"name": "poolId",
"type": "bytes32"
}
],
"name": "effectiveSigner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "eip712Domain",
"outputs": [
{
"internalType": "bytes1",
"name": "fields",
"type": "bytes1"
},
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "string",
"name": "version",
"type": "string"
},
{
"internalType": "uint256",
"name": "chainId",
"type": "uint256"
},
{
"internalType": "address",
"name": "verifyingContract",
"type": "address"
},
{
"internalType": "bytes32",
"name": "salt",
"type": "bytes32"
},
{
"internalType": "uint256[]",
"name": "extensions",
"type": "uint256[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "buyer",
"type": "address"
},
{
"internalType": "PoolId",
"name": "poolId",
"type": "bytes32"
},
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "uint128",
"name": "tokenOut",
"type": "uint128"
},
{
"internalType": "uint128",
"name": "maxWethIn",
"type": "uint128"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "deadline",
"type": "uint256"
}
],
"internalType": "struct QuiverV4Gate.BuyVoucher",
"name": "voucher",
"type": "tuple"
}
],
"name": "hashVoucher",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "hook",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "buyer",
"type": "address"
},
{
"internalType": "PoolId",
"name": "poolId",
"type": "bytes32"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
}
],
"name": "isAuthorized",
"outputs": [
{
"internalType": "bool",
"name": "authorized",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "launcher",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "PoolId",
"name": "poolId",
"type": "bytes32"
}
],
"name": "lockPoolSigner",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "owner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "pendingOwner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "PoolId[]",
"name": "poolIds",
"type": "bytes32[]"
}
],
"name": "poolSignerStatesBatch",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "creator",
"type": "address"
},
{
"internalType": "address",
"name": "customSigner",
"type": "address"
},
{
"internalType": "address",
"name": "effectiveSigner",
"type": "address"
},
{
"internalType": "bool",
"name": "rotationLocked",
"type": "bool"
}
],
"internalType": "struct QuiverV4Gate.PoolSignerState[]",
"name": "states",
"type": "tuple[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "Currency",
"name": "currency0",
"type": "address"
},
{
"internalType": "Currency",
"name": "currency1",
"type": "address"
},
{
"internalType": "uint24",
"name": "fee",
"type": "uint24"
},
{
"internalType": "int24",
"name": "tickSpacing",
"type": "int24"
},
{
"internalType": "contract IHooks",
"name": "hooks",
"type": "address"
}
],
"internalType": "struct PoolKey",
"name": "key",
"type": "tuple"
},
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "address",
"name": "creator",
"type": "address"
},
{
"internalType": "address",
"name": "gateSigner",
"type": "address"
},
{
"internalType": "bool",
"name": "gated",
"type": "bool"
}
],
"name": "registerPool",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "renounceOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "hook_",
"type": "address"
}
],
"name": "setHook",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "launcher_",
"type": "address"
}
],
"name": "setLauncher",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "PoolId",
"name": "poolId",
"type": "bytes32"
},
{
"internalType": "address",
"name": "newSigner",
"type": "address"
}
],
"name": "setPoolSigner",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "signer_",
"type": "address"
}
],
"name": "setSigner",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "signer",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "PoolId",
"name": "",
"type": "bytes32"
}
],
"name": "signerRotationLocked",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "PoolId",
"name": "",
"type": "bytes32"
}
],
"name": "tokenOfPool",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "transferOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "universalRouter",
"outputs": [
{
"internalType": "contract IUniversalRouterV211",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
},
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "usedNonces",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "weth",
"outputs": [
{
"internalType": "contract IWETH9",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"stateMutability": "payable",
"type": "receive"
}
]Source code
// SPDX-License-Identifier: BUSL-1.1
// Copyright (c) 2026 Quiver (quiver-app.io)
pragma solidity 0.8.26;
import { Ownable2Step } from "openzeppelin-contracts/contracts/access/Ownable2Step.sol";
import { Ownable } from "openzeppelin-contracts/contracts/access/Ownable.sol";
import { EIP712 } from "openzeppelin-contracts/contracts/utils/cryptography/EIP712.sol";
import { ECDSA } from "openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol";
import { IERC20 } from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import { SafeERC20 } from "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
import { PoolKey } from "v4-core/src/types/PoolKey.sol";
import { PoolId, PoolIdLibrary } from "v4-core/src/types/PoolId.sol";
import { Currency } from "v4-core/src/types/Currency.sol";
import { UniversalRouterV211Encoder } from "./libraries/UniversalRouterV211Encoder.sol";
interface IUniversalRouterV211 {
function execute(bytes calldata commands, bytes[] calldata inputs, uint256 deadline) external payable;
}
interface IWETH9 is IERC20 {
function withdraw(uint256 amount) external;
}
/// @notice EIP-712 voucher gateway for gated Quiver v4 buys.
contract QuiverV4Gate is EIP712, Ownable2Step {
using PoolIdLibrary for PoolKey;
using SafeERC20 for IERC20;
uint256 public constant MAX_VIEW_PAGE = 500;
bytes32 public constant BUY_TYPEHASH = keccak256(
"Buy(address buyer,bytes32 poolId,address token,uint128 tokenOut,uint128 maxWethIn,uint256 nonce,uint256 deadline)"
);
IUniversalRouterV211 public immutable universalRouter;
IWETH9 public immutable weth;
address public signer;
address public launcher;
address public hook;
mapping(PoolId => address) public tokenOfPool;
mapping(PoolId => address) public creatorOfPool;
mapping(PoolId => address) public customSignerOfPool;
mapping(PoolId => bool) public signerRotationLocked;
mapping(address => mapping(uint256 => bool)) public usedNonces;
struct BuyVoucher {
address buyer;
PoolId poolId;
address token;
uint128 tokenOut;
uint128 maxWethIn;
uint256 nonce;
uint256 deadline;
}
struct PoolSignerState {
address creator;
address customSigner;
address effectiveSigner;
bool rotationLocked;
}
event SignerChanged(address indexed previousSigner, address indexed newSigner);
event LauncherSet(address indexed launcher);
event HookSet(address indexed hook);
event PoolRegistered(
PoolId indexed poolId, address indexed token, address indexed creator, address customSigner, bool rotationLocked
);
event PoolSignerChanged(PoolId indexed poolId, address indexed previousSigner, address indexed newSigner);
event PoolSignerLocked(PoolId indexed poolId);
event BuyExecuted(
address indexed buyer, PoolId indexed poolId, uint256 indexed nonce, uint256 wethSpent, uint256 tokenOut
);
error OnlyLauncher();
error OnlyHook();
error OnlyCreator();
error LauncherAlreadySet();
error HookAlreadySet();
error SignerRotationLocked();
error InvalidVoucher();
error VoucherExpired();
error VoucherUsed();
error InvalidPool();
error TransferFailed();
error Reentrancy();
error PageTooLarge();
uint256 private _entered = 1;
constructor(address universalRouter_, address weth_, address signer_)
EIP712("QuiverV4Gate", "1")
Ownable(msg.sender)
{
if (universalRouter_ == address(0) || weth_ == address(0) || signer_ == address(0)) {
revert InvalidVoucher();
}
universalRouter = IUniversalRouterV211(universalRouter_);
weth = IWETH9(weth_);
signer = signer_;
}
receive() external payable {
if (msg.sender != address(weth)) revert TransferFailed();
}
modifier nonReentrant() {
if (_entered != 1) revert Reentrancy();
_entered = 2;
_;
_entered = 1;
}
function setLauncher(address launcher_) external onlyOwner {
if (launcher != address(0)) revert LauncherAlreadySet();
if (launcher_ == address(0)) revert InvalidVoucher();
launcher = launcher_;
emit LauncherSet(launcher_);
}
function setHook(address hook_) external onlyOwner {
if (hook != address(0)) revert HookAlreadySet();
if (hook_ == address(0)) revert InvalidVoucher();
hook = hook_;
emit HookSet(hook_);
}
function setSigner(address signer_) external onlyOwner {
if (signer_ == address(0)) revert InvalidVoucher();
emit SignerChanged(signer, signer_);
signer = signer_;
}
function registerPool(PoolKey calldata key, address token, address creator, address gateSigner, bool gated)
external
{
if (msg.sender != launcher) revert OnlyLauncher();
PoolId poolId = key.toId();
if (token == address(0) || creator == address(0) || tokenOfPool[poolId] != address(0)) revert InvalidPool();
tokenOfPool[poolId] = token;
creatorOfPool[poolId] = creator;
customSignerOfPool[poolId] = gateSigner;
signerRotationLocked[poolId] = !gated;
emit PoolRegistered(poolId, token, creator, gateSigner, !gated);
}
function setPoolSigner(PoolId poolId, address newSigner) external {
if (msg.sender != creatorOfPool[poolId]) revert OnlyCreator();
if (signerRotationLocked[poolId]) revert SignerRotationLocked();
address previousSigner = customSignerOfPool[poolId];
customSignerOfPool[poolId] = newSigner;
emit PoolSignerChanged(poolId, previousSigner, newSigner);
}
function lockPoolSigner(PoolId poolId) external {
if (msg.sender != hook) revert OnlyHook();
if (tokenOfPool[poolId] == address(0)) revert InvalidPool();
if (!signerRotationLocked[poolId]) {
signerRotationLocked[poolId] = true;
emit PoolSignerLocked(poolId);
}
}
function effectiveSigner(PoolId poolId) public view returns (address) {
if (tokenOfPool[poolId] == address(0)) revert InvalidPool();
address customSigner = customSignerOfPool[poolId];
return customSigner == address(0) ? signer : customSigner;
}
function poolSignerStatesBatch(PoolId[] calldata poolIds) external view returns (PoolSignerState[] memory states) {
if (poolIds.length > MAX_VIEW_PAGE) revert PageTooLarge();
states = new PoolSignerState[](poolIds.length);
for (uint256 index; index < poolIds.length; ++index) {
PoolId poolId = poolIds[index];
address customSigner = customSignerOfPool[poolId];
states[index] = PoolSignerState({
creator: creatorOfPool[poolId],
customSigner: customSigner,
effectiveSigner: customSigner == address(0) ? signer : customSigner,
rotationLocked: signerRotationLocked[poolId]
});
}
}
/// @notice Executes an exact-output buy through the canonical Universal Router.
/// Any unspent WETH is unwrapped and refunded to the buyer.
function buy(PoolKey calldata key, BuyVoucher calldata voucher, bytes calldata signature)
external
payable
nonReentrant
returns (uint256 tokenOut, uint256 wethSpent)
{
if (msg.sender != voucher.buyer || block.timestamp > voucher.deadline) revert VoucherExpired();
if (msg.value != voucher.maxWethIn || voucher.tokenOut == 0 || voucher.maxWethIn == 0) revert InvalidVoucher();
PoolId poolId = key.toId();
if (
PoolId.unwrap(poolId) != PoolId.unwrap(voucher.poolId) || tokenOfPool[poolId] != voucher.token
|| usedNonces[voucher.buyer][voucher.nonce]
) {
if (usedNonces[voucher.buyer][voucher.nonce]) revert VoucherUsed();
revert InvalidPool();
}
bytes32 digest = _hashTypedDataV4(
keccak256(
abi.encode(
BUY_TYPEHASH,
voucher.buyer,
PoolId.unwrap(voucher.poolId),
voucher.token,
voucher.tokenOut,
voucher.maxWethIn,
voucher.nonce,
voucher.deadline
)
)
);
if (ECDSA.recover(digest, signature) != effectiveSigner(poolId)) revert InvalidVoucher();
bool zeroForOne = Currency.unwrap(key.currency1) == voucher.token;
address output = Currency.unwrap(zeroForOne ? key.currency1 : key.currency0);
address input = Currency.unwrap(zeroForOne ? key.currency0 : key.currency1);
if (output != voucher.token || input != address(weth)) revert InvalidPool();
usedNonces[voucher.buyer][voucher.nonce] = true;
bytes32 authorizationKey = _authorizationKey(voucher.buyer, poolId, voucher.nonce);
assembly ("memory-safe") {
tstore(authorizationKey, 1)
}
uint256 tokenBefore = IERC20(voucher.token).balanceOf(address(this));
uint256 wethBefore = weth.balanceOf(address(this));
(bytes memory commands, bytes[] memory inputs) = UniversalRouterV211Encoder.exactOutputWethBuy(
key,
zeroForOne,
voucher.tokenOut,
voucher.maxWethIn,
abi.encode(voucher.buyer, poolId, voucher.nonce),
address(weth),
address(this)
);
universalRouter.execute{ value: msg.value }(commands, inputs, voucher.deadline);
assembly ("memory-safe") {
tstore(authorizationKey, 0)
}
tokenOut = IERC20(voucher.token).balanceOf(address(this)) - tokenBefore;
if (tokenOut != voucher.tokenOut) revert InvalidVoucher();
IERC20(voucher.token).safeTransfer(voucher.buyer, tokenOut);
uint256 wethRefund = weth.balanceOf(address(this)) - wethBefore;
wethSpent = voucher.maxWethIn - wethRefund;
if (wethRefund != 0) {
weth.withdraw(wethRefund);
(bool ok,) = voucher.buyer.call{ value: wethRefund }("");
if (!ok) revert TransferFailed();
}
emit BuyExecuted(voucher.buyer, poolId, voucher.nonce, wethSpent, tokenOut);
}
function isAuthorized(address buyer, PoolId poolId, uint256 nonce) external view returns (bool authorized) {
bytes32 key = _authorizationKey(buyer, poolId, nonce);
assembly ("memory-safe") {
authorized := tload(key)
}
}
function hashVoucher(BuyVoucher calldata voucher) external view returns (bytes32) {
return _hashTypedDataV4(
keccak256(
abi.encode(
BUY_TYPEHASH,
voucher.buyer,
PoolId.unwrap(voucher.poolId),
voucher.token,
voucher.tokenOut,
voucher.maxWethIn,
voucher.nonce,
voucher.deadline
)
)
);
}
function _authorizationKey(address buyer, PoolId poolId, uint256 nonce) private pure returns (bytes32) {
return keccak256(abi.encodePacked("QUIVER_V4_BUY", buyer, PoolId.unwrap(poolId), nonce));
}
}
Chain explorer1428msChain node89ms