Skip to content

Commit

Permalink
feat(nfts): testnet support and better order fetching logic
Browse files Browse the repository at this point in the history
  • Loading branch information
plondon committed Dec 6, 2021
1 parent ee1e728 commit e54870c
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ export const logLocation = 'components/nfts/sagas'
const taskToPromise = (t) => new Promise((resolve, reject) => t.fork(reject, resolve))

export default ({ api }: { api: APIType }) => {
const IS_TESTNET = api.ethProvider.network?.name === 'rinkeby'

const clearAndRefetchAssets = function* () {
yield put(A.resetNftAssets())
yield put(A.fetchNftAssets())
Expand Down Expand Up @@ -147,6 +149,16 @@ export default ({ api }: { api: APIType }) => {
)
// map events to token_ids
const token_ids: string[] = asset_events.map((e) => e.asset?.token_id).filter(Boolean)
// how many token_ids are the same?
const non_unique_token_ids_map = {}
let non_unique_token_ids = 0
for (let i = 0; i < token_ids.length; i++) {
if (non_unique_token_ids_map[token_ids[i]]) {
non_unique_token_ids += 1
} else {
non_unique_token_ids_map[token_ids[i]] = 1
}
}
// get previously queried token_ids
const { token_ids_queried } = marketplace
// uniquify old and new token_ids
Expand All @@ -162,7 +174,7 @@ export default ({ api }: { api: APIType }) => {
new_unique_token_ids.map((val) => `&token_ids=${val}`).join('')
)

const nextPage = marketplace.page + 1
const nextPage = marketplace.page + 1 + non_unique_token_ids
// when there are no more unique token_ids, we are done
const atBound = new_unique_token_ids.every((id) => token_ids_queried.includes(id))
// update marketplace state
Expand Down Expand Up @@ -221,6 +233,7 @@ export default ({ api }: { api: APIType }) => {
action.payload.order,
signer,
action.payload.offer ? expirationTime : undefined,
IS_TESTNET ? 'rinkeby' : 'mainnet',
action.payload.offer,
action.payload.paymentTokenAddress
)
Expand All @@ -246,7 +259,8 @@ export default ({ api }: { api: APIType }) => {
getNftSellOrder,
action.payload.asset,
signer,
action.payload.startPrice
action.payload.startPrice,
IS_TESTNET ? 'rinkeby' : 'mainnet'
)
fees = yield call(
calculateGasFees,
Expand Down Expand Up @@ -295,6 +309,7 @@ export default ({ api }: { api: APIType }) => {
action.payload.order,
signer,
expirationTime,
IS_TESTNET ? 'rinkeby' : 'mainnet',
amount,
coinfig.type.erc20Address
)
Expand Down Expand Up @@ -330,7 +345,9 @@ export default ({ api }: { api: APIType }) => {
const { buy, sell }: Await<ReturnType<typeof getNftBuyOrders>> = yield call(
getNftBuyOrders,
action.payload.order,
signer
signer,
undefined,
IS_TESTNET ? 'rinkeby' : 'mainnet'
)
const order: Order = yield call(fulfillNftOrder, buy, sell, signer, action.payload.gasData)
yield put(actions.modals.closeAllModals())
Expand All @@ -355,7 +372,8 @@ export default ({ api }: { api: APIType }) => {
getNftSellOrder,
action.payload.asset,
signer,
action.payload.startPrice
action.payload.startPrice,
IS_TESTNET ? 'rinkeby' : 'mainnet'
)
const order = yield call(fulfillNftSellOrder, signedOrder, signer, action.payload.gasData)
yield call(api.postNftOrder, order)
Expand Down Expand Up @@ -415,7 +433,8 @@ export default ({ api }: { api: APIType }) => {
const res: CollectionData = yield call(api.getNftCollectionInfo, action.payload.collection)
yield put(
A.setMarketplaceData({
collection: res
// @ts-ignore
collection: IS_TESTNET ? { ...res, collection_data: { ...res } } : res
})
)
yield put(A.fetchNftOrders())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
Order,
SellOrder
} from '@core/network/api/nfts/types'
import { calculateGasFees, getNftBuyOrders } from '@core/redux/payment/nfts'
import { calculateGasFees } from '@core/redux/payment/nfts'
import { Await } from '@core/types'

import { NftOrderStepEnum, NftsStateType } from './types'
Expand Down
11 changes: 8 additions & 3 deletions packages/blockchain-wallet-v4/src/network/api/eth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@ import * as ethers from 'ethers'

import { AccountTokensBalancesResponseType, EthAccountSummaryType, EthRawTxType } from './types'

export default ({ apiUrl, get, post }) => {
export default ({ apiUrl, get, openseaApi, post }) => {
// ONLY FOR TESTING OPENSEA!
const IS_TESTNET = openseaApi.includes('rinkeby')

const ethProvider = IS_TESTNET
? new ethers.providers.EtherscanProvider('rinkeby')
: ethers.providers.getDefaultProvider(`${apiUrl}/eth/nodes/rpc`)
//
// Deprecate
//

const ethProvider = new ethers.providers.EtherscanProvider('rinkeby')
//

// web3.eth.getBalance
const getEthBalances = (context) =>
Expand Down
2 changes: 1 addition & 1 deletion packages/blockchain-wallet-v4/src/network/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ const api = ({ apiKey, getAuthCredentials, networks, options, reauthenticate }:
nabuUrl,
...http
}),
...eth({ apiUrl, ...http }),
...eth({ apiUrl, openseaApi, ...http }),
...kvStore({ apiUrl, networks, ...http }),
...kyc({
authorizedGet: authorizedHttp.get,
Expand Down
8 changes: 5 additions & 3 deletions packages/blockchain-wallet-v4/src/network/api/nfts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ import {
export const NFT_ORDER_PAGE_LIMIT = 10

export default ({ apiUrl, get, openseaApi, post }) => {
const IS_TESTNET = openseaApi.includes('rinkeby')

const openseaUrl = `${openseaApi}/api/v1`
const openseaMarketplaceApi = `${openseaApi}/wyvern/v1`

const headers = {
'X-API-KEY': openseaApi.includes('rinkeby')
'X-API-KEY': IS_TESTNET
? 'b6f0671559ae4285bcecc7b9702f224a'
: 'd0b6281e87d84702b020419fdf58ea81'
}
Expand Down Expand Up @@ -84,9 +86,9 @@ export default ({ apiUrl, get, openseaApi, post }) => {

const getNftCollectionInfo = (slug: string) => {
return get({
endPoint: `/nft/collection/${slug}/`,
endPoint: `/nft/collection/${slug}/${IS_TESTNET ? 'rinkeby' : ''}`,
ignoreQueryParams: true,
url: `http://localhost:8081`
url: `${apiUrl}/explorer-gateway`
})
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export const getNftSellOrder = async (
asset: NftAsset,
signer: Signer,
startPrice = 0.011, // The starting price for auctions / sale price for fixed price sale orders (TODO: Remove default 0.1 value)
network: string,
endPrice: number | null = null, // Implement later for to enable dutch auction sales.
waitForHighestBid = false, // True = English auction,
paymentTokenAddress = '0x0000000000000000000000000000000000000000',
Expand All @@ -60,7 +61,8 @@ export const getNftSellOrder = async (
startPrice,
endPrice,
waitForHighestBid,
paymentTokenAddress
paymentTokenAddress,
network
)
}

Expand Down Expand Up @@ -100,6 +102,7 @@ export const getNftBuyOrders = async (
order: NftOrdersType['orders'][0],
signer: Signer,
expirationTime = 0,
network: string,
offer?: string,
paymentTokenAddress?: string
): Promise<{ buy: Order; sell: Order }> => {
Expand All @@ -108,6 +111,7 @@ export const getNftBuyOrders = async (
offer || null,
order,
signer,
network,
paymentTokenAddress || null
)
}
Expand Down
32 changes: 25 additions & 7 deletions packages/blockchain-wallet-v4/src/redux/payment/nfts/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ export const NULL_BLOCK_HASH = '0x0000000000000000000000000000000000000000000000
export const NULL_ADDRESS = '0x0000000000000000000000000000000000000000'
const MIN_EXPIRATION_SECONDS = 10
const ORDER_MATCHING_LATENCY_SECONDS = 60 * 60 * 24 * 7
const OPENSEA_FEE_RECIPIENT = '0x5b3256965e7c3cf26e11fcaf296dfc8807c01073'
const MAX_DIGITS_IN_UNSIGNED_256_INT = 72
export const DEFAULT_BUYER_FEE_BASIS_POINTS = 0
export const DEFAULT_SELLER_FEE_BASIS_POINTS = 250
Expand All @@ -45,7 +44,10 @@ export const ENJIN_ADDRESS = '0xfaaFDc07907ff5120a76b34b731b278c38d6043C'
export const ENJIN_COIN_ADDRESS = '0xf629cbd94d3791c9250152bd8dfbdf380e2a3b9c'
const WETH_ADDRESS = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'
const WYVERN_TOKEN_PAYMENT_PROXY = '0xe5c783ee536cf5e63e792988335c4255169be4e1'
const WYVERN_CONTRACT_ADDR = '0xd219a8bad2bd4075b7089d51c1841be83fbe1353'
const WYVERN_CONTRACT_ADDR_RINKEBY = '0x5206e78b21Ce315ce284FB24cf05e0585A93B1d9'
const WYVERN_CONTRACT_ADDR_MAINNET = '0x7Be8076f4EA4A4AD08075C2508e481d6C946D12b'
const OPENSEA_FEE_RECIPIENT_RINKEBY = NULL_ADDRESS
const OPENSEA_FEE_RECIPIENT = '0x5b3256965e7c3cf26e11fcaf296dfc8807c01073'

export const bigNumberToBN = (value: BigNumber) => {
return new BN(value.toString(), 10)
Expand Down Expand Up @@ -567,6 +569,7 @@ async function getTransferFeeSettings(
export function _makeMatchingOrder({
accountAddress,
expirationTime,
network,
offer,
order,
paymentTokenAddress,
Expand All @@ -575,6 +578,7 @@ export function _makeMatchingOrder({
// UnsignedOrder;
accountAddress: string
expirationTime: number
network: string
offer: null | string
order: Order
paymentTokenAddress: null | string
Expand Down Expand Up @@ -632,7 +636,7 @@ export function _makeMatchingOrder({

const times = _getTimeParameters(expirationTime)
// Compat for matching buy orders that have fee recipient still on them
const feeRecipient = OPENSEA_FEE_RECIPIENT
const feeRecipient = network === 'rinkeby' ? OPENSEA_FEE_RECIPIENT_RINKEBY : OPENSEA_FEE_RECIPIENT

const matchingOrder: UnhashedOrder = {
basePrice: offer ? new BigNumber(offer) : new BigNumber(order.basePrice),
Expand Down Expand Up @@ -1019,6 +1023,7 @@ export async function _makeSellOrder({
expirationTime,
extraBountyBasisPoints = 2.5,
listingTime,
network,
paymentTokenAddress,
quantity,
startAmount,
Expand All @@ -1032,6 +1037,7 @@ export async function _makeSellOrder({
expirationTime: number
extraBountyBasisPoints: number
listingTime?: number
network: string
paymentTokenAddress: string
quantity: number
startAmount: number
Expand Down Expand Up @@ -1092,7 +1098,10 @@ export async function _makeSellOrder({
basePrice: new BigNumber(basePrice.toString()),
calldata,
englishAuctionReservePrice: reservePrice ? new BigNumber(reservePrice.toString()) : undefined,
exchange: WYVERN_CONTRACT_ADDR.toLowerCase(),
exchange: (network === 'rinkeby'
? WYVERN_CONTRACT_ADDR_RINKEBY
: WYVERN_CONTRACT_ADDR_MAINNET
).toLowerCase(),
expirationTime: times.expirationTime,
extra: new BigNumber(extra.toString()),
feeMethod,
Expand Down Expand Up @@ -2064,6 +2073,7 @@ export async function _makeBuyOrder({
expirationTime,
extraBountyBasisPoints = 0,
listingTime,
network,
paymentTokenAddress,
quantity,
sellOrder,
Expand All @@ -2078,6 +2088,7 @@ export async function _makeBuyOrder({
expirationTime: number
extraBountyBasisPoints: number
listingTime?: number
network: string
paymentTokenAddress: string
quantity: number
sellOrder?: Order
Expand Down Expand Up @@ -2127,7 +2138,7 @@ export async function _makeBuyOrder({
return {
basePrice: new BigNumber(basePrice.toString()),
calldata,
exchange: WYVERN_CONTRACT_ADDR,
exchange: network === 'rinkeby' ? WYVERN_CONTRACT_ADDR_RINKEBY : WYVERN_CONTRACT_ADDR_MAINNET,
expirationTime: times.expirationTime,
extra: new BigNumber(extra.toString()),
feeMethod,
Expand Down Expand Up @@ -2170,7 +2181,8 @@ export async function createSellOrder(
startPrice: number,
endPrice: number | null,
waitForHighestBid: boolean,
paymentTokenAddress: string
paymentTokenAddress: string,
network: string
): Promise<Order> {
// 1. use the _makeSellOrder to create the object & initialize the proxy contract for this sale.
const accountAddress = await signer.getAddress()
Expand All @@ -2181,9 +2193,11 @@ export async function createSellOrder(
endAmount: endPrice,
expirationTime,
extraBountyBasisPoints: 0,
network,
paymentTokenAddress,
quantity: 1,
startAmount: startPrice, // only supports Ether Sales at the moment due to hardcoded conversion in _getPricingParameters)
startAmount: startPrice,
// only supports Ether Sales at the moment due to hardcoded conversion in _getPricingParameters)
waitForHighestBid
})
// 2. Validation of sell order fields & Transaction Approvals (Proxy initialized here if needed also)
Expand Down Expand Up @@ -2215,13 +2229,15 @@ export async function createMatchingOrders(
offer: null | string,
order: NftOrdersType['orders'][0],
signer: Signer,
network: string,
paymentTokenAddress: null | string
): Promise<{ buy: Order; sell: Order }> {
const accountAddress = await signer.getAddress()
// TODO: If its an english auction bid above the basePrice include an offer property in the _makeMatchingOrder call
const matchingOrder = _makeMatchingOrder({
accountAddress,
expirationTime,
network,
offer,
order,
paymentTokenAddress,
Expand Down Expand Up @@ -2507,11 +2523,13 @@ export async function calculateAtomicMatchFees(order: Order, counterOrder: Order
NULL_BLOCK_HASH
]
]
console.log(counterOrder)
const wyvernExchangeContract = new ethers.Contract(
counterOrder.exchange,
wyvernExchange_ABI,
signer
)
console.log(signer)
return new BigNumber(
await safeGasEstimation(wyvernExchangeContract.estimateGas.atomicMatch_, args, {
gasLimit: 350_000,
Expand Down

0 comments on commit e54870c

Please sign in to comment.