diff --git a/abi/polynomial_core_account.json b/abi/polynomial_core_account.json new file mode 100644 index 0000000..f633e7c --- /dev/null +++ b/abi/polynomial_core_account.json @@ -0,0 +1,371 @@ +[ + + { + "inputs": [ + { + "internalType": "address", + "name": "holder", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getApproved", + "outputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "holder", + "type": "address" + }, + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "isApprovedForAll", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "ownerOf", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "tokenByIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "tokenOfOwnerByIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "tokenURI", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "approved", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "setApprovalForAll", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "approved", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] \ No newline at end of file diff --git a/abi/polynomial_core_proxy.json b/abi/polynomial_core_proxy.json new file mode 100644 index 0000000..0fa4fbf --- /dev/null +++ b/abi/polynomial_core_proxy.json @@ -0,0 +1,42 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "firstImplementation", + "type": "address" + }, + { + "internalType": "address", + "name": "initialOwner", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "contr", + "type": "address" + } + ], + "name": "NotAContract", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddress", + "type": "error" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ] \ No newline at end of file diff --git a/constants/chains.py b/constants/chains.py index 7b0c8d3..21a872f 100644 --- a/constants/chains.py +++ b/constants/chains.py @@ -11,3 +11,4 @@ class Chain(Enum): MODE = "Mode" OPTIMISM = "Optimism" Lyra = "Lyra" + POLYNOMIAL = "Polynomial" \ No newline at end of file diff --git a/constants/polynomial.py b/constants/polynomial.py new file mode 100644 index 0000000..cf127ec --- /dev/null +++ b/constants/polynomial.py @@ -0,0 +1,13 @@ +from web3 import Web3 + +POLYNOMIAL_CORE_PROXY_ADDRESS = Web3.to_checksum_address( + "0xc133983D6d9140923b5eaE52664221d9099cf119" +) +POLYNOMIAL_CORE_ACCOUNT_ADDRESS = Web3.to_checksum_address( + "0x5B05C63AB7122f136EBCf03E1256D8611dfDffF7" +) +POLYNOMIAL_DEPLOYMENT_BLOCK = 1981537 + +POLYNOMIAL_USDE_TOKEN_ADDRESS = Web3.to_checksum_address( + "0x2A06DEAc3E863c23DD6a89Eeacd80aBA9E08B77B" +) diff --git a/integrations/integration_ids.py b/integrations/integration_ids.py index aa89852..55d5d14 100644 --- a/integrations/integration_ids.py +++ b/integrations/integration_ids.py @@ -383,6 +383,11 @@ class IntegrationID(Enum): Token.SUSDE, ) + POLYNOMIAL_SUSDE = ( + "polynomial_susde", + "Polynomial sUSDe", + Token.SUSDE + ) # Fluid FLUID = ("Fluid_susde", "Fluid sUSDe", Token.SUSDE) diff --git a/integrations/polynomial_susde.py b/integrations/polynomial_susde.py new file mode 100644 index 0000000..10c3349 --- /dev/null +++ b/integrations/polynomial_susde.py @@ -0,0 +1,79 @@ +from constants.chains import Chain +from integrations.integration import Integration +from integrations.integration_ids import IntegrationID +from utils.web3_utils import w3_polynomial, fetch_events_logs_with_retry, call_with_retry +from utils.polynomial import core_proxy_contract, core_account_proxy_contract +from constants.polynomial import POLYNOMIAL_DEPLOYMENT_BLOCK, POLYNOMIAL_USDE_TOKEN_ADDRESS + + +class PolynomialIntegration(Integration): + def __init__(self): + super().__init__( + IntegrationID.POLYNOMIAL_SUSDE, + POLYNOMIAL_DEPLOYMENT_BLOCK, + Chain.POLYNOMIAL, + [], + 5, + 1, + None, + None, + ) + self.blocknumber_to_susdeVaults = {} + + def get_balance(self, user: str, block: int) -> float: + # get the account NFT balance + balance = call_with_retry( + core_account_proxy_contract.functions.balanceOf(user), + block, + ) + + # loop through the balance and get the account ids + account_ids = [] + for i in range(balance): + account_id = call_with_retry( + core_account_proxy_contract.functions.tokenOfOwnerByIndex(user, i), + block, + ) + account_ids.append(account_id) + + # for each account id, check the balance + total_balance = 0 + for account_id in account_ids: + _, balance, _ = call_with_retry( + core_proxy_contract.functions.getAccountCollateral( + account_id, POLYNOMIAL_USDE_TOKEN_ADDRESS + ), + block, + ) + total_balance += balance + return total_balance / 1e18 + + def get_participants(self, blocks: list[int] | None) -> set[str]: + page_size = 1900 + start_block = 60000000 + target_block = w3_polynomial.eth.get_block_number() + + all_users: set[str] = set() + while start_block < target_block: + to_block = min(start_block + page_size, target_block) + transfers = fetch_events_logs_with_retry( + f"Polynomial users from {start_block} to {to_block}", + core_account_proxy_contract.events.Transfer(), + start_block, + to_block, + ) + for transfer in transfers: + all_users.add(transfer["args"]["to"]) + + start_block += page_size + + self.participants = all_users + print(all_users) + return all_users + + +if __name__ == "__main__": + polynomial = PolynomialIntegration() + participants = polynomial.get_participants(None) + print(len(participants)) + print(polynomial.get_balance(list(participants)[0], 7557919)) diff --git a/integrations/synthetix.py b/integrations/synthetix.py index 394e5d0..06a0c7b 100644 --- a/integrations/synthetix.py +++ b/integrations/synthetix.py @@ -54,12 +54,14 @@ def get_participants(self, blocks: list[int] | None) -> set[str]: all_users: set[str] = set() while start_block < target_block: to_block = min(start_block + page_size, target_block) + print(start_block) transfers = fetch_events_logs_with_retry( f"Synthetix V3 Arbitrum users from {start_block} to {to_block}", core_account_proxy_contract.events.Transfer(), start_block, to_block, ) + print(transfers) for transfer in transfers: all_users.add(transfer["args"]["to"]) start_block += page_size diff --git a/utils/polynomial.py b/utils/polynomial.py new file mode 100644 index 0000000..c76a91e --- /dev/null +++ b/utils/polynomial.py @@ -0,0 +1,22 @@ +import os +import json +from dotenv import load_dotenv +from utils.web3_utils import ( + w3_arb, +) + +from constants.polynomial import POLYNOMIAL_CORE_ACCOUNT_ADDRESS, POLYNOMIAL_CORE_PROXY_ADDRESS +with open("abi/polynomial_core_proxy.json") as f: + core_proxy_abi = json.load(f) + +with open("abi/polynomial_core_account.json") as f: + core_account_proxy_abi = json.load(f) + + +core_proxy_contract = w3_arb.eth.contract( + address=POLYNOMIAL_CORE_PROXY_ADDRESS, abi=core_proxy_abi +) + +core_account_proxy_contract = w3_arb.eth.contract( + address=POLYNOMIAL_CORE_ACCOUNT_ADDRESS, abi=core_account_proxy_abi +) \ No newline at end of file diff --git a/utils/web3_utils.py b/utils/web3_utils.py index c8150ef..4d90ec7 100644 --- a/utils/web3_utils.py +++ b/utils/web3_utils.py @@ -29,6 +29,8 @@ w3_fraxtal = Web3(Web3.HTTPProvider(FRAXTAL_NODE_URL)) LYRA_NODE_URL = os.getenv("LYRA_NODE_URL") w3_lyra = Web3(Web3.HTTPProvider(LYRA_NODE_URL)) +POLYNOMIAL_NODE_URL = os.getenv("POLYNOMIAL_NODE_URL") +w3_polynomial = Web3(Web3.HTTPProvider(POLYNOMIAL_NODE_URL)) W3_BY_CHAIN = { Chain.ETHEREUM: { @@ -55,6 +57,9 @@ Chain.Lyra: { "w3": w3_lyra, }, + Chain.POLYNOMIAL:{ + "w3": w3_polynomial, + } }