From 8215c6e9366489b804030b6d164b1c66a9295792 Mon Sep 17 00:00:00 2001 From: xyzseer Date: Thu, 25 Sep 2025 10:55:54 -0300 Subject: [PATCH 1/6] trading credits --- contracts/deploy/30-deploy-credits-manager.ts | 33 + .../deployments/gnosis/CreditsManager.json | 328 ++++++++++ contracts/deployments/gnosis/SeerCredits.json | 580 ++++++++++++++++++ contracts/package.json | 2 +- contracts/scripts/trading-credits.js | 100 +++ .../src/trading-credits/CreditsManager.sol | 104 ++++ contracts/src/trading-credits/SeerCredits.sol | 71 +++ .../components/Market/CollateralDropdown.tsx | 10 +- .../SwapTokens/SwapTokensConfirmation.tsx | 4 +- .../Market/SwapTokens/SwapTokensLimitUpTo.tsx | 5 +- .../Market/SwapTokens/SwapTokensMarket.tsx | 5 +- .../Market/SwapTokens/TokenSelector.tsx | 1 + web/src/hooks/trade/executeSwaprTrade.ts | 18 +- web/src/hooks/trade/executeUniswapTrade.ts | 15 +- web/src/hooks/trade/index.ts | 61 +- web/src/hooks/trade/useTradeConditions.ts | 16 +- web/src/hooks/trade/utils.ts | 31 +- web/src/hooks/useGlobalState.ts | 28 +- web/src/lib/config.ts | 8 + web/src/lib/paths.ts | 6 +- web/wagmi.config.ts | 1 + 21 files changed, 1382 insertions(+), 45 deletions(-) create mode 100644 contracts/deploy/30-deploy-credits-manager.ts create mode 100644 contracts/deployments/gnosis/CreditsManager.json create mode 100644 contracts/deployments/gnosis/SeerCredits.json create mode 100644 contracts/scripts/trading-credits.js create mode 100644 contracts/src/trading-credits/CreditsManager.sol create mode 100644 contracts/src/trading-credits/SeerCredits.sol diff --git a/contracts/deploy/30-deploy-credits-manager.ts b/contracts/deploy/30-deploy-credits-manager.ts new file mode 100644 index 00000000..482446ae --- /dev/null +++ b/contracts/deploy/30-deploy-credits-manager.ts @@ -0,0 +1,33 @@ +import { HardhatRuntimeEnvironment } from "hardhat/types"; +import { DeployFunction } from "hardhat-deploy/types"; + +const deployCreditsManager: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { + const { deployments, getNamedAccounts, getChainId } = hre; + const { deploy } = deployments; + + // fallback to hardhat node signers on local network + const namedAccounts = await getNamedAccounts() + const deployer = namedAccounts.deployer ?? (await hre.viem.getWalletClients())[0].account.address; + const chainId = Number(await getChainId()); + console.log("deploying to chainId %s with deployer %s", chainId, deployer); + + const seerCredits = await deploy("SeerCredits", { + from: deployer, + args: [deployer], + log: true, + }); + + const collateralToken = await deployments.get("CollateralToken"); + const creditsManager = await deploy("CreditsManager", { + from: deployer, + args: [collateralToken.address, seerCredits.address], + log: true, + }); + + const seerCreditsContract = await hre.ethers.getContractAt("SeerCredits", seerCredits.address); + await seerCreditsContract.changeCreditsManager(creditsManager.address); +}; + +deployCreditsManager.tags = ['CreditsManager']; + +export default deployCreditsManager; \ No newline at end of file diff --git a/contracts/deployments/gnosis/CreditsManager.json b/contracts/deployments/gnosis/CreditsManager.json new file mode 100644 index 00000000..fc0fbfb3 --- /dev/null +++ b/contracts/deployments/gnosis/CreditsManager.json @@ -0,0 +1,328 @@ +{ + "address": "0xFeB801b97b10625FaBee2A7839CDdb6E37C9768b", + "abi": [ + { + "inputs": [ + { + "internalType": "contract ERC20", + "name": "_token", + "type": "address" + }, + { + "internalType": "contract SeerCredits", + "name": "_seerCredits", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_user", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "canSpendCredits", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_governor", + "type": "address" + } + ], + "name": "changeGovernor", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "contract ERC20", + "name": "outputToken", + "type": "address" + } + ], + "name": "execute", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "governor", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "seerCredits", + "outputs": [ + { + "internalType": "contract SeerCredits", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_contract", + "type": "address" + }, + { + "internalType": "bool", + "name": "_whitelisted", + "type": "bool" + } + ], + "name": "setWhitelistedContract", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract ERC20", + "name": "_token", + "type": "address" + } + ], + "name": "sweepTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "token", + "outputs": [ + { + "internalType": "contract ERC20", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "whitelistedContracts", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "transactionHash": "0xa067e7e535e1895e09804f26fa7302f692674d34116d7a2a72ca8163dea4c626", + "receipt": { + "to": null, + "from": "0x4EDCA105188a0783Ab3A6f09c50567D1E3F8591D", + "contractAddress": "0xFeB801b97b10625FaBee2A7839CDdb6E37C9768b", + "transactionIndex": 6, + "gasUsed": "1309615", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xdf905cb2f90172b499442d00e4cdc7afc4b34a6101b58d7f21af20a5194cc59a", + "transactionHash": "0xa067e7e535e1895e09804f26fa7302f692674d34116d7a2a72ca8163dea4c626", + "logs": [], + "blockNumber": 42332226, + "cumulativeGasUsed": "3379432", + "status": 1, + "byzantium": true + }, + "args": [ + "0xaf204776c7245bf4147c2612bf6e5972ee483701", + "0x3a0D8671eFcBc172eDBE32F91169BBc984dC607C" + ], + "numDeployments": 2, + "solcInputHash": "2d3de33fa340cf567b57fc3a8edf08f0", + "metadata": "{\"compiler\":{\"version\":\"0.8.28+commit.7893614a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract ERC20\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"contract SeerCredits\",\"name\":\"_seerCredits\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_user\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"canSpendCredits\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_governor\",\"type\":\"address\"}],\"name\":\"changeGovernor\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"contract ERC20\",\"name\":\"outputToken\",\"type\":\"address\"}],\"name\":\"execute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"seerCredits\",\"outputs\":[{\"internalType\":\"contract SeerCredits\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_contract\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"_whitelisted\",\"type\":\"bool\"}],\"name\":\"setWhitelistedContract\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract ERC20\",\"name\":\"_token\",\"type\":\"address\"}],\"name\":\"sweepTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"token\",\"outputs\":[{\"internalType\":\"contract ERC20\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"whitelistedContracts\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"The contract receives an address `to` (expected to be a DEX router) and `data` to execute a swapThe swap data must be encoded to send tokens to `msg.sender`CreditsManager pays for the swap on behalf of the user by deducting credits from their balance\",\"kind\":\"dev\",\"methods\":{\"canSpendCredits(address,uint256)\":{\"details\":\"Check if a user can spend a specific amount of credits.\",\"params\":{\"_amount\":\"The amount of credits to check.\",\"_user\":\"The address of the user to check.\"},\"returns\":{\"_0\":\"True if the user can spend the specified amount of credits.\"}},\"changeGovernor(address)\":{\"details\":\"Change the governor of the contract.\",\"params\":{\"_governor\":\"The address of the new governor. TRUSTED\"}},\"constructor\":{\"details\":\"Constructor.\",\"params\":{\"_seerCredits\":\"The SeerCredits token contract. TRUSTED\",\"_token\":\"The ERC20 token used to swap from (e.g., sDAI on Gnosis). TRUSTED\"}},\"execute(address,bytes,uint256,address)\":{\"details\":\"Execute a swap through a DEX router (Uniswap, Swapr, etc.). CreditsManager pays for the swap.\",\"params\":{\"amount\":\"The amount of credits to spend (tokens approved to the DEX router).\",\"data\":\"The encoded swap call data. Must be encoded to send output tokens to msg.sender.\",\"outputToken\":\"The token that the user is buying (must have increased balance after swap).\",\"to\":\"The DEX router address (must be whitelisted).\"}},\"setWhitelistedContract(address,bool)\":{\"details\":\"Add or remove a contract from the whitelist.\",\"params\":{\"_contract\":\"The address of the contract to modify.\",\"_whitelisted\":\"True to add to whitelist, false to remove.\"}},\"sweepTokens(address)\":{\"details\":\"Sweep all tokens from the contract to the governor.\",\"params\":{\"_token\":\"The token to sweep. If address(0), uses the default token.\"}}},\"title\":\"CreditsManager\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"execute(address,bytes,uint256,address)\":{\"notice\":\"This function acts as a proxy - CreditsManager pays for the swap by deducting credits from user's balance.\"}},\"notice\":\"This contract acts as a proxy to DEXs (Uniswap, Swapr, etc.) where users can spend trading credits\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/trading-credits/CreditsManager.sol\":\"CreditsManager\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":false,\"runs\":200},\"remappings\":[]},\"sources\":{\"solmate/src/tokens/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity >=0.8.0;\\n\\n/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.\\n/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)\\n/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)\\n/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.\\nabstract contract ERC20 {\\n /*//////////////////////////////////////////////////////////////\\n EVENTS\\n //////////////////////////////////////////////////////////////*/\\n\\n event Transfer(address indexed from, address indexed to, uint256 amount);\\n\\n event Approval(address indexed owner, address indexed spender, uint256 amount);\\n\\n /*//////////////////////////////////////////////////////////////\\n METADATA STORAGE\\n //////////////////////////////////////////////////////////////*/\\n\\n string public name;\\n\\n string public symbol;\\n\\n uint8 public immutable decimals;\\n\\n /*//////////////////////////////////////////////////////////////\\n ERC20 STORAGE\\n //////////////////////////////////////////////////////////////*/\\n\\n uint256 public totalSupply;\\n\\n mapping(address => uint256) public balanceOf;\\n\\n mapping(address => mapping(address => uint256)) public allowance;\\n\\n /*//////////////////////////////////////////////////////////////\\n EIP-2612 STORAGE\\n //////////////////////////////////////////////////////////////*/\\n\\n uint256 internal immutable INITIAL_CHAIN_ID;\\n\\n bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;\\n\\n mapping(address => uint256) public nonces;\\n\\n /*//////////////////////////////////////////////////////////////\\n CONSTRUCTOR\\n //////////////////////////////////////////////////////////////*/\\n\\n constructor(\\n string memory _name,\\n string memory _symbol,\\n uint8 _decimals\\n ) {\\n name = _name;\\n symbol = _symbol;\\n decimals = _decimals;\\n\\n INITIAL_CHAIN_ID = block.chainid;\\n INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n ERC20 LOGIC\\n //////////////////////////////////////////////////////////////*/\\n\\n function approve(address spender, uint256 amount) public virtual returns (bool) {\\n allowance[msg.sender][spender] = amount;\\n\\n emit Approval(msg.sender, spender, amount);\\n\\n return true;\\n }\\n\\n function transfer(address to, uint256 amount) public virtual returns (bool) {\\n balanceOf[msg.sender] -= amount;\\n\\n // Cannot overflow because the sum of all user\\n // balances can't exceed the max uint256 value.\\n unchecked {\\n balanceOf[to] += amount;\\n }\\n\\n emit Transfer(msg.sender, to, amount);\\n\\n return true;\\n }\\n\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) public virtual returns (bool) {\\n uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.\\n\\n if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;\\n\\n balanceOf[from] -= amount;\\n\\n // Cannot overflow because the sum of all user\\n // balances can't exceed the max uint256 value.\\n unchecked {\\n balanceOf[to] += amount;\\n }\\n\\n emit Transfer(from, to, amount);\\n\\n return true;\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n EIP-2612 LOGIC\\n //////////////////////////////////////////////////////////////*/\\n\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) public virtual {\\n require(deadline >= block.timestamp, \\\"PERMIT_DEADLINE_EXPIRED\\\");\\n\\n // Unchecked because the only math done is incrementing\\n // the owner's nonce which cannot realistically overflow.\\n unchecked {\\n address recoveredAddress = ecrecover(\\n keccak256(\\n abi.encodePacked(\\n \\\"\\\\x19\\\\x01\\\",\\n DOMAIN_SEPARATOR(),\\n keccak256(\\n abi.encode(\\n keccak256(\\n \\\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\\\"\\n ),\\n owner,\\n spender,\\n value,\\n nonces[owner]++,\\n deadline\\n )\\n )\\n )\\n ),\\n v,\\n r,\\n s\\n );\\n\\n require(recoveredAddress != address(0) && recoveredAddress == owner, \\\"INVALID_SIGNER\\\");\\n\\n allowance[recoveredAddress][spender] = value;\\n }\\n\\n emit Approval(owner, spender, value);\\n }\\n\\n function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {\\n return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();\\n }\\n\\n function computeDomainSeparator() internal view virtual returns (bytes32) {\\n return\\n keccak256(\\n abi.encode(\\n keccak256(\\\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\\\"),\\n keccak256(bytes(name)),\\n keccak256(\\\"1\\\"),\\n block.chainid,\\n address(this)\\n )\\n );\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n INTERNAL MINT/BURN LOGIC\\n //////////////////////////////////////////////////////////////*/\\n\\n function _mint(address to, uint256 amount) internal virtual {\\n totalSupply += amount;\\n\\n // Cannot overflow because the sum of all user\\n // balances can't exceed the max uint256 value.\\n unchecked {\\n balanceOf[to] += amount;\\n }\\n\\n emit Transfer(address(0), to, amount);\\n }\\n\\n function _burn(address from, uint256 amount) internal virtual {\\n balanceOf[from] -= amount;\\n\\n // Cannot underflow because a user's balance\\n // will never be larger than the total supply.\\n unchecked {\\n totalSupply -= amount;\\n }\\n\\n emit Transfer(from, address(0), amount);\\n }\\n}\\n\",\"keccak256\":\"0xcdfd8db76b2a3415620e4d18cc5545f3d50de792dbf2c3dd5adb40cbe6f94b10\",\"license\":\"AGPL-3.0-only\"},\"src/trading-credits/CreditsManager.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.28;\\n\\nimport {ERC20} from \\\"solmate/src/tokens/ERC20.sol\\\";\\nimport \\\"./SeerCredits.sol\\\";\\n\\n/// @title CreditsManager\\n/// @notice This contract acts as a proxy to DEXs (Uniswap, Swapr, etc.) where users can spend trading credits\\n/// @dev The contract receives an address `to` (expected to be a DEX router) and `data` to execute a swap\\n/// @dev The swap data must be encoded to send tokens to `msg.sender`\\n/// @dev CreditsManager pays for the swap on behalf of the user by deducting credits from their balance\\ncontract CreditsManager {\\n address public governor; // The address that can make governance changes to the parameters of the contract.\\n ERC20 public token; // The token used to swap from (e.g., sDAI on Gnosis).\\n SeerCredits public seerCredits; // The SeerCredits token representing trading credits.\\n mapping(address => bool) public whitelistedContracts; // Whitelist of contracts that can be called.\\n\\n modifier onlyGovernor() {\\n require(msg.sender == governor, \\\"The caller must be the governor\\\");\\n _;\\n }\\n\\n /// @dev Constructor.\\n /// @param _token The ERC20 token used to swap from (e.g., sDAI on Gnosis). TRUSTED\\n /// @param _seerCredits The SeerCredits token contract. TRUSTED\\n constructor(ERC20 _token, SeerCredits _seerCredits) {\\n governor = msg.sender;\\n token = _token;\\n seerCredits = _seerCredits;\\n }\\n\\n /// @dev Change the governor of the contract.\\n /// @param _governor The address of the new governor. TRUSTED\\n function changeGovernor(address _governor) external onlyGovernor {\\n governor = _governor;\\n }\\n\\n\\n /// @dev Add or remove a contract from the whitelist.\\n /// @param _contract The address of the contract to modify.\\n /// @param _whitelisted True to add to whitelist, false to remove.\\n function setWhitelistedContract(address _contract, bool _whitelisted) external onlyGovernor {\\n whitelistedContracts[_contract] = _whitelisted;\\n }\\n\\n\\n /// @dev Check if a user can spend a specific amount of credits.\\n /// @param _user The address of the user to check.\\n /// @param _amount The amount of credits to check.\\n /// @return True if the user can spend the specified amount of credits.\\n function canSpendCredits(address _user, uint256 _amount) external view returns (bool) {\\n // Check if user has enough SeerCredits\\n if (seerCredits.balanceOf(_user) < _amount) {\\n return false;\\n }\\n\\n // Check if contract has enough token balance\\n if (token.balanceOf(address(this)) < _amount) {\\n return false;\\n }\\n\\n return true;\\n }\\n\\n /// @dev Sweep all tokens from the contract to the governor.\\n /// @param _token The token to sweep. If address(0), uses the default token.\\n function sweepTokens(ERC20 _token) external onlyGovernor {\\n ERC20 tokenToSweep = _token == ERC20(address(0)) ? token : _token;\\n uint256 balance = tokenToSweep.balanceOf(address(this));\\n require(balance > 0, \\\"No tokens to sweep\\\");\\n require(tokenToSweep.transfer(governor, balance), \\\"Token transfer failed\\\");\\n }\\n\\n /// @dev Execute a swap through a DEX router (Uniswap, Swapr, etc.). CreditsManager pays for the swap.\\n /// @param to The DEX router address (must be whitelisted).\\n /// @param data The encoded swap call data. Must be encoded to send output tokens to msg.sender.\\n /// @param amount The amount of credits to spend (tokens approved to the DEX router).\\n /// @param outputToken The token that the user is buying (must have increased balance after swap).\\n /// @notice This function acts as a proxy - CreditsManager pays for the swap by deducting credits from user's balance.\\n function execute(address to, bytes calldata data, uint256 amount, ERC20 outputToken) external {\\n require(whitelistedContracts[to], \\\"Contract not whitelisted\\\");\\n require(seerCredits.balanceOf(msg.sender) >= amount, \\\"Insufficient credits balance\\\");\\n\\n // Check user's balance of output token before the swap\\n uint256 balanceBefore = outputToken.balanceOf(msg.sender);\\n\\n // CreditsManager approves tokens to the DEX router (e.g., Uniswap, Swapr)\\n require(token.approve(to, amount), \\\"Token approval failed\\\");\\n\\n // Burn SeerCredits from user's balance - CreditsManager is paying for the swap\\n seerCredits.burn(msg.sender, amount);\\n\\n // Execute the swap call to the DEX router\\n // The swap data must be encoded to send output tokens to msg.sender\\n (bool success,) = to.call(data);\\n require(success, \\\"Call failed\\\");\\n\\n // Verify that the user received tokens (balance increased)\\n // This is a security measure to verify that the swap had msg.sender as recipient,\\n // otherwise the swap recipient would be CreditsManager itself\\n uint256 balanceAfter = outputToken.balanceOf(msg.sender);\\n require(balanceAfter > balanceBefore, \\\"No tokens received from swap\\\");\\n }\\n}\\n\",\"keccak256\":\"0x49a2b49182bf0b9355a010c261fac863f555bbeabed35c53dc46a96a51851905\",\"license\":\"MIT\"},\"src/trading-credits/SeerCredits.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.28;\\n\\nimport {ERC20} from \\\"solmate/src/tokens/ERC20.sol\\\";\\n\\n/// @title SeerCredits\\n/// @notice ERC20 token representing trading credits that users can spend on DEX swaps\\ncontract SeerCredits is ERC20 {\\n address public governor; // The address that can make governance changes to the parameters of the contract.\\n address public creditsManager; // The address that can burn tokens (CreditsManager contract).\\n\\n modifier onlyGovernor() {\\n require(msg.sender == governor, \\\"Only governor can call this function\\\");\\n _;\\n }\\n\\n modifier onlyCreditsManager() {\\n require(msg.sender == creditsManager, \\\"Only credits manager can call this function\\\");\\n _;\\n }\\n\\n /// @dev Constructor.\\n /// @param _governor The trusted governor of the contract.\\n constructor(address _governor) ERC20(\\\"Seer Credits\\\", \\\"SEER_CREDITS\\\", 18) {\\n governor = _governor;\\n creditsManager = _governor;\\n }\\n\\n /// @dev Change the governor of the contract.\\n /// @param _governor The address of the new governor.\\n function changeGovernor(address _governor) external onlyGovernor {\\n governor = _governor;\\n }\\n\\n /// @dev Change the credits manager of the contract.\\n /// @param _creditsManager The address of the new credits manager.\\n function changeCreditsManager(address _creditsManager) external onlyGovernor {\\n creditsManager = _creditsManager;\\n }\\n\\n function mint(address to, uint256 amount) external onlyGovernor {\\n _mint(to, amount);\\n }\\n\\n function burn(address from, uint256 amount) external onlyCreditsManager {\\n _burn(from, amount);\\n }\\n\\n\\n /// @dev Set credits balance for multiple addresses by minting or burning as needed.\\n /// @param _addresses The list of addresses to set credits balance for.\\n /// @param _amounts The list of amounts corresponding to each address.\\n function setCreditsBalance(address[] memory _addresses, uint256[] memory _amounts) external onlyGovernor {\\n require(_addresses.length == _amounts.length, \\\"Arrays length mismatch\\\");\\n for (uint256 i; i < _addresses.length; ++i) {\\n uint256 currentBalance = this.balanceOf(_addresses[i]);\\n uint256 targetBalance = _amounts[i];\\n \\n if (currentBalance > targetBalance) {\\n // Burn excess tokens\\n uint256 burnAmount = currentBalance - targetBalance;\\n _burn(_addresses[i], burnAmount);\\n } else if (targetBalance > currentBalance) {\\n // Mint additional tokens\\n uint256 mintAmount = targetBalance - currentBalance;\\n _mint(_addresses[i], mintAmount);\\n }\\n // If currentBalance == targetBalance, do nothing\\n }\\n }\\n}\",\"keccak256\":\"0x37b49e69085a26a612831d01a9e3eb4a6b95e3d5c826626cf46d8e74bc93b17f\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x608060405234801561001057600080fd5b5060405161176f38038061176f833981810160405281019061003291906101ae565b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050506101ee565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061012b82610100565b9050919050565b600061013d82610120565b9050919050565b61014d81610132565b811461015857600080fd5b50565b60008151905061016a81610144565b92915050565b600061017b82610120565b9050919050565b61018b81610170565b811461019657600080fd5b50565b6000815190506101a881610182565b92915050565b600080604083850312156101c5576101c46100fb565b5b60006101d38582860161015b565b92505060206101e485828601610199565b9150509250929050565b611572806101fd6000396000f3fe608060405234801561001057600080fd5b50600436106100935760003560e01c8063a6ec9ea511610066578063a6ec9ea514610132578063c421449214610150578063e4c0aaf41461016c578063f5f6d3af14610188578063fc0c546a146101a457610093565b80630c340a241461009857806313a93def146100b6578063391feebb146100e657806370ec9d0814610116575b600080fd5b6100a06101c2565b6040516100ad9190610d13565b60405180910390f35b6100d060048036038101906100cb9190610d9a565b6101e6565b6040516100dd9190610df5565b60405180910390f35b61010060048036038101906100fb9190610e10565b61034b565b60405161010d9190610df5565b60405180910390f35b610130600480360381019061012b9190610ee0565b61036b565b005b61013a61083a565b6040516101479190610fc7565b60405180910390f35b61016a6004803603810190610165919061100e565b610860565b005b61018660048036038101906101819190610e10565b610949565b005b6101a2600480360381019061019d919061104e565b610a1a565b005b6101ac610cac565b6040516101b9919061109c565b60405180910390f35b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600081600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231856040518263ffffffff1660e01b81526004016102449190610d13565b602060405180830381865afa158015610261573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061028591906110cc565b10156102945760009050610345565b81600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016102f09190610d13565b602060405180830381865afa15801561030d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061033191906110cc565b10156103405760009050610345565b600190505b92915050565b60036020528060005260406000206000915054906101000a900460ff1681565b600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff166103f7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103ee90611156565b60405180910390fd5b81600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231336040518263ffffffff1660e01b81526004016104539190610d13565b602060405180830381865afa158015610470573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061049491906110cc565b10156104d5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104cc906111c2565b60405180910390fd5b60008173ffffffffffffffffffffffffffffffffffffffff166370a08231336040518263ffffffff1660e01b81526004016105109190610d13565b602060405180830381865afa15801561052d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061055191906110cc565b9050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663095ea7b387856040518363ffffffff1660e01b81526004016105b09291906111f1565b6020604051808303816000875af11580156105cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105f3919061122f565b610632576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610629906112a8565b60405180910390fd5b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16639dc29fac33856040518363ffffffff1660e01b815260040161068f9291906111f1565b600060405180830381600087803b1580156106a957600080fd5b505af11580156106bd573d6000803e3d6000fd5b5050505060008673ffffffffffffffffffffffffffffffffffffffff1686866040516106ea929190611307565b6000604051808303816000865af19150503d8060008114610727576040519150601f19603f3d011682016040523d82523d6000602084013e61072c565b606091505b5050905080610770576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107679061136c565b60405180910390fd5b60008373ffffffffffffffffffffffffffffffffffffffff166370a08231336040518263ffffffff1660e01b81526004016107ab9190610d13565b602060405180830381865afa1580156107c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107ec91906110cc565b9050828111610830576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610827906113d8565b60405180910390fd5b5050505050505050565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146108ee576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e590611444565b60405180910390fd5b80600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146109d7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109ce90611444565b60405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610aa8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a9f90611444565b60405180910390fd5b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614610ae35781610b07565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff165b905060008173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401610b449190610d13565b602060405180830381865afa158015610b61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b8591906110cc565b905060008111610bca576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bc1906114b0565b60405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff1663a9059cbb60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff16836040518363ffffffff1660e01b8152600401610c259291906111f1565b6020604051808303816000875af1158015610c44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c68919061122f565b610ca7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c9e9061151c565b60405180910390fd5b505050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610cfd82610cd2565b9050919050565b610d0d81610cf2565b82525050565b6000602082019050610d286000830184610d04565b92915050565b600080fd5b600080fd5b610d4181610cf2565b8114610d4c57600080fd5b50565b600081359050610d5e81610d38565b92915050565b6000819050919050565b610d7781610d64565b8114610d8257600080fd5b50565b600081359050610d9481610d6e565b92915050565b60008060408385031215610db157610db0610d2e565b5b6000610dbf85828601610d4f565b9250506020610dd085828601610d85565b9150509250929050565b60008115159050919050565b610def81610dda565b82525050565b6000602082019050610e0a6000830184610de6565b92915050565b600060208284031215610e2657610e25610d2e565b5b6000610e3484828501610d4f565b91505092915050565b600080fd5b600080fd5b600080fd5b60008083601f840112610e6257610e61610e3d565b5b8235905067ffffffffffffffff811115610e7f57610e7e610e42565b5b602083019150836001820283011115610e9b57610e9a610e47565b5b9250929050565b6000610ead82610cf2565b9050919050565b610ebd81610ea2565b8114610ec857600080fd5b50565b600081359050610eda81610eb4565b92915050565b600080600080600060808688031215610efc57610efb610d2e565b5b6000610f0a88828901610d4f565b955050602086013567ffffffffffffffff811115610f2b57610f2a610d33565b5b610f3788828901610e4c565b94509450506040610f4a88828901610d85565b9250506060610f5b88828901610ecb565b9150509295509295909350565b6000819050919050565b6000610f8d610f88610f8384610cd2565b610f68565b610cd2565b9050919050565b6000610f9f82610f72565b9050919050565b6000610fb182610f94565b9050919050565b610fc181610fa6565b82525050565b6000602082019050610fdc6000830184610fb8565b92915050565b610feb81610dda565b8114610ff657600080fd5b50565b60008135905061100881610fe2565b92915050565b6000806040838503121561102557611024610d2e565b5b600061103385828601610d4f565b925050602061104485828601610ff9565b9150509250929050565b60006020828403121561106457611063610d2e565b5b600061107284828501610ecb565b91505092915050565b600061108682610f94565b9050919050565b6110968161107b565b82525050565b60006020820190506110b1600083018461108d565b92915050565b6000815190506110c681610d6e565b92915050565b6000602082840312156110e2576110e1610d2e565b5b60006110f0848285016110b7565b91505092915050565b600082825260208201905092915050565b7f436f6e7472616374206e6f742077686974656c69737465640000000000000000600082015250565b60006111406018836110f9565b915061114b8261110a565b602082019050919050565b6000602082019050818103600083015261116f81611133565b9050919050565b7f496e73756666696369656e7420637265646974732062616c616e636500000000600082015250565b60006111ac601c836110f9565b91506111b782611176565b602082019050919050565b600060208201905081810360008301526111db8161119f565b9050919050565b6111eb81610d64565b82525050565b60006040820190506112066000830185610d04565b61121360208301846111e2565b9392505050565b60008151905061122981610fe2565b92915050565b60006020828403121561124557611244610d2e565b5b60006112538482850161121a565b91505092915050565b7f546f6b656e20617070726f76616c206661696c65640000000000000000000000600082015250565b60006112926015836110f9565b915061129d8261125c565b602082019050919050565b600060208201905081810360008301526112c181611285565b9050919050565b600081905092915050565b82818337600083830152505050565b60006112ee83856112c8565b93506112fb8385846112d3565b82840190509392505050565b60006113148284866112e2565b91508190509392505050565b7f43616c6c206661696c6564000000000000000000000000000000000000000000600082015250565b6000611356600b836110f9565b915061136182611320565b602082019050919050565b6000602082019050818103600083015261138581611349565b9050919050565b7f4e6f20746f6b656e732072656365697665642066726f6d207377617000000000600082015250565b60006113c2601c836110f9565b91506113cd8261138c565b602082019050919050565b600060208201905081810360008301526113f1816113b5565b9050919050565b7f5468652063616c6c6572206d7573742062652074686520676f7665726e6f7200600082015250565b600061142e601f836110f9565b9150611439826113f8565b602082019050919050565b6000602082019050818103600083015261145d81611421565b9050919050565b7f4e6f20746f6b656e7320746f2073776565700000000000000000000000000000600082015250565b600061149a6012836110f9565b91506114a582611464565b602082019050919050565b600060208201905081810360008301526114c98161148d565b9050919050565b7f546f6b656e207472616e73666572206661696c65640000000000000000000000600082015250565b60006115066015836110f9565b9150611511826114d0565b602082019050919050565b60006020820190508181036000830152611535816114f9565b905091905056fea264697066735822122025b5fe756be70b17e1b31f8fe39241136a79b96fb3811558155a67463ae8df7c64736f6c634300081c0033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100935760003560e01c8063a6ec9ea511610066578063a6ec9ea514610132578063c421449214610150578063e4c0aaf41461016c578063f5f6d3af14610188578063fc0c546a146101a457610093565b80630c340a241461009857806313a93def146100b6578063391feebb146100e657806370ec9d0814610116575b600080fd5b6100a06101c2565b6040516100ad9190610d13565b60405180910390f35b6100d060048036038101906100cb9190610d9a565b6101e6565b6040516100dd9190610df5565b60405180910390f35b61010060048036038101906100fb9190610e10565b61034b565b60405161010d9190610df5565b60405180910390f35b610130600480360381019061012b9190610ee0565b61036b565b005b61013a61083a565b6040516101479190610fc7565b60405180910390f35b61016a6004803603810190610165919061100e565b610860565b005b61018660048036038101906101819190610e10565b610949565b005b6101a2600480360381019061019d919061104e565b610a1a565b005b6101ac610cac565b6040516101b9919061109c565b60405180910390f35b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600081600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231856040518263ffffffff1660e01b81526004016102449190610d13565b602060405180830381865afa158015610261573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061028591906110cc565b10156102945760009050610345565b81600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016102f09190610d13565b602060405180830381865afa15801561030d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061033191906110cc565b10156103405760009050610345565b600190505b92915050565b60036020528060005260406000206000915054906101000a900460ff1681565b600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff166103f7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103ee90611156565b60405180910390fd5b81600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231336040518263ffffffff1660e01b81526004016104539190610d13565b602060405180830381865afa158015610470573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061049491906110cc565b10156104d5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104cc906111c2565b60405180910390fd5b60008173ffffffffffffffffffffffffffffffffffffffff166370a08231336040518263ffffffff1660e01b81526004016105109190610d13565b602060405180830381865afa15801561052d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061055191906110cc565b9050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663095ea7b387856040518363ffffffff1660e01b81526004016105b09291906111f1565b6020604051808303816000875af11580156105cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105f3919061122f565b610632576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610629906112a8565b60405180910390fd5b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16639dc29fac33856040518363ffffffff1660e01b815260040161068f9291906111f1565b600060405180830381600087803b1580156106a957600080fd5b505af11580156106bd573d6000803e3d6000fd5b5050505060008673ffffffffffffffffffffffffffffffffffffffff1686866040516106ea929190611307565b6000604051808303816000865af19150503d8060008114610727576040519150601f19603f3d011682016040523d82523d6000602084013e61072c565b606091505b5050905080610770576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107679061136c565b60405180910390fd5b60008373ffffffffffffffffffffffffffffffffffffffff166370a08231336040518263ffffffff1660e01b81526004016107ab9190610d13565b602060405180830381865afa1580156107c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107ec91906110cc565b9050828111610830576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610827906113d8565b60405180910390fd5b5050505050505050565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146108ee576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e590611444565b60405180910390fd5b80600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146109d7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109ce90611444565b60405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610aa8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a9f90611444565b60405180910390fd5b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614610ae35781610b07565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff165b905060008173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401610b449190610d13565b602060405180830381865afa158015610b61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b8591906110cc565b905060008111610bca576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bc1906114b0565b60405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff1663a9059cbb60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff16836040518363ffffffff1660e01b8152600401610c259291906111f1565b6020604051808303816000875af1158015610c44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c68919061122f565b610ca7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c9e9061151c565b60405180910390fd5b505050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610cfd82610cd2565b9050919050565b610d0d81610cf2565b82525050565b6000602082019050610d286000830184610d04565b92915050565b600080fd5b600080fd5b610d4181610cf2565b8114610d4c57600080fd5b50565b600081359050610d5e81610d38565b92915050565b6000819050919050565b610d7781610d64565b8114610d8257600080fd5b50565b600081359050610d9481610d6e565b92915050565b60008060408385031215610db157610db0610d2e565b5b6000610dbf85828601610d4f565b9250506020610dd085828601610d85565b9150509250929050565b60008115159050919050565b610def81610dda565b82525050565b6000602082019050610e0a6000830184610de6565b92915050565b600060208284031215610e2657610e25610d2e565b5b6000610e3484828501610d4f565b91505092915050565b600080fd5b600080fd5b600080fd5b60008083601f840112610e6257610e61610e3d565b5b8235905067ffffffffffffffff811115610e7f57610e7e610e42565b5b602083019150836001820283011115610e9b57610e9a610e47565b5b9250929050565b6000610ead82610cf2565b9050919050565b610ebd81610ea2565b8114610ec857600080fd5b50565b600081359050610eda81610eb4565b92915050565b600080600080600060808688031215610efc57610efb610d2e565b5b6000610f0a88828901610d4f565b955050602086013567ffffffffffffffff811115610f2b57610f2a610d33565b5b610f3788828901610e4c565b94509450506040610f4a88828901610d85565b9250506060610f5b88828901610ecb565b9150509295509295909350565b6000819050919050565b6000610f8d610f88610f8384610cd2565b610f68565b610cd2565b9050919050565b6000610f9f82610f72565b9050919050565b6000610fb182610f94565b9050919050565b610fc181610fa6565b82525050565b6000602082019050610fdc6000830184610fb8565b92915050565b610feb81610dda565b8114610ff657600080fd5b50565b60008135905061100881610fe2565b92915050565b6000806040838503121561102557611024610d2e565b5b600061103385828601610d4f565b925050602061104485828601610ff9565b9150509250929050565b60006020828403121561106457611063610d2e565b5b600061107284828501610ecb565b91505092915050565b600061108682610f94565b9050919050565b6110968161107b565b82525050565b60006020820190506110b1600083018461108d565b92915050565b6000815190506110c681610d6e565b92915050565b6000602082840312156110e2576110e1610d2e565b5b60006110f0848285016110b7565b91505092915050565b600082825260208201905092915050565b7f436f6e7472616374206e6f742077686974656c69737465640000000000000000600082015250565b60006111406018836110f9565b915061114b8261110a565b602082019050919050565b6000602082019050818103600083015261116f81611133565b9050919050565b7f496e73756666696369656e7420637265646974732062616c616e636500000000600082015250565b60006111ac601c836110f9565b91506111b782611176565b602082019050919050565b600060208201905081810360008301526111db8161119f565b9050919050565b6111eb81610d64565b82525050565b60006040820190506112066000830185610d04565b61121360208301846111e2565b9392505050565b60008151905061122981610fe2565b92915050565b60006020828403121561124557611244610d2e565b5b60006112538482850161121a565b91505092915050565b7f546f6b656e20617070726f76616c206661696c65640000000000000000000000600082015250565b60006112926015836110f9565b915061129d8261125c565b602082019050919050565b600060208201905081810360008301526112c181611285565b9050919050565b600081905092915050565b82818337600083830152505050565b60006112ee83856112c8565b93506112fb8385846112d3565b82840190509392505050565b60006113148284866112e2565b91508190509392505050565b7f43616c6c206661696c6564000000000000000000000000000000000000000000600082015250565b6000611356600b836110f9565b915061136182611320565b602082019050919050565b6000602082019050818103600083015261138581611349565b9050919050565b7f4e6f20746f6b656e732072656365697665642066726f6d207377617000000000600082015250565b60006113c2601c836110f9565b91506113cd8261138c565b602082019050919050565b600060208201905081810360008301526113f1816113b5565b9050919050565b7f5468652063616c6c6572206d7573742062652074686520676f7665726e6f7200600082015250565b600061142e601f836110f9565b9150611439826113f8565b602082019050919050565b6000602082019050818103600083015261145d81611421565b9050919050565b7f4e6f20746f6b656e7320746f2073776565700000000000000000000000000000600082015250565b600061149a6012836110f9565b91506114a582611464565b602082019050919050565b600060208201905081810360008301526114c98161148d565b9050919050565b7f546f6b656e207472616e73666572206661696c65640000000000000000000000600082015250565b60006115066015836110f9565b9150611511826114d0565b602082019050919050565b60006020820190508181036000830152611535816114f9565b905091905056fea264697066735822122025b5fe756be70b17e1b31f8fe39241136a79b96fb3811558155a67463ae8df7c64736f6c634300081c0033", + "devdoc": { + "details": "The contract receives an address `to` (expected to be a DEX router) and `data` to execute a swapThe swap data must be encoded to send tokens to `msg.sender`CreditsManager pays for the swap on behalf of the user by deducting credits from their balance", + "kind": "dev", + "methods": { + "canSpendCredits(address,uint256)": { + "details": "Check if a user can spend a specific amount of credits.", + "params": { + "_amount": "The amount of credits to check.", + "_user": "The address of the user to check." + }, + "returns": { + "_0": "True if the user can spend the specified amount of credits." + } + }, + "changeGovernor(address)": { + "details": "Change the governor of the contract.", + "params": { + "_governor": "The address of the new governor. TRUSTED" + } + }, + "constructor": { + "details": "Constructor.", + "params": { + "_seerCredits": "The SeerCredits token contract. TRUSTED", + "_token": "The ERC20 token used to swap from (e.g., sDAI on Gnosis). TRUSTED" + } + }, + "execute(address,bytes,uint256,address)": { + "details": "Execute a swap through a DEX router (Uniswap, Swapr, etc.). CreditsManager pays for the swap.", + "params": { + "amount": "The amount of credits to spend (tokens approved to the DEX router).", + "data": "The encoded swap call data. Must be encoded to send output tokens to msg.sender.", + "outputToken": "The token that the user is buying (must have increased balance after swap).", + "to": "The DEX router address (must be whitelisted)." + } + }, + "setWhitelistedContract(address,bool)": { + "details": "Add or remove a contract from the whitelist.", + "params": { + "_contract": "The address of the contract to modify.", + "_whitelisted": "True to add to whitelist, false to remove." + } + }, + "sweepTokens(address)": { + "details": "Sweep all tokens from the contract to the governor.", + "params": { + "_token": "The token to sweep. If address(0), uses the default token." + } + } + }, + "title": "CreditsManager", + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "execute(address,bytes,uint256,address)": { + "notice": "This function acts as a proxy - CreditsManager pays for the swap by deducting credits from user's balance." + } + }, + "notice": "This contract acts as a proxy to DEXs (Uniswap, Swapr, etc.) where users can spend trading credits", + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 395, + "contract": "src/trading-credits/CreditsManager.sol:CreditsManager", + "label": "governor", + "offset": 0, + "slot": "0", + "type": "t_address" + }, + { + "astId": 398, + "contract": "src/trading-credits/CreditsManager.sol:CreditsManager", + "label": "token", + "offset": 0, + "slot": "1", + "type": "t_contract(ERC20)387" + }, + { + "astId": 401, + "contract": "src/trading-credits/CreditsManager.sol:CreditsManager", + "label": "seerCredits", + "offset": 0, + "slot": "2", + "type": "t_contract(SeerCredits)840" + }, + { + "astId": 405, + "contract": "src/trading-credits/CreditsManager.sol:CreditsManager", + "label": "whitelistedContracts", + "offset": 0, + "slot": "3", + "type": "t_mapping(t_address,t_bool)" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_contract(ERC20)387": { + "encoding": "inplace", + "label": "contract ERC20", + "numberOfBytes": "20" + }, + "t_contract(SeerCredits)840": { + "encoding": "inplace", + "label": "contract SeerCredits", + "numberOfBytes": "20" + }, + "t_mapping(t_address,t_bool)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => bool)", + "numberOfBytes": "32", + "value": "t_bool" + } + } + } +} \ No newline at end of file diff --git a/contracts/deployments/gnosis/SeerCredits.json b/contracts/deployments/gnosis/SeerCredits.json new file mode 100644 index 00000000..445116f9 --- /dev/null +++ b/contracts/deployments/gnosis/SeerCredits.json @@ -0,0 +1,580 @@ +{ + "address": "0x3a0D8671eFcBc172eDBE32F91169BBc984dC607C", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_governor", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [], + "name": "DOMAIN_SEPARATOR", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "burn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_creditsManager", + "type": "address" + } + ], + "name": "changeCreditsManager", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_governor", + "type": "address" + } + ], + "name": "changeGovernor", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "creditsManager", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "governor", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "nonces", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "permit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_addresses", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "_amounts", + "type": "uint256[]" + } + ], + "name": "setCreditsBalance", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "transactionHash": "0x259619472b4ecbea52c24564048ed46226eb0f841b9111aad1c7d63165fb762f", + "receipt": { + "to": null, + "from": "0x4EDCA105188a0783Ab3A6f09c50567D1E3F8591D", + "contractAddress": "0x3a0D8671eFcBc172eDBE32F91169BBc984dC607C", + "transactionIndex": 7, + "gasUsed": "2030777", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x19bb09414e217b211ff5d2e44c6517babfc91bb259ddf9b8f3ed6b68208258a3", + "transactionHash": "0x259619472b4ecbea52c24564048ed46226eb0f841b9111aad1c7d63165fb762f", + "logs": [], + "blockNumber": 42332224, + "cumulativeGasUsed": "11049057", + "status": 1, + "byzantium": true + }, + "args": [ + "0x4edca105188a0783ab3a6f09c50567d1e3f8591d" + ], + "numDeployments": 2, + "solcInputHash": "2d3de33fa340cf567b57fc3a8edf08f0", + "metadata": "{\"compiler\":{\"version\":\"0.8.28+commit.7893614a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_governor\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DOMAIN_SEPARATOR\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"burn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_creditsManager\",\"type\":\"address\"}],\"name\":\"changeCreditsManager\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_governor\",\"type\":\"address\"}],\"name\":\"changeGovernor\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"creditsManager\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"nonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"permit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_addresses\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_amounts\",\"type\":\"uint256[]\"}],\"name\":\"setCreditsBalance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"changeCreditsManager(address)\":{\"details\":\"Change the credits manager of the contract.\",\"params\":{\"_creditsManager\":\"The address of the new credits manager.\"}},\"changeGovernor(address)\":{\"details\":\"Change the governor of the contract.\",\"params\":{\"_governor\":\"The address of the new governor.\"}},\"constructor\":{\"details\":\"Constructor.\",\"params\":{\"_governor\":\"The trusted governor of the contract.\"}},\"setCreditsBalance(address[],uint256[])\":{\"details\":\"Set credits balance for multiple addresses by minting or burning as needed.\",\"params\":{\"_addresses\":\"The list of addresses to set credits balance for.\",\"_amounts\":\"The list of amounts corresponding to each address.\"}}},\"title\":\"SeerCredits\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"notice\":\"ERC20 token representing trading credits that users can spend on DEX swaps\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/trading-credits/SeerCredits.sol\":\"SeerCredits\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":false,\"runs\":200},\"remappings\":[]},\"sources\":{\"solmate/src/tokens/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity >=0.8.0;\\n\\n/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.\\n/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)\\n/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)\\n/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.\\nabstract contract ERC20 {\\n /*//////////////////////////////////////////////////////////////\\n EVENTS\\n //////////////////////////////////////////////////////////////*/\\n\\n event Transfer(address indexed from, address indexed to, uint256 amount);\\n\\n event Approval(address indexed owner, address indexed spender, uint256 amount);\\n\\n /*//////////////////////////////////////////////////////////////\\n METADATA STORAGE\\n //////////////////////////////////////////////////////////////*/\\n\\n string public name;\\n\\n string public symbol;\\n\\n uint8 public immutable decimals;\\n\\n /*//////////////////////////////////////////////////////////////\\n ERC20 STORAGE\\n //////////////////////////////////////////////////////////////*/\\n\\n uint256 public totalSupply;\\n\\n mapping(address => uint256) public balanceOf;\\n\\n mapping(address => mapping(address => uint256)) public allowance;\\n\\n /*//////////////////////////////////////////////////////////////\\n EIP-2612 STORAGE\\n //////////////////////////////////////////////////////////////*/\\n\\n uint256 internal immutable INITIAL_CHAIN_ID;\\n\\n bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;\\n\\n mapping(address => uint256) public nonces;\\n\\n /*//////////////////////////////////////////////////////////////\\n CONSTRUCTOR\\n //////////////////////////////////////////////////////////////*/\\n\\n constructor(\\n string memory _name,\\n string memory _symbol,\\n uint8 _decimals\\n ) {\\n name = _name;\\n symbol = _symbol;\\n decimals = _decimals;\\n\\n INITIAL_CHAIN_ID = block.chainid;\\n INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n ERC20 LOGIC\\n //////////////////////////////////////////////////////////////*/\\n\\n function approve(address spender, uint256 amount) public virtual returns (bool) {\\n allowance[msg.sender][spender] = amount;\\n\\n emit Approval(msg.sender, spender, amount);\\n\\n return true;\\n }\\n\\n function transfer(address to, uint256 amount) public virtual returns (bool) {\\n balanceOf[msg.sender] -= amount;\\n\\n // Cannot overflow because the sum of all user\\n // balances can't exceed the max uint256 value.\\n unchecked {\\n balanceOf[to] += amount;\\n }\\n\\n emit Transfer(msg.sender, to, amount);\\n\\n return true;\\n }\\n\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) public virtual returns (bool) {\\n uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.\\n\\n if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;\\n\\n balanceOf[from] -= amount;\\n\\n // Cannot overflow because the sum of all user\\n // balances can't exceed the max uint256 value.\\n unchecked {\\n balanceOf[to] += amount;\\n }\\n\\n emit Transfer(from, to, amount);\\n\\n return true;\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n EIP-2612 LOGIC\\n //////////////////////////////////////////////////////////////*/\\n\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) public virtual {\\n require(deadline >= block.timestamp, \\\"PERMIT_DEADLINE_EXPIRED\\\");\\n\\n // Unchecked because the only math done is incrementing\\n // the owner's nonce which cannot realistically overflow.\\n unchecked {\\n address recoveredAddress = ecrecover(\\n keccak256(\\n abi.encodePacked(\\n \\\"\\\\x19\\\\x01\\\",\\n DOMAIN_SEPARATOR(),\\n keccak256(\\n abi.encode(\\n keccak256(\\n \\\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\\\"\\n ),\\n owner,\\n spender,\\n value,\\n nonces[owner]++,\\n deadline\\n )\\n )\\n )\\n ),\\n v,\\n r,\\n s\\n );\\n\\n require(recoveredAddress != address(0) && recoveredAddress == owner, \\\"INVALID_SIGNER\\\");\\n\\n allowance[recoveredAddress][spender] = value;\\n }\\n\\n emit Approval(owner, spender, value);\\n }\\n\\n function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {\\n return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();\\n }\\n\\n function computeDomainSeparator() internal view virtual returns (bytes32) {\\n return\\n keccak256(\\n abi.encode(\\n keccak256(\\\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\\\"),\\n keccak256(bytes(name)),\\n keccak256(\\\"1\\\"),\\n block.chainid,\\n address(this)\\n )\\n );\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n INTERNAL MINT/BURN LOGIC\\n //////////////////////////////////////////////////////////////*/\\n\\n function _mint(address to, uint256 amount) internal virtual {\\n totalSupply += amount;\\n\\n // Cannot overflow because the sum of all user\\n // balances can't exceed the max uint256 value.\\n unchecked {\\n balanceOf[to] += amount;\\n }\\n\\n emit Transfer(address(0), to, amount);\\n }\\n\\n function _burn(address from, uint256 amount) internal virtual {\\n balanceOf[from] -= amount;\\n\\n // Cannot underflow because a user's balance\\n // will never be larger than the total supply.\\n unchecked {\\n totalSupply -= amount;\\n }\\n\\n emit Transfer(from, address(0), amount);\\n }\\n}\\n\",\"keccak256\":\"0xcdfd8db76b2a3415620e4d18cc5545f3d50de792dbf2c3dd5adb40cbe6f94b10\",\"license\":\"AGPL-3.0-only\"},\"src/trading-credits/SeerCredits.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.28;\\n\\nimport {ERC20} from \\\"solmate/src/tokens/ERC20.sol\\\";\\n\\n/// @title SeerCredits\\n/// @notice ERC20 token representing trading credits that users can spend on DEX swaps\\ncontract SeerCredits is ERC20 {\\n address public governor; // The address that can make governance changes to the parameters of the contract.\\n address public creditsManager; // The address that can burn tokens (CreditsManager contract).\\n\\n modifier onlyGovernor() {\\n require(msg.sender == governor, \\\"Only governor can call this function\\\");\\n _;\\n }\\n\\n modifier onlyCreditsManager() {\\n require(msg.sender == creditsManager, \\\"Only credits manager can call this function\\\");\\n _;\\n }\\n\\n /// @dev Constructor.\\n /// @param _governor The trusted governor of the contract.\\n constructor(address _governor) ERC20(\\\"Seer Credits\\\", \\\"SEER_CREDITS\\\", 18) {\\n governor = _governor;\\n creditsManager = _governor;\\n }\\n\\n /// @dev Change the governor of the contract.\\n /// @param _governor The address of the new governor.\\n function changeGovernor(address _governor) external onlyGovernor {\\n governor = _governor;\\n }\\n\\n /// @dev Change the credits manager of the contract.\\n /// @param _creditsManager The address of the new credits manager.\\n function changeCreditsManager(address _creditsManager) external onlyGovernor {\\n creditsManager = _creditsManager;\\n }\\n\\n function mint(address to, uint256 amount) external onlyGovernor {\\n _mint(to, amount);\\n }\\n\\n function burn(address from, uint256 amount) external onlyCreditsManager {\\n _burn(from, amount);\\n }\\n\\n\\n /// @dev Set credits balance for multiple addresses by minting or burning as needed.\\n /// @param _addresses The list of addresses to set credits balance for.\\n /// @param _amounts The list of amounts corresponding to each address.\\n function setCreditsBalance(address[] memory _addresses, uint256[] memory _amounts) external onlyGovernor {\\n require(_addresses.length == _amounts.length, \\\"Arrays length mismatch\\\");\\n for (uint256 i; i < _addresses.length; ++i) {\\n uint256 currentBalance = this.balanceOf(_addresses[i]);\\n uint256 targetBalance = _amounts[i];\\n \\n if (currentBalance > targetBalance) {\\n // Burn excess tokens\\n uint256 burnAmount = currentBalance - targetBalance;\\n _burn(_addresses[i], burnAmount);\\n } else if (targetBalance > currentBalance) {\\n // Mint additional tokens\\n uint256 mintAmount = targetBalance - currentBalance;\\n _mint(_addresses[i], mintAmount);\\n }\\n // If currentBalance == targetBalance, do nothing\\n }\\n }\\n}\",\"keccak256\":\"0x37b49e69085a26a612831d01a9e3eb4a6b95e3d5c826626cf46d8e74bc93b17f\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x60e060405234801561001057600080fd5b506040516128e23803806128e283398181016040528101906100329190610265565b6040518060400160405280600c81526020017f53656572204372656469747300000000000000000000000000000000000000008152506040518060400160405280600c81526020017f534545525f435245444954530000000000000000000000000000000000000000815250601282600090816100af91906104e2565b5081600190816100bf91906104e2565b508060ff1660808160ff16815250504660a081815250506100e461017660201b60201c565b60c0818152505050505080600660006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600760006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506106f8565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60006040516101a89190610657565b60405180910390207fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc646306040516020016101e79594939291906106a5565b60405160208183030381529060405280519060200120905090565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061023282610207565b9050919050565b61024281610227565b811461024d57600080fd5b50565b60008151905061025f81610239565b92915050565b60006020828403121561027b5761027a610202565b5b600061028984828501610250565b91505092915050565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061031357607f821691505b602082108103610326576103256102cc565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b60006008830261038e7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82610351565b6103988683610351565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b60006103df6103da6103d5846103b0565b6103ba565b6103b0565b9050919050565b6000819050919050565b6103f9836103c4565b61040d610405826103e6565b84845461035e565b825550505050565b600090565b610422610415565b61042d8184846103f0565b505050565b5b818110156104515761044660008261041a565b600181019050610433565b5050565b601f821115610496576104678161032c565b61047084610341565b8101602085101561047f578190505b61049361048b85610341565b830182610432565b50505b505050565b600082821c905092915050565b60006104b96000198460080261049b565b1980831691505092915050565b60006104d283836104a8565b9150826002028217905092915050565b6104eb82610292565b67ffffffffffffffff8111156105045761050361029d565b5b61050e82546102fb565b610519828285610455565b600060209050601f83116001811461054c576000841561053a578287015190505b61054485826104c6565b8655506105ac565b601f19841661055a8661032c565b60005b828110156105825784890151825560018201915060208501945060208101905061055d565b8683101561059f578489015161059b601f8916826104a8565b8355505b6001600288020188555050505b505050505050565b600081905092915050565b60008190508160005260206000209050919050565b600081546105e1816102fb565b6105eb81866105b4565b94506001821660008114610606576001811461061b5761064e565b60ff198316865281151582028601935061064e565b610624856105bf565b60005b8381101561064657815481890152600182019150602081019050610627565b838801955050505b50505092915050565b600061066382846105d4565b915081905092915050565b6000819050919050565b6106818161066e565b82525050565b610690816103b0565b82525050565b61069f81610227565b82525050565b600060a0820190506106ba6000830188610678565b6106c76020830187610678565b6106d46040830186610678565b6106e16060830185610687565b6106ee6080830184610696565b9695505050505050565b60805160a05160c0516121bb610727600039600061083801526000610804015260006107de01526121bb6000f3fe608060405234801561001057600080fd5b50600436106101215760003560e01c806370a08231116100ad578063aa425cbb11610071578063aa425cbb14610320578063d505accf1461033c578063dd62ed3e14610358578063e4c0aaf414610388578063e60cb498146103a457610121565b806370a08231146102565780637ecebe001461028657806395d89b41146102b65780639dc29fac146102d4578063a9059cbb146102f057610121565b806318160ddd116100f457806318160ddd146101b057806323b872dd146101ce578063313ce567146101fe5780633644e5151461021c57806340c10f191461023a57610121565b806306fdde0314610126578063095ea7b3146101445780630c340a241461017457806315fa932a14610192575b600080fd5b61012e6103c0565b60405161013b9190611517565b60405180910390f35b61015e600480360381019061015991906115e1565b61044e565b60405161016b919061163c565b60405180910390f35b61017c610540565b6040516101899190611666565b60405180910390f35b61019a610566565b6040516101a79190611666565b60405180910390f35b6101b861058c565b6040516101c59190611690565b60405180910390f35b6101e860048036038101906101e391906116ab565b610592565b6040516101f5919061163c565b60405180910390f35b6102066107dc565b604051610213919061171a565b60405180910390f35b610224610800565b604051610231919061174e565b60405180910390f35b610254600480360381019061024f91906115e1565b61085d565b005b610270600480360381019061026b9190611769565b6108fb565b60405161027d9190611690565b60405180910390f35b6102a0600480360381019061029b9190611769565b610913565b6040516102ad9190611690565b60405180910390f35b6102be61092b565b6040516102cb9190611517565b60405180910390f35b6102ee60048036038101906102e991906115e1565b6109b9565b005b61030a600480360381019061030591906115e1565b610a57565b604051610317919061163c565b60405180910390f35b61033a600480360381019061033591906119a1565b610b6b565b005b61035660048036038101906103519190611a71565b610d95565b005b610372600480360381019061036d9190611b13565b61108e565b60405161037f9190611690565b60405180910390f35b6103a2600480360381019061039d9190611769565b6110b3565b005b6103be60048036038101906103b99190611769565b611187565b005b600080546103cd90611b82565b80601f01602080910402602001604051908101604052809291908181526020018280546103f990611b82565b80156104465780601f1061041b57610100808354040283529160200191610446565b820191906000526020600020905b81548152906001019060200180831161042957829003601f168201915b505050505081565b600081600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405161052e9190611690565b60405180910390a36001905092915050565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60025481565b600080600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146106c85782816106479190611be2565b600460008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b82600360008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546107179190611be2565b9250508190555082600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040516107c89190611690565b60405180910390a360019150509392505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60007f000000000000000000000000000000000000000000000000000000000000000046146108365761083161125b565b610858565b7f00000000000000000000000000000000000000000000000000000000000000005b905090565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146108ed576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e490611c88565b60405180910390fd5b6108f782826112e7565b5050565b60036020528060005260406000206000915090505481565b60056020528060005260406000206000915090505481565b6001805461093890611b82565b80601f016020809104026020016040519081016040528092919081815260200182805461096490611b82565b80156109b15780601f10610986576101008083540402835291602001916109b1565b820191906000526020600020905b81548152906001019060200180831161099457829003601f168201915b505050505081565b600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610a49576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a4090611d1a565b60405180910390fd5b610a5382826113b7565b5050565b600081600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254610aa89190611be2565b9250508190555081600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610b599190611690565b60405180910390a36001905092915050565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610bfb576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bf290611c88565b60405180910390fd5b8051825114610c3f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c3690611d86565b60405180910390fd5b60005b8251811015610d905760003073ffffffffffffffffffffffffffffffffffffffff166370a08231858481518110610c7c57610c7b611da6565b5b60200260200101516040518263ffffffff1660e01b8152600401610ca09190611666565b602060405180830381865afa158015610cbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ce19190611dea565b90506000838381518110610cf857610cf7611da6565b5b6020026020010151905080821115610d445760008183610d189190611be2565b9050610d3e868581518110610d3057610d2f611da6565b5b6020026020010151826113b7565b50610d83565b81811115610d825760008282610d5a9190611be2565b9050610d80868581518110610d7257610d71611da6565b5b6020026020010151826112e7565b505b5b5050806001019050610c42565b505050565b42841015610dd8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610dcf90611e63565b60405180910390fd5b60006001610de4610800565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98a8a8a600560008f73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000815480929190600101919050558b604051602001610e6c96959493929190611e83565b60405160208183030381529060405280519060200120604051602001610e93929190611f5c565b6040516020818303038152906040528051906020012085858560405160008152602001604052604051610ec99493929190611f93565b6020604051602081039080840390855afa158015610eeb573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614158015610f5f57508773ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b610f9e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f9590612024565b60405180910390fd5b85600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550508573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258760405161107d9190611690565b60405180910390a350505050505050565b6004602052816000526040600020602052806000526040600020600091509150505481565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611143576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161113a90611c88565b60405180910390fd5b80600660006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611217576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161120e90611c88565b60405180910390fd5b80600760006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f600060405161128d91906120e7565b60405180910390207fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc646306040516020016112cc9594939291906120fe565b60405160208183030381529060405280519060200120905090565b80600260008282546112f99190612151565b9250508190555080600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516113ab9190611690565b60405180910390a35050565b80600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546114069190611be2565b9250508190555080600260008282540392505081905550600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161147b9190611690565b60405180910390a35050565b600081519050919050565b600082825260208201905092915050565b60005b838110156114c15780820151818401526020810190506114a6565b60008484015250505050565b6000601f19601f8301169050919050565b60006114e982611487565b6114f38185611492565b93506115038185602086016114a3565b61150c816114cd565b840191505092915050565b6000602082019050818103600083015261153181846114de565b905092915050565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006115788261154d565b9050919050565b6115888161156d565b811461159357600080fd5b50565b6000813590506115a58161157f565b92915050565b6000819050919050565b6115be816115ab565b81146115c957600080fd5b50565b6000813590506115db816115b5565b92915050565b600080604083850312156115f8576115f7611543565b5b600061160685828601611596565b9250506020611617858286016115cc565b9150509250929050565b60008115159050919050565b61163681611621565b82525050565b6000602082019050611651600083018461162d565b92915050565b6116608161156d565b82525050565b600060208201905061167b6000830184611657565b92915050565b61168a816115ab565b82525050565b60006020820190506116a56000830184611681565b92915050565b6000806000606084860312156116c4576116c3611543565b5b60006116d286828701611596565b93505060206116e386828701611596565b92505060406116f4868287016115cc565b9150509250925092565b600060ff82169050919050565b611714816116fe565b82525050565b600060208201905061172f600083018461170b565b92915050565b6000819050919050565b61174881611735565b82525050565b6000602082019050611763600083018461173f565b92915050565b60006020828403121561177f5761177e611543565b5b600061178d84828501611596565b91505092915050565b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6117d3826114cd565b810181811067ffffffffffffffff821117156117f2576117f161179b565b5b80604052505050565b6000611805611539565b905061181182826117ca565b919050565b600067ffffffffffffffff8211156118315761183061179b565b5b602082029050602081019050919050565b600080fd5b600061185a61185584611816565b6117fb565b9050808382526020820190506020840283018581111561187d5761187c611842565b5b835b818110156118a657806118928882611596565b84526020840193505060208101905061187f565b5050509392505050565b600082601f8301126118c5576118c4611796565b5b81356118d5848260208601611847565b91505092915050565b600067ffffffffffffffff8211156118f9576118f861179b565b5b602082029050602081019050919050565b600061191d611918846118de565b6117fb565b905080838252602082019050602084028301858111156119405761193f611842565b5b835b81811015611969578061195588826115cc565b845260208401935050602081019050611942565b5050509392505050565b600082601f83011261198857611987611796565b5b813561199884826020860161190a565b91505092915050565b600080604083850312156119b8576119b7611543565b5b600083013567ffffffffffffffff8111156119d6576119d5611548565b5b6119e2858286016118b0565b925050602083013567ffffffffffffffff811115611a0357611a02611548565b5b611a0f85828601611973565b9150509250929050565b611a22816116fe565b8114611a2d57600080fd5b50565b600081359050611a3f81611a19565b92915050565b611a4e81611735565b8114611a5957600080fd5b50565b600081359050611a6b81611a45565b92915050565b600080600080600080600060e0888a031215611a9057611a8f611543565b5b6000611a9e8a828b01611596565b9750506020611aaf8a828b01611596565b9650506040611ac08a828b016115cc565b9550506060611ad18a828b016115cc565b9450506080611ae28a828b01611a30565b93505060a0611af38a828b01611a5c565b92505060c0611b048a828b01611a5c565b91505092959891949750929550565b60008060408385031215611b2a57611b29611543565b5b6000611b3885828601611596565b9250506020611b4985828601611596565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680611b9a57607f821691505b602082108103611bad57611bac611b53565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000611bed826115ab565b9150611bf8836115ab565b9250828203905081811115611c1057611c0f611bb3565b5b92915050565b7f4f6e6c7920676f7665726e6f722063616e2063616c6c20746869732066756e6360008201527f74696f6e00000000000000000000000000000000000000000000000000000000602082015250565b6000611c72602483611492565b9150611c7d82611c16565b604082019050919050565b60006020820190508181036000830152611ca181611c65565b9050919050565b7f4f6e6c792063726564697473206d616e616765722063616e2063616c6c20746860008201527f69732066756e6374696f6e000000000000000000000000000000000000000000602082015250565b6000611d04602b83611492565b9150611d0f82611ca8565b604082019050919050565b60006020820190508181036000830152611d3381611cf7565b9050919050565b7f417272617973206c656e677468206d69736d6174636800000000000000000000600082015250565b6000611d70601683611492565b9150611d7b82611d3a565b602082019050919050565b60006020820190508181036000830152611d9f81611d63565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600081519050611de4816115b5565b92915050565b600060208284031215611e0057611dff611543565b5b6000611e0e84828501611dd5565b91505092915050565b7f5045524d49545f444541444c494e455f45585049524544000000000000000000600082015250565b6000611e4d601783611492565b9150611e5882611e17565b602082019050919050565b60006020820190508181036000830152611e7c81611e40565b9050919050565b600060c082019050611e98600083018961173f565b611ea56020830188611657565b611eb26040830187611657565b611ebf6060830186611681565b611ecc6080830185611681565b611ed960a0830184611681565b979650505050505050565b600081905092915050565b7f1901000000000000000000000000000000000000000000000000000000000000600082015250565b6000611f25600283611ee4565b9150611f3082611eef565b600282019050919050565b6000819050919050565b611f56611f5182611735565b611f3b565b82525050565b6000611f6782611f18565b9150611f738285611f45565b602082019150611f838284611f45565b6020820191508190509392505050565b6000608082019050611fa8600083018761173f565b611fb5602083018661170b565b611fc2604083018561173f565b611fcf606083018461173f565b95945050505050565b7f494e56414c49445f5349474e4552000000000000000000000000000000000000600082015250565b600061200e600e83611492565b915061201982611fd8565b602082019050919050565b6000602082019050818103600083015261203d81612001565b9050919050565b600081905092915050565b60008190508160005260206000209050919050565b6000815461207181611b82565b61207b8186612044565b9450600182166000811461209657600181146120ab576120de565b60ff19831686528115158202860193506120de565b6120b48561204f565b60005b838110156120d6578154818901526001820191506020810190506120b7565b838801955050505b50505092915050565b60006120f38284612064565b915081905092915050565b600060a082019050612113600083018861173f565b612120602083018761173f565b61212d604083018661173f565b61213a6060830185611681565b6121476080830184611657565b9695505050505050565b600061215c826115ab565b9150612167836115ab565b925082820190508082111561217f5761217e611bb3565b5b9291505056fea2646970667358221220f5c145f96cde2d6b38a0ab3bc709b26a257fda13bcc2ec52a5531cc641c540fd64736f6c634300081c0033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106101215760003560e01c806370a08231116100ad578063aa425cbb11610071578063aa425cbb14610320578063d505accf1461033c578063dd62ed3e14610358578063e4c0aaf414610388578063e60cb498146103a457610121565b806370a08231146102565780637ecebe001461028657806395d89b41146102b65780639dc29fac146102d4578063a9059cbb146102f057610121565b806318160ddd116100f457806318160ddd146101b057806323b872dd146101ce578063313ce567146101fe5780633644e5151461021c57806340c10f191461023a57610121565b806306fdde0314610126578063095ea7b3146101445780630c340a241461017457806315fa932a14610192575b600080fd5b61012e6103c0565b60405161013b9190611517565b60405180910390f35b61015e600480360381019061015991906115e1565b61044e565b60405161016b919061163c565b60405180910390f35b61017c610540565b6040516101899190611666565b60405180910390f35b61019a610566565b6040516101a79190611666565b60405180910390f35b6101b861058c565b6040516101c59190611690565b60405180910390f35b6101e860048036038101906101e391906116ab565b610592565b6040516101f5919061163c565b60405180910390f35b6102066107dc565b604051610213919061171a565b60405180910390f35b610224610800565b604051610231919061174e565b60405180910390f35b610254600480360381019061024f91906115e1565b61085d565b005b610270600480360381019061026b9190611769565b6108fb565b60405161027d9190611690565b60405180910390f35b6102a0600480360381019061029b9190611769565b610913565b6040516102ad9190611690565b60405180910390f35b6102be61092b565b6040516102cb9190611517565b60405180910390f35b6102ee60048036038101906102e991906115e1565b6109b9565b005b61030a600480360381019061030591906115e1565b610a57565b604051610317919061163c565b60405180910390f35b61033a600480360381019061033591906119a1565b610b6b565b005b61035660048036038101906103519190611a71565b610d95565b005b610372600480360381019061036d9190611b13565b61108e565b60405161037f9190611690565b60405180910390f35b6103a2600480360381019061039d9190611769565b6110b3565b005b6103be60048036038101906103b99190611769565b611187565b005b600080546103cd90611b82565b80601f01602080910402602001604051908101604052809291908181526020018280546103f990611b82565b80156104465780601f1061041b57610100808354040283529160200191610446565b820191906000526020600020905b81548152906001019060200180831161042957829003601f168201915b505050505081565b600081600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405161052e9190611690565b60405180910390a36001905092915050565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60025481565b600080600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146106c85782816106479190611be2565b600460008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b82600360008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546107179190611be2565b9250508190555082600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040516107c89190611690565b60405180910390a360019150509392505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60007f000000000000000000000000000000000000000000000000000000000000000046146108365761083161125b565b610858565b7f00000000000000000000000000000000000000000000000000000000000000005b905090565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146108ed576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e490611c88565b60405180910390fd5b6108f782826112e7565b5050565b60036020528060005260406000206000915090505481565b60056020528060005260406000206000915090505481565b6001805461093890611b82565b80601f016020809104026020016040519081016040528092919081815260200182805461096490611b82565b80156109b15780601f10610986576101008083540402835291602001916109b1565b820191906000526020600020905b81548152906001019060200180831161099457829003601f168201915b505050505081565b600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610a49576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a4090611d1a565b60405180910390fd5b610a5382826113b7565b5050565b600081600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254610aa89190611be2565b9250508190555081600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610b599190611690565b60405180910390a36001905092915050565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610bfb576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bf290611c88565b60405180910390fd5b8051825114610c3f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c3690611d86565b60405180910390fd5b60005b8251811015610d905760003073ffffffffffffffffffffffffffffffffffffffff166370a08231858481518110610c7c57610c7b611da6565b5b60200260200101516040518263ffffffff1660e01b8152600401610ca09190611666565b602060405180830381865afa158015610cbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ce19190611dea565b90506000838381518110610cf857610cf7611da6565b5b6020026020010151905080821115610d445760008183610d189190611be2565b9050610d3e868581518110610d3057610d2f611da6565b5b6020026020010151826113b7565b50610d83565b81811115610d825760008282610d5a9190611be2565b9050610d80868581518110610d7257610d71611da6565b5b6020026020010151826112e7565b505b5b5050806001019050610c42565b505050565b42841015610dd8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610dcf90611e63565b60405180910390fd5b60006001610de4610800565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98a8a8a600560008f73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000815480929190600101919050558b604051602001610e6c96959493929190611e83565b60405160208183030381529060405280519060200120604051602001610e93929190611f5c565b6040516020818303038152906040528051906020012085858560405160008152602001604052604051610ec99493929190611f93565b6020604051602081039080840390855afa158015610eeb573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614158015610f5f57508773ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b610f9e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f9590612024565b60405180910390fd5b85600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550508573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258760405161107d9190611690565b60405180910390a350505050505050565b6004602052816000526040600020602052806000526040600020600091509150505481565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611143576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161113a90611c88565b60405180910390fd5b80600660006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611217576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161120e90611c88565b60405180910390fd5b80600760006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f600060405161128d91906120e7565b60405180910390207fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc646306040516020016112cc9594939291906120fe565b60405160208183030381529060405280519060200120905090565b80600260008282546112f99190612151565b9250508190555080600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516113ab9190611690565b60405180910390a35050565b80600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546114069190611be2565b9250508190555080600260008282540392505081905550600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161147b9190611690565b60405180910390a35050565b600081519050919050565b600082825260208201905092915050565b60005b838110156114c15780820151818401526020810190506114a6565b60008484015250505050565b6000601f19601f8301169050919050565b60006114e982611487565b6114f38185611492565b93506115038185602086016114a3565b61150c816114cd565b840191505092915050565b6000602082019050818103600083015261153181846114de565b905092915050565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006115788261154d565b9050919050565b6115888161156d565b811461159357600080fd5b50565b6000813590506115a58161157f565b92915050565b6000819050919050565b6115be816115ab565b81146115c957600080fd5b50565b6000813590506115db816115b5565b92915050565b600080604083850312156115f8576115f7611543565b5b600061160685828601611596565b9250506020611617858286016115cc565b9150509250929050565b60008115159050919050565b61163681611621565b82525050565b6000602082019050611651600083018461162d565b92915050565b6116608161156d565b82525050565b600060208201905061167b6000830184611657565b92915050565b61168a816115ab565b82525050565b60006020820190506116a56000830184611681565b92915050565b6000806000606084860312156116c4576116c3611543565b5b60006116d286828701611596565b93505060206116e386828701611596565b92505060406116f4868287016115cc565b9150509250925092565b600060ff82169050919050565b611714816116fe565b82525050565b600060208201905061172f600083018461170b565b92915050565b6000819050919050565b61174881611735565b82525050565b6000602082019050611763600083018461173f565b92915050565b60006020828403121561177f5761177e611543565b5b600061178d84828501611596565b91505092915050565b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6117d3826114cd565b810181811067ffffffffffffffff821117156117f2576117f161179b565b5b80604052505050565b6000611805611539565b905061181182826117ca565b919050565b600067ffffffffffffffff8211156118315761183061179b565b5b602082029050602081019050919050565b600080fd5b600061185a61185584611816565b6117fb565b9050808382526020820190506020840283018581111561187d5761187c611842565b5b835b818110156118a657806118928882611596565b84526020840193505060208101905061187f565b5050509392505050565b600082601f8301126118c5576118c4611796565b5b81356118d5848260208601611847565b91505092915050565b600067ffffffffffffffff8211156118f9576118f861179b565b5b602082029050602081019050919050565b600061191d611918846118de565b6117fb565b905080838252602082019050602084028301858111156119405761193f611842565b5b835b81811015611969578061195588826115cc565b845260208401935050602081019050611942565b5050509392505050565b600082601f83011261198857611987611796565b5b813561199884826020860161190a565b91505092915050565b600080604083850312156119b8576119b7611543565b5b600083013567ffffffffffffffff8111156119d6576119d5611548565b5b6119e2858286016118b0565b925050602083013567ffffffffffffffff811115611a0357611a02611548565b5b611a0f85828601611973565b9150509250929050565b611a22816116fe565b8114611a2d57600080fd5b50565b600081359050611a3f81611a19565b92915050565b611a4e81611735565b8114611a5957600080fd5b50565b600081359050611a6b81611a45565b92915050565b600080600080600080600060e0888a031215611a9057611a8f611543565b5b6000611a9e8a828b01611596565b9750506020611aaf8a828b01611596565b9650506040611ac08a828b016115cc565b9550506060611ad18a828b016115cc565b9450506080611ae28a828b01611a30565b93505060a0611af38a828b01611a5c565b92505060c0611b048a828b01611a5c565b91505092959891949750929550565b60008060408385031215611b2a57611b29611543565b5b6000611b3885828601611596565b9250506020611b4985828601611596565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680611b9a57607f821691505b602082108103611bad57611bac611b53565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000611bed826115ab565b9150611bf8836115ab565b9250828203905081811115611c1057611c0f611bb3565b5b92915050565b7f4f6e6c7920676f7665726e6f722063616e2063616c6c20746869732066756e6360008201527f74696f6e00000000000000000000000000000000000000000000000000000000602082015250565b6000611c72602483611492565b9150611c7d82611c16565b604082019050919050565b60006020820190508181036000830152611ca181611c65565b9050919050565b7f4f6e6c792063726564697473206d616e616765722063616e2063616c6c20746860008201527f69732066756e6374696f6e000000000000000000000000000000000000000000602082015250565b6000611d04602b83611492565b9150611d0f82611ca8565b604082019050919050565b60006020820190508181036000830152611d3381611cf7565b9050919050565b7f417272617973206c656e677468206d69736d6174636800000000000000000000600082015250565b6000611d70601683611492565b9150611d7b82611d3a565b602082019050919050565b60006020820190508181036000830152611d9f81611d63565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600081519050611de4816115b5565b92915050565b600060208284031215611e0057611dff611543565b5b6000611e0e84828501611dd5565b91505092915050565b7f5045524d49545f444541444c494e455f45585049524544000000000000000000600082015250565b6000611e4d601783611492565b9150611e5882611e17565b602082019050919050565b60006020820190508181036000830152611e7c81611e40565b9050919050565b600060c082019050611e98600083018961173f565b611ea56020830188611657565b611eb26040830187611657565b611ebf6060830186611681565b611ecc6080830185611681565b611ed960a0830184611681565b979650505050505050565b600081905092915050565b7f1901000000000000000000000000000000000000000000000000000000000000600082015250565b6000611f25600283611ee4565b9150611f3082611eef565b600282019050919050565b6000819050919050565b611f56611f5182611735565b611f3b565b82525050565b6000611f6782611f18565b9150611f738285611f45565b602082019150611f838284611f45565b6020820191508190509392505050565b6000608082019050611fa8600083018761173f565b611fb5602083018661170b565b611fc2604083018561173f565b611fcf606083018461173f565b95945050505050565b7f494e56414c49445f5349474e4552000000000000000000000000000000000000600082015250565b600061200e600e83611492565b915061201982611fd8565b602082019050919050565b6000602082019050818103600083015261203d81612001565b9050919050565b600081905092915050565b60008190508160005260206000209050919050565b6000815461207181611b82565b61207b8186612044565b9450600182166000811461209657600181146120ab576120de565b60ff19831686528115158202860193506120de565b6120b48561204f565b60005b838110156120d6578154818901526001820191506020810190506120b7565b838801955050505b50505092915050565b60006120f38284612064565b915081905092915050565b600060a082019050612113600083018861173f565b612120602083018761173f565b61212d604083018661173f565b61213a6060830185611681565b6121476080830184611657565b9695505050505050565b600061215c826115ab565b9150612167836115ab565b925082820190508082111561217f5761217e611bb3565b5b9291505056fea2646970667358221220f5c145f96cde2d6b38a0ab3bc709b26a257fda13bcc2ec52a5531cc641c540fd64736f6c634300081c0033", + "devdoc": { + "kind": "dev", + "methods": { + "changeCreditsManager(address)": { + "details": "Change the credits manager of the contract.", + "params": { + "_creditsManager": "The address of the new credits manager." + } + }, + "changeGovernor(address)": { + "details": "Change the governor of the contract.", + "params": { + "_governor": "The address of the new governor." + } + }, + "constructor": { + "details": "Constructor.", + "params": { + "_governor": "The trusted governor of the contract." + } + }, + "setCreditsBalance(address[],uint256[])": { + "details": "Set credits balance for multiple addresses by minting or burning as needed.", + "params": { + "_addresses": "The list of addresses to set credits balance for.", + "_amounts": "The list of amounts corresponding to each address." + } + } + }, + "title": "SeerCredits", + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": {}, + "notice": "ERC20 token representing trading credits that users can spend on DEX swaps", + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 20, + "contract": "src/trading-credits/SeerCredits.sol:SeerCredits", + "label": "name", + "offset": 0, + "slot": "0", + "type": "t_string_storage" + }, + { + "astId": 22, + "contract": "src/trading-credits/SeerCredits.sol:SeerCredits", + "label": "symbol", + "offset": 0, + "slot": "1", + "type": "t_string_storage" + }, + { + "astId": 26, + "contract": "src/trading-credits/SeerCredits.sol:SeerCredits", + "label": "totalSupply", + "offset": 0, + "slot": "2", + "type": "t_uint256" + }, + { + "astId": 30, + "contract": "src/trading-credits/SeerCredits.sol:SeerCredits", + "label": "balanceOf", + "offset": 0, + "slot": "3", + "type": "t_mapping(t_address,t_uint256)" + }, + { + "astId": 36, + "contract": "src/trading-credits/SeerCredits.sol:SeerCredits", + "label": "allowance", + "offset": 0, + "slot": "4", + "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))" + }, + { + "astId": 44, + "contract": "src/trading-credits/SeerCredits.sol:SeerCredits", + "label": "nonces", + "offset": 0, + "slot": "5", + "type": "t_mapping(t_address,t_uint256)" + }, + { + "astId": 652, + "contract": "src/trading-credits/SeerCredits.sol:SeerCredits", + "label": "governor", + "offset": 0, + "slot": "6", + "type": "t_address" + }, + { + "astId": 654, + "contract": "src/trading-credits/SeerCredits.sol:SeerCredits", + "label": "creditsManager", + "offset": 0, + "slot": "7", + "type": "t_address" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_mapping(t_address,t_mapping(t_address,t_uint256))": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => mapping(address => uint256))", + "numberOfBytes": "32", + "value": "t_mapping(t_address,t_uint256)" + }, + "t_mapping(t_address,t_uint256)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => uint256)", + "numberOfBytes": "32", + "value": "t_uint256" + }, + "t_string_storage": { + "encoding": "bytes", + "label": "string", + "numberOfBytes": "32" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + } + } + } +} \ No newline at end of file diff --git a/contracts/package.json b/contracts/package.json index 17feb20c..b22de68c 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -5,7 +5,7 @@ "hhf:mainnet": "npx hardhat node --fork https://eth-pokt.nodies.app --no-deploy --config mainnetforked.config.ts", "hhf:gnosis": "npx hardhat node --fork https://gnosis-pokt.nodies.app --port 8546 --no-deploy --config gnosisforked.config.ts", "hh-local-deploy": "npx hardhat deploy --network localhost && cp -r deployments/localhost/*.json deployments/hardhat && cd ../web && yarn wagmi generate", - "verify:gnosis": "npx hardhat --network gnosis etherscan-verify --api-url https://api.gnosisscan.io", + "verify:gnosis": "npx hardhat --network gnosis etherscan-verify --api-url https://api.etherscan.io/v2/api?chainid=100", "verify:optimism": "npx hardhat --network optimism etherscan-verify --api-url https://api.etherscan.io/v2/api?chainid=10", "verify:base": "npx hardhat --network base etherscan-verify --api-url https://api.etherscan.io/v2/api?chainid=8453", "verify:ethereum": "npx hardhat --network ethereum etherscan-verify", diff --git a/contracts/scripts/trading-credits.js b/contracts/scripts/trading-credits.js new file mode 100644 index 00000000..f976fa2f --- /dev/null +++ b/contracts/scripts/trading-credits.js @@ -0,0 +1,100 @@ +/** + * CreditsManager Management Script + * + * This script allows you to interact with the CreditsManager contract to: + * - Set credits balance for multiple addresses + * - Add/remove contracts from the whitelist + * - Add/remove output tokens from the whitelist + * + * Usage: + * 1. Modify the configuration object below with your desired addresses and amounts + * 2. Leave objects empty or strings empty to skip those actions + * 3. Run: npx hardhat run scripts/credits-manager.js --network + * + * Example networks: localhost, hardhat, gnosis, ethereum, etc. + * + * To skip an action: + * - Leave credits object empty to skip setCreditsBalance + * - Leave contractToWhitelist empty to skip setWhitelistedContract + */ + +const { ethers } = require("hardhat"); + +async function main() { + // Configuration - modify these values as needed + const config = { + // Set credits for addresses (leave empty object to skip this action) + // amounts are in decimal units (e.g., "1" = 1 token, "0.5" = 0.5 tokens) + credits: { + "0x0000000000000000000000000000000000000000": "1", + }, + + // Contract to add to whitelist (leave empty string to skip this action) + contractToWhitelist: "0xfFB643E73f280B97809A8b41f7232AB401a04ee1", + }; + + // Get the CreditsManager contract + const { deployments } = require("hardhat"); + const SeerCreditsDeployment = await deployments.get("SeerCredits"); + const SeerCredits = await ethers.getContractAt("SeerCredits", SeerCreditsDeployment.address); + const CreditsManagerDeployment = await deployments.get("CreditsManager"); + const CreditsManager = await ethers.getContractAt("CreditsManager", CreditsManagerDeployment.address); + const [deployer] = await ethers.getSigners(); + + console.log("Using account:", deployer.address); + console.log("SeerCredits contract:", SeerCredits.address); + console.log("CreditsManager contract:", CreditsManager.address); + console.log("Account balance:", ethers.formatEther(await deployer.provider.getBalance(deployer.address)), "ETH"); + + // Set credits balance (only if credits object has entries) + if (Object.keys(config.credits).length > 0) { + console.log("\n=== Setting Credits Balance ==="); + + // Convert credits object to arrays for the contract call + const addresses = Object.keys(config.credits); + const amounts = Object.values(config.credits); + + console.log("Credits to set:"); + addresses.forEach((address, index) => { + console.log(` ${address}: ${amounts[index]} tokens`); + }); + + try { + // Convert amounts from decimal to wei + const amountsInWei = amounts.map(amount => ethers.parseEther(amount)); + + const tx = await SeerCredits.setCreditsBalance(addresses, amountsInWei); + console.log("Transaction hash:", tx.hash); + await tx.wait(); + console.log("✅ Credits balance set successfully!"); + } catch (error) { + console.error("❌ Error setting credits balance:", error.message); + } + } else { + console.log("⏭️ Skipping setCreditsBalance - no credits provided"); + } + + // Add contract to whitelist (only if contractToWhitelist is provided) + if (config.contractToWhitelist && config.contractToWhitelist.trim() !== "") { + console.log("\n=== Adding Contract to Whitelist ==="); + console.log("Contract address:", config.contractToWhitelist); + + try { + const tx = await CreditsManager.setWhitelistedContract(config.contractToWhitelist, true); + console.log("Transaction hash:", tx.hash); + await tx.wait(); + console.log("✅ Contract added to whitelist successfully!"); + } catch (error) { + console.error("❌ Error adding contract to whitelist:", error.message); + } + } else { + console.log("⏭️ Skipping setWhitelistedContract - no contract address provided"); + } +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); diff --git a/contracts/src/trading-credits/CreditsManager.sol b/contracts/src/trading-credits/CreditsManager.sol new file mode 100644 index 00000000..4be97fd8 --- /dev/null +++ b/contracts/src/trading-credits/CreditsManager.sol @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.28; + +import {ERC20} from "solmate/src/tokens/ERC20.sol"; +import "./SeerCredits.sol"; + +/// @title CreditsManager +/// @notice This contract acts as a proxy to DEXs (Uniswap, Swapr, etc.) where users can spend trading credits +/// @dev The contract receives an address `to` (expected to be a DEX router) and `data` to execute a swap +/// @dev The swap data must be encoded to send tokens to `msg.sender` +/// @dev CreditsManager pays for the swap on behalf of the user by deducting credits from their balance +contract CreditsManager { + address public governor; // The address that can make governance changes to the parameters of the contract. + ERC20 public token; // The token used to swap from (e.g., sDAI on Gnosis). + SeerCredits public seerCredits; // The SeerCredits token representing trading credits. + mapping(address => bool) public whitelistedContracts; // Whitelist of contracts that can be called. + + modifier onlyGovernor() { + require(msg.sender == governor, "The caller must be the governor"); + _; + } + + /// @dev Constructor. + /// @param _token The ERC20 token used to swap from (e.g., sDAI on Gnosis). TRUSTED + /// @param _seerCredits The SeerCredits token contract. TRUSTED + constructor(ERC20 _token, SeerCredits _seerCredits) { + governor = msg.sender; + token = _token; + seerCredits = _seerCredits; + } + + /// @dev Change the governor of the contract. + /// @param _governor The address of the new governor. TRUSTED + function changeGovernor(address _governor) external onlyGovernor { + governor = _governor; + } + + + /// @dev Add or remove a contract from the whitelist. + /// @param _contract The address of the contract to modify. + /// @param _whitelisted True to add to whitelist, false to remove. + function setWhitelistedContract(address _contract, bool _whitelisted) external onlyGovernor { + whitelistedContracts[_contract] = _whitelisted; + } + + + /// @dev Check if a user can spend a specific amount of credits. + /// @param _user The address of the user to check. + /// @param _amount The amount of credits to check. + /// @return True if the user can spend the specified amount of credits. + function canSpendCredits(address _user, uint256 _amount) external view returns (bool) { + // Check if user has enough SeerCredits + if (seerCredits.balanceOf(_user) < _amount) { + return false; + } + + // Check if contract has enough token balance + if (token.balanceOf(address(this)) < _amount) { + return false; + } + + return true; + } + + /// @dev Sweep all tokens from the contract to the governor. + /// @param _token The token to sweep. If address(0), uses the default token. + function sweepTokens(ERC20 _token) external onlyGovernor { + ERC20 tokenToSweep = _token == ERC20(address(0)) ? token : _token; + uint256 balance = tokenToSweep.balanceOf(address(this)); + require(balance > 0, "No tokens to sweep"); + require(tokenToSweep.transfer(governor, balance), "Token transfer failed"); + } + + /// @dev Execute a swap through a DEX router (Uniswap, Swapr, etc.). CreditsManager pays for the swap. + /// @param to The DEX router address (must be whitelisted). + /// @param data The encoded swap call data. Must be encoded to send output tokens to msg.sender. + /// @param amount The amount of credits to spend (tokens approved to the DEX router). + /// @param outputToken The token that the user is buying (must have increased balance after swap). + /// @notice This function acts as a proxy - CreditsManager pays for the swap by deducting credits from user's balance. + function execute(address to, bytes calldata data, uint256 amount, ERC20 outputToken) external { + require(whitelistedContracts[to], "Contract not whitelisted"); + require(seerCredits.balanceOf(msg.sender) >= amount, "Insufficient credits balance"); + + // Check user's balance of output token before the swap + uint256 balanceBefore = outputToken.balanceOf(msg.sender); + + // CreditsManager approves tokens to the DEX router (e.g., Uniswap, Swapr) + require(token.approve(to, amount), "Token approval failed"); + + // Burn SeerCredits from user's balance - CreditsManager is paying for the swap + seerCredits.burn(msg.sender, amount); + + // Execute the swap call to the DEX router + // The swap data must be encoded to send output tokens to msg.sender + (bool success,) = to.call(data); + require(success, "Call failed"); + + // Verify that the user received tokens (balance increased) + // This is a security measure to verify that the swap had msg.sender as recipient, + // otherwise the swap recipient would be CreditsManager itself + uint256 balanceAfter = outputToken.balanceOf(msg.sender); + require(balanceAfter > balanceBefore, "No tokens received from swap"); + } +} diff --git a/contracts/src/trading-credits/SeerCredits.sol b/contracts/src/trading-credits/SeerCredits.sol new file mode 100644 index 00000000..010c1771 --- /dev/null +++ b/contracts/src/trading-credits/SeerCredits.sol @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.28; + +import {ERC20} from "solmate/src/tokens/ERC20.sol"; + +/// @title SeerCredits +/// @notice ERC20 token representing trading credits that users can spend on DEX swaps +contract SeerCredits is ERC20 { + address public governor; // The address that can make governance changes to the parameters of the contract. + address public creditsManager; // The address that can burn tokens (CreditsManager contract). + + modifier onlyGovernor() { + require(msg.sender == governor, "Only governor can call this function"); + _; + } + + modifier onlyCreditsManager() { + require(msg.sender == creditsManager, "Only credits manager can call this function"); + _; + } + + /// @dev Constructor. + /// @param _governor The trusted governor of the contract. + constructor(address _governor) ERC20("Seer Credits", "SEER_CREDITS", 18) { + governor = _governor; + creditsManager = _governor; + } + + /// @dev Change the governor of the contract. + /// @param _governor The address of the new governor. + function changeGovernor(address _governor) external onlyGovernor { + governor = _governor; + } + + /// @dev Change the credits manager of the contract. + /// @param _creditsManager The address of the new credits manager. + function changeCreditsManager(address _creditsManager) external onlyGovernor { + creditsManager = _creditsManager; + } + + function mint(address to, uint256 amount) external onlyGovernor { + _mint(to, amount); + } + + function burn(address from, uint256 amount) external onlyCreditsManager { + _burn(from, amount); + } + + + /// @dev Set credits balance for multiple addresses by minting or burning as needed. + /// @param _addresses The list of addresses to set credits balance for. + /// @param _amounts The list of amounts corresponding to each address. + function setCreditsBalance(address[] memory _addresses, uint256[] memory _amounts) external onlyGovernor { + require(_addresses.length == _amounts.length, "Arrays length mismatch"); + for (uint256 i; i < _addresses.length; ++i) { + uint256 currentBalance = this.balanceOf(_addresses[i]); + uint256 targetBalance = _amounts[i]; + + if (currentBalance > targetBalance) { + // Burn excess tokens + uint256 burnAmount = currentBalance - targetBalance; + _burn(_addresses[i], burnAmount); + } else if (targetBalance > currentBalance) { + // Mint additional tokens + uint256 mintAmount = targetBalance - currentBalance; + _mint(_addresses[i], mintAmount); + } + // If currentBalance == targetBalance, do nothing + } + } +} \ No newline at end of file diff --git a/web/src/components/Market/CollateralDropdown.tsx b/web/src/components/Market/CollateralDropdown.tsx index 370156c9..bdc93f32 100644 --- a/web/src/components/Market/CollateralDropdown.tsx +++ b/web/src/components/Market/CollateralDropdown.tsx @@ -1,3 +1,4 @@ +import { seerCreditsAddress } from "@/hooks/contracts/generated-trading-credits"; import { useTokensInfo } from "@/hooks/useTokenInfo"; import { COLLATERAL_TOKENS } from "@/lib/config"; import { ArrowDropDown } from "@/lib/icons"; @@ -14,9 +15,10 @@ type CollateralDropdownProps = { market: Market; selectedCollateral: Token; setSelectedCollateral: (selectedCollateral: Token) => void; + type: "buy" | "sell"; }; -function getCollateralOptions(market: Market): Address[] { +function getCollateralOptions(market: Market, type: "buy" | "sell"): Address[] { if (market.type === "Futarchy") { return [market.collateralToken1, market.collateralToken2]; } @@ -31,6 +33,10 @@ function getCollateralOptions(market: Market): Address[] { options.push(COLLATERAL_TOKENS[market.chainId].secondary?.wrapped!.address!); } + if (type === "sell" && market.chainId in seerCreditsAddress) { + options.push(seerCreditsAddress[market.chainId as keyof typeof seerCreditsAddress]); + } + // TODO: allow to swap using multple alternative tokens /* if (COLLATERAL_TOKENS[market.chainId].swap) { options.push(...COLLATERAL_TOKENS[market.chainId].swap!.map(t => t.address)); @@ -42,7 +48,7 @@ function getCollateralOptions(market: Market): Address[] { const CollateralDropdown = (props: CollateralDropdownProps) => { const { market, selectedCollateral, setSelectedCollateral } = props; - const { data: collateralTokens } = useTokensInfo(getCollateralOptions(market), market.chainId); + const { data: collateralTokens } = useTokensInfo(getCollateralOptions(market, props.type), market.chainId); const [isOpen, setIsOpen] = useState(false); if (market.parentMarket.id !== zeroAddress || !collateralTokens || collateralTokens.length === 0) { diff --git a/web/src/components/Market/SwapTokens/SwapTokensConfirmation.tsx b/web/src/components/Market/SwapTokens/SwapTokensConfirmation.tsx index f100cbdb..a0bb664e 100644 --- a/web/src/components/Market/SwapTokens/SwapTokensConfirmation.tsx +++ b/web/src/components/Market/SwapTokens/SwapTokensConfirmation.tsx @@ -20,6 +20,7 @@ interface SwapTokensConfirmationProps { originalAmount: string; isBuyExactOutputNative: boolean; isSellToNative: boolean; + isSeerCredits: boolean; } export function SwapTokensConfirmation({ @@ -30,6 +31,7 @@ export function SwapTokensConfirmation({ collateral, isBuyExactOutputNative, isSellToNative, + isSeerCredits, }: SwapTokensConfirmationProps) { const [isInvertedPrice, toggleInvertedPrice] = useState(false); const tradeInfo = useGetTradeInfo(trade); @@ -76,7 +78,7 @@ export function SwapTokensConfirmation({

- {inputAmount} {inputToken} + {inputAmount} {isSeerCredits ? "SEER_CREDITS" : inputToken}

diff --git a/web/src/components/Market/SwapTokens/SwapTokensLimitUpTo.tsx b/web/src/components/Market/SwapTokens/SwapTokensLimitUpTo.tsx index fe5f0fa5..2dcb48e8 100644 --- a/web/src/components/Market/SwapTokens/SwapTokensLimitUpTo.tsx +++ b/web/src/components/Market/SwapTokens/SwapTokensLimitUpTo.tsx @@ -7,7 +7,7 @@ import { useTradeConditions } from "@/hooks/trade/useTradeConditions"; import useDebounce from "@/hooks/useDebounce"; import { useGlobalState } from "@/hooks/useGlobalState"; import { useModal } from "@/hooks/useModal"; -import { COLLATERAL_TOKENS } from "@/lib/config"; +import { COLLATERAL_TOKENS, isSeerCredits } from "@/lib/config"; import { ArrowSwap, Parameter, QuestionIcon } from "@/lib/icons"; import { FUTARCHY_LP_PAIRS_MAPPING, Market } from "@/lib/market"; import { paths } from "@/lib/paths"; @@ -116,6 +116,7 @@ export function SwapTokensLimitUpto({ outcomeToken, swapType, tradeType, + orderType: "limit", errors, }); @@ -171,6 +172,7 @@ export function SwapTokensLimitUpto({ account: account!, isBuyExactOutputNative, isSellToNative, + isSeerCredits: isSeerCredits(market.chainId, selectedCollateral.address), }); }; @@ -348,6 +350,7 @@ export function SwapTokensLimitUpto({ originalAmount={amount} isBuyExactOutputNative={isBuyExactOutputNative} isSellToNative={isSellToNative} + isSeerCredits={false} /> } /> diff --git a/web/src/components/Market/SwapTokens/SwapTokensMarket.tsx b/web/src/components/Market/SwapTokens/SwapTokensMarket.tsx index 6d06f37a..24bfc924 100644 --- a/web/src/components/Market/SwapTokens/SwapTokensMarket.tsx +++ b/web/src/components/Market/SwapTokens/SwapTokensMarket.tsx @@ -5,7 +5,7 @@ import { useSearchParams } from "@/hooks/useSearchParams"; import { useTradeConditions } from "@/hooks/trade/useTradeConditions"; import { useGlobalState } from "@/hooks/useGlobalState"; -import { COLLATERAL_TOKENS } from "@/lib/config"; +import { COLLATERAL_TOKENS, isSeerCredits } from "@/lib/config"; import { ArrowDown, Parameter, QuestionIcon } from "@/lib/icons"; import { FUTARCHY_LP_PAIRS_MAPPING, Market } from "@/lib/market"; import { paths } from "@/lib/paths"; @@ -173,6 +173,7 @@ export function SwapTokensMarket({ outcomeToken, swapType, tradeType, + orderType: "market", errors, }); @@ -209,6 +210,7 @@ export function SwapTokensMarket({ account: account!, isBuyExactOutputNative, isSellToNative, + isSeerCredits: isSeerCredits(market.chainId, selectedCollateral.address), }); }; @@ -320,6 +322,7 @@ export function SwapTokensMarket({ originalAmount={amount} isBuyExactOutputNative={isBuyExactOutputNative} isSellToNative={isSellToNative} + isSeerCredits={isSeerCredits(market.chainId, selectedCollateral.address)} /> } /> diff --git a/web/src/components/Market/SwapTokens/TokenSelector.tsx b/web/src/components/Market/SwapTokens/TokenSelector.tsx index adc0343e..9598edca 100644 --- a/web/src/components/Market/SwapTokens/TokenSelector.tsx +++ b/web/src/components/Market/SwapTokens/TokenSelector.tsx @@ -42,6 +42,7 @@ export const TokenSelector = ({ return ( setPreferredCollateral(selectedCollateral, market.chainId)} /> diff --git a/web/src/hooks/trade/executeSwaprTrade.ts b/web/src/hooks/trade/executeSwaprTrade.ts index 7a733101..495b3c50 100644 --- a/web/src/hooks/trade/executeSwaprTrade.ts +++ b/web/src/hooks/trade/executeSwaprTrade.ts @@ -5,6 +5,7 @@ import { SwaprV3Trade } from "@swapr/sdk"; import { sendTransaction } from "@wagmi/core"; import { Address, TransactionReceipt, encodeFunctionData, zeroAddress } from "viem"; import { routerAbi } from "./abis"; +import { getWrappedSeerCreditsExecution } from "./utils"; const SWAPR_SWAP_ROUTER = "0xffb643e73f280b97809a8b41f7232ab401a04ee1"; @@ -13,16 +14,19 @@ export async function executeSwaprTrade( account: Address, isBuyExactOutputNative: boolean, isSellToNative: boolean, + isSeerCredits: boolean, ): Promise { - const result = await toastifyTx( - async () => - sendTransaction(config, await getSwaprTradeExecution(trade, account, isBuyExactOutputNative, isSellToNative)), - { - txSent: { title: "Executing trade..." }, - txSuccess: { title: "Trade executed!" }, - }, + const tradeExecution = getWrappedSeerCreditsExecution( + isSeerCredits, + trade, + await getSwaprTradeExecution(trade, account, isBuyExactOutputNative, isSellToNative), ); + const result = await toastifyTx(async () => sendTransaction(config, tradeExecution), { + txSent: { title: "Executing trade..." }, + txSuccess: { title: "Trade executed!" }, + }); + if (!result.status) { throw result.error; } diff --git a/web/src/hooks/trade/executeUniswapTrade.ts b/web/src/hooks/trade/executeUniswapTrade.ts index 4763e2fd..2d9ffb6a 100644 --- a/web/src/hooks/trade/executeUniswapTrade.ts +++ b/web/src/hooks/trade/executeUniswapTrade.ts @@ -4,9 +4,20 @@ import { UniswapTrade } from "@swapr/sdk"; import { sendTransaction } from "@wagmi/core"; import { Address, TransactionReceipt } from "viem"; import { Execution } from "../useCheck7702Support"; +import { getWrappedSeerCreditsExecution } from "./utils"; -export async function executeUniswapTrade(trade: UniswapTrade, account: Address): Promise { - const result = await toastifyTx(async () => sendTransaction(config, await getUniswapTradeExecution(trade, account)), { +export async function executeUniswapTrade( + trade: UniswapTrade, + account: Address, + isSeerCredits: boolean, +): Promise { + const tradeExecution = getWrappedSeerCreditsExecution( + isSeerCredits, + trade, + await getUniswapTradeExecution(trade, account), + ); + + const result = await toastifyTx(async () => sendTransaction(config, tradeExecution), { txSent: { title: "Executing trade..." }, txSuccess: { title: "Trade executed!" }, }); diff --git a/web/src/hooks/trade/index.ts b/web/src/hooks/trade/index.ts index 51f2aa33..a4e3d3dd 100644 --- a/web/src/hooks/trade/index.ts +++ b/web/src/hooks/trade/index.ts @@ -2,6 +2,7 @@ import { createCowOrder, executeCoWTrade } from "@/hooks/trade/executeCowTrade"; import { executeSwaprTrade, getSwaprTradeExecution } from "@/hooks/trade/executeSwaprTrade"; import { executeUniswapTrade, getUniswapTradeExecution } from "@/hooks/trade/executeUniswapTrade"; import { SupportedChain } from "@/lib/chains"; +import { COLLATERAL_TOKENS, isSeerCredits } from "@/lib/config"; import SEER_ENV from "@/lib/env"; import { queryClient } from "@/lib/query-client"; import { toastifyTx } from "@/lib/toastify"; @@ -29,11 +30,10 @@ function useSwaprQuote( outcomeToken: Token, collateralToken: Token, swapType: "buy" | "sell", - enabled = true, - tradeType: TradeType = TradeType.EXACT_INPUT, + enabled: boolean, + tradeType: TradeType, + maxSlippage: string, ) { - const maxSlippage = useGlobalState((state) => state.maxSlippage); - const isInstantSwap = useGlobalState((state) => state.isInstantSwap); return useQuery({ queryKey: [ "useQuote", @@ -45,7 +45,6 @@ function useSwaprQuote( collateralToken, swapType, maxSlippage, - isInstantSwap, tradeType, ], enabled: Number(amount) > 0 && chainId === gnosis.id && enabled, @@ -85,15 +84,13 @@ export function useCowQuote( outcomeToken: Token, collateralToken: Token, swapType: "buy" | "sell", - enabled = true, - tradeType: TradeType = TradeType.EXACT_INPUT, + enabled: boolean, + tradeType: TradeType, + maxSlippage: string, ) { - const maxSlippage = useGlobalState((state) => state.maxSlippage); - const isInstantSwap = useGlobalState((state) => state.isInstantSwap); const queryKey = [ ...getUseCowQuoteQueryKey(chainId, account, amount, outcomeToken, collateralToken, swapType, tradeType), maxSlippage, - isInstantSwap, ]; const previousData = queryClient.getQueryData(queryKey); const isFastQuery = previousData === undefined; @@ -117,11 +114,10 @@ function useUniswapQuote( outcomeToken: Token, collateralToken: Token, swapType: "buy" | "sell", - enabled = true, - tradeType: TradeType = TradeType.EXACT_INPUT, + enabled: boolean, + tradeType: TradeType, + maxSlippage: string, ) { - const maxSlippage = useGlobalState((state) => state.maxSlippage); - const isInstantSwap = useGlobalState((state) => state.isInstantSwap); return useQuery({ queryKey: [ "useQuote", @@ -133,7 +129,6 @@ function useUniswapQuote( collateralToken, swapType, maxSlippage, - isInstantSwap, tradeType, ], enabled: @@ -148,7 +143,7 @@ function useUniswapQuote( } export function useQuoteTrade( - chainId: number, + chainId: SupportedChain, account: Address | undefined, amount: string, outcomeToken: Token, @@ -156,36 +151,54 @@ export function useQuoteTrade( swapType: "buy" | "sell", tradeType: TradeType, ) { + const isSeerCreditsCollateral = isSeerCredits(chainId, collateralToken.address); + + const realCollateralToken: Token = isSeerCreditsCollateral ? COLLATERAL_TOKENS[chainId].primary : collateralToken; + + const maxSlippage = useGlobalState((state) => state.maxSlippage); const isInstantSwap = useGlobalState((state) => state.isInstantSwap); + const shouldUseInstantSwap = isInstantSwap || isSeerCreditsCollateral; const cowResult = useCowQuote( chainId, account, amount, outcomeToken, - collateralToken, + realCollateralToken, swapType, - !isInstantSwap, + !shouldUseInstantSwap, tradeType, + maxSlippage, ); const isCowResultOk = cowResult.status === "success" && cowResult.data?.value && cowResult.data.value > 0n; - const swaprResult = useSwaprQuote(chainId, account, amount, outcomeToken, collateralToken, swapType, true, tradeType); + const swaprResult = useSwaprQuote( + chainId, + account, + amount, + outcomeToken, + realCollateralToken, + swapType, + true, + tradeType, + maxSlippage, + ); const uniswapResult = useUniswapQuote( chainId, account, amount, outcomeToken, - collateralToken, + realCollateralToken, swapType, true, tradeType, + maxSlippage, ); if (isCowResultOk) { return cowResult; } - if (chainId === mainnet.id || chainId === optimism.id || chainId === base.id) { + if (chainId === mainnet.id || chainId === optimism.id) { return uniswapResult; } return swaprResult; @@ -243,6 +256,7 @@ interface TradeTokensProps { account: Address; isBuyExactOutputNative: boolean; isSellToNative: boolean; + isSeerCredits: boolean; } async function tradeTokens({ @@ -250,16 +264,17 @@ async function tradeTokens({ account, isBuyExactOutputNative, isSellToNative, + isSeerCredits, }: TradeTokensProps): Promise { if (trade instanceof CoWTrade) { return executeCoWTrade(trade); } if (trade instanceof UniswapTrade) { - return executeUniswapTrade(trade, account); + return executeUniswapTrade(trade, account, isSeerCredits); } - return executeSwaprTrade(trade, account, isBuyExactOutputNative, isSellToNative); + return executeSwaprTrade(trade, account, isBuyExactOutputNative, isSellToNative, isSeerCredits); } function useTradeLegacy(account: Address | undefined, trade: Trade | undefined, onSuccess: () => unknown) { diff --git a/web/src/hooks/trade/useTradeConditions.ts b/web/src/hooks/trade/useTradeConditions.ts index abddbd8b..996025d6 100644 --- a/web/src/hooks/trade/useTradeConditions.ts +++ b/web/src/hooks/trade/useTradeConditions.ts @@ -18,14 +18,26 @@ interface Props { outcomeToken: Token; swapType: "buy" | "sell"; tradeType: TradeType; + orderType: "market" | "limit"; errors: FieldErrors<{ amount: string }>; } -export function useTradeConditions({ market, outcomeToken, fixedCollateral, swapType, tradeType, errors }: Props) { +export function useTradeConditions({ + market, + outcomeToken, + fixedCollateral, + swapType, + tradeType, + orderType, + errors, +}: Props) { const maxSlippage = useGlobalState((state) => state.maxSlippage); const isInstantSwap = useGlobalState((state) => state.isInstantSwap); const primaryCollateral = COLLATERAL_TOKENS[market.chainId].primary; - const preferredCollateral = useGlobalState((state) => state.getPreferredCollateral(market.chainId)); + const preferredCollateral = useGlobalState((state) => + state.getPreferredCollateral(market.chainId, swapType, orderType), + ); + const selectedCollateral = fixedCollateral || preferredCollateral || primaryCollateral; const { address: account } = useAccount(); diff --git a/web/src/hooks/trade/utils.ts b/web/src/hooks/trade/utils.ts index e4bf3cdc..93344ca3 100644 --- a/web/src/hooks/trade/utils.ts +++ b/web/src/hooks/trade/utils.ts @@ -3,8 +3,10 @@ import { COLLATERAL_TOKENS } from "@/lib/config"; import { OrderBookApi, OrderStatus } from "@cowprotocol/cow-sdk"; import { CoWTrade, Token as SwaprToken, SwaprV3Trade, TokenAmount, UniswapTrade } from "@swapr/sdk"; import { ethers, providers } from "ethers"; -import { Account, Address, Chain, Client, TransactionReceipt, Transport } from "viem"; +import { Account, Address, Chain, Client, TransactionReceipt, Transport, encodeFunctionData } from "viem"; +import { creditsManagerAbi, creditsManagerAddress } from "../contracts/generated-trading-credits"; import { approveTokens } from "../useApproveTokens"; +import { Execution } from "../useCheck7702Support"; import { fetchNeededApprovals } from "../useMissingApprovals"; export function setSwaprTradeLimit(trade: SwaprV3Trade, newInputValue: bigint) { @@ -150,3 +152,30 @@ export function clientToSigner(client: Client) { const signer = provider.getSigner(account.address); return signer; } + +export function getWrappedSeerCreditsExecution( + isSeerCredits: boolean, + trade: SwaprV3Trade | UniswapTrade, + tradeExecution: Execution, +): Execution { + if (!isSeerCredits) { + return tradeExecution; + } + + const executeData = encodeFunctionData({ + abi: creditsManagerAbi, + functionName: "execute", + args: [ + tradeExecution.to, + tradeExecution.data, + BigInt(trade.inputAmount.raw.toString()), + trade.outputAmount.currency.address! as Address, + ], + }); + + return { + to: creditsManagerAddress[trade.chainId as keyof typeof creditsManagerAddress], + data: executeData, + value: 0n, + }; +} diff --git a/web/src/hooks/useGlobalState.ts b/web/src/hooks/useGlobalState.ts index 859afcfd..c3d4bc2e 100644 --- a/web/src/hooks/useGlobalState.ts +++ b/web/src/hooks/useGlobalState.ts @@ -1,3 +1,5 @@ +import { SupportedChain } from "@/lib/chains"; +import { isSeerCredits } from "@/lib/config"; import { Token } from "@/lib/tokens"; import { Address } from "viem"; import { create } from "zustand"; @@ -25,7 +27,11 @@ type Action = { setMaxSlippage: (value: string) => void; setInstantSwap: (value: boolean) => void; setPreferredCollateral: (token: Token, chainId: number) => void; - getPreferredCollateral: (chainId: number) => Token | undefined; + getPreferredCollateral: ( + chainId: number, + swapType: "buy" | "sell", + orderType: "market" | "limit", + ) => Token | undefined; }; const useGlobalState = create()( @@ -70,8 +76,24 @@ const useGlobalState = create()( [chainId]: token, }, })), - getPreferredCollateral: (chainId: number): Token | undefined => { - return useGlobalState.getState().preferredCollaterals[chainId]; + getPreferredCollateral: ( + chainId: number, + swapType: "buy" | "sell", + orderType: "market" | "limit", + ): Token | undefined => { + const preferredCollateral = useGlobalState.getState().preferredCollaterals[chainId]; + + if ( + orderType === "limit" || + (swapType === "sell" && + preferredCollateral && + isSeerCredits(chainId as SupportedChain, preferredCollateral.address)) + ) { + // SEER_CREDITS can only be used as a sell token in market orders, not as a buy token or in limit orders + return undefined; + } + + return preferredCollateral; }, }), { diff --git a/web/src/lib/config.ts b/web/src/lib/config.ts index db5a3162..269ea930 100644 --- a/web/src/lib/config.ts +++ b/web/src/lib/config.ts @@ -4,6 +4,7 @@ import { mainnetRouterAddress, routerAddress, } from "@/hooks/contracts/generated-router"; +import { seerCreditsAddress } from "@/hooks/contracts/generated-trading-credits"; import { Address, parseUnits } from "viem"; import { hardhat, sepolia } from "viem/chains"; import { DEFAULT_CHAIN, SupportedChain, base, gnosis, mainnet, optimism } from "./chains"; @@ -182,6 +183,13 @@ export function isOpStack(chainId: SupportedChain) { return chainId === optimism.id /* || chainId === base.id */; } +export function isSeerCredits(chainId: SupportedChain, tokenAddress: Address) { + return ( + chainId in seerCreditsAddress && + tokenAddress.toLowerCase() === seerCreditsAddress[chainId as keyof typeof seerCreditsAddress].toLowerCase() + ); +} + export const NETWORK_ICON_MAPPING: { [key: number]: string } = { [gnosis.id]: "/assets/images/gnosis.webp", [mainnet.id]: "/assets/images/ethereum.webp", diff --git a/web/src/lib/paths.ts b/web/src/lib/paths.ts index 7589906d..148eab2e 100644 --- a/web/src/lib/paths.ts +++ b/web/src/lib/paths.ts @@ -1,7 +1,7 @@ import { lightGeneralizedTcrAddress } from "@/hooks/contracts/generated-curate"; import { Address } from "viem"; import { SupportedChain } from "./chains"; -import { TOKENS_BY_CHAIN } from "./config"; +import { TOKENS_BY_CHAIN, isSeerCredits } from "./config"; import { Market } from "./market"; function marketPath(market: Market): string; @@ -67,6 +67,10 @@ export const paths = { } } + if (isSeerCredits(chainId as SupportedChain, address as Address)) { + return "/assets/android-icon-192x192.png"; + } + return `https://raw.githubusercontent.com/cowprotocol/token-lists/main/src/public/images/${chainId}/${address}/logo.png`; }, }; diff --git a/web/wagmi.config.ts b/web/wagmi.config.ts index a29d9abe..6eb284ea 100644 --- a/web/wagmi.config.ts +++ b/web/wagmi.config.ts @@ -76,6 +76,7 @@ const getConfig = async (): Promise => { "market-view": ["MarketView"], router: ["Router", "MainnetRouter", "GnosisRouter", "ConditionalRouter", "FutarchyRouter"], "multi-drop": ["MultiDrop", "GovernedRecipient"], + "trading-credits": ["SeerCredits", "CreditsManager"], }; return Object.entries(contractsMapping).map(([key, contractNames]) => ({ From 5ae9f6587389ee999e24b7d37789ae8ef6732e2a Mon Sep 17 00:00:00 2001 From: xyzseer Date: Mon, 29 Sep 2025 17:28:44 -0300 Subject: [PATCH 2/6] create admin role + add credits --- contracts/scripts/trading-credits.js | 2 +- contracts/src/trading-credits/SeerCredits.sol | 30 ++++++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/contracts/scripts/trading-credits.js b/contracts/scripts/trading-credits.js index f976fa2f..efa6afd1 100644 --- a/contracts/scripts/trading-credits.js +++ b/contracts/scripts/trading-credits.js @@ -9,7 +9,7 @@ * Usage: * 1. Modify the configuration object below with your desired addresses and amounts * 2. Leave objects empty or strings empty to skip those actions - * 3. Run: npx hardhat run scripts/credits-manager.js --network + * 3. Run: npx hardhat run scripts/trading-credits.js --network * * Example networks: localhost, hardhat, gnosis, ethereum, etc. * diff --git a/contracts/src/trading-credits/SeerCredits.sol b/contracts/src/trading-credits/SeerCredits.sol index 010c1771..948fbea4 100644 --- a/contracts/src/trading-credits/SeerCredits.sol +++ b/contracts/src/trading-credits/SeerCredits.sol @@ -8,6 +8,7 @@ import {ERC20} from "solmate/src/tokens/ERC20.sol"; contract SeerCredits is ERC20 { address public governor; // The address that can make governance changes to the parameters of the contract. address public creditsManager; // The address that can burn tokens (CreditsManager contract). + mapping(address => bool) public isAdmin; // Mapping to track admin addresses modifier onlyGovernor() { require(msg.sender == governor, "Only governor can call this function"); @@ -19,16 +20,23 @@ contract SeerCredits is ERC20 { _; } + modifier onlyAdmin() { + require(isAdmin[msg.sender], "Only admin can call this function"); + _; + } + /// @dev Constructor. /// @param _governor The trusted governor of the contract. constructor(address _governor) ERC20("Seer Credits", "SEER_CREDITS", 18) { governor = _governor; creditsManager = _governor; + isAdmin[_governor] = true; } /// @dev Change the governor of the contract. /// @param _governor The address of the new governor. function changeGovernor(address _governor) external onlyGovernor { + require(_governor != address(0), "Invalid governor address"); governor = _governor; } @@ -38,6 +46,14 @@ contract SeerCredits is ERC20 { creditsManager = _creditsManager; } + /// @dev Set admin status for an address. + /// @param _admin The address to set admin status for. + /// @param _isAdmin Boolean indicating whether the address should be an admin. + function setAdmin(address _admin, bool _isAdmin) external onlyGovernor { + require(_admin != address(0), "Invalid admin address"); + isAdmin[_admin] = _isAdmin; + } + function mint(address to, uint256 amount) external onlyGovernor { _mint(to, amount); } @@ -50,7 +66,7 @@ contract SeerCredits is ERC20 { /// @dev Set credits balance for multiple addresses by minting or burning as needed. /// @param _addresses The list of addresses to set credits balance for. /// @param _amounts The list of amounts corresponding to each address. - function setCreditsBalance(address[] memory _addresses, uint256[] memory _amounts) external onlyGovernor { + function setCreditsBalance(address[] memory _addresses, uint256[] memory _amounts) external onlyAdmin { require(_addresses.length == _amounts.length, "Arrays length mismatch"); for (uint256 i; i < _addresses.length; ++i) { uint256 currentBalance = this.balanceOf(_addresses[i]); @@ -68,4 +84,16 @@ contract SeerCredits is ERC20 { // If currentBalance == targetBalance, do nothing } } + + /// @dev Add credits balance to multiple addresses by minting tokens. + /// @param _addresses The list of addresses to add credits balance to. + /// @param _amounts The list of amounts to add to each address. + function addCreditsBalance(address[] memory _addresses, uint256[] memory _amounts) external onlyAdmin { + require(_addresses.length == _amounts.length, "Arrays length mismatch"); + for (uint256 i; i < _addresses.length; ++i) { + if (_amounts[i] > 0) { + _mint(_addresses[i], _amounts[i]); + } + } + } } \ No newline at end of file From b42154887ae432e6cd91eef0986d9c579279b7e5 Mon Sep 17 00:00:00 2001 From: xyzseer Date: Tue, 30 Sep 2025 11:12:32 -0300 Subject: [PATCH 3/6] fix fill-to-price orders --- .../Market/SwapTokens/SwapTokens.tsx | 25 ++++--- .../Market/SwapTokens/SwapTokensLimitUpTo.tsx | 68 ++++--------------- .../Market/SwapTokens/SwapTokensMarket.tsx | 1 - .../Market/SwapTokens/TokenSelector.tsx | 4 -- web/src/hooks/trade/index.ts | 2 +- web/src/hooks/trade/useTradeConditions.ts | 15 +--- web/src/hooks/trade/utils.ts | 3 +- web/src/hooks/useGlobalState.ts | 19 ++---- 8 files changed, 37 insertions(+), 100 deletions(-) diff --git a/web/src/components/Market/SwapTokens/SwapTokens.tsx b/web/src/components/Market/SwapTokens/SwapTokens.tsx index c77a68ee..852405a4 100644 --- a/web/src/components/Market/SwapTokens/SwapTokens.tsx +++ b/web/src/components/Market/SwapTokens/SwapTokens.tsx @@ -60,17 +60,20 @@ export function SwapTokens({ hasEnoughLiquidity === false && orderType === "market" && "grayscale opacity-40 pointer-events-none", )} > -

- setOrderType(type)} - defaultLabel="Order Type" - /> -
+ {/* Futarchy markets only support Market orders, while Generic markets support both Market and Fill-to-price orders */} + {market.type === "Generic" && ( +
+ setOrderType(type)} + defaultLabel="Order Type" + /> +
+ )} {orderType === "market" && ( 1 && swapType === "buy"; - const renderLimitTokenDisplay = () => { - const imageElement = (() => { - if (isUndefined(fixedCollateral)) { - return ( - {isSecondaryCollateral - ); - } - if (market.type === "Futarchy") { - return ( - - ); - } - if (!parentMarket) { - return
; - } - return ( - - ); - })(); - return ( -
-
{imageElement}
-

- {isSecondaryCollateral ? primaryCollateral.symbol : selectedCollateral.symbol} -

-
- ); - }; - const renderButtons = () => { if (isCowFastQuote) { return ( @@ -350,7 +299,7 @@ export function SwapTokensLimitUpto({ originalAmount={amount} isBuyExactOutputNative={isBuyExactOutputNative} isSellToNative={isSellToNative} - isSeerCredits={false} + isSeerCredits={isSeerCredits(market.chainId, selectedCollateral.address)} /> } /> @@ -425,7 +374,16 @@ export function SwapTokensLimitUpto({ errorClassName="hidden" />
- {renderLimitTokenDisplay()} +
+
+ {primaryCollateral.symbol} +
+

{primaryCollateral.symbol}

+
@@ -614,7 +572,7 @@ export function SwapTokensLimitUpto({ )}
- {market.type === "Futarchy" && } + {/* market.type === "Futarchy" && */}
Parameters:{" "}
{ - const isTokenCollateral = isTwoStringsEqual( - type === "sell" ? sellToken.address : buyToken.address, - selectedCollateral.address, - ); if (isTokenCollateral) { if (isUndefined(fixedCollateral)) { return ( diff --git a/web/src/hooks/trade/index.ts b/web/src/hooks/trade/index.ts index a4e3d3dd..2341dc52 100644 --- a/web/src/hooks/trade/index.ts +++ b/web/src/hooks/trade/index.ts @@ -204,7 +204,7 @@ export function useQuoteTrade( return swaprResult; } -function getMaximumAmountIn(trade: Trade) { +export function getMaximumAmountIn(trade: Trade) { let maximumAmountIn = BigInt(trade.maximumAmountIn().raw.toString()); if (trade instanceof UniswapTrade) { const routerInterface = new Interface(UNISWAP_ROUTER_ABI); diff --git a/web/src/hooks/trade/useTradeConditions.ts b/web/src/hooks/trade/useTradeConditions.ts index 996025d6..39738fe0 100644 --- a/web/src/hooks/trade/useTradeConditions.ts +++ b/web/src/hooks/trade/useTradeConditions.ts @@ -18,25 +18,14 @@ interface Props { outcomeToken: Token; swapType: "buy" | "sell"; tradeType: TradeType; - orderType: "market" | "limit"; errors: FieldErrors<{ amount: string }>; } -export function useTradeConditions({ - market, - outcomeToken, - fixedCollateral, - swapType, - tradeType, - orderType, - errors, -}: Props) { +export function useTradeConditions({ market, outcomeToken, fixedCollateral, swapType, tradeType, errors }: Props) { const maxSlippage = useGlobalState((state) => state.maxSlippage); const isInstantSwap = useGlobalState((state) => state.isInstantSwap); const primaryCollateral = COLLATERAL_TOKENS[market.chainId].primary; - const preferredCollateral = useGlobalState((state) => - state.getPreferredCollateral(market.chainId, swapType, orderType), - ); + const preferredCollateral = useGlobalState((state) => state.getPreferredCollateral(market.chainId, swapType)); const selectedCollateral = fixedCollateral || preferredCollateral || primaryCollateral; diff --git a/web/src/hooks/trade/utils.ts b/web/src/hooks/trade/utils.ts index 93344ca3..010d2ab8 100644 --- a/web/src/hooks/trade/utils.ts +++ b/web/src/hooks/trade/utils.ts @@ -4,6 +4,7 @@ import { OrderBookApi, OrderStatus } from "@cowprotocol/cow-sdk"; import { CoWTrade, Token as SwaprToken, SwaprV3Trade, TokenAmount, UniswapTrade } from "@swapr/sdk"; import { ethers, providers } from "ethers"; import { Account, Address, Chain, Client, TransactionReceipt, Transport, encodeFunctionData } from "viem"; +import { getMaximumAmountIn } from "."; import { creditsManagerAbi, creditsManagerAddress } from "../contracts/generated-trading-credits"; import { approveTokens } from "../useApproveTokens"; import { Execution } from "../useCheck7702Support"; @@ -168,7 +169,7 @@ export function getWrappedSeerCreditsExecution( args: [ tradeExecution.to, tradeExecution.data, - BigInt(trade.inputAmount.raw.toString()), + getMaximumAmountIn(trade), trade.outputAmount.currency.address! as Address, ], }); diff --git a/web/src/hooks/useGlobalState.ts b/web/src/hooks/useGlobalState.ts index c3d4bc2e..12714bb3 100644 --- a/web/src/hooks/useGlobalState.ts +++ b/web/src/hooks/useGlobalState.ts @@ -27,11 +27,7 @@ type Action = { setMaxSlippage: (value: string) => void; setInstantSwap: (value: boolean) => void; setPreferredCollateral: (token: Token, chainId: number) => void; - getPreferredCollateral: ( - chainId: number, - swapType: "buy" | "sell", - orderType: "market" | "limit", - ) => Token | undefined; + getPreferredCollateral: (chainId: number, swapType: "buy" | "sell") => Token | undefined; }; const useGlobalState = create()( @@ -76,18 +72,13 @@ const useGlobalState = create()( [chainId]: token, }, })), - getPreferredCollateral: ( - chainId: number, - swapType: "buy" | "sell", - orderType: "market" | "limit", - ): Token | undefined => { + getPreferredCollateral: (chainId: number, swapType: "buy" | "sell"): Token | undefined => { const preferredCollateral = useGlobalState.getState().preferredCollaterals[chainId]; if ( - orderType === "limit" || - (swapType === "sell" && - preferredCollateral && - isSeerCredits(chainId as SupportedChain, preferredCollateral.address)) + preferredCollateral && + isSeerCredits(chainId as SupportedChain, preferredCollateral.address) && + swapType === "sell" ) { // SEER_CREDITS can only be used as a sell token in market orders, not as a buy token or in limit orders return undefined; From 7c8d044f399d9469ef38f66fa40c8e3061160a2c Mon Sep 17 00:00:00 2001 From: xyzseer Date: Wed, 1 Oct 2025 01:16:15 -0300 Subject: [PATCH 4/6] maxSlippage refactor --- web/src/hooks/trade/index.ts | 35 +++++++++++++++++++++-------- web/src/lib/market-odds.ts | 43 +++++++++++++++++++++++++++++++----- web/src/lib/trade.ts | 14 +++++++----- web/src/lib/tradeExactOut.ts | 14 +++++++----- 4 files changed, 82 insertions(+), 24 deletions(-) diff --git a/web/src/hooks/trade/index.ts b/web/src/hooks/trade/index.ts index 2341dc52..43610702 100644 --- a/web/src/hooks/trade/index.ts +++ b/web/src/hooks/trade/index.ts @@ -51,8 +51,8 @@ function useSwaprQuote( retry: false, queryFn: async () => tradeType === TradeType.EXACT_INPUT - ? getSwaprQuote(chainId, account, amount, outcomeToken, collateralToken, swapType) - : getSwaprQuoteExactOut(chainId, account, amount, outcomeToken, collateralToken, swapType), + ? getSwaprQuote(chainId, account, amount, outcomeToken, collateralToken, swapType, maxSlippage) + : getSwaprQuoteExactOut(chainId, account, amount, outcomeToken, collateralToken, swapType, maxSlippage), refetchInterval: QUOTE_REFETCH_INTERVAL, }); } @@ -65,6 +65,7 @@ const getUseCowQuoteQueryKey = ( collateralToken: Token, swapType: "buy" | "sell", tradeType: TradeType, + maxSlippage: string, ) => [ "useQuote", "useCowQuote", @@ -75,6 +76,7 @@ const getUseCowQuoteQueryKey = ( collateralToken, swapType, tradeType, + maxSlippage, ]; export function useCowQuote( @@ -88,10 +90,16 @@ export function useCowQuote( tradeType: TradeType, maxSlippage: string, ) { - const queryKey = [ - ...getUseCowQuoteQueryKey(chainId, account, amount, outcomeToken, collateralToken, swapType, tradeType), + const queryKey = getUseCowQuoteQueryKey( + chainId, + account, + amount, + outcomeToken, + collateralToken, + swapType, + tradeType, maxSlippage, - ]; + ); const previousData = queryClient.getQueryData(queryKey); const isFastQuery = previousData === undefined; return useQuery({ @@ -100,8 +108,17 @@ export function useCowQuote( retry: false, queryFn: async () => tradeType === TradeType.EXACT_INPUT - ? getCowQuote(chainId, account, amount, outcomeToken, collateralToken, swapType, isFastQuery) - : getCowQuoteExactOut(chainId, account, amount, outcomeToken, collateralToken, swapType, isFastQuery), + ? getCowQuote(chainId, account, amount, outcomeToken, collateralToken, swapType, maxSlippage, isFastQuery) + : getCowQuoteExactOut( + chainId, + account, + amount, + outcomeToken, + collateralToken, + swapType, + maxSlippage, + isFastQuery, + ), refetchInterval: (query) => query.state.dataUpdateCount <= 1 && query.state.errorUpdateCount === 0 ? 1 : QUOTE_REFETCH_INTERVAL, }); @@ -136,8 +153,8 @@ function useUniswapQuote( retry: false, queryFn: async () => tradeType === TradeType.EXACT_INPUT - ? getUniswapQuote(chainId, account, amount, outcomeToken, collateralToken, swapType) - : getUniswapQuoteExactOut(chainId, account, amount, outcomeToken, collateralToken, swapType), + ? getUniswapQuote(chainId, account, amount, outcomeToken, collateralToken, swapType, maxSlippage) + : getUniswapQuoteExactOut(chainId, account, amount, outcomeToken, collateralToken, swapType, maxSlippage), refetchInterval: QUOTE_REFETCH_INTERVAL, }); } diff --git a/web/src/lib/market-odds.ts b/web/src/lib/market-odds.ts index 7d6a70ae..440c2646 100644 --- a/web/src/lib/market-odds.ts +++ b/web/src/lib/market-odds.ts @@ -1,6 +1,7 @@ import { tickToPrice } from "@/hooks/liquidity/utils"; import { OrderDirection, Pool_OrderBy, getSdk as getSwaprSdk } from "@/hooks/queries/gql-generated-swapr"; import { getSdk as getUniswapSdk } from "@/hooks/queries/gql-generated-uniswap"; +import { useGlobalState } from "@/hooks/useGlobalState"; import { SupportedChain, gnosis, mainnet } from "@/lib/chains"; import { Market, getMarketUnit, getToken0Token1, isOdd } from "@/lib/market"; import { swaprGraphQLClient, uniswapGraphQLClient } from "@/lib/subgraph"; @@ -52,7 +53,8 @@ async function getTokenSwapResult( collateralToken: Token, chainId: SupportedChain, amount: string, - swapType: "buy" | "sell" = "buy", + swapType: "buy" | "sell", + maxSlippage: string, ): Promise { const outcomeToken = { address: wrappedAddress, symbol: "SEER_OUTCOME", decimals: 18 }; // call cowQuote first, if not possible then we call using rpc @@ -71,7 +73,15 @@ async function getTokenSwapResult( // we either call uniswap or swapr quote based on chainId if (chainId === gnosis.id) { try { - const swaprQuote = await getSwaprQuote(chainId, undefined, amount, outcomeToken, collateralToken, swapType); + const swaprQuote = await getSwaprQuote( + chainId, + undefined, + amount, + outcomeToken, + collateralToken, + swapType, + maxSlippage, + ); return swaprQuote.value; } catch (e) { return 0n; @@ -80,7 +90,15 @@ async function getTokenSwapResult( if (chainId === mainnet.id || isOpStack(chainId)) { try { - const uniswapQuote = await getUniswapQuote(chainId, undefined, amount, outcomeToken, collateralToken, swapType); + const uniswapQuote = await getUniswapQuote( + chainId, + undefined, + amount, + outcomeToken, + collateralToken, + swapType, + maxSlippage, + ); return uniswapQuote.value; } catch (e) { return 0n; @@ -95,11 +113,26 @@ async function getTokenPriceFromSwap(wrappedAddress: Address, collateralToken: T const SELL_AMOUNT = 3; //outcome token try { - const price = await getTokenSwapResult(wrappedAddress, collateralToken, chainId, String(BUY_AMOUNT)); + const maxSlippage = useGlobalState.getState().maxSlippage; + const price = await getTokenSwapResult( + wrappedAddress, + collateralToken, + chainId, + String(BUY_AMOUNT), + "buy", + maxSlippage, + ); const pricePerShare = BUY_AMOUNT / Number(formatUnits(price, 18)); if (pricePerShare > CEIL_PRICE) { // low buy liquidity, try to get sell price instead - const sellPrice = await getTokenSwapResult(wrappedAddress, collateralToken, chainId, String(SELL_AMOUNT), "sell"); + const sellPrice = await getTokenSwapResult( + wrappedAddress, + collateralToken, + chainId, + String(SELL_AMOUNT), + "sell", + maxSlippage, + ); const sellPricePerShare = Number(formatUnits(sellPrice, 18)) / SELL_AMOUNT; if (sellPricePerShare === 0 || sellPricePerShare > CEIL_PRICE) { return Number.NaN; diff --git a/web/src/lib/trade.ts b/web/src/lib/trade.ts index 20a56ae3..0f74348c 100644 --- a/web/src/lib/trade.ts +++ b/web/src/lib/trade.ts @@ -1,4 +1,3 @@ -import { useGlobalState } from "@/hooks/useGlobalState"; import { NATIVE_TOKEN, isTwoStringsEqual, parseFraction } from "@/lib/utils"; import { PriceQuality } from "@cowprotocol/cow-sdk"; import { @@ -34,6 +33,7 @@ export type QuoteTradeFn = ( outcomeToken: Token, collateralToken: Token, swapType: "buy" | "sell", + maxSlippage: string, isFastQuery?: boolean, ) => Promise; @@ -121,6 +121,7 @@ export async function getTradeArgs( outcomeToken: Token, collateralToken: Token, swapType: "buy" | "sell", + maxSlippage: string, ) { const [buyToken, sellToken] = swapType === "buy" ? [outcomeToken, collateralToken] : ([collateralToken, outcomeToken] as [Token, Token]); @@ -129,7 +130,7 @@ export async function getTradeArgs( const { currencyIn, currencyOut, currencyAmountIn } = getCurrenciesFromTokens(chainId, buyToken, sellToken, amount); - const slippage = String(Number(useGlobalState.getState().maxSlippage) / 100); + const slippage = String(Number(maxSlippage) / 100); const [numerator, denominator] = parseFraction(slippage) ?? []; const maximumSlippage = Number.isInteger(numerator) && Number.isInteger(denominator) @@ -154,9 +155,10 @@ export const getCowQuote: QuoteTradeFn = async ( outcomeToken: Token, collateralToken: Token, swapType: "buy" | "sell", + maxSlippage: string, isFastQuery?: boolean, ) => { - const args = await getTradeArgs(chainId, amount, outcomeToken, collateralToken, swapType); + const args = await getTradeArgs(chainId, amount, outcomeToken, collateralToken, swapType, maxSlippage); const trade = await CoWTrade.bestTradeExactIn({ currencyAmountIn: args.currencyAmountIn, @@ -189,8 +191,9 @@ export const getUniswapQuote: QuoteTradeFn = async ( outcomeToken: Token, collateralToken: Token, swapType: "buy" | "sell", + maxSlippage: string, ) => { - const args = await getTradeArgs(chainId, amount, outcomeToken, collateralToken, swapType); + const args = await getTradeArgs(chainId, amount, outcomeToken, collateralToken, swapType, maxSlippage); const trade = await getUniswapTrade( args.currencyIn, @@ -222,8 +225,9 @@ export const getSwaprQuote: QuoteTradeFn = async ( outcomeToken: Token, collateralToken: Token, swapType: "buy" | "sell", + maxSlippage: string, ) => { - const args = await getTradeArgs(chainId, amount, outcomeToken, collateralToken, swapType); + const args = await getTradeArgs(chainId, amount, outcomeToken, collateralToken, swapType, maxSlippage); const trade = await getSwaprTrade( args.currencyIn, diff --git a/web/src/lib/tradeExactOut.ts b/web/src/lib/tradeExactOut.ts index 557b8507..53ec57e5 100644 --- a/web/src/lib/tradeExactOut.ts +++ b/web/src/lib/tradeExactOut.ts @@ -1,4 +1,3 @@ -import { useGlobalState } from "@/hooks/useGlobalState"; import { NATIVE_TOKEN, isTwoStringsEqual, parseFraction } from "@/lib/utils"; import { PriceQuality } from "@cowprotocol/cow-sdk"; import { @@ -34,6 +33,7 @@ export type QuoteTradeFn = ( outcomeToken: Token, collateralToken: Token, swapType: "buy" | "sell", + maxSlippage: string, isFastQuery?: boolean, ) => Promise; @@ -120,6 +120,7 @@ export async function getTradeArgs( outcomeToken: Token, collateralToken: Token, swapType: "buy" | "sell", + maxSlippage: string, ) { const [buyToken, sellToken] = swapType === "buy" ? [outcomeToken, collateralToken] : ([collateralToken, outcomeToken] as [Token, Token]); @@ -128,7 +129,7 @@ export async function getTradeArgs( const { currencyIn, currencyOut, currencyAmountOut } = getCurrenciesFromTokens(chainId, buyToken, sellToken, amount); - const slippage = String(Number(useGlobalState.getState().maxSlippage) / 100); + const slippage = String(Number(maxSlippage) / 100); const [numerator, denominator] = parseFraction(slippage) ?? []; const maximumSlippage = Number.isInteger(numerator) && Number.isInteger(denominator) @@ -161,9 +162,10 @@ export const getCowQuoteExactOut: QuoteTradeFn = async ( outcomeToken: Token, collateralToken: Token, swapType: "buy" | "sell", + maxSlippage: string, isFastQuery?: boolean, ) => { - const args = await getTradeArgs(chainId, amount, outcomeToken, collateralToken, swapType); + const args = await getTradeArgs(chainId, amount, outcomeToken, collateralToken, swapType, maxSlippage); const trade = await CoWTrade.bestTradeExactOut({ currencyIn: args.currencyIn, currencyAmountOut: args.currencyAmountOut, @@ -195,8 +197,9 @@ export const getUniswapQuoteExactOut: QuoteTradeFn = async ( outcomeToken: Token, collateralToken: Token, swapType: "buy" | "sell", + maxSlippage: string, ) => { - const args = await getTradeArgs(chainId, amount, outcomeToken, collateralToken, swapType); + const args = await getTradeArgs(chainId, amount, outcomeToken, collateralToken, swapType, maxSlippage); const trade = await getUniswapTradeExactOut( args.currencyIn, @@ -228,8 +231,9 @@ export const getSwaprQuoteExactOut: QuoteTradeFn = async ( outcomeToken: Token, collateralToken: Token, swapType: "buy" | "sell", + maxSlippage: string, ) => { - const args = await getTradeArgs(chainId, amount, outcomeToken, collateralToken, swapType); + const args = await getTradeArgs(chainId, amount, outcomeToken, collateralToken, swapType, maxSlippage); const trade = await getSwaprTradeExactOut( args.currencyIn, From a867a62700cfedc78ec3757d34cce4f58cd06567 Mon Sep 17 00:00:00 2001 From: xyzseer Date: Thu, 2 Oct 2025 16:08:31 -0300 Subject: [PATCH 5/6] fix approvals, deploy latest contracts --- .../deployments/gnosis/CreditsManager.json | 32 ++--- contracts/deployments/gnosis/SeerCredits.json | 117 +++++++++++++++--- .../Market/SwapTokens/SwapTokensLimitUpTo.tsx | 9 +- .../Market/SwapTokens/SwapTokensMarket.tsx | 8 +- web/src/hooks/trade/index.ts | 30 +++-- 5 files changed, 150 insertions(+), 46 deletions(-) diff --git a/contracts/deployments/gnosis/CreditsManager.json b/contracts/deployments/gnosis/CreditsManager.json index fc0fbfb3..a50c4f8b 100644 --- a/contracts/deployments/gnosis/CreditsManager.json +++ b/contracts/deployments/gnosis/CreditsManager.json @@ -1,5 +1,5 @@ { - "address": "0xFeB801b97b10625FaBee2A7839CDdb6E37C9768b", + "address": "0xB29D0C9875D93483891c0645fdC13D665a4d2D70", "abi": [ { "inputs": [ @@ -172,31 +172,31 @@ "type": "function" } ], - "transactionHash": "0xa067e7e535e1895e09804f26fa7302f692674d34116d7a2a72ca8163dea4c626", + "transactionHash": "0xf4eec13292dfc56d837282eb3cd505519f5a768ce41ab52ae99479e01ad590fb", "receipt": { "to": null, "from": "0x4EDCA105188a0783Ab3A6f09c50567D1E3F8591D", - "contractAddress": "0xFeB801b97b10625FaBee2A7839CDdb6E37C9768b", - "transactionIndex": 6, + "contractAddress": "0xB29D0C9875D93483891c0645fdC13D665a4d2D70", + "transactionIndex": 7, "gasUsed": "1309615", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0xdf905cb2f90172b499442d00e4cdc7afc4b34a6101b58d7f21af20a5194cc59a", - "transactionHash": "0xa067e7e535e1895e09804f26fa7302f692674d34116d7a2a72ca8163dea4c626", + "blockHash": "0xc614bc2759c6db47f2f39ce697aeff174d9e02ce175d8850cb6c820e77cb3a00", + "transactionHash": "0xf4eec13292dfc56d837282eb3cd505519f5a768ce41ab52ae99479e01ad590fb", "logs": [], - "blockNumber": 42332226, - "cumulativeGasUsed": "3379432", + "blockNumber": 42439736, + "cumulativeGasUsed": "2580237", "status": 1, "byzantium": true }, "args": [ "0xaf204776c7245bf4147c2612bf6e5972ee483701", - "0x3a0D8671eFcBc172eDBE32F91169BBc984dC607C" + "0xEDd48e43EBd4E2b31238a5CBA8FD548fC051aCAF" ], - "numDeployments": 2, - "solcInputHash": "2d3de33fa340cf567b57fc3a8edf08f0", - "metadata": "{\"compiler\":{\"version\":\"0.8.28+commit.7893614a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract ERC20\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"contract SeerCredits\",\"name\":\"_seerCredits\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_user\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"canSpendCredits\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_governor\",\"type\":\"address\"}],\"name\":\"changeGovernor\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"contract ERC20\",\"name\":\"outputToken\",\"type\":\"address\"}],\"name\":\"execute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"seerCredits\",\"outputs\":[{\"internalType\":\"contract SeerCredits\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_contract\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"_whitelisted\",\"type\":\"bool\"}],\"name\":\"setWhitelistedContract\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract ERC20\",\"name\":\"_token\",\"type\":\"address\"}],\"name\":\"sweepTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"token\",\"outputs\":[{\"internalType\":\"contract ERC20\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"whitelistedContracts\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"The contract receives an address `to` (expected to be a DEX router) and `data` to execute a swapThe swap data must be encoded to send tokens to `msg.sender`CreditsManager pays for the swap on behalf of the user by deducting credits from their balance\",\"kind\":\"dev\",\"methods\":{\"canSpendCredits(address,uint256)\":{\"details\":\"Check if a user can spend a specific amount of credits.\",\"params\":{\"_amount\":\"The amount of credits to check.\",\"_user\":\"The address of the user to check.\"},\"returns\":{\"_0\":\"True if the user can spend the specified amount of credits.\"}},\"changeGovernor(address)\":{\"details\":\"Change the governor of the contract.\",\"params\":{\"_governor\":\"The address of the new governor. TRUSTED\"}},\"constructor\":{\"details\":\"Constructor.\",\"params\":{\"_seerCredits\":\"The SeerCredits token contract. TRUSTED\",\"_token\":\"The ERC20 token used to swap from (e.g., sDAI on Gnosis). TRUSTED\"}},\"execute(address,bytes,uint256,address)\":{\"details\":\"Execute a swap through a DEX router (Uniswap, Swapr, etc.). CreditsManager pays for the swap.\",\"params\":{\"amount\":\"The amount of credits to spend (tokens approved to the DEX router).\",\"data\":\"The encoded swap call data. Must be encoded to send output tokens to msg.sender.\",\"outputToken\":\"The token that the user is buying (must have increased balance after swap).\",\"to\":\"The DEX router address (must be whitelisted).\"}},\"setWhitelistedContract(address,bool)\":{\"details\":\"Add or remove a contract from the whitelist.\",\"params\":{\"_contract\":\"The address of the contract to modify.\",\"_whitelisted\":\"True to add to whitelist, false to remove.\"}},\"sweepTokens(address)\":{\"details\":\"Sweep all tokens from the contract to the governor.\",\"params\":{\"_token\":\"The token to sweep. If address(0), uses the default token.\"}}},\"title\":\"CreditsManager\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"execute(address,bytes,uint256,address)\":{\"notice\":\"This function acts as a proxy - CreditsManager pays for the swap by deducting credits from user's balance.\"}},\"notice\":\"This contract acts as a proxy to DEXs (Uniswap, Swapr, etc.) where users can spend trading credits\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/trading-credits/CreditsManager.sol\":\"CreditsManager\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":false,\"runs\":200},\"remappings\":[]},\"sources\":{\"solmate/src/tokens/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity >=0.8.0;\\n\\n/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.\\n/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)\\n/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)\\n/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.\\nabstract contract ERC20 {\\n /*//////////////////////////////////////////////////////////////\\n EVENTS\\n //////////////////////////////////////////////////////////////*/\\n\\n event Transfer(address indexed from, address indexed to, uint256 amount);\\n\\n event Approval(address indexed owner, address indexed spender, uint256 amount);\\n\\n /*//////////////////////////////////////////////////////////////\\n METADATA STORAGE\\n //////////////////////////////////////////////////////////////*/\\n\\n string public name;\\n\\n string public symbol;\\n\\n uint8 public immutable decimals;\\n\\n /*//////////////////////////////////////////////////////////////\\n ERC20 STORAGE\\n //////////////////////////////////////////////////////////////*/\\n\\n uint256 public totalSupply;\\n\\n mapping(address => uint256) public balanceOf;\\n\\n mapping(address => mapping(address => uint256)) public allowance;\\n\\n /*//////////////////////////////////////////////////////////////\\n EIP-2612 STORAGE\\n //////////////////////////////////////////////////////////////*/\\n\\n uint256 internal immutable INITIAL_CHAIN_ID;\\n\\n bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;\\n\\n mapping(address => uint256) public nonces;\\n\\n /*//////////////////////////////////////////////////////////////\\n CONSTRUCTOR\\n //////////////////////////////////////////////////////////////*/\\n\\n constructor(\\n string memory _name,\\n string memory _symbol,\\n uint8 _decimals\\n ) {\\n name = _name;\\n symbol = _symbol;\\n decimals = _decimals;\\n\\n INITIAL_CHAIN_ID = block.chainid;\\n INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n ERC20 LOGIC\\n //////////////////////////////////////////////////////////////*/\\n\\n function approve(address spender, uint256 amount) public virtual returns (bool) {\\n allowance[msg.sender][spender] = amount;\\n\\n emit Approval(msg.sender, spender, amount);\\n\\n return true;\\n }\\n\\n function transfer(address to, uint256 amount) public virtual returns (bool) {\\n balanceOf[msg.sender] -= amount;\\n\\n // Cannot overflow because the sum of all user\\n // balances can't exceed the max uint256 value.\\n unchecked {\\n balanceOf[to] += amount;\\n }\\n\\n emit Transfer(msg.sender, to, amount);\\n\\n return true;\\n }\\n\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) public virtual returns (bool) {\\n uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.\\n\\n if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;\\n\\n balanceOf[from] -= amount;\\n\\n // Cannot overflow because the sum of all user\\n // balances can't exceed the max uint256 value.\\n unchecked {\\n balanceOf[to] += amount;\\n }\\n\\n emit Transfer(from, to, amount);\\n\\n return true;\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n EIP-2612 LOGIC\\n //////////////////////////////////////////////////////////////*/\\n\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) public virtual {\\n require(deadline >= block.timestamp, \\\"PERMIT_DEADLINE_EXPIRED\\\");\\n\\n // Unchecked because the only math done is incrementing\\n // the owner's nonce which cannot realistically overflow.\\n unchecked {\\n address recoveredAddress = ecrecover(\\n keccak256(\\n abi.encodePacked(\\n \\\"\\\\x19\\\\x01\\\",\\n DOMAIN_SEPARATOR(),\\n keccak256(\\n abi.encode(\\n keccak256(\\n \\\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\\\"\\n ),\\n owner,\\n spender,\\n value,\\n nonces[owner]++,\\n deadline\\n )\\n )\\n )\\n ),\\n v,\\n r,\\n s\\n );\\n\\n require(recoveredAddress != address(0) && recoveredAddress == owner, \\\"INVALID_SIGNER\\\");\\n\\n allowance[recoveredAddress][spender] = value;\\n }\\n\\n emit Approval(owner, spender, value);\\n }\\n\\n function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {\\n return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();\\n }\\n\\n function computeDomainSeparator() internal view virtual returns (bytes32) {\\n return\\n keccak256(\\n abi.encode(\\n keccak256(\\\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\\\"),\\n keccak256(bytes(name)),\\n keccak256(\\\"1\\\"),\\n block.chainid,\\n address(this)\\n )\\n );\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n INTERNAL MINT/BURN LOGIC\\n //////////////////////////////////////////////////////////////*/\\n\\n function _mint(address to, uint256 amount) internal virtual {\\n totalSupply += amount;\\n\\n // Cannot overflow because the sum of all user\\n // balances can't exceed the max uint256 value.\\n unchecked {\\n balanceOf[to] += amount;\\n }\\n\\n emit Transfer(address(0), to, amount);\\n }\\n\\n function _burn(address from, uint256 amount) internal virtual {\\n balanceOf[from] -= amount;\\n\\n // Cannot underflow because a user's balance\\n // will never be larger than the total supply.\\n unchecked {\\n totalSupply -= amount;\\n }\\n\\n emit Transfer(from, address(0), amount);\\n }\\n}\\n\",\"keccak256\":\"0xcdfd8db76b2a3415620e4d18cc5545f3d50de792dbf2c3dd5adb40cbe6f94b10\",\"license\":\"AGPL-3.0-only\"},\"src/trading-credits/CreditsManager.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.28;\\n\\nimport {ERC20} from \\\"solmate/src/tokens/ERC20.sol\\\";\\nimport \\\"./SeerCredits.sol\\\";\\n\\n/// @title CreditsManager\\n/// @notice This contract acts as a proxy to DEXs (Uniswap, Swapr, etc.) where users can spend trading credits\\n/// @dev The contract receives an address `to` (expected to be a DEX router) and `data` to execute a swap\\n/// @dev The swap data must be encoded to send tokens to `msg.sender`\\n/// @dev CreditsManager pays for the swap on behalf of the user by deducting credits from their balance\\ncontract CreditsManager {\\n address public governor; // The address that can make governance changes to the parameters of the contract.\\n ERC20 public token; // The token used to swap from (e.g., sDAI on Gnosis).\\n SeerCredits public seerCredits; // The SeerCredits token representing trading credits.\\n mapping(address => bool) public whitelistedContracts; // Whitelist of contracts that can be called.\\n\\n modifier onlyGovernor() {\\n require(msg.sender == governor, \\\"The caller must be the governor\\\");\\n _;\\n }\\n\\n /// @dev Constructor.\\n /// @param _token The ERC20 token used to swap from (e.g., sDAI on Gnosis). TRUSTED\\n /// @param _seerCredits The SeerCredits token contract. TRUSTED\\n constructor(ERC20 _token, SeerCredits _seerCredits) {\\n governor = msg.sender;\\n token = _token;\\n seerCredits = _seerCredits;\\n }\\n\\n /// @dev Change the governor of the contract.\\n /// @param _governor The address of the new governor. TRUSTED\\n function changeGovernor(address _governor) external onlyGovernor {\\n governor = _governor;\\n }\\n\\n\\n /// @dev Add or remove a contract from the whitelist.\\n /// @param _contract The address of the contract to modify.\\n /// @param _whitelisted True to add to whitelist, false to remove.\\n function setWhitelistedContract(address _contract, bool _whitelisted) external onlyGovernor {\\n whitelistedContracts[_contract] = _whitelisted;\\n }\\n\\n\\n /// @dev Check if a user can spend a specific amount of credits.\\n /// @param _user The address of the user to check.\\n /// @param _amount The amount of credits to check.\\n /// @return True if the user can spend the specified amount of credits.\\n function canSpendCredits(address _user, uint256 _amount) external view returns (bool) {\\n // Check if user has enough SeerCredits\\n if (seerCredits.balanceOf(_user) < _amount) {\\n return false;\\n }\\n\\n // Check if contract has enough token balance\\n if (token.balanceOf(address(this)) < _amount) {\\n return false;\\n }\\n\\n return true;\\n }\\n\\n /// @dev Sweep all tokens from the contract to the governor.\\n /// @param _token The token to sweep. If address(0), uses the default token.\\n function sweepTokens(ERC20 _token) external onlyGovernor {\\n ERC20 tokenToSweep = _token == ERC20(address(0)) ? token : _token;\\n uint256 balance = tokenToSweep.balanceOf(address(this));\\n require(balance > 0, \\\"No tokens to sweep\\\");\\n require(tokenToSweep.transfer(governor, balance), \\\"Token transfer failed\\\");\\n }\\n\\n /// @dev Execute a swap through a DEX router (Uniswap, Swapr, etc.). CreditsManager pays for the swap.\\n /// @param to The DEX router address (must be whitelisted).\\n /// @param data The encoded swap call data. Must be encoded to send output tokens to msg.sender.\\n /// @param amount The amount of credits to spend (tokens approved to the DEX router).\\n /// @param outputToken The token that the user is buying (must have increased balance after swap).\\n /// @notice This function acts as a proxy - CreditsManager pays for the swap by deducting credits from user's balance.\\n function execute(address to, bytes calldata data, uint256 amount, ERC20 outputToken) external {\\n require(whitelistedContracts[to], \\\"Contract not whitelisted\\\");\\n require(seerCredits.balanceOf(msg.sender) >= amount, \\\"Insufficient credits balance\\\");\\n\\n // Check user's balance of output token before the swap\\n uint256 balanceBefore = outputToken.balanceOf(msg.sender);\\n\\n // CreditsManager approves tokens to the DEX router (e.g., Uniswap, Swapr)\\n require(token.approve(to, amount), \\\"Token approval failed\\\");\\n\\n // Burn SeerCredits from user's balance - CreditsManager is paying for the swap\\n seerCredits.burn(msg.sender, amount);\\n\\n // Execute the swap call to the DEX router\\n // The swap data must be encoded to send output tokens to msg.sender\\n (bool success,) = to.call(data);\\n require(success, \\\"Call failed\\\");\\n\\n // Verify that the user received tokens (balance increased)\\n // This is a security measure to verify that the swap had msg.sender as recipient,\\n // otherwise the swap recipient would be CreditsManager itself\\n uint256 balanceAfter = outputToken.balanceOf(msg.sender);\\n require(balanceAfter > balanceBefore, \\\"No tokens received from swap\\\");\\n }\\n}\\n\",\"keccak256\":\"0x49a2b49182bf0b9355a010c261fac863f555bbeabed35c53dc46a96a51851905\",\"license\":\"MIT\"},\"src/trading-credits/SeerCredits.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.28;\\n\\nimport {ERC20} from \\\"solmate/src/tokens/ERC20.sol\\\";\\n\\n/// @title SeerCredits\\n/// @notice ERC20 token representing trading credits that users can spend on DEX swaps\\ncontract SeerCredits is ERC20 {\\n address public governor; // The address that can make governance changes to the parameters of the contract.\\n address public creditsManager; // The address that can burn tokens (CreditsManager contract).\\n\\n modifier onlyGovernor() {\\n require(msg.sender == governor, \\\"Only governor can call this function\\\");\\n _;\\n }\\n\\n modifier onlyCreditsManager() {\\n require(msg.sender == creditsManager, \\\"Only credits manager can call this function\\\");\\n _;\\n }\\n\\n /// @dev Constructor.\\n /// @param _governor The trusted governor of the contract.\\n constructor(address _governor) ERC20(\\\"Seer Credits\\\", \\\"SEER_CREDITS\\\", 18) {\\n governor = _governor;\\n creditsManager = _governor;\\n }\\n\\n /// @dev Change the governor of the contract.\\n /// @param _governor The address of the new governor.\\n function changeGovernor(address _governor) external onlyGovernor {\\n governor = _governor;\\n }\\n\\n /// @dev Change the credits manager of the contract.\\n /// @param _creditsManager The address of the new credits manager.\\n function changeCreditsManager(address _creditsManager) external onlyGovernor {\\n creditsManager = _creditsManager;\\n }\\n\\n function mint(address to, uint256 amount) external onlyGovernor {\\n _mint(to, amount);\\n }\\n\\n function burn(address from, uint256 amount) external onlyCreditsManager {\\n _burn(from, amount);\\n }\\n\\n\\n /// @dev Set credits balance for multiple addresses by minting or burning as needed.\\n /// @param _addresses The list of addresses to set credits balance for.\\n /// @param _amounts The list of amounts corresponding to each address.\\n function setCreditsBalance(address[] memory _addresses, uint256[] memory _amounts) external onlyGovernor {\\n require(_addresses.length == _amounts.length, \\\"Arrays length mismatch\\\");\\n for (uint256 i; i < _addresses.length; ++i) {\\n uint256 currentBalance = this.balanceOf(_addresses[i]);\\n uint256 targetBalance = _amounts[i];\\n \\n if (currentBalance > targetBalance) {\\n // Burn excess tokens\\n uint256 burnAmount = currentBalance - targetBalance;\\n _burn(_addresses[i], burnAmount);\\n } else if (targetBalance > currentBalance) {\\n // Mint additional tokens\\n uint256 mintAmount = targetBalance - currentBalance;\\n _mint(_addresses[i], mintAmount);\\n }\\n // If currentBalance == targetBalance, do nothing\\n }\\n }\\n}\",\"keccak256\":\"0x37b49e69085a26a612831d01a9e3eb4a6b95e3d5c826626cf46d8e74bc93b17f\",\"license\":\"MIT\"}},\"version\":1}", - "bytecode": "0x608060405234801561001057600080fd5b5060405161176f38038061176f833981810160405281019061003291906101ae565b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050506101ee565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061012b82610100565b9050919050565b600061013d82610120565b9050919050565b61014d81610132565b811461015857600080fd5b50565b60008151905061016a81610144565b92915050565b600061017b82610120565b9050919050565b61018b81610170565b811461019657600080fd5b50565b6000815190506101a881610182565b92915050565b600080604083850312156101c5576101c46100fb565b5b60006101d38582860161015b565b92505060206101e485828601610199565b9150509250929050565b611572806101fd6000396000f3fe608060405234801561001057600080fd5b50600436106100935760003560e01c8063a6ec9ea511610066578063a6ec9ea514610132578063c421449214610150578063e4c0aaf41461016c578063f5f6d3af14610188578063fc0c546a146101a457610093565b80630c340a241461009857806313a93def146100b6578063391feebb146100e657806370ec9d0814610116575b600080fd5b6100a06101c2565b6040516100ad9190610d13565b60405180910390f35b6100d060048036038101906100cb9190610d9a565b6101e6565b6040516100dd9190610df5565b60405180910390f35b61010060048036038101906100fb9190610e10565b61034b565b60405161010d9190610df5565b60405180910390f35b610130600480360381019061012b9190610ee0565b61036b565b005b61013a61083a565b6040516101479190610fc7565b60405180910390f35b61016a6004803603810190610165919061100e565b610860565b005b61018660048036038101906101819190610e10565b610949565b005b6101a2600480360381019061019d919061104e565b610a1a565b005b6101ac610cac565b6040516101b9919061109c565b60405180910390f35b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600081600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231856040518263ffffffff1660e01b81526004016102449190610d13565b602060405180830381865afa158015610261573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061028591906110cc565b10156102945760009050610345565b81600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016102f09190610d13565b602060405180830381865afa15801561030d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061033191906110cc565b10156103405760009050610345565b600190505b92915050565b60036020528060005260406000206000915054906101000a900460ff1681565b600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff166103f7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103ee90611156565b60405180910390fd5b81600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231336040518263ffffffff1660e01b81526004016104539190610d13565b602060405180830381865afa158015610470573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061049491906110cc565b10156104d5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104cc906111c2565b60405180910390fd5b60008173ffffffffffffffffffffffffffffffffffffffff166370a08231336040518263ffffffff1660e01b81526004016105109190610d13565b602060405180830381865afa15801561052d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061055191906110cc565b9050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663095ea7b387856040518363ffffffff1660e01b81526004016105b09291906111f1565b6020604051808303816000875af11580156105cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105f3919061122f565b610632576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610629906112a8565b60405180910390fd5b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16639dc29fac33856040518363ffffffff1660e01b815260040161068f9291906111f1565b600060405180830381600087803b1580156106a957600080fd5b505af11580156106bd573d6000803e3d6000fd5b5050505060008673ffffffffffffffffffffffffffffffffffffffff1686866040516106ea929190611307565b6000604051808303816000865af19150503d8060008114610727576040519150601f19603f3d011682016040523d82523d6000602084013e61072c565b606091505b5050905080610770576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107679061136c565b60405180910390fd5b60008373ffffffffffffffffffffffffffffffffffffffff166370a08231336040518263ffffffff1660e01b81526004016107ab9190610d13565b602060405180830381865afa1580156107c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107ec91906110cc565b9050828111610830576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610827906113d8565b60405180910390fd5b5050505050505050565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146108ee576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e590611444565b60405180910390fd5b80600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146109d7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109ce90611444565b60405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610aa8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a9f90611444565b60405180910390fd5b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614610ae35781610b07565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff165b905060008173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401610b449190610d13565b602060405180830381865afa158015610b61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b8591906110cc565b905060008111610bca576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bc1906114b0565b60405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff1663a9059cbb60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff16836040518363ffffffff1660e01b8152600401610c259291906111f1565b6020604051808303816000875af1158015610c44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c68919061122f565b610ca7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c9e9061151c565b60405180910390fd5b505050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610cfd82610cd2565b9050919050565b610d0d81610cf2565b82525050565b6000602082019050610d286000830184610d04565b92915050565b600080fd5b600080fd5b610d4181610cf2565b8114610d4c57600080fd5b50565b600081359050610d5e81610d38565b92915050565b6000819050919050565b610d7781610d64565b8114610d8257600080fd5b50565b600081359050610d9481610d6e565b92915050565b60008060408385031215610db157610db0610d2e565b5b6000610dbf85828601610d4f565b9250506020610dd085828601610d85565b9150509250929050565b60008115159050919050565b610def81610dda565b82525050565b6000602082019050610e0a6000830184610de6565b92915050565b600060208284031215610e2657610e25610d2e565b5b6000610e3484828501610d4f565b91505092915050565b600080fd5b600080fd5b600080fd5b60008083601f840112610e6257610e61610e3d565b5b8235905067ffffffffffffffff811115610e7f57610e7e610e42565b5b602083019150836001820283011115610e9b57610e9a610e47565b5b9250929050565b6000610ead82610cf2565b9050919050565b610ebd81610ea2565b8114610ec857600080fd5b50565b600081359050610eda81610eb4565b92915050565b600080600080600060808688031215610efc57610efb610d2e565b5b6000610f0a88828901610d4f565b955050602086013567ffffffffffffffff811115610f2b57610f2a610d33565b5b610f3788828901610e4c565b94509450506040610f4a88828901610d85565b9250506060610f5b88828901610ecb565b9150509295509295909350565b6000819050919050565b6000610f8d610f88610f8384610cd2565b610f68565b610cd2565b9050919050565b6000610f9f82610f72565b9050919050565b6000610fb182610f94565b9050919050565b610fc181610fa6565b82525050565b6000602082019050610fdc6000830184610fb8565b92915050565b610feb81610dda565b8114610ff657600080fd5b50565b60008135905061100881610fe2565b92915050565b6000806040838503121561102557611024610d2e565b5b600061103385828601610d4f565b925050602061104485828601610ff9565b9150509250929050565b60006020828403121561106457611063610d2e565b5b600061107284828501610ecb565b91505092915050565b600061108682610f94565b9050919050565b6110968161107b565b82525050565b60006020820190506110b1600083018461108d565b92915050565b6000815190506110c681610d6e565b92915050565b6000602082840312156110e2576110e1610d2e565b5b60006110f0848285016110b7565b91505092915050565b600082825260208201905092915050565b7f436f6e7472616374206e6f742077686974656c69737465640000000000000000600082015250565b60006111406018836110f9565b915061114b8261110a565b602082019050919050565b6000602082019050818103600083015261116f81611133565b9050919050565b7f496e73756666696369656e7420637265646974732062616c616e636500000000600082015250565b60006111ac601c836110f9565b91506111b782611176565b602082019050919050565b600060208201905081810360008301526111db8161119f565b9050919050565b6111eb81610d64565b82525050565b60006040820190506112066000830185610d04565b61121360208301846111e2565b9392505050565b60008151905061122981610fe2565b92915050565b60006020828403121561124557611244610d2e565b5b60006112538482850161121a565b91505092915050565b7f546f6b656e20617070726f76616c206661696c65640000000000000000000000600082015250565b60006112926015836110f9565b915061129d8261125c565b602082019050919050565b600060208201905081810360008301526112c181611285565b9050919050565b600081905092915050565b82818337600083830152505050565b60006112ee83856112c8565b93506112fb8385846112d3565b82840190509392505050565b60006113148284866112e2565b91508190509392505050565b7f43616c6c206661696c6564000000000000000000000000000000000000000000600082015250565b6000611356600b836110f9565b915061136182611320565b602082019050919050565b6000602082019050818103600083015261138581611349565b9050919050565b7f4e6f20746f6b656e732072656365697665642066726f6d207377617000000000600082015250565b60006113c2601c836110f9565b91506113cd8261138c565b602082019050919050565b600060208201905081810360008301526113f1816113b5565b9050919050565b7f5468652063616c6c6572206d7573742062652074686520676f7665726e6f7200600082015250565b600061142e601f836110f9565b9150611439826113f8565b602082019050919050565b6000602082019050818103600083015261145d81611421565b9050919050565b7f4e6f20746f6b656e7320746f2073776565700000000000000000000000000000600082015250565b600061149a6012836110f9565b91506114a582611464565b602082019050919050565b600060208201905081810360008301526114c98161148d565b9050919050565b7f546f6b656e207472616e73666572206661696c65640000000000000000000000600082015250565b60006115066015836110f9565b9150611511826114d0565b602082019050919050565b60006020820190508181036000830152611535816114f9565b905091905056fea264697066735822122025b5fe756be70b17e1b31f8fe39241136a79b96fb3811558155a67463ae8df7c64736f6c634300081c0033", - "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100935760003560e01c8063a6ec9ea511610066578063a6ec9ea514610132578063c421449214610150578063e4c0aaf41461016c578063f5f6d3af14610188578063fc0c546a146101a457610093565b80630c340a241461009857806313a93def146100b6578063391feebb146100e657806370ec9d0814610116575b600080fd5b6100a06101c2565b6040516100ad9190610d13565b60405180910390f35b6100d060048036038101906100cb9190610d9a565b6101e6565b6040516100dd9190610df5565b60405180910390f35b61010060048036038101906100fb9190610e10565b61034b565b60405161010d9190610df5565b60405180910390f35b610130600480360381019061012b9190610ee0565b61036b565b005b61013a61083a565b6040516101479190610fc7565b60405180910390f35b61016a6004803603810190610165919061100e565b610860565b005b61018660048036038101906101819190610e10565b610949565b005b6101a2600480360381019061019d919061104e565b610a1a565b005b6101ac610cac565b6040516101b9919061109c565b60405180910390f35b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600081600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231856040518263ffffffff1660e01b81526004016102449190610d13565b602060405180830381865afa158015610261573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061028591906110cc565b10156102945760009050610345565b81600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016102f09190610d13565b602060405180830381865afa15801561030d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061033191906110cc565b10156103405760009050610345565b600190505b92915050565b60036020528060005260406000206000915054906101000a900460ff1681565b600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff166103f7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103ee90611156565b60405180910390fd5b81600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231336040518263ffffffff1660e01b81526004016104539190610d13565b602060405180830381865afa158015610470573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061049491906110cc565b10156104d5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104cc906111c2565b60405180910390fd5b60008173ffffffffffffffffffffffffffffffffffffffff166370a08231336040518263ffffffff1660e01b81526004016105109190610d13565b602060405180830381865afa15801561052d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061055191906110cc565b9050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663095ea7b387856040518363ffffffff1660e01b81526004016105b09291906111f1565b6020604051808303816000875af11580156105cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105f3919061122f565b610632576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610629906112a8565b60405180910390fd5b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16639dc29fac33856040518363ffffffff1660e01b815260040161068f9291906111f1565b600060405180830381600087803b1580156106a957600080fd5b505af11580156106bd573d6000803e3d6000fd5b5050505060008673ffffffffffffffffffffffffffffffffffffffff1686866040516106ea929190611307565b6000604051808303816000865af19150503d8060008114610727576040519150601f19603f3d011682016040523d82523d6000602084013e61072c565b606091505b5050905080610770576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107679061136c565b60405180910390fd5b60008373ffffffffffffffffffffffffffffffffffffffff166370a08231336040518263ffffffff1660e01b81526004016107ab9190610d13565b602060405180830381865afa1580156107c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107ec91906110cc565b9050828111610830576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610827906113d8565b60405180910390fd5b5050505050505050565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146108ee576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e590611444565b60405180910390fd5b80600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146109d7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109ce90611444565b60405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610aa8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a9f90611444565b60405180910390fd5b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614610ae35781610b07565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff165b905060008173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401610b449190610d13565b602060405180830381865afa158015610b61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b8591906110cc565b905060008111610bca576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bc1906114b0565b60405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff1663a9059cbb60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff16836040518363ffffffff1660e01b8152600401610c259291906111f1565b6020604051808303816000875af1158015610c44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c68919061122f565b610ca7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c9e9061151c565b60405180910390fd5b505050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610cfd82610cd2565b9050919050565b610d0d81610cf2565b82525050565b6000602082019050610d286000830184610d04565b92915050565b600080fd5b600080fd5b610d4181610cf2565b8114610d4c57600080fd5b50565b600081359050610d5e81610d38565b92915050565b6000819050919050565b610d7781610d64565b8114610d8257600080fd5b50565b600081359050610d9481610d6e565b92915050565b60008060408385031215610db157610db0610d2e565b5b6000610dbf85828601610d4f565b9250506020610dd085828601610d85565b9150509250929050565b60008115159050919050565b610def81610dda565b82525050565b6000602082019050610e0a6000830184610de6565b92915050565b600060208284031215610e2657610e25610d2e565b5b6000610e3484828501610d4f565b91505092915050565b600080fd5b600080fd5b600080fd5b60008083601f840112610e6257610e61610e3d565b5b8235905067ffffffffffffffff811115610e7f57610e7e610e42565b5b602083019150836001820283011115610e9b57610e9a610e47565b5b9250929050565b6000610ead82610cf2565b9050919050565b610ebd81610ea2565b8114610ec857600080fd5b50565b600081359050610eda81610eb4565b92915050565b600080600080600060808688031215610efc57610efb610d2e565b5b6000610f0a88828901610d4f565b955050602086013567ffffffffffffffff811115610f2b57610f2a610d33565b5b610f3788828901610e4c565b94509450506040610f4a88828901610d85565b9250506060610f5b88828901610ecb565b9150509295509295909350565b6000819050919050565b6000610f8d610f88610f8384610cd2565b610f68565b610cd2565b9050919050565b6000610f9f82610f72565b9050919050565b6000610fb182610f94565b9050919050565b610fc181610fa6565b82525050565b6000602082019050610fdc6000830184610fb8565b92915050565b610feb81610dda565b8114610ff657600080fd5b50565b60008135905061100881610fe2565b92915050565b6000806040838503121561102557611024610d2e565b5b600061103385828601610d4f565b925050602061104485828601610ff9565b9150509250929050565b60006020828403121561106457611063610d2e565b5b600061107284828501610ecb565b91505092915050565b600061108682610f94565b9050919050565b6110968161107b565b82525050565b60006020820190506110b1600083018461108d565b92915050565b6000815190506110c681610d6e565b92915050565b6000602082840312156110e2576110e1610d2e565b5b60006110f0848285016110b7565b91505092915050565b600082825260208201905092915050565b7f436f6e7472616374206e6f742077686974656c69737465640000000000000000600082015250565b60006111406018836110f9565b915061114b8261110a565b602082019050919050565b6000602082019050818103600083015261116f81611133565b9050919050565b7f496e73756666696369656e7420637265646974732062616c616e636500000000600082015250565b60006111ac601c836110f9565b91506111b782611176565b602082019050919050565b600060208201905081810360008301526111db8161119f565b9050919050565b6111eb81610d64565b82525050565b60006040820190506112066000830185610d04565b61121360208301846111e2565b9392505050565b60008151905061122981610fe2565b92915050565b60006020828403121561124557611244610d2e565b5b60006112538482850161121a565b91505092915050565b7f546f6b656e20617070726f76616c206661696c65640000000000000000000000600082015250565b60006112926015836110f9565b915061129d8261125c565b602082019050919050565b600060208201905081810360008301526112c181611285565b9050919050565b600081905092915050565b82818337600083830152505050565b60006112ee83856112c8565b93506112fb8385846112d3565b82840190509392505050565b60006113148284866112e2565b91508190509392505050565b7f43616c6c206661696c6564000000000000000000000000000000000000000000600082015250565b6000611356600b836110f9565b915061136182611320565b602082019050919050565b6000602082019050818103600083015261138581611349565b9050919050565b7f4e6f20746f6b656e732072656365697665642066726f6d207377617000000000600082015250565b60006113c2601c836110f9565b91506113cd8261138c565b602082019050919050565b600060208201905081810360008301526113f1816113b5565b9050919050565b7f5468652063616c6c6572206d7573742062652074686520676f7665726e6f7200600082015250565b600061142e601f836110f9565b9150611439826113f8565b602082019050919050565b6000602082019050818103600083015261145d81611421565b9050919050565b7f4e6f20746f6b656e7320746f2073776565700000000000000000000000000000600082015250565b600061149a6012836110f9565b91506114a582611464565b602082019050919050565b600060208201905081810360008301526114c98161148d565b9050919050565b7f546f6b656e207472616e73666572206661696c65640000000000000000000000600082015250565b60006115066015836110f9565b9150611511826114d0565b602082019050919050565b60006020820190508181036000830152611535816114f9565b905091905056fea264697066735822122025b5fe756be70b17e1b31f8fe39241136a79b96fb3811558155a67463ae8df7c64736f6c634300081c0033", + "numDeployments": 3, + "solcInputHash": "7693ac2519ab88153958ebed4942cb22", + "metadata": "{\"compiler\":{\"version\":\"0.8.28+commit.7893614a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract ERC20\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"contract SeerCredits\",\"name\":\"_seerCredits\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_user\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"canSpendCredits\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_governor\",\"type\":\"address\"}],\"name\":\"changeGovernor\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"contract ERC20\",\"name\":\"outputToken\",\"type\":\"address\"}],\"name\":\"execute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"seerCredits\",\"outputs\":[{\"internalType\":\"contract SeerCredits\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_contract\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"_whitelisted\",\"type\":\"bool\"}],\"name\":\"setWhitelistedContract\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract ERC20\",\"name\":\"_token\",\"type\":\"address\"}],\"name\":\"sweepTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"token\",\"outputs\":[{\"internalType\":\"contract ERC20\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"whitelistedContracts\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"The contract receives an address `to` (expected to be a DEX router) and `data` to execute a swapThe swap data must be encoded to send tokens to `msg.sender`CreditsManager pays for the swap on behalf of the user by deducting credits from their balance\",\"kind\":\"dev\",\"methods\":{\"canSpendCredits(address,uint256)\":{\"details\":\"Check if a user can spend a specific amount of credits.\",\"params\":{\"_amount\":\"The amount of credits to check.\",\"_user\":\"The address of the user to check.\"},\"returns\":{\"_0\":\"True if the user can spend the specified amount of credits.\"}},\"changeGovernor(address)\":{\"details\":\"Change the governor of the contract.\",\"params\":{\"_governor\":\"The address of the new governor. TRUSTED\"}},\"constructor\":{\"details\":\"Constructor.\",\"params\":{\"_seerCredits\":\"The SeerCredits token contract. TRUSTED\",\"_token\":\"The ERC20 token used to swap from (e.g., sDAI on Gnosis). TRUSTED\"}},\"execute(address,bytes,uint256,address)\":{\"details\":\"Execute a swap through a DEX router (Uniswap, Swapr, etc.). CreditsManager pays for the swap.\",\"params\":{\"amount\":\"The amount of credits to spend (tokens approved to the DEX router).\",\"data\":\"The encoded swap call data. Must be encoded to send output tokens to msg.sender.\",\"outputToken\":\"The token that the user is buying (must have increased balance after swap).\",\"to\":\"The DEX router address (must be whitelisted).\"}},\"setWhitelistedContract(address,bool)\":{\"details\":\"Add or remove a contract from the whitelist.\",\"params\":{\"_contract\":\"The address of the contract to modify.\",\"_whitelisted\":\"True to add to whitelist, false to remove.\"}},\"sweepTokens(address)\":{\"details\":\"Sweep all tokens from the contract to the governor.\",\"params\":{\"_token\":\"The token to sweep. If address(0), uses the default token.\"}}},\"title\":\"CreditsManager\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"execute(address,bytes,uint256,address)\":{\"notice\":\"This function acts as a proxy - CreditsManager pays for the swap by deducting credits from user's balance.\"}},\"notice\":\"This contract acts as a proxy to DEXs (Uniswap, Swapr, etc.) where users can spend trading credits\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/trading-credits/CreditsManager.sol\":\"CreditsManager\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":false,\"runs\":200},\"remappings\":[]},\"sources\":{\"solmate/src/tokens/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity >=0.8.0;\\n\\n/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.\\n/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)\\n/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)\\n/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.\\nabstract contract ERC20 {\\n /*//////////////////////////////////////////////////////////////\\n EVENTS\\n //////////////////////////////////////////////////////////////*/\\n\\n event Transfer(address indexed from, address indexed to, uint256 amount);\\n\\n event Approval(address indexed owner, address indexed spender, uint256 amount);\\n\\n /*//////////////////////////////////////////////////////////////\\n METADATA STORAGE\\n //////////////////////////////////////////////////////////////*/\\n\\n string public name;\\n\\n string public symbol;\\n\\n uint8 public immutable decimals;\\n\\n /*//////////////////////////////////////////////////////////////\\n ERC20 STORAGE\\n //////////////////////////////////////////////////////////////*/\\n\\n uint256 public totalSupply;\\n\\n mapping(address => uint256) public balanceOf;\\n\\n mapping(address => mapping(address => uint256)) public allowance;\\n\\n /*//////////////////////////////////////////////////////////////\\n EIP-2612 STORAGE\\n //////////////////////////////////////////////////////////////*/\\n\\n uint256 internal immutable INITIAL_CHAIN_ID;\\n\\n bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;\\n\\n mapping(address => uint256) public nonces;\\n\\n /*//////////////////////////////////////////////////////////////\\n CONSTRUCTOR\\n //////////////////////////////////////////////////////////////*/\\n\\n constructor(\\n string memory _name,\\n string memory _symbol,\\n uint8 _decimals\\n ) {\\n name = _name;\\n symbol = _symbol;\\n decimals = _decimals;\\n\\n INITIAL_CHAIN_ID = block.chainid;\\n INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n ERC20 LOGIC\\n //////////////////////////////////////////////////////////////*/\\n\\n function approve(address spender, uint256 amount) public virtual returns (bool) {\\n allowance[msg.sender][spender] = amount;\\n\\n emit Approval(msg.sender, spender, amount);\\n\\n return true;\\n }\\n\\n function transfer(address to, uint256 amount) public virtual returns (bool) {\\n balanceOf[msg.sender] -= amount;\\n\\n // Cannot overflow because the sum of all user\\n // balances can't exceed the max uint256 value.\\n unchecked {\\n balanceOf[to] += amount;\\n }\\n\\n emit Transfer(msg.sender, to, amount);\\n\\n return true;\\n }\\n\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) public virtual returns (bool) {\\n uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.\\n\\n if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;\\n\\n balanceOf[from] -= amount;\\n\\n // Cannot overflow because the sum of all user\\n // balances can't exceed the max uint256 value.\\n unchecked {\\n balanceOf[to] += amount;\\n }\\n\\n emit Transfer(from, to, amount);\\n\\n return true;\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n EIP-2612 LOGIC\\n //////////////////////////////////////////////////////////////*/\\n\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) public virtual {\\n require(deadline >= block.timestamp, \\\"PERMIT_DEADLINE_EXPIRED\\\");\\n\\n // Unchecked because the only math done is incrementing\\n // the owner's nonce which cannot realistically overflow.\\n unchecked {\\n address recoveredAddress = ecrecover(\\n keccak256(\\n abi.encodePacked(\\n \\\"\\\\x19\\\\x01\\\",\\n DOMAIN_SEPARATOR(),\\n keccak256(\\n abi.encode(\\n keccak256(\\n \\\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\\\"\\n ),\\n owner,\\n spender,\\n value,\\n nonces[owner]++,\\n deadline\\n )\\n )\\n )\\n ),\\n v,\\n r,\\n s\\n );\\n\\n require(recoveredAddress != address(0) && recoveredAddress == owner, \\\"INVALID_SIGNER\\\");\\n\\n allowance[recoveredAddress][spender] = value;\\n }\\n\\n emit Approval(owner, spender, value);\\n }\\n\\n function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {\\n return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();\\n }\\n\\n function computeDomainSeparator() internal view virtual returns (bytes32) {\\n return\\n keccak256(\\n abi.encode(\\n keccak256(\\\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\\\"),\\n keccak256(bytes(name)),\\n keccak256(\\\"1\\\"),\\n block.chainid,\\n address(this)\\n )\\n );\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n INTERNAL MINT/BURN LOGIC\\n //////////////////////////////////////////////////////////////*/\\n\\n function _mint(address to, uint256 amount) internal virtual {\\n totalSupply += amount;\\n\\n // Cannot overflow because the sum of all user\\n // balances can't exceed the max uint256 value.\\n unchecked {\\n balanceOf[to] += amount;\\n }\\n\\n emit Transfer(address(0), to, amount);\\n }\\n\\n function _burn(address from, uint256 amount) internal virtual {\\n balanceOf[from] -= amount;\\n\\n // Cannot underflow because a user's balance\\n // will never be larger than the total supply.\\n unchecked {\\n totalSupply -= amount;\\n }\\n\\n emit Transfer(from, address(0), amount);\\n }\\n}\\n\",\"keccak256\":\"0xcdfd8db76b2a3415620e4d18cc5545f3d50de792dbf2c3dd5adb40cbe6f94b10\",\"license\":\"AGPL-3.0-only\"},\"src/trading-credits/CreditsManager.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.28;\\n\\nimport {ERC20} from \\\"solmate/src/tokens/ERC20.sol\\\";\\nimport \\\"./SeerCredits.sol\\\";\\n\\n/// @title CreditsManager\\n/// @notice This contract acts as a proxy to DEXs (Uniswap, Swapr, etc.) where users can spend trading credits\\n/// @dev The contract receives an address `to` (expected to be a DEX router) and `data` to execute a swap\\n/// @dev The swap data must be encoded to send tokens to `msg.sender`\\n/// @dev CreditsManager pays for the swap on behalf of the user by deducting credits from their balance\\ncontract CreditsManager {\\n address public governor; // The address that can make governance changes to the parameters of the contract.\\n ERC20 public token; // The token used to swap from (e.g., sDAI on Gnosis).\\n SeerCredits public seerCredits; // The SeerCredits token representing trading credits.\\n mapping(address => bool) public whitelistedContracts; // Whitelist of contracts that can be called.\\n\\n modifier onlyGovernor() {\\n require(msg.sender == governor, \\\"The caller must be the governor\\\");\\n _;\\n }\\n\\n /// @dev Constructor.\\n /// @param _token The ERC20 token used to swap from (e.g., sDAI on Gnosis). TRUSTED\\n /// @param _seerCredits The SeerCredits token contract. TRUSTED\\n constructor(ERC20 _token, SeerCredits _seerCredits) {\\n governor = msg.sender;\\n token = _token;\\n seerCredits = _seerCredits;\\n }\\n\\n /// @dev Change the governor of the contract.\\n /// @param _governor The address of the new governor. TRUSTED\\n function changeGovernor(address _governor) external onlyGovernor {\\n governor = _governor;\\n }\\n\\n\\n /// @dev Add or remove a contract from the whitelist.\\n /// @param _contract The address of the contract to modify.\\n /// @param _whitelisted True to add to whitelist, false to remove.\\n function setWhitelistedContract(address _contract, bool _whitelisted) external onlyGovernor {\\n whitelistedContracts[_contract] = _whitelisted;\\n }\\n\\n\\n /// @dev Check if a user can spend a specific amount of credits.\\n /// @param _user The address of the user to check.\\n /// @param _amount The amount of credits to check.\\n /// @return True if the user can spend the specified amount of credits.\\n function canSpendCredits(address _user, uint256 _amount) external view returns (bool) {\\n // Check if user has enough SeerCredits\\n if (seerCredits.balanceOf(_user) < _amount) {\\n return false;\\n }\\n\\n // Check if contract has enough token balance\\n if (token.balanceOf(address(this)) < _amount) {\\n return false;\\n }\\n\\n return true;\\n }\\n\\n /// @dev Sweep all tokens from the contract to the governor.\\n /// @param _token The token to sweep. If address(0), uses the default token.\\n function sweepTokens(ERC20 _token) external onlyGovernor {\\n ERC20 tokenToSweep = _token == ERC20(address(0)) ? token : _token;\\n uint256 balance = tokenToSweep.balanceOf(address(this));\\n require(balance > 0, \\\"No tokens to sweep\\\");\\n require(tokenToSweep.transfer(governor, balance), \\\"Token transfer failed\\\");\\n }\\n\\n /// @dev Execute a swap through a DEX router (Uniswap, Swapr, etc.). CreditsManager pays for the swap.\\n /// @param to The DEX router address (must be whitelisted).\\n /// @param data The encoded swap call data. Must be encoded to send output tokens to msg.sender.\\n /// @param amount The amount of credits to spend (tokens approved to the DEX router).\\n /// @param outputToken The token that the user is buying (must have increased balance after swap).\\n /// @notice This function acts as a proxy - CreditsManager pays for the swap by deducting credits from user's balance.\\n function execute(address to, bytes calldata data, uint256 amount, ERC20 outputToken) external {\\n require(whitelistedContracts[to], \\\"Contract not whitelisted\\\");\\n require(seerCredits.balanceOf(msg.sender) >= amount, \\\"Insufficient credits balance\\\");\\n\\n // Check user's balance of output token before the swap\\n uint256 balanceBefore = outputToken.balanceOf(msg.sender);\\n\\n // CreditsManager approves tokens to the DEX router (e.g., Uniswap, Swapr)\\n require(token.approve(to, amount), \\\"Token approval failed\\\");\\n\\n // Burn SeerCredits from user's balance - CreditsManager is paying for the swap\\n seerCredits.burn(msg.sender, amount);\\n\\n // Execute the swap call to the DEX router\\n // The swap data must be encoded to send output tokens to msg.sender\\n (bool success,) = to.call(data);\\n require(success, \\\"Call failed\\\");\\n\\n // Verify that the user received tokens (balance increased)\\n // This is a security measure to verify that the swap had msg.sender as recipient,\\n // otherwise the swap recipient would be CreditsManager itself\\n uint256 balanceAfter = outputToken.balanceOf(msg.sender);\\n require(balanceAfter > balanceBefore, \\\"No tokens received from swap\\\");\\n }\\n}\\n\",\"keccak256\":\"0x49a2b49182bf0b9355a010c261fac863f555bbeabed35c53dc46a96a51851905\",\"license\":\"MIT\"},\"src/trading-credits/SeerCredits.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.28;\\n\\nimport {ERC20} from \\\"solmate/src/tokens/ERC20.sol\\\";\\n\\n/// @title SeerCredits\\n/// @notice ERC20 token representing trading credits that users can spend on DEX swaps\\ncontract SeerCredits is ERC20 {\\n address public governor; // The address that can make governance changes to the parameters of the contract.\\n address public creditsManager; // The address that can burn tokens (CreditsManager contract).\\n mapping(address => bool) public isAdmin; // Mapping to track admin addresses\\n\\n modifier onlyGovernor() {\\n require(msg.sender == governor, \\\"Only governor can call this function\\\");\\n _;\\n }\\n\\n modifier onlyCreditsManager() {\\n require(msg.sender == creditsManager, \\\"Only credits manager can call this function\\\");\\n _;\\n }\\n\\n modifier onlyAdmin() {\\n require(isAdmin[msg.sender], \\\"Only admin can call this function\\\");\\n _;\\n }\\n\\n /// @dev Constructor.\\n /// @param _governor The trusted governor of the contract.\\n constructor(address _governor) ERC20(\\\"Seer Credits\\\", \\\"SEER_CREDITS\\\", 18) {\\n governor = _governor;\\n creditsManager = _governor;\\n isAdmin[_governor] = true;\\n }\\n\\n /// @dev Change the governor of the contract.\\n /// @param _governor The address of the new governor.\\n function changeGovernor(address _governor) external onlyGovernor {\\n require(_governor != address(0), \\\"Invalid governor address\\\");\\n governor = _governor;\\n }\\n\\n /// @dev Change the credits manager of the contract.\\n /// @param _creditsManager The address of the new credits manager.\\n function changeCreditsManager(address _creditsManager) external onlyGovernor {\\n creditsManager = _creditsManager;\\n }\\n\\n /// @dev Set admin status for an address.\\n /// @param _admin The address to set admin status for.\\n /// @param _isAdmin Boolean indicating whether the address should be an admin.\\n function setAdmin(address _admin, bool _isAdmin) external onlyGovernor {\\n require(_admin != address(0), \\\"Invalid admin address\\\");\\n isAdmin[_admin] = _isAdmin;\\n }\\n\\n function mint(address to, uint256 amount) external onlyGovernor {\\n _mint(to, amount);\\n }\\n\\n function burn(address from, uint256 amount) external onlyCreditsManager {\\n _burn(from, amount);\\n }\\n\\n\\n /// @dev Set credits balance for multiple addresses by minting or burning as needed.\\n /// @param _addresses The list of addresses to set credits balance for.\\n /// @param _amounts The list of amounts corresponding to each address.\\n function setCreditsBalance(address[] memory _addresses, uint256[] memory _amounts) external onlyAdmin {\\n require(_addresses.length == _amounts.length, \\\"Arrays length mismatch\\\");\\n for (uint256 i; i < _addresses.length; ++i) {\\n uint256 currentBalance = this.balanceOf(_addresses[i]);\\n uint256 targetBalance = _amounts[i];\\n \\n if (currentBalance > targetBalance) {\\n // Burn excess tokens\\n uint256 burnAmount = currentBalance - targetBalance;\\n _burn(_addresses[i], burnAmount);\\n } else if (targetBalance > currentBalance) {\\n // Mint additional tokens\\n uint256 mintAmount = targetBalance - currentBalance;\\n _mint(_addresses[i], mintAmount);\\n }\\n // If currentBalance == targetBalance, do nothing\\n }\\n }\\n\\n /// @dev Add credits balance to multiple addresses by minting tokens.\\n /// @param _addresses The list of addresses to add credits balance to.\\n /// @param _amounts The list of amounts to add to each address.\\n function addCreditsBalance(address[] memory _addresses, uint256[] memory _amounts) external onlyAdmin {\\n require(_addresses.length == _amounts.length, \\\"Arrays length mismatch\\\");\\n for (uint256 i; i < _addresses.length; ++i) {\\n if (_amounts[i] > 0) {\\n _mint(_addresses[i], _amounts[i]);\\n }\\n }\\n }\\n}\",\"keccak256\":\"0xbbf9e34771ae3c29750998d870dbb0f0c71b0972057b78c85f3f523de50ded25\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x608060405234801561001057600080fd5b5060405161176f38038061176f833981810160405281019061003291906101ae565b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050506101ee565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061012b82610100565b9050919050565b600061013d82610120565b9050919050565b61014d81610132565b811461015857600080fd5b50565b60008151905061016a81610144565b92915050565b600061017b82610120565b9050919050565b61018b81610170565b811461019657600080fd5b50565b6000815190506101a881610182565b92915050565b600080604083850312156101c5576101c46100fb565b5b60006101d38582860161015b565b92505060206101e485828601610199565b9150509250929050565b611572806101fd6000396000f3fe608060405234801561001057600080fd5b50600436106100935760003560e01c8063a6ec9ea511610066578063a6ec9ea514610132578063c421449214610150578063e4c0aaf41461016c578063f5f6d3af14610188578063fc0c546a146101a457610093565b80630c340a241461009857806313a93def146100b6578063391feebb146100e657806370ec9d0814610116575b600080fd5b6100a06101c2565b6040516100ad9190610d13565b60405180910390f35b6100d060048036038101906100cb9190610d9a565b6101e6565b6040516100dd9190610df5565b60405180910390f35b61010060048036038101906100fb9190610e10565b61034b565b60405161010d9190610df5565b60405180910390f35b610130600480360381019061012b9190610ee0565b61036b565b005b61013a61083a565b6040516101479190610fc7565b60405180910390f35b61016a6004803603810190610165919061100e565b610860565b005b61018660048036038101906101819190610e10565b610949565b005b6101a2600480360381019061019d919061104e565b610a1a565b005b6101ac610cac565b6040516101b9919061109c565b60405180910390f35b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600081600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231856040518263ffffffff1660e01b81526004016102449190610d13565b602060405180830381865afa158015610261573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061028591906110cc565b10156102945760009050610345565b81600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016102f09190610d13565b602060405180830381865afa15801561030d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061033191906110cc565b10156103405760009050610345565b600190505b92915050565b60036020528060005260406000206000915054906101000a900460ff1681565b600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff166103f7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103ee90611156565b60405180910390fd5b81600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231336040518263ffffffff1660e01b81526004016104539190610d13565b602060405180830381865afa158015610470573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061049491906110cc565b10156104d5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104cc906111c2565b60405180910390fd5b60008173ffffffffffffffffffffffffffffffffffffffff166370a08231336040518263ffffffff1660e01b81526004016105109190610d13565b602060405180830381865afa15801561052d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061055191906110cc565b9050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663095ea7b387856040518363ffffffff1660e01b81526004016105b09291906111f1565b6020604051808303816000875af11580156105cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105f3919061122f565b610632576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610629906112a8565b60405180910390fd5b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16639dc29fac33856040518363ffffffff1660e01b815260040161068f9291906111f1565b600060405180830381600087803b1580156106a957600080fd5b505af11580156106bd573d6000803e3d6000fd5b5050505060008673ffffffffffffffffffffffffffffffffffffffff1686866040516106ea929190611307565b6000604051808303816000865af19150503d8060008114610727576040519150601f19603f3d011682016040523d82523d6000602084013e61072c565b606091505b5050905080610770576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107679061136c565b60405180910390fd5b60008373ffffffffffffffffffffffffffffffffffffffff166370a08231336040518263ffffffff1660e01b81526004016107ab9190610d13565b602060405180830381865afa1580156107c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107ec91906110cc565b9050828111610830576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610827906113d8565b60405180910390fd5b5050505050505050565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146108ee576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e590611444565b60405180910390fd5b80600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146109d7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109ce90611444565b60405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610aa8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a9f90611444565b60405180910390fd5b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614610ae35781610b07565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff165b905060008173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401610b449190610d13565b602060405180830381865afa158015610b61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b8591906110cc565b905060008111610bca576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bc1906114b0565b60405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff1663a9059cbb60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff16836040518363ffffffff1660e01b8152600401610c259291906111f1565b6020604051808303816000875af1158015610c44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c68919061122f565b610ca7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c9e9061151c565b60405180910390fd5b505050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610cfd82610cd2565b9050919050565b610d0d81610cf2565b82525050565b6000602082019050610d286000830184610d04565b92915050565b600080fd5b600080fd5b610d4181610cf2565b8114610d4c57600080fd5b50565b600081359050610d5e81610d38565b92915050565b6000819050919050565b610d7781610d64565b8114610d8257600080fd5b50565b600081359050610d9481610d6e565b92915050565b60008060408385031215610db157610db0610d2e565b5b6000610dbf85828601610d4f565b9250506020610dd085828601610d85565b9150509250929050565b60008115159050919050565b610def81610dda565b82525050565b6000602082019050610e0a6000830184610de6565b92915050565b600060208284031215610e2657610e25610d2e565b5b6000610e3484828501610d4f565b91505092915050565b600080fd5b600080fd5b600080fd5b60008083601f840112610e6257610e61610e3d565b5b8235905067ffffffffffffffff811115610e7f57610e7e610e42565b5b602083019150836001820283011115610e9b57610e9a610e47565b5b9250929050565b6000610ead82610cf2565b9050919050565b610ebd81610ea2565b8114610ec857600080fd5b50565b600081359050610eda81610eb4565b92915050565b600080600080600060808688031215610efc57610efb610d2e565b5b6000610f0a88828901610d4f565b955050602086013567ffffffffffffffff811115610f2b57610f2a610d33565b5b610f3788828901610e4c565b94509450506040610f4a88828901610d85565b9250506060610f5b88828901610ecb565b9150509295509295909350565b6000819050919050565b6000610f8d610f88610f8384610cd2565b610f68565b610cd2565b9050919050565b6000610f9f82610f72565b9050919050565b6000610fb182610f94565b9050919050565b610fc181610fa6565b82525050565b6000602082019050610fdc6000830184610fb8565b92915050565b610feb81610dda565b8114610ff657600080fd5b50565b60008135905061100881610fe2565b92915050565b6000806040838503121561102557611024610d2e565b5b600061103385828601610d4f565b925050602061104485828601610ff9565b9150509250929050565b60006020828403121561106457611063610d2e565b5b600061107284828501610ecb565b91505092915050565b600061108682610f94565b9050919050565b6110968161107b565b82525050565b60006020820190506110b1600083018461108d565b92915050565b6000815190506110c681610d6e565b92915050565b6000602082840312156110e2576110e1610d2e565b5b60006110f0848285016110b7565b91505092915050565b600082825260208201905092915050565b7f436f6e7472616374206e6f742077686974656c69737465640000000000000000600082015250565b60006111406018836110f9565b915061114b8261110a565b602082019050919050565b6000602082019050818103600083015261116f81611133565b9050919050565b7f496e73756666696369656e7420637265646974732062616c616e636500000000600082015250565b60006111ac601c836110f9565b91506111b782611176565b602082019050919050565b600060208201905081810360008301526111db8161119f565b9050919050565b6111eb81610d64565b82525050565b60006040820190506112066000830185610d04565b61121360208301846111e2565b9392505050565b60008151905061122981610fe2565b92915050565b60006020828403121561124557611244610d2e565b5b60006112538482850161121a565b91505092915050565b7f546f6b656e20617070726f76616c206661696c65640000000000000000000000600082015250565b60006112926015836110f9565b915061129d8261125c565b602082019050919050565b600060208201905081810360008301526112c181611285565b9050919050565b600081905092915050565b82818337600083830152505050565b60006112ee83856112c8565b93506112fb8385846112d3565b82840190509392505050565b60006113148284866112e2565b91508190509392505050565b7f43616c6c206661696c6564000000000000000000000000000000000000000000600082015250565b6000611356600b836110f9565b915061136182611320565b602082019050919050565b6000602082019050818103600083015261138581611349565b9050919050565b7f4e6f20746f6b656e732072656365697665642066726f6d207377617000000000600082015250565b60006113c2601c836110f9565b91506113cd8261138c565b602082019050919050565b600060208201905081810360008301526113f1816113b5565b9050919050565b7f5468652063616c6c6572206d7573742062652074686520676f7665726e6f7200600082015250565b600061142e601f836110f9565b9150611439826113f8565b602082019050919050565b6000602082019050818103600083015261145d81611421565b9050919050565b7f4e6f20746f6b656e7320746f2073776565700000000000000000000000000000600082015250565b600061149a6012836110f9565b91506114a582611464565b602082019050919050565b600060208201905081810360008301526114c98161148d565b9050919050565b7f546f6b656e207472616e73666572206661696c65640000000000000000000000600082015250565b60006115066015836110f9565b9150611511826114d0565b602082019050919050565b60006020820190508181036000830152611535816114f9565b905091905056fea2646970667358221220f409874a62e38ccb17baffe05d64e89f0fa6fd6243b7a4baf89b287a7cb5e17b64736f6c634300081c0033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100935760003560e01c8063a6ec9ea511610066578063a6ec9ea514610132578063c421449214610150578063e4c0aaf41461016c578063f5f6d3af14610188578063fc0c546a146101a457610093565b80630c340a241461009857806313a93def146100b6578063391feebb146100e657806370ec9d0814610116575b600080fd5b6100a06101c2565b6040516100ad9190610d13565b60405180910390f35b6100d060048036038101906100cb9190610d9a565b6101e6565b6040516100dd9190610df5565b60405180910390f35b61010060048036038101906100fb9190610e10565b61034b565b60405161010d9190610df5565b60405180910390f35b610130600480360381019061012b9190610ee0565b61036b565b005b61013a61083a565b6040516101479190610fc7565b60405180910390f35b61016a6004803603810190610165919061100e565b610860565b005b61018660048036038101906101819190610e10565b610949565b005b6101a2600480360381019061019d919061104e565b610a1a565b005b6101ac610cac565b6040516101b9919061109c565b60405180910390f35b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600081600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231856040518263ffffffff1660e01b81526004016102449190610d13565b602060405180830381865afa158015610261573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061028591906110cc565b10156102945760009050610345565b81600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016102f09190610d13565b602060405180830381865afa15801561030d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061033191906110cc565b10156103405760009050610345565b600190505b92915050565b60036020528060005260406000206000915054906101000a900460ff1681565b600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff166103f7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103ee90611156565b60405180910390fd5b81600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231336040518263ffffffff1660e01b81526004016104539190610d13565b602060405180830381865afa158015610470573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061049491906110cc565b10156104d5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104cc906111c2565b60405180910390fd5b60008173ffffffffffffffffffffffffffffffffffffffff166370a08231336040518263ffffffff1660e01b81526004016105109190610d13565b602060405180830381865afa15801561052d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061055191906110cc565b9050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663095ea7b387856040518363ffffffff1660e01b81526004016105b09291906111f1565b6020604051808303816000875af11580156105cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105f3919061122f565b610632576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610629906112a8565b60405180910390fd5b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16639dc29fac33856040518363ffffffff1660e01b815260040161068f9291906111f1565b600060405180830381600087803b1580156106a957600080fd5b505af11580156106bd573d6000803e3d6000fd5b5050505060008673ffffffffffffffffffffffffffffffffffffffff1686866040516106ea929190611307565b6000604051808303816000865af19150503d8060008114610727576040519150601f19603f3d011682016040523d82523d6000602084013e61072c565b606091505b5050905080610770576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107679061136c565b60405180910390fd5b60008373ffffffffffffffffffffffffffffffffffffffff166370a08231336040518263ffffffff1660e01b81526004016107ab9190610d13565b602060405180830381865afa1580156107c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107ec91906110cc565b9050828111610830576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610827906113d8565b60405180910390fd5b5050505050505050565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146108ee576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e590611444565b60405180910390fd5b80600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146109d7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109ce90611444565b60405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610aa8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a9f90611444565b60405180910390fd5b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614610ae35781610b07565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff165b905060008173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401610b449190610d13565b602060405180830381865afa158015610b61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b8591906110cc565b905060008111610bca576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bc1906114b0565b60405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff1663a9059cbb60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff16836040518363ffffffff1660e01b8152600401610c259291906111f1565b6020604051808303816000875af1158015610c44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c68919061122f565b610ca7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c9e9061151c565b60405180910390fd5b505050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610cfd82610cd2565b9050919050565b610d0d81610cf2565b82525050565b6000602082019050610d286000830184610d04565b92915050565b600080fd5b600080fd5b610d4181610cf2565b8114610d4c57600080fd5b50565b600081359050610d5e81610d38565b92915050565b6000819050919050565b610d7781610d64565b8114610d8257600080fd5b50565b600081359050610d9481610d6e565b92915050565b60008060408385031215610db157610db0610d2e565b5b6000610dbf85828601610d4f565b9250506020610dd085828601610d85565b9150509250929050565b60008115159050919050565b610def81610dda565b82525050565b6000602082019050610e0a6000830184610de6565b92915050565b600060208284031215610e2657610e25610d2e565b5b6000610e3484828501610d4f565b91505092915050565b600080fd5b600080fd5b600080fd5b60008083601f840112610e6257610e61610e3d565b5b8235905067ffffffffffffffff811115610e7f57610e7e610e42565b5b602083019150836001820283011115610e9b57610e9a610e47565b5b9250929050565b6000610ead82610cf2565b9050919050565b610ebd81610ea2565b8114610ec857600080fd5b50565b600081359050610eda81610eb4565b92915050565b600080600080600060808688031215610efc57610efb610d2e565b5b6000610f0a88828901610d4f565b955050602086013567ffffffffffffffff811115610f2b57610f2a610d33565b5b610f3788828901610e4c565b94509450506040610f4a88828901610d85565b9250506060610f5b88828901610ecb565b9150509295509295909350565b6000819050919050565b6000610f8d610f88610f8384610cd2565b610f68565b610cd2565b9050919050565b6000610f9f82610f72565b9050919050565b6000610fb182610f94565b9050919050565b610fc181610fa6565b82525050565b6000602082019050610fdc6000830184610fb8565b92915050565b610feb81610dda565b8114610ff657600080fd5b50565b60008135905061100881610fe2565b92915050565b6000806040838503121561102557611024610d2e565b5b600061103385828601610d4f565b925050602061104485828601610ff9565b9150509250929050565b60006020828403121561106457611063610d2e565b5b600061107284828501610ecb565b91505092915050565b600061108682610f94565b9050919050565b6110968161107b565b82525050565b60006020820190506110b1600083018461108d565b92915050565b6000815190506110c681610d6e565b92915050565b6000602082840312156110e2576110e1610d2e565b5b60006110f0848285016110b7565b91505092915050565b600082825260208201905092915050565b7f436f6e7472616374206e6f742077686974656c69737465640000000000000000600082015250565b60006111406018836110f9565b915061114b8261110a565b602082019050919050565b6000602082019050818103600083015261116f81611133565b9050919050565b7f496e73756666696369656e7420637265646974732062616c616e636500000000600082015250565b60006111ac601c836110f9565b91506111b782611176565b602082019050919050565b600060208201905081810360008301526111db8161119f565b9050919050565b6111eb81610d64565b82525050565b60006040820190506112066000830185610d04565b61121360208301846111e2565b9392505050565b60008151905061122981610fe2565b92915050565b60006020828403121561124557611244610d2e565b5b60006112538482850161121a565b91505092915050565b7f546f6b656e20617070726f76616c206661696c65640000000000000000000000600082015250565b60006112926015836110f9565b915061129d8261125c565b602082019050919050565b600060208201905081810360008301526112c181611285565b9050919050565b600081905092915050565b82818337600083830152505050565b60006112ee83856112c8565b93506112fb8385846112d3565b82840190509392505050565b60006113148284866112e2565b91508190509392505050565b7f43616c6c206661696c6564000000000000000000000000000000000000000000600082015250565b6000611356600b836110f9565b915061136182611320565b602082019050919050565b6000602082019050818103600083015261138581611349565b9050919050565b7f4e6f20746f6b656e732072656365697665642066726f6d207377617000000000600082015250565b60006113c2601c836110f9565b91506113cd8261138c565b602082019050919050565b600060208201905081810360008301526113f1816113b5565b9050919050565b7f5468652063616c6c6572206d7573742062652074686520676f7665726e6f7200600082015250565b600061142e601f836110f9565b9150611439826113f8565b602082019050919050565b6000602082019050818103600083015261145d81611421565b9050919050565b7f4e6f20746f6b656e7320746f2073776565700000000000000000000000000000600082015250565b600061149a6012836110f9565b91506114a582611464565b602082019050919050565b600060208201905081810360008301526114c98161148d565b9050919050565b7f546f6b656e207472616e73666572206661696c65640000000000000000000000600082015250565b60006115066015836110f9565b9150611511826114d0565b602082019050919050565b60006020820190508181036000830152611535816114f9565b905091905056fea2646970667358221220f409874a62e38ccb17baffe05d64e89f0fa6fd6243b7a4baf89b287a7cb5e17b64736f6c634300081c0033", "devdoc": { "details": "The contract receives an address `to` (expected to be a DEX router) and `data` to execute a swapThe swap data must be encoded to send tokens to `msg.sender`CreditsManager pays for the swap on behalf of the user by deducting credits from their balance", "kind": "dev", @@ -284,7 +284,7 @@ "label": "seerCredits", "offset": 0, "slot": "2", - "type": "t_contract(SeerCredits)840" + "type": "t_contract(SeerCredits)949" }, { "astId": 405, @@ -311,7 +311,7 @@ "label": "contract ERC20", "numberOfBytes": "20" }, - "t_contract(SeerCredits)840": { + "t_contract(SeerCredits)949": { "encoding": "inplace", "label": "contract SeerCredits", "numberOfBytes": "20" diff --git a/contracts/deployments/gnosis/SeerCredits.json b/contracts/deployments/gnosis/SeerCredits.json index 445116f9..016f1399 100644 --- a/contracts/deployments/gnosis/SeerCredits.json +++ b/contracts/deployments/gnosis/SeerCredits.json @@ -1,5 +1,5 @@ { - "address": "0x3a0D8671eFcBc172eDBE32F91169BBc984dC607C", + "address": "0xEDd48e43EBd4E2b31238a5CBA8FD548fC051aCAF", "abi": [ { "inputs": [ @@ -75,6 +75,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_addresses", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "_amounts", + "type": "uint256[]" + } + ], + "name": "addCreditsBalance", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -225,6 +243,25 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "isAdmin", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -318,6 +355,24 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "_admin", + "type": "address" + }, + { + "internalType": "bool", + "name": "_isAdmin", + "type": "bool" + } + ], + "name": "setAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -416,33 +471,40 @@ "type": "function" } ], - "transactionHash": "0x259619472b4ecbea52c24564048ed46226eb0f841b9111aad1c7d63165fb762f", + "transactionHash": "0x97ece1a58e5088c3793327c9706e35c7d5da89ab27222f609b4f9e941b60d48e", "receipt": { "to": null, "from": "0x4EDCA105188a0783Ab3A6f09c50567D1E3F8591D", - "contractAddress": "0x3a0D8671eFcBc172eDBE32F91169BBc984dC607C", - "transactionIndex": 7, - "gasUsed": "2030777", + "contractAddress": "0xEDd48e43EBd4E2b31238a5CBA8FD548fC051aCAF", + "transactionIndex": 12, + "gasUsed": "2360089", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0x19bb09414e217b211ff5d2e44c6517babfc91bb259ddf9b8f3ed6b68208258a3", - "transactionHash": "0x259619472b4ecbea52c24564048ed46226eb0f841b9111aad1c7d63165fb762f", + "blockHash": "0x80543184420e87a1d2f39f18d15a37f3aed51ccdb36218ed12174d596f917265", + "transactionHash": "0x97ece1a58e5088c3793327c9706e35c7d5da89ab27222f609b4f9e941b60d48e", "logs": [], - "blockNumber": 42332224, - "cumulativeGasUsed": "11049057", + "blockNumber": 42439735, + "cumulativeGasUsed": "6549730", "status": 1, "byzantium": true }, "args": [ "0x4edca105188a0783ab3a6f09c50567d1e3f8591d" ], - "numDeployments": 2, - "solcInputHash": "2d3de33fa340cf567b57fc3a8edf08f0", - "metadata": "{\"compiler\":{\"version\":\"0.8.28+commit.7893614a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_governor\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DOMAIN_SEPARATOR\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"burn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_creditsManager\",\"type\":\"address\"}],\"name\":\"changeCreditsManager\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_governor\",\"type\":\"address\"}],\"name\":\"changeGovernor\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"creditsManager\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"nonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"permit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_addresses\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_amounts\",\"type\":\"uint256[]\"}],\"name\":\"setCreditsBalance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"changeCreditsManager(address)\":{\"details\":\"Change the credits manager of the contract.\",\"params\":{\"_creditsManager\":\"The address of the new credits manager.\"}},\"changeGovernor(address)\":{\"details\":\"Change the governor of the contract.\",\"params\":{\"_governor\":\"The address of the new governor.\"}},\"constructor\":{\"details\":\"Constructor.\",\"params\":{\"_governor\":\"The trusted governor of the contract.\"}},\"setCreditsBalance(address[],uint256[])\":{\"details\":\"Set credits balance for multiple addresses by minting or burning as needed.\",\"params\":{\"_addresses\":\"The list of addresses to set credits balance for.\",\"_amounts\":\"The list of amounts corresponding to each address.\"}}},\"title\":\"SeerCredits\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"notice\":\"ERC20 token representing trading credits that users can spend on DEX swaps\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/trading-credits/SeerCredits.sol\":\"SeerCredits\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":false,\"runs\":200},\"remappings\":[]},\"sources\":{\"solmate/src/tokens/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity >=0.8.0;\\n\\n/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.\\n/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)\\n/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)\\n/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.\\nabstract contract ERC20 {\\n /*//////////////////////////////////////////////////////////////\\n EVENTS\\n //////////////////////////////////////////////////////////////*/\\n\\n event Transfer(address indexed from, address indexed to, uint256 amount);\\n\\n event Approval(address indexed owner, address indexed spender, uint256 amount);\\n\\n /*//////////////////////////////////////////////////////////////\\n METADATA STORAGE\\n //////////////////////////////////////////////////////////////*/\\n\\n string public name;\\n\\n string public symbol;\\n\\n uint8 public immutable decimals;\\n\\n /*//////////////////////////////////////////////////////////////\\n ERC20 STORAGE\\n //////////////////////////////////////////////////////////////*/\\n\\n uint256 public totalSupply;\\n\\n mapping(address => uint256) public balanceOf;\\n\\n mapping(address => mapping(address => uint256)) public allowance;\\n\\n /*//////////////////////////////////////////////////////////////\\n EIP-2612 STORAGE\\n //////////////////////////////////////////////////////////////*/\\n\\n uint256 internal immutable INITIAL_CHAIN_ID;\\n\\n bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;\\n\\n mapping(address => uint256) public nonces;\\n\\n /*//////////////////////////////////////////////////////////////\\n CONSTRUCTOR\\n //////////////////////////////////////////////////////////////*/\\n\\n constructor(\\n string memory _name,\\n string memory _symbol,\\n uint8 _decimals\\n ) {\\n name = _name;\\n symbol = _symbol;\\n decimals = _decimals;\\n\\n INITIAL_CHAIN_ID = block.chainid;\\n INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n ERC20 LOGIC\\n //////////////////////////////////////////////////////////////*/\\n\\n function approve(address spender, uint256 amount) public virtual returns (bool) {\\n allowance[msg.sender][spender] = amount;\\n\\n emit Approval(msg.sender, spender, amount);\\n\\n return true;\\n }\\n\\n function transfer(address to, uint256 amount) public virtual returns (bool) {\\n balanceOf[msg.sender] -= amount;\\n\\n // Cannot overflow because the sum of all user\\n // balances can't exceed the max uint256 value.\\n unchecked {\\n balanceOf[to] += amount;\\n }\\n\\n emit Transfer(msg.sender, to, amount);\\n\\n return true;\\n }\\n\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) public virtual returns (bool) {\\n uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.\\n\\n if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;\\n\\n balanceOf[from] -= amount;\\n\\n // Cannot overflow because the sum of all user\\n // balances can't exceed the max uint256 value.\\n unchecked {\\n balanceOf[to] += amount;\\n }\\n\\n emit Transfer(from, to, amount);\\n\\n return true;\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n EIP-2612 LOGIC\\n //////////////////////////////////////////////////////////////*/\\n\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) public virtual {\\n require(deadline >= block.timestamp, \\\"PERMIT_DEADLINE_EXPIRED\\\");\\n\\n // Unchecked because the only math done is incrementing\\n // the owner's nonce which cannot realistically overflow.\\n unchecked {\\n address recoveredAddress = ecrecover(\\n keccak256(\\n abi.encodePacked(\\n \\\"\\\\x19\\\\x01\\\",\\n DOMAIN_SEPARATOR(),\\n keccak256(\\n abi.encode(\\n keccak256(\\n \\\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\\\"\\n ),\\n owner,\\n spender,\\n value,\\n nonces[owner]++,\\n deadline\\n )\\n )\\n )\\n ),\\n v,\\n r,\\n s\\n );\\n\\n require(recoveredAddress != address(0) && recoveredAddress == owner, \\\"INVALID_SIGNER\\\");\\n\\n allowance[recoveredAddress][spender] = value;\\n }\\n\\n emit Approval(owner, spender, value);\\n }\\n\\n function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {\\n return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();\\n }\\n\\n function computeDomainSeparator() internal view virtual returns (bytes32) {\\n return\\n keccak256(\\n abi.encode(\\n keccak256(\\\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\\\"),\\n keccak256(bytes(name)),\\n keccak256(\\\"1\\\"),\\n block.chainid,\\n address(this)\\n )\\n );\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n INTERNAL MINT/BURN LOGIC\\n //////////////////////////////////////////////////////////////*/\\n\\n function _mint(address to, uint256 amount) internal virtual {\\n totalSupply += amount;\\n\\n // Cannot overflow because the sum of all user\\n // balances can't exceed the max uint256 value.\\n unchecked {\\n balanceOf[to] += amount;\\n }\\n\\n emit Transfer(address(0), to, amount);\\n }\\n\\n function _burn(address from, uint256 amount) internal virtual {\\n balanceOf[from] -= amount;\\n\\n // Cannot underflow because a user's balance\\n // will never be larger than the total supply.\\n unchecked {\\n totalSupply -= amount;\\n }\\n\\n emit Transfer(from, address(0), amount);\\n }\\n}\\n\",\"keccak256\":\"0xcdfd8db76b2a3415620e4d18cc5545f3d50de792dbf2c3dd5adb40cbe6f94b10\",\"license\":\"AGPL-3.0-only\"},\"src/trading-credits/SeerCredits.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.28;\\n\\nimport {ERC20} from \\\"solmate/src/tokens/ERC20.sol\\\";\\n\\n/// @title SeerCredits\\n/// @notice ERC20 token representing trading credits that users can spend on DEX swaps\\ncontract SeerCredits is ERC20 {\\n address public governor; // The address that can make governance changes to the parameters of the contract.\\n address public creditsManager; // The address that can burn tokens (CreditsManager contract).\\n\\n modifier onlyGovernor() {\\n require(msg.sender == governor, \\\"Only governor can call this function\\\");\\n _;\\n }\\n\\n modifier onlyCreditsManager() {\\n require(msg.sender == creditsManager, \\\"Only credits manager can call this function\\\");\\n _;\\n }\\n\\n /// @dev Constructor.\\n /// @param _governor The trusted governor of the contract.\\n constructor(address _governor) ERC20(\\\"Seer Credits\\\", \\\"SEER_CREDITS\\\", 18) {\\n governor = _governor;\\n creditsManager = _governor;\\n }\\n\\n /// @dev Change the governor of the contract.\\n /// @param _governor The address of the new governor.\\n function changeGovernor(address _governor) external onlyGovernor {\\n governor = _governor;\\n }\\n\\n /// @dev Change the credits manager of the contract.\\n /// @param _creditsManager The address of the new credits manager.\\n function changeCreditsManager(address _creditsManager) external onlyGovernor {\\n creditsManager = _creditsManager;\\n }\\n\\n function mint(address to, uint256 amount) external onlyGovernor {\\n _mint(to, amount);\\n }\\n\\n function burn(address from, uint256 amount) external onlyCreditsManager {\\n _burn(from, amount);\\n }\\n\\n\\n /// @dev Set credits balance for multiple addresses by minting or burning as needed.\\n /// @param _addresses The list of addresses to set credits balance for.\\n /// @param _amounts The list of amounts corresponding to each address.\\n function setCreditsBalance(address[] memory _addresses, uint256[] memory _amounts) external onlyGovernor {\\n require(_addresses.length == _amounts.length, \\\"Arrays length mismatch\\\");\\n for (uint256 i; i < _addresses.length; ++i) {\\n uint256 currentBalance = this.balanceOf(_addresses[i]);\\n uint256 targetBalance = _amounts[i];\\n \\n if (currentBalance > targetBalance) {\\n // Burn excess tokens\\n uint256 burnAmount = currentBalance - targetBalance;\\n _burn(_addresses[i], burnAmount);\\n } else if (targetBalance > currentBalance) {\\n // Mint additional tokens\\n uint256 mintAmount = targetBalance - currentBalance;\\n _mint(_addresses[i], mintAmount);\\n }\\n // If currentBalance == targetBalance, do nothing\\n }\\n }\\n}\",\"keccak256\":\"0x37b49e69085a26a612831d01a9e3eb4a6b95e3d5c826626cf46d8e74bc93b17f\",\"license\":\"MIT\"}},\"version\":1}", - "bytecode": "0x60e060405234801561001057600080fd5b506040516128e23803806128e283398181016040528101906100329190610265565b6040518060400160405280600c81526020017f53656572204372656469747300000000000000000000000000000000000000008152506040518060400160405280600c81526020017f534545525f435245444954530000000000000000000000000000000000000000815250601282600090816100af91906104e2565b5081600190816100bf91906104e2565b508060ff1660808160ff16815250504660a081815250506100e461017660201b60201c565b60c0818152505050505080600660006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600760006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506106f8565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60006040516101a89190610657565b60405180910390207fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc646306040516020016101e79594939291906106a5565b60405160208183030381529060405280519060200120905090565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061023282610207565b9050919050565b61024281610227565b811461024d57600080fd5b50565b60008151905061025f81610239565b92915050565b60006020828403121561027b5761027a610202565b5b600061028984828501610250565b91505092915050565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061031357607f821691505b602082108103610326576103256102cc565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b60006008830261038e7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82610351565b6103988683610351565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b60006103df6103da6103d5846103b0565b6103ba565b6103b0565b9050919050565b6000819050919050565b6103f9836103c4565b61040d610405826103e6565b84845461035e565b825550505050565b600090565b610422610415565b61042d8184846103f0565b505050565b5b818110156104515761044660008261041a565b600181019050610433565b5050565b601f821115610496576104678161032c565b61047084610341565b8101602085101561047f578190505b61049361048b85610341565b830182610432565b50505b505050565b600082821c905092915050565b60006104b96000198460080261049b565b1980831691505092915050565b60006104d283836104a8565b9150826002028217905092915050565b6104eb82610292565b67ffffffffffffffff8111156105045761050361029d565b5b61050e82546102fb565b610519828285610455565b600060209050601f83116001811461054c576000841561053a578287015190505b61054485826104c6565b8655506105ac565b601f19841661055a8661032c565b60005b828110156105825784890151825560018201915060208501945060208101905061055d565b8683101561059f578489015161059b601f8916826104a8565b8355505b6001600288020188555050505b505050505050565b600081905092915050565b60008190508160005260206000209050919050565b600081546105e1816102fb565b6105eb81866105b4565b94506001821660008114610606576001811461061b5761064e565b60ff198316865281151582028601935061064e565b610624856105bf565b60005b8381101561064657815481890152600182019150602081019050610627565b838801955050505b50505092915050565b600061066382846105d4565b915081905092915050565b6000819050919050565b6106818161066e565b82525050565b610690816103b0565b82525050565b61069f81610227565b82525050565b600060a0820190506106ba6000830188610678565b6106c76020830187610678565b6106d46040830186610678565b6106e16060830185610687565b6106ee6080830184610696565b9695505050505050565b60805160a05160c0516121bb610727600039600061083801526000610804015260006107de01526121bb6000f3fe608060405234801561001057600080fd5b50600436106101215760003560e01c806370a08231116100ad578063aa425cbb11610071578063aa425cbb14610320578063d505accf1461033c578063dd62ed3e14610358578063e4c0aaf414610388578063e60cb498146103a457610121565b806370a08231146102565780637ecebe001461028657806395d89b41146102b65780639dc29fac146102d4578063a9059cbb146102f057610121565b806318160ddd116100f457806318160ddd146101b057806323b872dd146101ce578063313ce567146101fe5780633644e5151461021c57806340c10f191461023a57610121565b806306fdde0314610126578063095ea7b3146101445780630c340a241461017457806315fa932a14610192575b600080fd5b61012e6103c0565b60405161013b9190611517565b60405180910390f35b61015e600480360381019061015991906115e1565b61044e565b60405161016b919061163c565b60405180910390f35b61017c610540565b6040516101899190611666565b60405180910390f35b61019a610566565b6040516101a79190611666565b60405180910390f35b6101b861058c565b6040516101c59190611690565b60405180910390f35b6101e860048036038101906101e391906116ab565b610592565b6040516101f5919061163c565b60405180910390f35b6102066107dc565b604051610213919061171a565b60405180910390f35b610224610800565b604051610231919061174e565b60405180910390f35b610254600480360381019061024f91906115e1565b61085d565b005b610270600480360381019061026b9190611769565b6108fb565b60405161027d9190611690565b60405180910390f35b6102a0600480360381019061029b9190611769565b610913565b6040516102ad9190611690565b60405180910390f35b6102be61092b565b6040516102cb9190611517565b60405180910390f35b6102ee60048036038101906102e991906115e1565b6109b9565b005b61030a600480360381019061030591906115e1565b610a57565b604051610317919061163c565b60405180910390f35b61033a600480360381019061033591906119a1565b610b6b565b005b61035660048036038101906103519190611a71565b610d95565b005b610372600480360381019061036d9190611b13565b61108e565b60405161037f9190611690565b60405180910390f35b6103a2600480360381019061039d9190611769565b6110b3565b005b6103be60048036038101906103b99190611769565b611187565b005b600080546103cd90611b82565b80601f01602080910402602001604051908101604052809291908181526020018280546103f990611b82565b80156104465780601f1061041b57610100808354040283529160200191610446565b820191906000526020600020905b81548152906001019060200180831161042957829003601f168201915b505050505081565b600081600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405161052e9190611690565b60405180910390a36001905092915050565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60025481565b600080600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146106c85782816106479190611be2565b600460008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b82600360008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546107179190611be2565b9250508190555082600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040516107c89190611690565b60405180910390a360019150509392505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60007f000000000000000000000000000000000000000000000000000000000000000046146108365761083161125b565b610858565b7f00000000000000000000000000000000000000000000000000000000000000005b905090565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146108ed576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e490611c88565b60405180910390fd5b6108f782826112e7565b5050565b60036020528060005260406000206000915090505481565b60056020528060005260406000206000915090505481565b6001805461093890611b82565b80601f016020809104026020016040519081016040528092919081815260200182805461096490611b82565b80156109b15780601f10610986576101008083540402835291602001916109b1565b820191906000526020600020905b81548152906001019060200180831161099457829003601f168201915b505050505081565b600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610a49576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a4090611d1a565b60405180910390fd5b610a5382826113b7565b5050565b600081600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254610aa89190611be2565b9250508190555081600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610b599190611690565b60405180910390a36001905092915050565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610bfb576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bf290611c88565b60405180910390fd5b8051825114610c3f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c3690611d86565b60405180910390fd5b60005b8251811015610d905760003073ffffffffffffffffffffffffffffffffffffffff166370a08231858481518110610c7c57610c7b611da6565b5b60200260200101516040518263ffffffff1660e01b8152600401610ca09190611666565b602060405180830381865afa158015610cbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ce19190611dea565b90506000838381518110610cf857610cf7611da6565b5b6020026020010151905080821115610d445760008183610d189190611be2565b9050610d3e868581518110610d3057610d2f611da6565b5b6020026020010151826113b7565b50610d83565b81811115610d825760008282610d5a9190611be2565b9050610d80868581518110610d7257610d71611da6565b5b6020026020010151826112e7565b505b5b5050806001019050610c42565b505050565b42841015610dd8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610dcf90611e63565b60405180910390fd5b60006001610de4610800565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98a8a8a600560008f73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000815480929190600101919050558b604051602001610e6c96959493929190611e83565b60405160208183030381529060405280519060200120604051602001610e93929190611f5c565b6040516020818303038152906040528051906020012085858560405160008152602001604052604051610ec99493929190611f93565b6020604051602081039080840390855afa158015610eeb573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614158015610f5f57508773ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b610f9e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f9590612024565b60405180910390fd5b85600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550508573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258760405161107d9190611690565b60405180910390a350505050505050565b6004602052816000526040600020602052806000526040600020600091509150505481565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611143576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161113a90611c88565b60405180910390fd5b80600660006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611217576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161120e90611c88565b60405180910390fd5b80600760006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f600060405161128d91906120e7565b60405180910390207fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc646306040516020016112cc9594939291906120fe565b60405160208183030381529060405280519060200120905090565b80600260008282546112f99190612151565b9250508190555080600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516113ab9190611690565b60405180910390a35050565b80600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546114069190611be2565b9250508190555080600260008282540392505081905550600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161147b9190611690565b60405180910390a35050565b600081519050919050565b600082825260208201905092915050565b60005b838110156114c15780820151818401526020810190506114a6565b60008484015250505050565b6000601f19601f8301169050919050565b60006114e982611487565b6114f38185611492565b93506115038185602086016114a3565b61150c816114cd565b840191505092915050565b6000602082019050818103600083015261153181846114de565b905092915050565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006115788261154d565b9050919050565b6115888161156d565b811461159357600080fd5b50565b6000813590506115a58161157f565b92915050565b6000819050919050565b6115be816115ab565b81146115c957600080fd5b50565b6000813590506115db816115b5565b92915050565b600080604083850312156115f8576115f7611543565b5b600061160685828601611596565b9250506020611617858286016115cc565b9150509250929050565b60008115159050919050565b61163681611621565b82525050565b6000602082019050611651600083018461162d565b92915050565b6116608161156d565b82525050565b600060208201905061167b6000830184611657565b92915050565b61168a816115ab565b82525050565b60006020820190506116a56000830184611681565b92915050565b6000806000606084860312156116c4576116c3611543565b5b60006116d286828701611596565b93505060206116e386828701611596565b92505060406116f4868287016115cc565b9150509250925092565b600060ff82169050919050565b611714816116fe565b82525050565b600060208201905061172f600083018461170b565b92915050565b6000819050919050565b61174881611735565b82525050565b6000602082019050611763600083018461173f565b92915050565b60006020828403121561177f5761177e611543565b5b600061178d84828501611596565b91505092915050565b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6117d3826114cd565b810181811067ffffffffffffffff821117156117f2576117f161179b565b5b80604052505050565b6000611805611539565b905061181182826117ca565b919050565b600067ffffffffffffffff8211156118315761183061179b565b5b602082029050602081019050919050565b600080fd5b600061185a61185584611816565b6117fb565b9050808382526020820190506020840283018581111561187d5761187c611842565b5b835b818110156118a657806118928882611596565b84526020840193505060208101905061187f565b5050509392505050565b600082601f8301126118c5576118c4611796565b5b81356118d5848260208601611847565b91505092915050565b600067ffffffffffffffff8211156118f9576118f861179b565b5b602082029050602081019050919050565b600061191d611918846118de565b6117fb565b905080838252602082019050602084028301858111156119405761193f611842565b5b835b81811015611969578061195588826115cc565b845260208401935050602081019050611942565b5050509392505050565b600082601f83011261198857611987611796565b5b813561199884826020860161190a565b91505092915050565b600080604083850312156119b8576119b7611543565b5b600083013567ffffffffffffffff8111156119d6576119d5611548565b5b6119e2858286016118b0565b925050602083013567ffffffffffffffff811115611a0357611a02611548565b5b611a0f85828601611973565b9150509250929050565b611a22816116fe565b8114611a2d57600080fd5b50565b600081359050611a3f81611a19565b92915050565b611a4e81611735565b8114611a5957600080fd5b50565b600081359050611a6b81611a45565b92915050565b600080600080600080600060e0888a031215611a9057611a8f611543565b5b6000611a9e8a828b01611596565b9750506020611aaf8a828b01611596565b9650506040611ac08a828b016115cc565b9550506060611ad18a828b016115cc565b9450506080611ae28a828b01611a30565b93505060a0611af38a828b01611a5c565b92505060c0611b048a828b01611a5c565b91505092959891949750929550565b60008060408385031215611b2a57611b29611543565b5b6000611b3885828601611596565b9250506020611b4985828601611596565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680611b9a57607f821691505b602082108103611bad57611bac611b53565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000611bed826115ab565b9150611bf8836115ab565b9250828203905081811115611c1057611c0f611bb3565b5b92915050565b7f4f6e6c7920676f7665726e6f722063616e2063616c6c20746869732066756e6360008201527f74696f6e00000000000000000000000000000000000000000000000000000000602082015250565b6000611c72602483611492565b9150611c7d82611c16565b604082019050919050565b60006020820190508181036000830152611ca181611c65565b9050919050565b7f4f6e6c792063726564697473206d616e616765722063616e2063616c6c20746860008201527f69732066756e6374696f6e000000000000000000000000000000000000000000602082015250565b6000611d04602b83611492565b9150611d0f82611ca8565b604082019050919050565b60006020820190508181036000830152611d3381611cf7565b9050919050565b7f417272617973206c656e677468206d69736d6174636800000000000000000000600082015250565b6000611d70601683611492565b9150611d7b82611d3a565b602082019050919050565b60006020820190508181036000830152611d9f81611d63565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600081519050611de4816115b5565b92915050565b600060208284031215611e0057611dff611543565b5b6000611e0e84828501611dd5565b91505092915050565b7f5045524d49545f444541444c494e455f45585049524544000000000000000000600082015250565b6000611e4d601783611492565b9150611e5882611e17565b602082019050919050565b60006020820190508181036000830152611e7c81611e40565b9050919050565b600060c082019050611e98600083018961173f565b611ea56020830188611657565b611eb26040830187611657565b611ebf6060830186611681565b611ecc6080830185611681565b611ed960a0830184611681565b979650505050505050565b600081905092915050565b7f1901000000000000000000000000000000000000000000000000000000000000600082015250565b6000611f25600283611ee4565b9150611f3082611eef565b600282019050919050565b6000819050919050565b611f56611f5182611735565b611f3b565b82525050565b6000611f6782611f18565b9150611f738285611f45565b602082019150611f838284611f45565b6020820191508190509392505050565b6000608082019050611fa8600083018761173f565b611fb5602083018661170b565b611fc2604083018561173f565b611fcf606083018461173f565b95945050505050565b7f494e56414c49445f5349474e4552000000000000000000000000000000000000600082015250565b600061200e600e83611492565b915061201982611fd8565b602082019050919050565b6000602082019050818103600083015261203d81612001565b9050919050565b600081905092915050565b60008190508160005260206000209050919050565b6000815461207181611b82565b61207b8186612044565b9450600182166000811461209657600181146120ab576120de565b60ff19831686528115158202860193506120de565b6120b48561204f565b60005b838110156120d6578154818901526001820191506020810190506120b7565b838801955050505b50505092915050565b60006120f38284612064565b915081905092915050565b600060a082019050612113600083018861173f565b612120602083018761173f565b61212d604083018661173f565b61213a6060830185611681565b6121476080830184611657565b9695505050505050565b600061215c826115ab565b9150612167836115ab565b925082820190508082111561217f5761217e611bb3565b5b9291505056fea2646970667358221220f5c145f96cde2d6b38a0ab3bc709b26a257fda13bcc2ec52a5531cc641c540fd64736f6c634300081c0033", - "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106101215760003560e01c806370a08231116100ad578063aa425cbb11610071578063aa425cbb14610320578063d505accf1461033c578063dd62ed3e14610358578063e4c0aaf414610388578063e60cb498146103a457610121565b806370a08231146102565780637ecebe001461028657806395d89b41146102b65780639dc29fac146102d4578063a9059cbb146102f057610121565b806318160ddd116100f457806318160ddd146101b057806323b872dd146101ce578063313ce567146101fe5780633644e5151461021c57806340c10f191461023a57610121565b806306fdde0314610126578063095ea7b3146101445780630c340a241461017457806315fa932a14610192575b600080fd5b61012e6103c0565b60405161013b9190611517565b60405180910390f35b61015e600480360381019061015991906115e1565b61044e565b60405161016b919061163c565b60405180910390f35b61017c610540565b6040516101899190611666565b60405180910390f35b61019a610566565b6040516101a79190611666565b60405180910390f35b6101b861058c565b6040516101c59190611690565b60405180910390f35b6101e860048036038101906101e391906116ab565b610592565b6040516101f5919061163c565b60405180910390f35b6102066107dc565b604051610213919061171a565b60405180910390f35b610224610800565b604051610231919061174e565b60405180910390f35b610254600480360381019061024f91906115e1565b61085d565b005b610270600480360381019061026b9190611769565b6108fb565b60405161027d9190611690565b60405180910390f35b6102a0600480360381019061029b9190611769565b610913565b6040516102ad9190611690565b60405180910390f35b6102be61092b565b6040516102cb9190611517565b60405180910390f35b6102ee60048036038101906102e991906115e1565b6109b9565b005b61030a600480360381019061030591906115e1565b610a57565b604051610317919061163c565b60405180910390f35b61033a600480360381019061033591906119a1565b610b6b565b005b61035660048036038101906103519190611a71565b610d95565b005b610372600480360381019061036d9190611b13565b61108e565b60405161037f9190611690565b60405180910390f35b6103a2600480360381019061039d9190611769565b6110b3565b005b6103be60048036038101906103b99190611769565b611187565b005b600080546103cd90611b82565b80601f01602080910402602001604051908101604052809291908181526020018280546103f990611b82565b80156104465780601f1061041b57610100808354040283529160200191610446565b820191906000526020600020905b81548152906001019060200180831161042957829003601f168201915b505050505081565b600081600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405161052e9190611690565b60405180910390a36001905092915050565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60025481565b600080600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146106c85782816106479190611be2565b600460008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b82600360008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546107179190611be2565b9250508190555082600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040516107c89190611690565b60405180910390a360019150509392505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60007f000000000000000000000000000000000000000000000000000000000000000046146108365761083161125b565b610858565b7f00000000000000000000000000000000000000000000000000000000000000005b905090565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146108ed576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e490611c88565b60405180910390fd5b6108f782826112e7565b5050565b60036020528060005260406000206000915090505481565b60056020528060005260406000206000915090505481565b6001805461093890611b82565b80601f016020809104026020016040519081016040528092919081815260200182805461096490611b82565b80156109b15780601f10610986576101008083540402835291602001916109b1565b820191906000526020600020905b81548152906001019060200180831161099457829003601f168201915b505050505081565b600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610a49576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a4090611d1a565b60405180910390fd5b610a5382826113b7565b5050565b600081600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254610aa89190611be2565b9250508190555081600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610b599190611690565b60405180910390a36001905092915050565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610bfb576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bf290611c88565b60405180910390fd5b8051825114610c3f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c3690611d86565b60405180910390fd5b60005b8251811015610d905760003073ffffffffffffffffffffffffffffffffffffffff166370a08231858481518110610c7c57610c7b611da6565b5b60200260200101516040518263ffffffff1660e01b8152600401610ca09190611666565b602060405180830381865afa158015610cbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ce19190611dea565b90506000838381518110610cf857610cf7611da6565b5b6020026020010151905080821115610d445760008183610d189190611be2565b9050610d3e868581518110610d3057610d2f611da6565b5b6020026020010151826113b7565b50610d83565b81811115610d825760008282610d5a9190611be2565b9050610d80868581518110610d7257610d71611da6565b5b6020026020010151826112e7565b505b5b5050806001019050610c42565b505050565b42841015610dd8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610dcf90611e63565b60405180910390fd5b60006001610de4610800565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98a8a8a600560008f73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000815480929190600101919050558b604051602001610e6c96959493929190611e83565b60405160208183030381529060405280519060200120604051602001610e93929190611f5c565b6040516020818303038152906040528051906020012085858560405160008152602001604052604051610ec99493929190611f93565b6020604051602081039080840390855afa158015610eeb573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614158015610f5f57508773ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b610f9e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f9590612024565b60405180910390fd5b85600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550508573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258760405161107d9190611690565b60405180910390a350505050505050565b6004602052816000526040600020602052806000526040600020600091509150505481565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611143576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161113a90611c88565b60405180910390fd5b80600660006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611217576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161120e90611c88565b60405180910390fd5b80600760006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f600060405161128d91906120e7565b60405180910390207fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc646306040516020016112cc9594939291906120fe565b60405160208183030381529060405280519060200120905090565b80600260008282546112f99190612151565b9250508190555080600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516113ab9190611690565b60405180910390a35050565b80600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546114069190611be2565b9250508190555080600260008282540392505081905550600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161147b9190611690565b60405180910390a35050565b600081519050919050565b600082825260208201905092915050565b60005b838110156114c15780820151818401526020810190506114a6565b60008484015250505050565b6000601f19601f8301169050919050565b60006114e982611487565b6114f38185611492565b93506115038185602086016114a3565b61150c816114cd565b840191505092915050565b6000602082019050818103600083015261153181846114de565b905092915050565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006115788261154d565b9050919050565b6115888161156d565b811461159357600080fd5b50565b6000813590506115a58161157f565b92915050565b6000819050919050565b6115be816115ab565b81146115c957600080fd5b50565b6000813590506115db816115b5565b92915050565b600080604083850312156115f8576115f7611543565b5b600061160685828601611596565b9250506020611617858286016115cc565b9150509250929050565b60008115159050919050565b61163681611621565b82525050565b6000602082019050611651600083018461162d565b92915050565b6116608161156d565b82525050565b600060208201905061167b6000830184611657565b92915050565b61168a816115ab565b82525050565b60006020820190506116a56000830184611681565b92915050565b6000806000606084860312156116c4576116c3611543565b5b60006116d286828701611596565b93505060206116e386828701611596565b92505060406116f4868287016115cc565b9150509250925092565b600060ff82169050919050565b611714816116fe565b82525050565b600060208201905061172f600083018461170b565b92915050565b6000819050919050565b61174881611735565b82525050565b6000602082019050611763600083018461173f565b92915050565b60006020828403121561177f5761177e611543565b5b600061178d84828501611596565b91505092915050565b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6117d3826114cd565b810181811067ffffffffffffffff821117156117f2576117f161179b565b5b80604052505050565b6000611805611539565b905061181182826117ca565b919050565b600067ffffffffffffffff8211156118315761183061179b565b5b602082029050602081019050919050565b600080fd5b600061185a61185584611816565b6117fb565b9050808382526020820190506020840283018581111561187d5761187c611842565b5b835b818110156118a657806118928882611596565b84526020840193505060208101905061187f565b5050509392505050565b600082601f8301126118c5576118c4611796565b5b81356118d5848260208601611847565b91505092915050565b600067ffffffffffffffff8211156118f9576118f861179b565b5b602082029050602081019050919050565b600061191d611918846118de565b6117fb565b905080838252602082019050602084028301858111156119405761193f611842565b5b835b81811015611969578061195588826115cc565b845260208401935050602081019050611942565b5050509392505050565b600082601f83011261198857611987611796565b5b813561199884826020860161190a565b91505092915050565b600080604083850312156119b8576119b7611543565b5b600083013567ffffffffffffffff8111156119d6576119d5611548565b5b6119e2858286016118b0565b925050602083013567ffffffffffffffff811115611a0357611a02611548565b5b611a0f85828601611973565b9150509250929050565b611a22816116fe565b8114611a2d57600080fd5b50565b600081359050611a3f81611a19565b92915050565b611a4e81611735565b8114611a5957600080fd5b50565b600081359050611a6b81611a45565b92915050565b600080600080600080600060e0888a031215611a9057611a8f611543565b5b6000611a9e8a828b01611596565b9750506020611aaf8a828b01611596565b9650506040611ac08a828b016115cc565b9550506060611ad18a828b016115cc565b9450506080611ae28a828b01611a30565b93505060a0611af38a828b01611a5c565b92505060c0611b048a828b01611a5c565b91505092959891949750929550565b60008060408385031215611b2a57611b29611543565b5b6000611b3885828601611596565b9250506020611b4985828601611596565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680611b9a57607f821691505b602082108103611bad57611bac611b53565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000611bed826115ab565b9150611bf8836115ab565b9250828203905081811115611c1057611c0f611bb3565b5b92915050565b7f4f6e6c7920676f7665726e6f722063616e2063616c6c20746869732066756e6360008201527f74696f6e00000000000000000000000000000000000000000000000000000000602082015250565b6000611c72602483611492565b9150611c7d82611c16565b604082019050919050565b60006020820190508181036000830152611ca181611c65565b9050919050565b7f4f6e6c792063726564697473206d616e616765722063616e2063616c6c20746860008201527f69732066756e6374696f6e000000000000000000000000000000000000000000602082015250565b6000611d04602b83611492565b9150611d0f82611ca8565b604082019050919050565b60006020820190508181036000830152611d3381611cf7565b9050919050565b7f417272617973206c656e677468206d69736d6174636800000000000000000000600082015250565b6000611d70601683611492565b9150611d7b82611d3a565b602082019050919050565b60006020820190508181036000830152611d9f81611d63565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600081519050611de4816115b5565b92915050565b600060208284031215611e0057611dff611543565b5b6000611e0e84828501611dd5565b91505092915050565b7f5045524d49545f444541444c494e455f45585049524544000000000000000000600082015250565b6000611e4d601783611492565b9150611e5882611e17565b602082019050919050565b60006020820190508181036000830152611e7c81611e40565b9050919050565b600060c082019050611e98600083018961173f565b611ea56020830188611657565b611eb26040830187611657565b611ebf6060830186611681565b611ecc6080830185611681565b611ed960a0830184611681565b979650505050505050565b600081905092915050565b7f1901000000000000000000000000000000000000000000000000000000000000600082015250565b6000611f25600283611ee4565b9150611f3082611eef565b600282019050919050565b6000819050919050565b611f56611f5182611735565b611f3b565b82525050565b6000611f6782611f18565b9150611f738285611f45565b602082019150611f838284611f45565b6020820191508190509392505050565b6000608082019050611fa8600083018761173f565b611fb5602083018661170b565b611fc2604083018561173f565b611fcf606083018461173f565b95945050505050565b7f494e56414c49445f5349474e4552000000000000000000000000000000000000600082015250565b600061200e600e83611492565b915061201982611fd8565b602082019050919050565b6000602082019050818103600083015261203d81612001565b9050919050565b600081905092915050565b60008190508160005260206000209050919050565b6000815461207181611b82565b61207b8186612044565b9450600182166000811461209657600181146120ab576120de565b60ff19831686528115158202860193506120de565b6120b48561204f565b60005b838110156120d6578154818901526001820191506020810190506120b7565b838801955050505b50505092915050565b60006120f38284612064565b915081905092915050565b600060a082019050612113600083018861173f565b612120602083018761173f565b61212d604083018661173f565b61213a6060830185611681565b6121476080830184611657565b9695505050505050565b600061215c826115ab565b9150612167836115ab565b925082820190508082111561217f5761217e611bb3565b5b9291505056fea2646970667358221220f5c145f96cde2d6b38a0ab3bc709b26a257fda13bcc2ec52a5531cc641c540fd64736f6c634300081c0033", + "numDeployments": 3, + "solcInputHash": "7693ac2519ab88153958ebed4942cb22", + "metadata": "{\"compiler\":{\"version\":\"0.8.28+commit.7893614a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_governor\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DOMAIN_SEPARATOR\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_addresses\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_amounts\",\"type\":\"uint256[]\"}],\"name\":\"addCreditsBalance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"burn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_creditsManager\",\"type\":\"address\"}],\"name\":\"changeCreditsManager\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_governor\",\"type\":\"address\"}],\"name\":\"changeGovernor\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"creditsManager\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"isAdmin\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"nonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"permit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_admin\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"_isAdmin\",\"type\":\"bool\"}],\"name\":\"setAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_addresses\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_amounts\",\"type\":\"uint256[]\"}],\"name\":\"setCreditsBalance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"addCreditsBalance(address[],uint256[])\":{\"details\":\"Add credits balance to multiple addresses by minting tokens.\",\"params\":{\"_addresses\":\"The list of addresses to add credits balance to.\",\"_amounts\":\"The list of amounts to add to each address.\"}},\"changeCreditsManager(address)\":{\"details\":\"Change the credits manager of the contract.\",\"params\":{\"_creditsManager\":\"The address of the new credits manager.\"}},\"changeGovernor(address)\":{\"details\":\"Change the governor of the contract.\",\"params\":{\"_governor\":\"The address of the new governor.\"}},\"constructor\":{\"details\":\"Constructor.\",\"params\":{\"_governor\":\"The trusted governor of the contract.\"}},\"setAdmin(address,bool)\":{\"details\":\"Set admin status for an address.\",\"params\":{\"_admin\":\"The address to set admin status for.\",\"_isAdmin\":\"Boolean indicating whether the address should be an admin.\"}},\"setCreditsBalance(address[],uint256[])\":{\"details\":\"Set credits balance for multiple addresses by minting or burning as needed.\",\"params\":{\"_addresses\":\"The list of addresses to set credits balance for.\",\"_amounts\":\"The list of amounts corresponding to each address.\"}}},\"title\":\"SeerCredits\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"notice\":\"ERC20 token representing trading credits that users can spend on DEX swaps\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/trading-credits/SeerCredits.sol\":\"SeerCredits\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":false,\"runs\":200},\"remappings\":[]},\"sources\":{\"solmate/src/tokens/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity >=0.8.0;\\n\\n/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.\\n/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)\\n/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)\\n/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.\\nabstract contract ERC20 {\\n /*//////////////////////////////////////////////////////////////\\n EVENTS\\n //////////////////////////////////////////////////////////////*/\\n\\n event Transfer(address indexed from, address indexed to, uint256 amount);\\n\\n event Approval(address indexed owner, address indexed spender, uint256 amount);\\n\\n /*//////////////////////////////////////////////////////////////\\n METADATA STORAGE\\n //////////////////////////////////////////////////////////////*/\\n\\n string public name;\\n\\n string public symbol;\\n\\n uint8 public immutable decimals;\\n\\n /*//////////////////////////////////////////////////////////////\\n ERC20 STORAGE\\n //////////////////////////////////////////////////////////////*/\\n\\n uint256 public totalSupply;\\n\\n mapping(address => uint256) public balanceOf;\\n\\n mapping(address => mapping(address => uint256)) public allowance;\\n\\n /*//////////////////////////////////////////////////////////////\\n EIP-2612 STORAGE\\n //////////////////////////////////////////////////////////////*/\\n\\n uint256 internal immutable INITIAL_CHAIN_ID;\\n\\n bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;\\n\\n mapping(address => uint256) public nonces;\\n\\n /*//////////////////////////////////////////////////////////////\\n CONSTRUCTOR\\n //////////////////////////////////////////////////////////////*/\\n\\n constructor(\\n string memory _name,\\n string memory _symbol,\\n uint8 _decimals\\n ) {\\n name = _name;\\n symbol = _symbol;\\n decimals = _decimals;\\n\\n INITIAL_CHAIN_ID = block.chainid;\\n INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n ERC20 LOGIC\\n //////////////////////////////////////////////////////////////*/\\n\\n function approve(address spender, uint256 amount) public virtual returns (bool) {\\n allowance[msg.sender][spender] = amount;\\n\\n emit Approval(msg.sender, spender, amount);\\n\\n return true;\\n }\\n\\n function transfer(address to, uint256 amount) public virtual returns (bool) {\\n balanceOf[msg.sender] -= amount;\\n\\n // Cannot overflow because the sum of all user\\n // balances can't exceed the max uint256 value.\\n unchecked {\\n balanceOf[to] += amount;\\n }\\n\\n emit Transfer(msg.sender, to, amount);\\n\\n return true;\\n }\\n\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) public virtual returns (bool) {\\n uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.\\n\\n if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;\\n\\n balanceOf[from] -= amount;\\n\\n // Cannot overflow because the sum of all user\\n // balances can't exceed the max uint256 value.\\n unchecked {\\n balanceOf[to] += amount;\\n }\\n\\n emit Transfer(from, to, amount);\\n\\n return true;\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n EIP-2612 LOGIC\\n //////////////////////////////////////////////////////////////*/\\n\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) public virtual {\\n require(deadline >= block.timestamp, \\\"PERMIT_DEADLINE_EXPIRED\\\");\\n\\n // Unchecked because the only math done is incrementing\\n // the owner's nonce which cannot realistically overflow.\\n unchecked {\\n address recoveredAddress = ecrecover(\\n keccak256(\\n abi.encodePacked(\\n \\\"\\\\x19\\\\x01\\\",\\n DOMAIN_SEPARATOR(),\\n keccak256(\\n abi.encode(\\n keccak256(\\n \\\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\\\"\\n ),\\n owner,\\n spender,\\n value,\\n nonces[owner]++,\\n deadline\\n )\\n )\\n )\\n ),\\n v,\\n r,\\n s\\n );\\n\\n require(recoveredAddress != address(0) && recoveredAddress == owner, \\\"INVALID_SIGNER\\\");\\n\\n allowance[recoveredAddress][spender] = value;\\n }\\n\\n emit Approval(owner, spender, value);\\n }\\n\\n function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {\\n return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();\\n }\\n\\n function computeDomainSeparator() internal view virtual returns (bytes32) {\\n return\\n keccak256(\\n abi.encode(\\n keccak256(\\\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\\\"),\\n keccak256(bytes(name)),\\n keccak256(\\\"1\\\"),\\n block.chainid,\\n address(this)\\n )\\n );\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n INTERNAL MINT/BURN LOGIC\\n //////////////////////////////////////////////////////////////*/\\n\\n function _mint(address to, uint256 amount) internal virtual {\\n totalSupply += amount;\\n\\n // Cannot overflow because the sum of all user\\n // balances can't exceed the max uint256 value.\\n unchecked {\\n balanceOf[to] += amount;\\n }\\n\\n emit Transfer(address(0), to, amount);\\n }\\n\\n function _burn(address from, uint256 amount) internal virtual {\\n balanceOf[from] -= amount;\\n\\n // Cannot underflow because a user's balance\\n // will never be larger than the total supply.\\n unchecked {\\n totalSupply -= amount;\\n }\\n\\n emit Transfer(from, address(0), amount);\\n }\\n}\\n\",\"keccak256\":\"0xcdfd8db76b2a3415620e4d18cc5545f3d50de792dbf2c3dd5adb40cbe6f94b10\",\"license\":\"AGPL-3.0-only\"},\"src/trading-credits/SeerCredits.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.28;\\n\\nimport {ERC20} from \\\"solmate/src/tokens/ERC20.sol\\\";\\n\\n/// @title SeerCredits\\n/// @notice ERC20 token representing trading credits that users can spend on DEX swaps\\ncontract SeerCredits is ERC20 {\\n address public governor; // The address that can make governance changes to the parameters of the contract.\\n address public creditsManager; // The address that can burn tokens (CreditsManager contract).\\n mapping(address => bool) public isAdmin; // Mapping to track admin addresses\\n\\n modifier onlyGovernor() {\\n require(msg.sender == governor, \\\"Only governor can call this function\\\");\\n _;\\n }\\n\\n modifier onlyCreditsManager() {\\n require(msg.sender == creditsManager, \\\"Only credits manager can call this function\\\");\\n _;\\n }\\n\\n modifier onlyAdmin() {\\n require(isAdmin[msg.sender], \\\"Only admin can call this function\\\");\\n _;\\n }\\n\\n /// @dev Constructor.\\n /// @param _governor The trusted governor of the contract.\\n constructor(address _governor) ERC20(\\\"Seer Credits\\\", \\\"SEER_CREDITS\\\", 18) {\\n governor = _governor;\\n creditsManager = _governor;\\n isAdmin[_governor] = true;\\n }\\n\\n /// @dev Change the governor of the contract.\\n /// @param _governor The address of the new governor.\\n function changeGovernor(address _governor) external onlyGovernor {\\n require(_governor != address(0), \\\"Invalid governor address\\\");\\n governor = _governor;\\n }\\n\\n /// @dev Change the credits manager of the contract.\\n /// @param _creditsManager The address of the new credits manager.\\n function changeCreditsManager(address _creditsManager) external onlyGovernor {\\n creditsManager = _creditsManager;\\n }\\n\\n /// @dev Set admin status for an address.\\n /// @param _admin The address to set admin status for.\\n /// @param _isAdmin Boolean indicating whether the address should be an admin.\\n function setAdmin(address _admin, bool _isAdmin) external onlyGovernor {\\n require(_admin != address(0), \\\"Invalid admin address\\\");\\n isAdmin[_admin] = _isAdmin;\\n }\\n\\n function mint(address to, uint256 amount) external onlyGovernor {\\n _mint(to, amount);\\n }\\n\\n function burn(address from, uint256 amount) external onlyCreditsManager {\\n _burn(from, amount);\\n }\\n\\n\\n /// @dev Set credits balance for multiple addresses by minting or burning as needed.\\n /// @param _addresses The list of addresses to set credits balance for.\\n /// @param _amounts The list of amounts corresponding to each address.\\n function setCreditsBalance(address[] memory _addresses, uint256[] memory _amounts) external onlyAdmin {\\n require(_addresses.length == _amounts.length, \\\"Arrays length mismatch\\\");\\n for (uint256 i; i < _addresses.length; ++i) {\\n uint256 currentBalance = this.balanceOf(_addresses[i]);\\n uint256 targetBalance = _amounts[i];\\n \\n if (currentBalance > targetBalance) {\\n // Burn excess tokens\\n uint256 burnAmount = currentBalance - targetBalance;\\n _burn(_addresses[i], burnAmount);\\n } else if (targetBalance > currentBalance) {\\n // Mint additional tokens\\n uint256 mintAmount = targetBalance - currentBalance;\\n _mint(_addresses[i], mintAmount);\\n }\\n // If currentBalance == targetBalance, do nothing\\n }\\n }\\n\\n /// @dev Add credits balance to multiple addresses by minting tokens.\\n /// @param _addresses The list of addresses to add credits balance to.\\n /// @param _amounts The list of amounts to add to each address.\\n function addCreditsBalance(address[] memory _addresses, uint256[] memory _amounts) external onlyAdmin {\\n require(_addresses.length == _amounts.length, \\\"Arrays length mismatch\\\");\\n for (uint256 i; i < _addresses.length; ++i) {\\n if (_amounts[i] > 0) {\\n _mint(_addresses[i], _amounts[i]);\\n }\\n }\\n }\\n}\",\"keccak256\":\"0xbbf9e34771ae3c29750998d870dbb0f0c71b0972057b78c85f3f523de50ded25\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x60e060405234801561001057600080fd5b50604051612ecc380380612ecc833981810160405281019061003291906102bd565b6040518060400160405280600c81526020017f53656572204372656469747300000000000000000000000000000000000000008152506040518060400160405280600c81526020017f534545525f435245444954530000000000000000000000000000000000000000815250601282600090816100af919061053a565b5081600190816100bf919061053a565b508060ff1660808160ff16815250504660a081815250506100e46101ce60201b60201c565b60c0818152505050505080600660006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600760006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001600860008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555050610750565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f600060405161020091906106af565b60405180910390207fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6463060405160200161023f9594939291906106fd565b60405160208183030381529060405280519060200120905090565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061028a8261025f565b9050919050565b61029a8161027f565b81146102a557600080fd5b50565b6000815190506102b781610291565b92915050565b6000602082840312156102d3576102d261025a565b5b60006102e1848285016102a8565b91505092915050565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061036b57607f821691505b60208210810361037e5761037d610324565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b6000600883026103e67fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff826103a9565b6103f086836103a9565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b600061043761043261042d84610408565b610412565b610408565b9050919050565b6000819050919050565b6104518361041c565b61046561045d8261043e565b8484546103b6565b825550505050565b600090565b61047a61046d565b610485818484610448565b505050565b5b818110156104a95761049e600082610472565b60018101905061048b565b5050565b601f8211156104ee576104bf81610384565b6104c884610399565b810160208510156104d7578190505b6104eb6104e385610399565b83018261048a565b50505b505050565b600082821c905092915050565b6000610511600019846008026104f3565b1980831691505092915050565b600061052a8383610500565b9150826002028217905092915050565b610543826102ea565b67ffffffffffffffff81111561055c5761055b6102f5565b5b6105668254610353565b6105718282856104ad565b600060209050601f8311600181146105a45760008415610592578287015190505b61059c858261051e565b865550610604565b601f1984166105b286610384565b60005b828110156105da578489015182556001820191506020850194506020810190506105b5565b868310156105f757848901516105f3601f891682610500565b8355505b6001600288020188555050505b505050505050565b600081905092915050565b60008190508160005260206000209050919050565b6000815461063981610353565b610643818661060c565b9450600182166000811461065e5760018114610673576106a6565b60ff19831686528115158202860193506106a6565b61067c85610617565b60005b8381101561069e5781548189015260018201915060208101905061067f565b838801955050505b50505092915050565b60006106bb828461062c565b915081905092915050565b6000819050919050565b6106d9816106c6565b82525050565b6106e881610408565b82525050565b6106f78161027f565b82525050565b600060a08201905061071260008301886106d0565b61071f60208301876106d0565b61072c60408301866106d0565b61073960608301856106df565b61074660808301846106ee565b9695505050505050565b60805160a05160c05161274d61077f60003960006108e1015260006108ad01526000610887015261274d6000f3fe608060405234801561001057600080fd5b50600436106101425760003560e01c806370a08231116100b8578063a9059cbb1161007c578063a9059cbb14610379578063aa425cbb146103a9578063d505accf146103c5578063dd62ed3e146103e1578063e4c0aaf414610411578063e60cb4981461042d57610142565b806370a08231146102c35780637ecebe00146102f35780639202c7a01461032357806395d89b411461033f5780639dc29fac1461035d57610142565b806323b872dd1161010a57806323b872dd146101ef57806324d7806c1461021f578063313ce5671461024f5780633644e5151461026d57806340c10f191461028b5780634b0bddd2146102a757610142565b806306fdde0314610147578063095ea7b3146101655780630c340a241461019557806315fa932a146101b357806318160ddd146101d1575b600080fd5b61014f610449565b60405161015c91906118d3565b60405180910390f35b61017f600480360381019061017a919061199d565b6104d7565b60405161018c91906119f8565b60405180910390f35b61019d6105c9565b6040516101aa9190611a22565b60405180910390f35b6101bb6105ef565b6040516101c89190611a22565b60405180910390f35b6101d9610615565b6040516101e69190611a4c565b60405180910390f35b61020960048036038101906102049190611a67565b61061b565b60405161021691906119f8565b60405180910390f35b61023960048036038101906102349190611aba565b610865565b60405161024691906119f8565b60405180910390f35b610257610885565b6040516102649190611b03565b60405180910390f35b6102756108a9565b6040516102829190611b37565b60405180910390f35b6102a560048036038101906102a0919061199d565b610906565b005b6102c160048036038101906102bc9190611b7e565b6109a4565b005b6102dd60048036038101906102d89190611aba565b610afe565b6040516102ea9190611a4c565b60405180910390f35b61030d60048036038101906103089190611aba565b610b16565b60405161031a9190611a4c565b60405180910390f35b61033d60048036038101906103389190611dc9565b610b2e565b005b610347610c7c565b60405161035491906118d3565b60405180910390f35b6103776004803603810190610372919061199d565b610d0a565b005b610393600480360381019061038e919061199d565b610da8565b6040516103a091906119f8565b60405180910390f35b6103c360048036038101906103be9190611dc9565b610ebc565b005b6103df60048036038101906103da9190611e99565b6110e2565b005b6103fb60048036038101906103f69190611f3b565b6113db565b6040516104089190611a4c565b60405180910390f35b61042b60048036038101906104269190611aba565b611400565b005b61044760048036038101906104429190611aba565b611543565b005b6000805461045690611faa565b80601f016020809104026020016040519081016040528092919081815260200182805461048290611faa565b80156104cf5780601f106104a4576101008083540402835291602001916104cf565b820191906000526020600020905b8154815290600101906020018083116104b257829003601f168201915b505050505081565b600081600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040516105b79190611a4c565b60405180910390a36001905092915050565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60025481565b600080600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146107515782816106d0919061200a565b600460008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b82600360008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546107a0919061200a565b9250508190555082600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040516108519190611a4c565b60405180910390a360019150509392505050565b60086020528060005260406000206000915054906101000a900460ff1681565b7f000000000000000000000000000000000000000000000000000000000000000081565b60007f000000000000000000000000000000000000000000000000000000000000000046146108df576108da611617565b610901565b7f00000000000000000000000000000000000000000000000000000000000000005b905090565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610996576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161098d906120b0565b60405180910390fd5b6109a082826116a3565b5050565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610a34576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a2b906120b0565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610aa3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a9a9061211c565b60405180910390fd5b80600860008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b60036020528060005260406000206000915090505481565b60056020528060005260406000206000915090505481565b600860003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610bba576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb1906121ae565b60405180910390fd5b8051825114610bfe576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bf59061221a565b60405180910390fd5b60005b8251811015610c77576000828281518110610c1f57610c1e61223a565b5b60200260200101511115610c6c57610c6b838281518110610c4357610c4261223a565b5b6020026020010151838381518110610c5e57610c5d61223a565b5b60200260200101516116a3565b5b806001019050610c01565b505050565b60018054610c8990611faa565b80601f0160208091040260200160405190810160405280929190818152602001828054610cb590611faa565b8015610d025780601f10610cd757610100808354040283529160200191610d02565b820191906000526020600020905b815481529060010190602001808311610ce557829003601f168201915b505050505081565b600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610d9a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d91906122db565b60405180910390fd5b610da48282611773565b5050565b600081600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254610df9919061200a565b9250508190555081600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610eaa9190611a4c565b60405180910390a36001905092915050565b600860003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610f48576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f3f906121ae565b60405180910390fd5b8051825114610f8c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f839061221a565b60405180910390fd5b60005b82518110156110dd5760003073ffffffffffffffffffffffffffffffffffffffff166370a08231858481518110610fc957610fc861223a565b5b60200260200101516040518263ffffffff1660e01b8152600401610fed9190611a22565b602060405180830381865afa15801561100a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061102e9190612310565b905060008383815181106110455761104461223a565b5b60200260200101519050808211156110915760008183611065919061200a565b905061108b86858151811061107d5761107c61223a565b5b602002602001015182611773565b506110d0565b818111156110cf57600082826110a7919061200a565b90506110cd8685815181106110bf576110be61223a565b5b6020026020010151826116a3565b505b5b5050806001019050610f8f565b505050565b42841015611125576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161111c90612389565b60405180910390fd5b600060016111316108a9565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98a8a8a600560008f73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000815480929190600101919050558b6040516020016111b9969594939291906123a9565b604051602081830303815290604052805190602001206040516020016111e0929190612482565b604051602081830303815290604052805190602001208585856040516000815260200160405260405161121694939291906124b9565b6020604051602081039080840390855afa158015611238573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141580156112ac57508773ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b6112eb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112e29061254a565b60405180910390fd5b85600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550508573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925876040516113ca9190611a4c565b60405180910390a350505050505050565b6004602052816000526040600020602052806000526040600020600091509150505481565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611490576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611487906120b0565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036114ff576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114f6906125b6565b60405180910390fd5b80600660006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146115d3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016115ca906120b0565b60405180910390fd5b80600760006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60006040516116499190612679565b60405180910390207fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc64630604051602001611688959493929190612690565b60405160208183030381529060405280519060200120905090565b80600260008282546116b591906126e3565b9250508190555080600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516117679190611a4c565b60405180910390a35050565b80600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546117c2919061200a565b9250508190555080600260008282540392505081905550600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516118379190611a4c565b60405180910390a35050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561187d578082015181840152602081019050611862565b60008484015250505050565b6000601f19601f8301169050919050565b60006118a582611843565b6118af818561184e565b93506118bf81856020860161185f565b6118c881611889565b840191505092915050565b600060208201905081810360008301526118ed818461189a565b905092915050565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061193482611909565b9050919050565b61194481611929565b811461194f57600080fd5b50565b6000813590506119618161193b565b92915050565b6000819050919050565b61197a81611967565b811461198557600080fd5b50565b60008135905061199781611971565b92915050565b600080604083850312156119b4576119b36118ff565b5b60006119c285828601611952565b92505060206119d385828601611988565b9150509250929050565b60008115159050919050565b6119f2816119dd565b82525050565b6000602082019050611a0d60008301846119e9565b92915050565b611a1c81611929565b82525050565b6000602082019050611a376000830184611a13565b92915050565b611a4681611967565b82525050565b6000602082019050611a616000830184611a3d565b92915050565b600080600060608486031215611a8057611a7f6118ff565b5b6000611a8e86828701611952565b9350506020611a9f86828701611952565b9250506040611ab086828701611988565b9150509250925092565b600060208284031215611ad057611acf6118ff565b5b6000611ade84828501611952565b91505092915050565b600060ff82169050919050565b611afd81611ae7565b82525050565b6000602082019050611b186000830184611af4565b92915050565b6000819050919050565b611b3181611b1e565b82525050565b6000602082019050611b4c6000830184611b28565b92915050565b611b5b816119dd565b8114611b6657600080fd5b50565b600081359050611b7881611b52565b92915050565b60008060408385031215611b9557611b946118ff565b5b6000611ba385828601611952565b9250506020611bb485828601611b69565b9150509250929050565b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b611bfb82611889565b810181811067ffffffffffffffff82111715611c1a57611c19611bc3565b5b80604052505050565b6000611c2d6118f5565b9050611c398282611bf2565b919050565b600067ffffffffffffffff821115611c5957611c58611bc3565b5b602082029050602081019050919050565b600080fd5b6000611c82611c7d84611c3e565b611c23565b90508083825260208201905060208402830185811115611ca557611ca4611c6a565b5b835b81811015611cce5780611cba8882611952565b845260208401935050602081019050611ca7565b5050509392505050565b600082601f830112611ced57611cec611bbe565b5b8135611cfd848260208601611c6f565b91505092915050565b600067ffffffffffffffff821115611d2157611d20611bc3565b5b602082029050602081019050919050565b6000611d45611d4084611d06565b611c23565b90508083825260208201905060208402830185811115611d6857611d67611c6a565b5b835b81811015611d915780611d7d8882611988565b845260208401935050602081019050611d6a565b5050509392505050565b600082601f830112611db057611daf611bbe565b5b8135611dc0848260208601611d32565b91505092915050565b60008060408385031215611de057611ddf6118ff565b5b600083013567ffffffffffffffff811115611dfe57611dfd611904565b5b611e0a85828601611cd8565b925050602083013567ffffffffffffffff811115611e2b57611e2a611904565b5b611e3785828601611d9b565b9150509250929050565b611e4a81611ae7565b8114611e5557600080fd5b50565b600081359050611e6781611e41565b92915050565b611e7681611b1e565b8114611e8157600080fd5b50565b600081359050611e9381611e6d565b92915050565b600080600080600080600060e0888a031215611eb857611eb76118ff565b5b6000611ec68a828b01611952565b9750506020611ed78a828b01611952565b9650506040611ee88a828b01611988565b9550506060611ef98a828b01611988565b9450506080611f0a8a828b01611e58565b93505060a0611f1b8a828b01611e84565b92505060c0611f2c8a828b01611e84565b91505092959891949750929550565b60008060408385031215611f5257611f516118ff565b5b6000611f6085828601611952565b9250506020611f7185828601611952565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680611fc257607f821691505b602082108103611fd557611fd4611f7b565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061201582611967565b915061202083611967565b925082820390508181111561203857612037611fdb565b5b92915050565b7f4f6e6c7920676f7665726e6f722063616e2063616c6c20746869732066756e6360008201527f74696f6e00000000000000000000000000000000000000000000000000000000602082015250565b600061209a60248361184e565b91506120a58261203e565b604082019050919050565b600060208201905081810360008301526120c98161208d565b9050919050565b7f496e76616c69642061646d696e20616464726573730000000000000000000000600082015250565b600061210660158361184e565b9150612111826120d0565b602082019050919050565b60006020820190508181036000830152612135816120f9565b9050919050565b7f4f6e6c792061646d696e2063616e2063616c6c20746869732066756e6374696f60008201527f6e00000000000000000000000000000000000000000000000000000000000000602082015250565b600061219860218361184e565b91506121a38261213c565b604082019050919050565b600060208201905081810360008301526121c78161218b565b9050919050565b7f417272617973206c656e677468206d69736d6174636800000000000000000000600082015250565b600061220460168361184e565b915061220f826121ce565b602082019050919050565b60006020820190508181036000830152612233816121f7565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4f6e6c792063726564697473206d616e616765722063616e2063616c6c20746860008201527f69732066756e6374696f6e000000000000000000000000000000000000000000602082015250565b60006122c5602b8361184e565b91506122d082612269565b604082019050919050565b600060208201905081810360008301526122f4816122b8565b9050919050565b60008151905061230a81611971565b92915050565b600060208284031215612326576123256118ff565b5b6000612334848285016122fb565b91505092915050565b7f5045524d49545f444541444c494e455f45585049524544000000000000000000600082015250565b600061237360178361184e565b915061237e8261233d565b602082019050919050565b600060208201905081810360008301526123a281612366565b9050919050565b600060c0820190506123be6000830189611b28565b6123cb6020830188611a13565b6123d86040830187611a13565b6123e56060830186611a3d565b6123f26080830185611a3d565b6123ff60a0830184611a3d565b979650505050505050565b600081905092915050565b7f1901000000000000000000000000000000000000000000000000000000000000600082015250565b600061244b60028361240a565b915061245682612415565b600282019050919050565b6000819050919050565b61247c61247782611b1e565b612461565b82525050565b600061248d8261243e565b9150612499828561246b565b6020820191506124a9828461246b565b6020820191508190509392505050565b60006080820190506124ce6000830187611b28565b6124db6020830186611af4565b6124e86040830185611b28565b6124f56060830184611b28565b95945050505050565b7f494e56414c49445f5349474e4552000000000000000000000000000000000000600082015250565b6000612534600e8361184e565b915061253f826124fe565b602082019050919050565b6000602082019050818103600083015261256381612527565b9050919050565b7f496e76616c696420676f7665726e6f7220616464726573730000000000000000600082015250565b60006125a060188361184e565b91506125ab8261256a565b602082019050919050565b600060208201905081810360008301526125cf81612593565b9050919050565b600081905092915050565b60008190508160005260206000209050919050565b6000815461260381611faa565b61260d81866125d6565b94506001821660008114612628576001811461263d57612670565b60ff1983168652811515820286019350612670565b612646856125e1565b60005b8381101561266857815481890152600182019150602081019050612649565b838801955050505b50505092915050565b600061268582846125f6565b915081905092915050565b600060a0820190506126a56000830188611b28565b6126b26020830187611b28565b6126bf6040830186611b28565b6126cc6060830185611a3d565b6126d96080830184611a13565b9695505050505050565b60006126ee82611967565b91506126f983611967565b925082820190508082111561271157612710611fdb565b5b9291505056fea2646970667358221220d1646c449ba3dcbd2c1bcc230d497ca6b37b305dd49bcc03107a275d8f9df16b64736f6c634300081c0033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106101425760003560e01c806370a08231116100b8578063a9059cbb1161007c578063a9059cbb14610379578063aa425cbb146103a9578063d505accf146103c5578063dd62ed3e146103e1578063e4c0aaf414610411578063e60cb4981461042d57610142565b806370a08231146102c35780637ecebe00146102f35780639202c7a01461032357806395d89b411461033f5780639dc29fac1461035d57610142565b806323b872dd1161010a57806323b872dd146101ef57806324d7806c1461021f578063313ce5671461024f5780633644e5151461026d57806340c10f191461028b5780634b0bddd2146102a757610142565b806306fdde0314610147578063095ea7b3146101655780630c340a241461019557806315fa932a146101b357806318160ddd146101d1575b600080fd5b61014f610449565b60405161015c91906118d3565b60405180910390f35b61017f600480360381019061017a919061199d565b6104d7565b60405161018c91906119f8565b60405180910390f35b61019d6105c9565b6040516101aa9190611a22565b60405180910390f35b6101bb6105ef565b6040516101c89190611a22565b60405180910390f35b6101d9610615565b6040516101e69190611a4c565b60405180910390f35b61020960048036038101906102049190611a67565b61061b565b60405161021691906119f8565b60405180910390f35b61023960048036038101906102349190611aba565b610865565b60405161024691906119f8565b60405180910390f35b610257610885565b6040516102649190611b03565b60405180910390f35b6102756108a9565b6040516102829190611b37565b60405180910390f35b6102a560048036038101906102a0919061199d565b610906565b005b6102c160048036038101906102bc9190611b7e565b6109a4565b005b6102dd60048036038101906102d89190611aba565b610afe565b6040516102ea9190611a4c565b60405180910390f35b61030d60048036038101906103089190611aba565b610b16565b60405161031a9190611a4c565b60405180910390f35b61033d60048036038101906103389190611dc9565b610b2e565b005b610347610c7c565b60405161035491906118d3565b60405180910390f35b6103776004803603810190610372919061199d565b610d0a565b005b610393600480360381019061038e919061199d565b610da8565b6040516103a091906119f8565b60405180910390f35b6103c360048036038101906103be9190611dc9565b610ebc565b005b6103df60048036038101906103da9190611e99565b6110e2565b005b6103fb60048036038101906103f69190611f3b565b6113db565b6040516104089190611a4c565b60405180910390f35b61042b60048036038101906104269190611aba565b611400565b005b61044760048036038101906104429190611aba565b611543565b005b6000805461045690611faa565b80601f016020809104026020016040519081016040528092919081815260200182805461048290611faa565b80156104cf5780601f106104a4576101008083540402835291602001916104cf565b820191906000526020600020905b8154815290600101906020018083116104b257829003601f168201915b505050505081565b600081600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040516105b79190611a4c565b60405180910390a36001905092915050565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60025481565b600080600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146107515782816106d0919061200a565b600460008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b82600360008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546107a0919061200a565b9250508190555082600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040516108519190611a4c565b60405180910390a360019150509392505050565b60086020528060005260406000206000915054906101000a900460ff1681565b7f000000000000000000000000000000000000000000000000000000000000000081565b60007f000000000000000000000000000000000000000000000000000000000000000046146108df576108da611617565b610901565b7f00000000000000000000000000000000000000000000000000000000000000005b905090565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610996576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161098d906120b0565b60405180910390fd5b6109a082826116a3565b5050565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610a34576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a2b906120b0565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610aa3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a9a9061211c565b60405180910390fd5b80600860008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b60036020528060005260406000206000915090505481565b60056020528060005260406000206000915090505481565b600860003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610bba576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb1906121ae565b60405180910390fd5b8051825114610bfe576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bf59061221a565b60405180910390fd5b60005b8251811015610c77576000828281518110610c1f57610c1e61223a565b5b60200260200101511115610c6c57610c6b838281518110610c4357610c4261223a565b5b6020026020010151838381518110610c5e57610c5d61223a565b5b60200260200101516116a3565b5b806001019050610c01565b505050565b60018054610c8990611faa565b80601f0160208091040260200160405190810160405280929190818152602001828054610cb590611faa565b8015610d025780601f10610cd757610100808354040283529160200191610d02565b820191906000526020600020905b815481529060010190602001808311610ce557829003601f168201915b505050505081565b600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610d9a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d91906122db565b60405180910390fd5b610da48282611773565b5050565b600081600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254610df9919061200a565b9250508190555081600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610eaa9190611a4c565b60405180910390a36001905092915050565b600860003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610f48576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f3f906121ae565b60405180910390fd5b8051825114610f8c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f839061221a565b60405180910390fd5b60005b82518110156110dd5760003073ffffffffffffffffffffffffffffffffffffffff166370a08231858481518110610fc957610fc861223a565b5b60200260200101516040518263ffffffff1660e01b8152600401610fed9190611a22565b602060405180830381865afa15801561100a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061102e9190612310565b905060008383815181106110455761104461223a565b5b60200260200101519050808211156110915760008183611065919061200a565b905061108b86858151811061107d5761107c61223a565b5b602002602001015182611773565b506110d0565b818111156110cf57600082826110a7919061200a565b90506110cd8685815181106110bf576110be61223a565b5b6020026020010151826116a3565b505b5b5050806001019050610f8f565b505050565b42841015611125576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161111c90612389565b60405180910390fd5b600060016111316108a9565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98a8a8a600560008f73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000815480929190600101919050558b6040516020016111b9969594939291906123a9565b604051602081830303815290604052805190602001206040516020016111e0929190612482565b604051602081830303815290604052805190602001208585856040516000815260200160405260405161121694939291906124b9565b6020604051602081039080840390855afa158015611238573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141580156112ac57508773ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b6112eb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112e29061254a565b60405180910390fd5b85600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550508573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925876040516113ca9190611a4c565b60405180910390a350505050505050565b6004602052816000526040600020602052806000526040600020600091509150505481565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611490576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611487906120b0565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036114ff576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114f6906125b6565b60405180910390fd5b80600660006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146115d3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016115ca906120b0565b60405180910390fd5b80600760006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60006040516116499190612679565b60405180910390207fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc64630604051602001611688959493929190612690565b60405160208183030381529060405280519060200120905090565b80600260008282546116b591906126e3565b9250508190555080600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516117679190611a4c565b60405180910390a35050565b80600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546117c2919061200a565b9250508190555080600260008282540392505081905550600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516118379190611a4c565b60405180910390a35050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561187d578082015181840152602081019050611862565b60008484015250505050565b6000601f19601f8301169050919050565b60006118a582611843565b6118af818561184e565b93506118bf81856020860161185f565b6118c881611889565b840191505092915050565b600060208201905081810360008301526118ed818461189a565b905092915050565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061193482611909565b9050919050565b61194481611929565b811461194f57600080fd5b50565b6000813590506119618161193b565b92915050565b6000819050919050565b61197a81611967565b811461198557600080fd5b50565b60008135905061199781611971565b92915050565b600080604083850312156119b4576119b36118ff565b5b60006119c285828601611952565b92505060206119d385828601611988565b9150509250929050565b60008115159050919050565b6119f2816119dd565b82525050565b6000602082019050611a0d60008301846119e9565b92915050565b611a1c81611929565b82525050565b6000602082019050611a376000830184611a13565b92915050565b611a4681611967565b82525050565b6000602082019050611a616000830184611a3d565b92915050565b600080600060608486031215611a8057611a7f6118ff565b5b6000611a8e86828701611952565b9350506020611a9f86828701611952565b9250506040611ab086828701611988565b9150509250925092565b600060208284031215611ad057611acf6118ff565b5b6000611ade84828501611952565b91505092915050565b600060ff82169050919050565b611afd81611ae7565b82525050565b6000602082019050611b186000830184611af4565b92915050565b6000819050919050565b611b3181611b1e565b82525050565b6000602082019050611b4c6000830184611b28565b92915050565b611b5b816119dd565b8114611b6657600080fd5b50565b600081359050611b7881611b52565b92915050565b60008060408385031215611b9557611b946118ff565b5b6000611ba385828601611952565b9250506020611bb485828601611b69565b9150509250929050565b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b611bfb82611889565b810181811067ffffffffffffffff82111715611c1a57611c19611bc3565b5b80604052505050565b6000611c2d6118f5565b9050611c398282611bf2565b919050565b600067ffffffffffffffff821115611c5957611c58611bc3565b5b602082029050602081019050919050565b600080fd5b6000611c82611c7d84611c3e565b611c23565b90508083825260208201905060208402830185811115611ca557611ca4611c6a565b5b835b81811015611cce5780611cba8882611952565b845260208401935050602081019050611ca7565b5050509392505050565b600082601f830112611ced57611cec611bbe565b5b8135611cfd848260208601611c6f565b91505092915050565b600067ffffffffffffffff821115611d2157611d20611bc3565b5b602082029050602081019050919050565b6000611d45611d4084611d06565b611c23565b90508083825260208201905060208402830185811115611d6857611d67611c6a565b5b835b81811015611d915780611d7d8882611988565b845260208401935050602081019050611d6a565b5050509392505050565b600082601f830112611db057611daf611bbe565b5b8135611dc0848260208601611d32565b91505092915050565b60008060408385031215611de057611ddf6118ff565b5b600083013567ffffffffffffffff811115611dfe57611dfd611904565b5b611e0a85828601611cd8565b925050602083013567ffffffffffffffff811115611e2b57611e2a611904565b5b611e3785828601611d9b565b9150509250929050565b611e4a81611ae7565b8114611e5557600080fd5b50565b600081359050611e6781611e41565b92915050565b611e7681611b1e565b8114611e8157600080fd5b50565b600081359050611e9381611e6d565b92915050565b600080600080600080600060e0888a031215611eb857611eb76118ff565b5b6000611ec68a828b01611952565b9750506020611ed78a828b01611952565b9650506040611ee88a828b01611988565b9550506060611ef98a828b01611988565b9450506080611f0a8a828b01611e58565b93505060a0611f1b8a828b01611e84565b92505060c0611f2c8a828b01611e84565b91505092959891949750929550565b60008060408385031215611f5257611f516118ff565b5b6000611f6085828601611952565b9250506020611f7185828601611952565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680611fc257607f821691505b602082108103611fd557611fd4611f7b565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061201582611967565b915061202083611967565b925082820390508181111561203857612037611fdb565b5b92915050565b7f4f6e6c7920676f7665726e6f722063616e2063616c6c20746869732066756e6360008201527f74696f6e00000000000000000000000000000000000000000000000000000000602082015250565b600061209a60248361184e565b91506120a58261203e565b604082019050919050565b600060208201905081810360008301526120c98161208d565b9050919050565b7f496e76616c69642061646d696e20616464726573730000000000000000000000600082015250565b600061210660158361184e565b9150612111826120d0565b602082019050919050565b60006020820190508181036000830152612135816120f9565b9050919050565b7f4f6e6c792061646d696e2063616e2063616c6c20746869732066756e6374696f60008201527f6e00000000000000000000000000000000000000000000000000000000000000602082015250565b600061219860218361184e565b91506121a38261213c565b604082019050919050565b600060208201905081810360008301526121c78161218b565b9050919050565b7f417272617973206c656e677468206d69736d6174636800000000000000000000600082015250565b600061220460168361184e565b915061220f826121ce565b602082019050919050565b60006020820190508181036000830152612233816121f7565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4f6e6c792063726564697473206d616e616765722063616e2063616c6c20746860008201527f69732066756e6374696f6e000000000000000000000000000000000000000000602082015250565b60006122c5602b8361184e565b91506122d082612269565b604082019050919050565b600060208201905081810360008301526122f4816122b8565b9050919050565b60008151905061230a81611971565b92915050565b600060208284031215612326576123256118ff565b5b6000612334848285016122fb565b91505092915050565b7f5045524d49545f444541444c494e455f45585049524544000000000000000000600082015250565b600061237360178361184e565b915061237e8261233d565b602082019050919050565b600060208201905081810360008301526123a281612366565b9050919050565b600060c0820190506123be6000830189611b28565b6123cb6020830188611a13565b6123d86040830187611a13565b6123e56060830186611a3d565b6123f26080830185611a3d565b6123ff60a0830184611a3d565b979650505050505050565b600081905092915050565b7f1901000000000000000000000000000000000000000000000000000000000000600082015250565b600061244b60028361240a565b915061245682612415565b600282019050919050565b6000819050919050565b61247c61247782611b1e565b612461565b82525050565b600061248d8261243e565b9150612499828561246b565b6020820191506124a9828461246b565b6020820191508190509392505050565b60006080820190506124ce6000830187611b28565b6124db6020830186611af4565b6124e86040830185611b28565b6124f56060830184611b28565b95945050505050565b7f494e56414c49445f5349474e4552000000000000000000000000000000000000600082015250565b6000612534600e8361184e565b915061253f826124fe565b602082019050919050565b6000602082019050818103600083015261256381612527565b9050919050565b7f496e76616c696420676f7665726e6f7220616464726573730000000000000000600082015250565b60006125a060188361184e565b91506125ab8261256a565b602082019050919050565b600060208201905081810360008301526125cf81612593565b9050919050565b600081905092915050565b60008190508160005260206000209050919050565b6000815461260381611faa565b61260d81866125d6565b94506001821660008114612628576001811461263d57612670565b60ff1983168652811515820286019350612670565b612646856125e1565b60005b8381101561266857815481890152600182019150602081019050612649565b838801955050505b50505092915050565b600061268582846125f6565b915081905092915050565b600060a0820190506126a56000830188611b28565b6126b26020830187611b28565b6126bf6040830186611b28565b6126cc6060830185611a3d565b6126d96080830184611a13565b9695505050505050565b60006126ee82611967565b91506126f983611967565b925082820190508082111561271157612710611fdb565b5b9291505056fea2646970667358221220d1646c449ba3dcbd2c1bcc230d497ca6b37b305dd49bcc03107a275d8f9df16b64736f6c634300081c0033", "devdoc": { "kind": "dev", "methods": { + "addCreditsBalance(address[],uint256[])": { + "details": "Add credits balance to multiple addresses by minting tokens.", + "params": { + "_addresses": "The list of addresses to add credits balance to.", + "_amounts": "The list of amounts to add to each address." + } + }, "changeCreditsManager(address)": { "details": "Change the credits manager of the contract.", "params": { @@ -461,6 +523,13 @@ "_governor": "The trusted governor of the contract." } }, + "setAdmin(address,bool)": { + "details": "Set admin status for an address.", + "params": { + "_admin": "The address to set admin status for.", + "_isAdmin": "Boolean indicating whether the address should be an admin." + } + }, "setCreditsBalance(address[],uint256[])": { "details": "Set credits balance for multiple addresses by minting or burning as needed.", "params": { @@ -543,6 +612,14 @@ "offset": 0, "slot": "7", "type": "t_address" + }, + { + "astId": 658, + "contract": "src/trading-credits/SeerCredits.sol:SeerCredits", + "label": "isAdmin", + "offset": 0, + "slot": "8", + "type": "t_mapping(t_address,t_bool)" } ], "types": { @@ -551,6 +628,18 @@ "label": "address", "numberOfBytes": "20" }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_mapping(t_address,t_bool)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => bool)", + "numberOfBytes": "32", + "value": "t_bool" + }, "t_mapping(t_address,t_mapping(t_address,t_uint256))": { "encoding": "mapping", "key": "t_address", diff --git a/web/src/components/Market/SwapTokens/SwapTokensLimitUpTo.tsx b/web/src/components/Market/SwapTokens/SwapTokensLimitUpTo.tsx index 7f3402c0..20400bb0 100644 --- a/web/src/components/Market/SwapTokens/SwapTokensLimitUpTo.tsx +++ b/web/src/components/Market/SwapTokens/SwapTokensLimitUpTo.tsx @@ -139,6 +139,9 @@ export function SwapTokensLimitUpto({ swapType, tradeType === TradeType.EXACT_INPUT ? Number(amountOut) : Number(amount), ); + + const isSeerCreditsCollateral = isSeerCredits(market.chainId, selectedCollateral.address); + const { data: quoteData, isLoading: quoteIsLoading, @@ -158,7 +161,7 @@ export function SwapTokensLimitUpto({ const { tradeTokens, approvals: { data: missingApprovals = [], isLoading: isLoadingApprovals }, - } = useTrade(account, quoteData?.trade, async () => { + } = useTrade(account, quoteData?.trade, isSeerCreditsCollateral, async () => { reset(); closeConfirmSwapModal(); }); @@ -169,7 +172,7 @@ export function SwapTokensLimitUpto({ account: account!, isBuyExactOutputNative, isSellToNative, - isSeerCredits: isSeerCredits(market.chainId, selectedCollateral.address), + isSeerCredits: isSeerCreditsCollateral, }); }; @@ -299,7 +302,7 @@ export function SwapTokensLimitUpto({ originalAmount={amount} isBuyExactOutputNative={isBuyExactOutputNative} isSellToNative={isSellToNative} - isSeerCredits={isSeerCredits(market.chainId, selectedCollateral.address)} + isSeerCredits={isSeerCreditsCollateral} /> } /> diff --git a/web/src/components/Market/SwapTokens/SwapTokensMarket.tsx b/web/src/components/Market/SwapTokens/SwapTokensMarket.tsx index 402125a2..084057e0 100644 --- a/web/src/components/Market/SwapTokens/SwapTokensMarket.tsx +++ b/web/src/components/Market/SwapTokens/SwapTokensMarket.tsx @@ -179,6 +179,8 @@ export function SwapTokensMarket({ const debouncedAmount = useDebounce(amount, 500); const debouncedAmountOut = useDebounce(amountOut, 500); + const isSeerCreditsCollateral = isSeerCredits(market.chainId, selectedCollateral.address); + const { data: quoteData, isLoading: quoteIsLoading, @@ -198,7 +200,7 @@ export function SwapTokensMarket({ const { tradeTokens, approvals: { data: missingApprovals = [], isLoading: isLoadingApprovals }, - } = useTrade(account, quoteData?.trade, async () => { + } = useTrade(account, quoteData?.trade, isSeerCreditsCollateral, async () => { reset(); closeConfirmSwapModal(); }); @@ -209,7 +211,7 @@ export function SwapTokensMarket({ account: account!, isBuyExactOutputNative, isSellToNative, - isSeerCredits: isSeerCredits(market.chainId, selectedCollateral.address), + isSeerCredits: isSeerCreditsCollateral, }); }; @@ -321,7 +323,7 @@ export function SwapTokensMarket({ originalAmount={amount} isBuyExactOutputNative={isBuyExactOutputNative} isSellToNative={isSellToNative} - isSeerCredits={isSeerCredits(market.chainId, selectedCollateral.address)} + isSeerCredits={isSeerCreditsCollateral} /> } /> diff --git a/web/src/hooks/trade/index.ts b/web/src/hooks/trade/index.ts index 43610702..a0792285 100644 --- a/web/src/hooks/trade/index.ts +++ b/web/src/hooks/trade/index.ts @@ -23,6 +23,11 @@ import { UNISWAP_ROUTER_ABI } from "./abis"; const QUOTE_REFETCH_INTERVAL = Number(SEER_ENV.VITE_QUOTE_REFETCH_INTERVAL) || 30_000; +const EMPTY_APPROVALS = { + data: [], + isLoading: false, +}; + function useSwaprQuote( chainId: number, account: Address | undefined, @@ -294,13 +299,18 @@ async function tradeTokens({ return executeSwaprTrade(trade, account, isBuyExactOutputNative, isSellToNative, isSeerCredits); } -function useTradeLegacy(account: Address | undefined, trade: Trade | undefined, onSuccess: () => unknown) { +function useTradeLegacy( + account: Address | undefined, + trade: Trade | undefined, + isSeerCredits: boolean, + onSuccess: () => unknown, +) { const { addPendingOrder } = useGlobalState(); const approvals = useMissingTradeApproval(account, trade); return { - approvals, + approvals: isSeerCredits ? EMPTY_APPROVALS : approvals, tradeTokens: useMutation({ mutationFn: tradeTokens, onSuccess: (result: string | TransactionReceipt) => { @@ -351,13 +361,8 @@ async function tradeTokens7702(props: TradeTokensProps): Promise unknown) => { const { addPendingOrder } = useGlobalState(); - const approvals = { - data: [], - isLoading: false, - }; - return { - approvals, + approvals: EMPTY_APPROVALS, tradeTokens: useMutation({ mutationFn: (props: TradeTokensProps) => tradeTokens7702(props), onSuccess: (result: string | TransactionReceipt) => { @@ -374,10 +379,15 @@ const useTrade7702 = (onSuccess: () => unknown) => { }; }; -export const useTrade = (account: Address | undefined, trade: Trade | undefined, onSuccess: () => unknown) => { +export const useTrade = ( + account: Address | undefined, + trade: Trade | undefined, + isSeerCredits: boolean, + onSuccess: () => unknown, +) => { const supports7702 = useCheck7702Support(); const trade7702 = useTrade7702(onSuccess); - const tradeLegacy = useTradeLegacy(account, trade, onSuccess); + const tradeLegacy = useTradeLegacy(account, trade, isSeerCredits, onSuccess); return supports7702 ? trade7702 : tradeLegacy; }; From 4b271475c769b226de8eef26af16d17aad887880 Mon Sep 17 00:00:00 2001 From: xyzseer Date: Thu, 27 Nov 2025 16:27:17 -0300 Subject: [PATCH 6/6] batch tx: ignore approval --- web/src/hooks/trade/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/hooks/trade/index.ts b/web/src/hooks/trade/index.ts index 8903f5d2..0feecc0d 100644 --- a/web/src/hooks/trade/index.ts +++ b/web/src/hooks/trade/index.ts @@ -332,7 +332,7 @@ async function tradeTokens7702(props: TradeTokensProps): Promise