import { JsonRpcProvider } from '@ethersproject/providers' import { generatedWallets } from '@zoralabs/core/dist/utils/generatedWallets' import { approveCurrency, deployCurrency, mintCurrency } from '../utils/currency' import { BigNumber } from 'ethers' import { Wallet } from '@ethersproject/wallet' import { promises as fs } from 'fs' import crypto from 'crypto' import axios from 'axios' import fleekStorage from '@fleekhq/fleek-storage-js' import { acceptBid, mint, removeAsk, removeBid, setAsk, setBid, totalSupply, transfer, } from '../utils/media' import { MarketFactory, MediaFactory } from '@zoralabs/core/dist/typechain' import Decimal from '@zoralabs/core/dist/utils/Decimal' import { getRandomInt } from '../utils/utils' import { AddressZero } from '@ethersproject/constants' import randomWords from 'random-words' import { generateMetadata, validateMetadata } from '@zoralabs/zdk' async function startSeed() { // read from chainId.json const args = require('minimist')(process.argv.slice(2)) if (!args.chainId) { throw new Error('--chainId chain ID is required') } const path = `${process.cwd()}/.env${ args.chainId === 1 ? '.prod' : args.chainId === 4 ? '.dev' : '.local' }` await require('dotenv').config({path}) const provider = new JsonRpcProvider(process.env.RPC_ENDPOINT) const fleekApiKey = process.env.FLEEK_API_KEY const fleekApiSecret = process.env.FLEEK_API_SECRET let [wallet1, wallet2] = generatedWallets(provider) const sharedAddressPath = `${process.cwd()}/config/${args.chainId}.json` // @ts-ignore const config = JSON.parse(await fs.readFile(sharedAddressPath)) if (config.mediaAddress == null) { throw new Error('media address not specified in config') } if (config.marketAddress == null) { throw new Error('market address not specified in config') } const mediaAddress = config.mediaAddress const marketAddress = config.marketAddress const auctionHouseAddress = config.auctionHouseAddress if (args.fullMonty) { await fullMonty( provider, wallet1, mediaAddress, marketAddress, auctionHouseAddress, fleekApiSecret, fleekApiKey ) } else if (args.mint) { await mintMedia(provider, mediaAddress, fleekApiSecret, fleekApiKey) } else if (args.asks) { if (!args.currencyAddress) { throw new Error('must specify --currencyAddress') } const currencyAddress = args.currencyAddress await setRandomAsks( generatedWallets(provider), mediaAddress, marketAddress, currencyAddress ) } else if (args.bids) { if (!args.currencyAddress) { throw new Error('must specify --currencyAddress') } const currencyAddress = args.currencyAddress await setRandomBids(generatedWallets(provider), mediaAddress, currencyAddress) } else if (args.removeAsks) { await removeAsks(generatedWallets(provider), mediaAddress) } else if (args.transfers) { await randomTransfers(generatedWallets(provider), mediaAddress) } else if (args.currency) { if (!args.name) { throw new Error('must specify --name') } if (!args.symbol) { throw new Error('must specify --symbol') } setUpNewCurrency(provider, wallet1, marketAddress, args.name, args.symbol) } else if (args.bids) { if (!args.currencyAddress) { throw new Error('must specify --currencyAddress') } const currencyAddress = args.currencyAddress await setRandomBids(generatedWallets(provider), mediaAddress, currencyAddress) } else if (args.removeAsks) { await removeAsks(generatedWallets(provider), mediaAddress) } else if (args.transfers) { await randomTransfers(generatedWallets(provider), mediaAddress) } else if (args.currency) { if (!args.name) { throw new Error('must specify --name') } if (!args.symbol) { throw new Error('must specify --symbol') } await setUpNewCurrency(provider, wallet1, marketAddress, args.name, args.symbol) } else if (args.mintCurrency) { if (!args.currencyAddress) { throw new Error('must specify --currencyAddress') } const currencyAddress = args.currencyAddress console.log('Minting Currency for Each Generated Wallet') for (const wallet of generatedWallets(provider)) { await mintCurrency( wallet1, currencyAddress, wallet.address, BigNumber.from('100000000000000000000000') ) } // for each address approve the market max uint256 console.log('Granting Approval to Market Contract for each Generated Wallet') for (const wallet of generatedWallets(provider)) { await approveCurrency(wallet, currencyAddress, marketAddress) } } else if (args.removeBids) { await removeBids(generatedWallets(provider), mediaAddress, marketAddress) } else if (args.acceptRandomBids) { await acceptRandomBids(generatedWallets(provider), mediaAddress, marketAddress) } else if (args.mintCurToAddr) { if (!args.currencyAddress) { throw new Error('must specify --currencyAddress') } const currencyAddress = args.currencyAddress if (!args.toAddr) { throw new Error('must specify --toAddr') } const toAddr = args.toAddr await mintCurrency( wallet1, currencyAddress, toAddr, BigNumber.from('100000000000000000000000') ) } } async function fullMonty( provider, masterWallet, mediaAddress, marketAddress, auctionHouseAddress, fleekApiSecret, fleekApiKey ) { // deploy DAI let breckAddress = await deployCurrency(masterWallet) // mint 100,000 DAI for each wallet console.log('Currency Address: ', breckAddress) console.log('Minting Currency for Each Generated Wallet') for (const wallet of generatedWallets(provider)) { await mintCurrency( masterWallet, breckAddress, wallet.address, BigNumber.from('100000000000000000000000') ) } // for each address approve the market max uint256 console.log('Granting Approval to Market Contract for each Generated Wallet') for (const wallet of generatedWallets(provider)) { await approveCurrency(wallet, breckAddress, marketAddress) } await mintMedia(provider, mediaAddress, fleekApiSecret, fleekApiKey) await setRandomAsks( generatedWallets(provider), mediaAddress, marketAddress, breckAddress ) await setRandomBids(generatedWallets(provider), mediaAddress, breckAddress) // await setupRandomAuctions( // generatedWallets(provider), // mediaAddress, // marketAddress, // breckAddress // ) } async function setUpNewCurrency( provider: JsonRpcProvider, masterWallet: Wallet, marketAddress: string, name: string, symbol: string ) { let currencyAddress = await deployCurrency(masterWallet, name, symbol) // mint 100,000 BRECK for each wallet console.log('Currency Address: ', currencyAddress) console.log('Minting Currency for Each Generated Wallet') for (const wallet of generatedWallets(provider)) { await mintCurrency( masterWallet, currencyAddress, wallet.address, BigNumber.from('100000000000000000000000') ) } // for each address approve the market max uint256 console.log('Granting Approval to Market Contract for each Generated Wallet') for (const wallet of generatedWallets(provider)) { await approveCurrency(wallet, currencyAddress, marketAddress) } } async function mintMedia( provider: JsonRpcProvider, mediaAddress: string, fleekApiSecret: string, fleekApiKey: string ) { for (const wallet of generatedWallets(provider)) { //const wallets = ['0xe834ec434daba538cd1b9fe1582052b880bd7e63', '0xe36ea790bc9d7ab70c55260c66d52b1eca985f84', '0x6ecbe1db9ef729cbe972c83fb886247691fb6beb', '0x5409ed021d9299bf6814279a6a1411a7e866a631', '0x78dc5d2d739606d31509c31d654056a45185ecb6', '0xa8dda8d7f5310e4a9e24f8eba77e091ac264f872', '0x06cef8e666768cc40cc78cf93d9611019ddcb628', '0x4404ac8bd8f9618d27ad2f1485aa1b2cfd82482d', '0x7457d5e02197480db681d3fdf256c7aca21bdc12'] // if (wallets.includes(wallet.address.toLowerCase())){ // continue; // } let picsumIds = new Set() for (let i = 0; i < 25; i++) { const x = getRandomInt(200, 600) const y = getRandomInt(200, 600) const blur = getRandomInt(1, 10) let response = await axios.get(`https://picsum.photos/${x}/${y}`, { responseType: 'arraybuffer', }) let picsumId = response.headers['picsum-id'] while (picsumIds.has(picsumId)) { response = await axios.get(`https://picsum.photos/${x}/${y}`, { responseType: 'arraybuffer', }) picsumId = response.headers['picsum-id'] } picsumIds.add(picsumId) let sha256 = crypto.createHash('sha256') sha256.update(response.data) let contentHash = sha256.digest() // upload the file to ipfs const contentCID = await fleekStorage.upload({ apiKey: fleekApiKey, apiSecret: fleekApiSecret, key: wallet.address.concat('-').concat(i.toString()), data: response.data, }) const randomName = randomWords({min: 2, max: 5, join: ' '}) const randomDescription = randomWords({exactly: 10, join: ' '}) const metadata = { version: 'zora-20210101', name: randomName, description: randomDescription, mimeType: 'image/jpeg', } const minified = generateMetadata(metadata.version, metadata) const validated = validateMetadata(metadata.version, JSON.parse(minified)) // hash the metadata let metadataSha256 = crypto.createHash('sha256') metadataSha256.update(Buffer.from(minified)) let metadataHash = metadataSha256.digest() // upload it to ipfs const metadataCID = await fleekStorage.upload({ apiKey: fleekApiKey, apiSecret: fleekApiSecret, key: wallet.address.concat('-').concat( i .toString() .concat('-') .concat('metadata') ), data: minified, }) const contentHashString = contentCID.hash.replace(/['"]+/g, '') const metadataHashString = metadataCID.hash.replace(/['"]+/g, '') console.log('https://ipfs.io/ipfs/'.concat(contentHashString)) console.log('https://ipfs.io/ipfs/'.concat(metadataHashString)) let mediaData = { tokenURI: 'https://ipfs.io/ipfs/'.concat(contentHashString), metadataURI: 'https://ipfs.io/ipfs/'.concat(metadataHashString), contentHash: Uint8Array.from(contentHash), metadataHash: Uint8Array.from(metadataHash), } // mint the thing console.log('Minting new media for address: ', wallet.address.toLowerCase()) await mint(mediaAddress, wallet, mediaData) } } console.log('Completed Seeding GraphQL with Minted Media') } async function removeBids( wallets: Array<Wallet>, mediaAddress: string, marketAddress: string ) { for (const wallet of wallets) { const media = MediaFactory.connect(mediaAddress, wallet) const market = MarketFactory.connect(marketAddress, wallet) const numTokens = await media.balanceOf(wallet.address) for (let i = 0; i < numTokens.toNumber(); i++) { let tokenId = await media.tokenOfOwnerByIndex(wallet.address, i) if (tokenId.toNumber() % 2 == 0) { continue } console.log(`Removing Bids for Token Id: ${tokenId}`) for (const bidder of wallets.filter(w => w != wallet)) { console.log(bidder.address) let bid = await market.bidForTokenBidder(tokenId, bidder.address) if (bid.bidder != AddressZero) { console.log(`Removing bid from ${bidder.address} on token id: ${tokenId}`) await removeBid(mediaAddress, bidder, tokenId) } } } } } async function acceptRandomBids( wallets: Array<Wallet>, mediaAddress: string, marketAddress: string ) { for (const wallet of wallets) { const media = MediaFactory.connect(mediaAddress, wallet) const market = MarketFactory.connect(marketAddress, wallet) const numTokens = await media.balanceOf(wallet.address) for (let i = 0; i < numTokens.toNumber(); i++) { let tokenId = await media.tokenOfOwnerByIndex(wallet.address, i) if (tokenId.toNumber() % 2 == 0) { continue } console.log(`Accepting a Bid for Token Id: ${tokenId}`) for (const bidder of wallets.filter(w => w != wallet)) { console.log(bidder.address) let bid = await market.bidForTokenBidder(tokenId, bidder.address) if (bid.bidder != AddressZero) { console.log(`Accepting bid from ${bidder.address} on token id: ${tokenId}`) await acceptBid(mediaAddress, wallet, tokenId, bid) break } } } } } async function setRandomAsks( wallets: Array<Wallet>, mediaAddress: string, marketAddress: string, currencyAddress: string ) { // for each wallet for (const wallet of wallets) { const media = MediaFactory.connect(mediaAddress, wallet) const market = MarketFactory.connect(marketAddress, wallet) const numTokens = await media.balanceOf(wallet.address) for (let i = 0; i < numTokens.toNumber(); i++) { let tokenId = await media.tokenOfOwnerByIndex(wallet.address, i) if (tokenId.toNumber() % 2 == 0) { continue } // let currentAsk = await market.currentAskForToken(tokenId); // if (currentAsk.currency != AddressZero) { // console.log(`Ask: ${currentAsk.toString()} already exists for token: ${tokenId}`); // continue; // } let ask = { currency: currencyAddress, amount: Decimal.new(getRandomInt(0, 1000)).value, } console.log('Setting Ask for Token Id: ', tokenId) await setAsk(mediaAddress, wallet, tokenId, ask) } } } async function setRandomBids( wallets: Array<Wallet>, mediaAddress: string, currencyAddress: string ) { for (const wallet of wallets) { console.log(`Bidding for wallet ${wallet.address}`) const media = MediaFactory.connect(mediaAddress, wallet) const numTokens = await media.balanceOf(wallet.address) for (let j = 0; j < 25; j++) { // get each token let tokenIds = new Set() for (let i = 0; i < numTokens.toNumber(); i++) { let tokenId = await media.tokenOfOwnerByIndex(wallet.address, i) tokenIds.add(tokenId) } // do this like 5 times // generate a random token to bid on const supply = await totalSupply(mediaAddress, wallet) console.log(`Total Supply: ${supply}`) let randomTokenId = getRandomInt(0, supply.toNumber()) while (tokenIds.has(randomTokenId)) { randomTokenId = getRandomInt(0, supply.toNumber()) } let bid = { currency: currencyAddress, amount: Decimal.new(getRandomInt(0, 1000)).value, sellOnShare: {value: Decimal.new(getRandomInt(0, 10)).value}, recipient: wallet.address, bidder: wallet.address, } console.log(`Setting bid from ${wallet.address} for token ${randomTokenId}`) await setBid(mediaAddress, wallet, BigNumber.from(randomTokenId), bid) } } } async function removeAsks(wallets: Array<Wallet>, mediaAddress: string) { for (const wallet of wallets) { const media = MediaFactory.connect(mediaAddress, wallet) const numTokens = await media.balanceOf(wallet.address) for (let i = 0; i < numTokens.toNumber(); i++) { let tokenId = await media.tokenOfOwnerByIndex(wallet.address, i) console.log('Removing Ask for Token Id: ', tokenId) await removeAsk(mediaAddress, wallet, tokenId) } } } async function randomTransfers(wallets: Array<Wallet>, mediaAddress: string) { for (const wallet of wallets) { const media = MediaFactory.connect(mediaAddress, wallet) const numTokens = await media.balanceOf(wallet.address) const rand = getRandomInt(0, numTokens.toNumber()) const tokenId = await media.tokenOfOwnerByIndex(wallet.address, rand) const randWalletId = getRandomInt(0, 9) console.log( `Transferring ${tokenId} from ${wallet.address} to ${wallets[randWalletId].address}.` ) await transfer(mediaAddress, wallet, tokenId, wallets[randWalletId].address) } } // async function setupRandomAuctions(wallets: Array<Wallet>, mediaAddress: string, auctionHouseAddress: string, currencyAddress: string) startSeed().catch((e: Error) => { console.error(e) process.exit(1) })