diff --git a/data/blur.json b/data/blur.json new file mode 100644 index 0000000..ff1a386 --- /dev/null +++ b/data/blur.json @@ -0,0 +1,1200 @@ +[ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "previousAdmin", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "beacon", + "type": "address" + } + ], + "name": "BeaconUpgraded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "Closed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "blockRange", + "type": "uint256" + } + ], + "name": "NewBlockRange", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract IExecutionDelegate", + "name": "executionDelegate", + "type": "address" + } + ], + "name": "NewExecutionDelegate", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oracle", + "type": "address" + } + ], + "name": "NewOracle", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract IPolicyManager", + "name": "policyManager", + "type": "address" + } + ], + "name": "NewPolicyManager", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "trader", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newNonce", + "type": "uint256" + } + ], + "name": "NonceIncremented", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "Opened", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + } + ], + "name": "OrderCancelled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "maker", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "taker", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "trader", + "type": "address" + }, + { + "internalType": "enum Side", + "name": "side", + "type": "uint8" + }, + { + "internalType": "address", + "name": "matchingPolicy", + "type": "address" + }, + { + "internalType": "address", + "name": "collection", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "paymentToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "price", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "listingTime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expirationTime", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint16", + "name": "rate", + "type": "uint16" + }, + { + "internalType": "address payable", + "name": "recipient", + "type": "address" + } + ], + "internalType": "struct Fee[]", + "name": "fees", + "type": "tuple[]" + }, + { + "internalType": "uint256", + "name": "salt", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "extraParams", + "type": "bytes" + } + ], + "indexed": false, + "internalType": "struct Order", + "name": "sell", + "type": "tuple" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "sellHash", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "address", + "name": "trader", + "type": "address" + }, + { + "internalType": "enum Side", + "name": "side", + "type": "uint8" + }, + { + "internalType": "address", + "name": "matchingPolicy", + "type": "address" + }, + { + "internalType": "address", + "name": "collection", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "paymentToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "price", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "listingTime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expirationTime", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint16", + "name": "rate", + "type": "uint16" + }, + { + "internalType": "address payable", + "name": "recipient", + "type": "address" + } + ], + "internalType": "struct Fee[]", + "name": "fees", + "type": "tuple[]" + }, + { + "internalType": "uint256", + "name": "salt", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "extraParams", + "type": "bytes" + } + ], + "indexed": false, + "internalType": "struct Order", + "name": "buy", + "type": "tuple" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "buyHash", + "type": "bytes32" + } + ], + "name": "OrdersMatched", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "Upgraded", + "type": "event" + }, + { + "inputs": [], + "name": "FEE_TYPEHASH", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "INVERSE_BASIS_POINT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "NAME", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ORACLE_ORDER_TYPEHASH", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ORDER_TYPEHASH", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ROOT_TYPEHASH", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "VERSION", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "WETH", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "blockRange", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "trader", + "type": "address" + }, + { + "internalType": "enum Side", + "name": "side", + "type": "uint8" + }, + { + "internalType": "address", + "name": "matchingPolicy", + "type": "address" + }, + { + "internalType": "address", + "name": "collection", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "paymentToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "price", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "listingTime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expirationTime", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint16", + "name": "rate", + "type": "uint16" + }, + { + "internalType": "address payable", + "name": "recipient", + "type": "address" + } + ], + "internalType": "struct Fee[]", + "name": "fees", + "type": "tuple[]" + }, + { + "internalType": "uint256", + "name": "salt", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "extraParams", + "type": "bytes" + } + ], + "internalType": "struct Order", + "name": "order", + "type": "tuple" + } + ], + "name": "cancelOrder", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "trader", + "type": "address" + }, + { + "internalType": "enum Side", + "name": "side", + "type": "uint8" + }, + { + "internalType": "address", + "name": "matchingPolicy", + "type": "address" + }, + { + "internalType": "address", + "name": "collection", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "paymentToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "price", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "listingTime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expirationTime", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint16", + "name": "rate", + "type": "uint16" + }, + { + "internalType": "address payable", + "name": "recipient", + "type": "address" + } + ], + "internalType": "struct Fee[]", + "name": "fees", + "type": "tuple[]" + }, + { + "internalType": "uint256", + "name": "salt", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "extraParams", + "type": "bytes" + } + ], + "internalType": "struct Order[]", + "name": "orders", + "type": "tuple[]" + } + ], + "name": "cancelOrders", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "cancelledOrFilled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "close", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "trader", + "type": "address" + }, + { + "internalType": "enum Side", + "name": "side", + "type": "uint8" + }, + { + "internalType": "address", + "name": "matchingPolicy", + "type": "address" + }, + { + "internalType": "address", + "name": "collection", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "paymentToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "price", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "listingTime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expirationTime", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint16", + "name": "rate", + "type": "uint16" + }, + { + "internalType": "address payable", + "name": "recipient", + "type": "address" + } + ], + "internalType": "struct Fee[]", + "name": "fees", + "type": "tuple[]" + }, + { + "internalType": "uint256", + "name": "salt", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "extraParams", + "type": "bytes" + } + ], + "internalType": "struct Order", + "name": "order", + "type": "tuple" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "extraSignature", + "type": "bytes" + }, + { + "internalType": "enum SignatureVersion", + "name": "signatureVersion", + "type": "uint8" + }, + { + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" + } + ], + "internalType": "struct Input", + "name": "sell", + "type": "tuple" + }, + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "trader", + "type": "address" + }, + { + "internalType": "enum Side", + "name": "side", + "type": "uint8" + }, + { + "internalType": "address", + "name": "matchingPolicy", + "type": "address" + }, + { + "internalType": "address", + "name": "collection", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "paymentToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "price", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "listingTime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expirationTime", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint16", + "name": "rate", + "type": "uint16" + }, + { + "internalType": "address payable", + "name": "recipient", + "type": "address" + } + ], + "internalType": "struct Fee[]", + "name": "fees", + "type": "tuple[]" + }, + { + "internalType": "uint256", + "name": "salt", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "extraParams", + "type": "bytes" + } + ], + "internalType": "struct Order", + "name": "order", + "type": "tuple" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "extraSignature", + "type": "bytes" + }, + { + "internalType": "enum SignatureVersion", + "name": "signatureVersion", + "type": "uint8" + }, + { + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" + } + ], + "internalType": "struct Input", + "name": "buy", + "type": "tuple" + } + ], + "name": "execute", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "executionDelegate", + "outputs": [ + { + "internalType": "contract IExecutionDelegate", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "incrementNonce", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IExecutionDelegate", + "name": "_executionDelegate", + "type": "address" + }, + { + "internalType": "contract IPolicyManager", + "name": "_policyManager", + "type": "address" + }, + { + "internalType": "address", + "name": "_oracle", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_blockRange", + "type": "uint256" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "isOpen", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "nonces", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "open", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "oracle", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "policyManager", + "outputs": [ + { + "internalType": "contract IPolicyManager", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proxiableUUID", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_blockRange", + "type": "uint256" + } + ], + "name": "setBlockRange", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IExecutionDelegate", + "name": "_executionDelegate", + "type": "address" + } + ], + "name": "setExecutionDelegate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_oracle", + "type": "address" + } + ], + "name": "setOracle", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IPolicyManager", + "name": "_policyManager", + "type": "address" + } + ], + "name": "setPolicyManager", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + } + ], + "name": "upgradeTo", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "upgradeToAndCall", + "outputs": [], + "stateMutability": "payable", + "type": "function" + } +] \ No newline at end of file diff --git a/src/scraper.js b/src/scraper.js index 566e280..0f63eee 100644 --- a/src/scraper.js +++ b/src/scraper.js @@ -19,6 +19,7 @@ const MARKETPLACE_ABI = require('../data/marketplace'); const SEAPORT_ABI = require('../data/seaport'); const WYVERN_ABI = require('../data/wyvern'); const LOOKSRARE_ABI = require('../data/looksrare'); +const BLUR_ABI = require('../data/blur'); const WETH_ADDRESS = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'; const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'; const TRANSFER_SINGLE_TOPIC = '0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62'; @@ -26,9 +27,11 @@ const LOOKSRARE_SALE_TOPIC = '0x95fb6205e23ff6bda16a2d1dba56b9ad7c783f67c96fa149 const SEAPORT_SALE_TOPIC = '0x9d9af8e38d66c62e2c12f0225249fd9d721c54b83f48d9352c97c6cacdcb6f31'; const WYVERN_SALE_TOPIC = '0xc4109843e0b7d514e4c093114b863f8e7d8d9a458c372cd51bfe526b588006c9' const X2Y2_SALE_TOPIC = '0x3cbb63f144840e5b1b0a38a7c19211d2e89de4d7c5faf8b2d3c1776c302d1d33'; +const BLUR_SALE_TOPIC = '0x61cbb2a3dee0b6064c2e681aadd61677fb4ef319f0b547508d495626f5a62f64'; const seaportInterface = new ethers.utils.Interface(SEAPORT_ABI); const looksrareInterface = new ethers.utils.Interface(LOOKSRARE_ABI); const wyvernInterface = new ethers.utils.Interface(WYVERN_ABI); +const blurInterface = new ethers.utils.Interface(BLUR_ABI); const provider = new ethers.providers.WebSocketProvider(process.env.GETH_NODE); const db = new Database('./storage/sqlite.db'); @@ -257,6 +260,23 @@ class Scrape extends Collection { if (amountWei === BigInt(0)) { amountWei = BigInt(`0x${dataSlices[26]}`); } + } else if (log.topics[0].toLowerCase() === BLUR_SALE_TOPIC.toLowerCase()) { + // Handle Blur sales + sale = true; + platform = 'blur'; + const logDescription = blurInterface.parseLog(log); + fromAddress = logDescription.args.maker; + toAddress = logDescription.args.taker; + tokenId = BigInt(logDescription.args.sell.tokenId); + amountWei = BigInt(logDescription.args.sell.price); + // Blur's marketplace orders don't include the purchaser, only their proxy contract which passes the token through + // This little hack just grabs the Transfer event after the Blur sale to get the end recipient + let rl = receipt.logs.filter( + l => l.logIndex === log.logIndex + 2 && l.topics[0].toLowerCase() === TRANSFER_TOPIC + ); + if (rl.length > 0) { + toAddress = ethers.utils.defaultAbiCoder.decode(['address'], rl[0].topics[2])[0].toLowerCase(); + } } if (sale) { amountEther = ethers.utils.formatEther(amountWei);