1
0
mirror of https://github.com/oceanprotocol/ocean.js.git synced 2024-11-26 20:39:05 +01:00

Feature/Add order util method (#1759)

* added order  helper method using contracts calls

* fixes consume fees  & lint

* cleanup

* update order helper method to be more generic

* fix all warnings
This commit is contained in:
Bogdan Fazakas 2023-08-25 17:33:06 +03:00 committed by GitHub
parent 2724e63bff
commit faa7de3601
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 257 additions and 35 deletions

View File

@ -737,6 +737,17 @@ export class Datatoken extends SmartContract {
return decimals
}
/**
* It returns the token template index.
* @param {String} dtAddress Datatoken adress
* @return {Promise<number>}
*/
public async getId(dtAddress: string): Promise<number> {
const dtContract = this.getContract(dtAddress)
const id = await dtContract.getId()
return id
}
/**
* It returns the token symbol
* @param {String} dtAddress Datatoken adress
@ -770,6 +781,28 @@ export class Datatoken extends SmartContract {
return nftAddress
}
/**
* It returns the list of fixedRateExchanges created for this datatoken.
* @param {String} dtAddress Datatoken adress
* @return {Promise<number>}
*/
public async getFixedRates(dtAddress: string): Promise<any[]> {
const dtContract = this.getContract(dtAddress)
const fixedRates = await dtContract.getFixedRates()
return fixedRates
}
/**
* It returns the list of dispensers created for this datatoken.
* @param {String} dtAddress Datatoken adress
* @return {Promise<number>}
*/
public async getDispensers(dtAddress: string): Promise<any[]> {
const dtContract = this.getContract(dtAddress)
const dispensers = await dtContract.getDispensers()
return dispensers
}
/**
* Returns true if address has deployERC20 role
* @param {String} dtAddress Datatoken adress

View File

@ -1,7 +1,7 @@
import { ethers, Signer, providers, Contract, ContractFunction, BigNumber } from 'ethers'
import { Config } from '../config'
import { minAbi, GASLIMIT_DEFAULT, LoggerInstance, FEE_HISTORY_NOT_SUPPORTED } from '.'
import { minAbi } from '.'
const MIN_GAS_FEE_POLYGON = 30000000000 // minimum recommended 30 gwei polygon main and mumbai fees
const POLYGON_NETWORK_ID = 137

View File

@ -9,7 +9,9 @@ export enum LogLevel {
/* eslint-enable no-unused-vars */
export class Logger {
constructor(private logLevel: LogLevel = LogLevel.Error) {}
constructor(private logLevel?: LogLevel) {
this.logLevel = logLevel || LogLevel.Error
}
public setLevel(logLevel: LogLevel): void {
this.logLevel = logLevel

204
src/utils/OrderUtils.ts Normal file
View File

@ -0,0 +1,204 @@
import { Signer } from 'ethers'
import {
ProviderInstance,
Datatoken,
Dispenser,
Config,
OrderParams,
Asset,
FreOrderParams,
approve,
FixedRateExchange,
ConsumeMarketFee
} from '../index'
import Decimal from 'decimal.js'
/**
* Orders an asset based on the specified pricing schema and configuration.
* @param {Asset} asset - The asset to be ordered.
* @param {Signer} consumerAccount - The signer account of the consumer.
* @param {Config} config - The configuration settings.
* @param {Datatoken} datatoken - The Datatoken instance.
* @param {ConsumeMarketFee} [consumeMarketOrderFee] - Optional consume market fee.
* @param {string} [consumeMarketFixedSwapFee='0'] - Fixed swap fee for consuming the market.
* @param {number} [datatokenIndex=0] - Index of the datatoken within the asset.
* @param {number} [serviceIndex=0] - Index of the service within the asset.
* @param {number} [fixedRateIndex=0] - Index of the fixed rate within the pricing schema.
* @returns {Promise<void>} - A promise that resolves when the asset order process is completed.
* @throws {Error} If the pricing schema is not supported or if required indexes are invalid.
*/
export async function orderAsset(
asset: Asset,
consumerAccount: Signer,
config: Config,
datatoken: Datatoken,
consumeMarketOrderFee?: ConsumeMarketFee,
consumeMarketFixedSwapFee: string = '0',
datatokenIndex: number = 0,
serviceIndex: number = 0,
fixedRateIndex: number = 0
) {
if (!consumeMarketOrderFee)
consumeMarketOrderFee = {
consumeMarketFeeAddress: '0x0000000000000000000000000000000000000000',
consumeMarketFeeAmount: '0',
consumeMarketFeeToken:
asset.stats.price.tokenAddress || '0x0000000000000000000000000000000000000000'
}
if (!asset.datatokens[datatokenIndex].address)
throw new Error(
`The datatoken with index: ${datatokenIndex} does not exist for the asset with did: ${asset.id}`
)
if (!asset.services[serviceIndex].id)
throw new Error(
`There is no service with index: ${serviceIndex} defined for the asset with did: ${asset.id}`
)
const templateIndex = await datatoken.getId(asset.datatokens[datatokenIndex].address)
const fixedRates = await datatoken.getFixedRates(
asset.datatokens[datatokenIndex].address
)
const dispensers = await datatoken.getDispensers(
asset.datatokens[datatokenIndex].address
)
const publishMarketFees = await datatoken.getPublishingMarketFee(
asset.datatokens[datatokenIndex].address
)
const pricingType =
fixedRates.length > 0 ? 'fixed' : dispensers.length > 0 ? 'free' : 'NOT_ALLOWED'
const initializeData = await ProviderInstance.initialize(
asset.id,
asset.services[serviceIndex].id,
0,
await consumerAccount.getAddress(),
config.providerUri
)
const orderParams = {
consumer: await consumerAccount.getAddress(),
serviceIndex,
_providerFee: initializeData.providerFee,
_consumeMarketFee: consumeMarketOrderFee
} as OrderParams
switch (pricingType) {
case 'free': {
if (templateIndex === 1) {
const dispenser = new Dispenser(config.dispenserAddress, consumerAccount)
const dispenserTx = await dispenser.dispense(
asset.datatokens[datatokenIndex].address,
'1',
await consumerAccount.getAddress()
)
if (!dispenserTx) {
return
}
return await datatoken.startOrder(
asset.datatokens[datatokenIndex].address,
orderParams.consumer,
orderParams.serviceIndex,
orderParams._providerFee,
orderParams._consumeMarketFee
)
}
if (templateIndex === 2) {
return await datatoken.buyFromDispenserAndOrder(
asset.services[serviceIndex].datatokenAddress,
orderParams,
config.dispenserAddress
)
}
break
}
case 'fixed': {
const fre = new FixedRateExchange(config.fixedRateExchangeAddress, consumerAccount)
if (!fixedRates[fixedRateIndex].id)
throw new Error(
`There is no fixed rate exchange with index: ${serviceIndex} for the asset with did: ${asset.id}`
)
const fees = await fre.getFeesInfo(fixedRates[fixedRateIndex].id)
const exchange = await fre.getExchange(fixedRates[fixedRateIndex].id)
const { baseTokenAmount } = await fre.calcBaseInGivenDatatokensOut(
fees.exchangeId,
'1',
consumeMarketOrderFee.consumeMarketFeeAmount
)
const price = new Decimal(+baseTokenAmount || 0)
.add(new Decimal(consumeMarketOrderFee.consumeMarketFeeAmount || 0))
.add(new Decimal(+publishMarketFees.publishMarketFeeAmount || 0))
.toString()
const freParams = {
exchangeContract: config.fixedRateExchangeAddress,
exchangeId: fees.exchangeId,
maxBaseTokenAmount: price,
baseTokenAddress: exchange.baseToken,
baseTokenDecimals: parseInt(exchange.btDecimals) || 18,
swapMarketFee: consumeMarketFixedSwapFee,
marketFeeAddress: publishMarketFees.publishMarketFeeAddress
} as FreOrderParams
if (templateIndex === 1) {
const tx: any = await approve(
consumerAccount,
config,
await consumerAccount.getAddress(),
exchange.baseToken,
config.fixedRateExchangeAddress,
price,
false
)
const txApprove = typeof tx !== 'number' ? await tx.wait() : tx
if (!txApprove) {
return
}
const freTx = await fre.buyDatatokens(
exchange.exchangeId,
'1',
price,
publishMarketFees.publishMarketFeeAddress,
consumeMarketFixedSwapFee
)
const buyDtTx = await freTx.wait()
if (!buyDtTx) {
return
}
return await datatoken.startOrder(
asset.datatokens[datatokenIndex].address,
orderParams.consumer,
orderParams.serviceIndex,
orderParams._providerFee,
orderParams._consumeMarketFee
)
}
if (templateIndex === 2) {
const tx: any = await approve(
consumerAccount,
config,
await consumerAccount.getAddress(),
exchange.baseToken,
asset.datatokens[datatokenIndex].address,
price,
false
)
const txApprove = typeof tx !== 'number' ? await tx.wait() : tx
if (!txApprove) {
return
}
return await datatoken.buyFromFreAndOrder(
asset.datatokens[datatokenIndex].address,
orderParams,
freParams
)
}
break
}
default:
throw new Error('Pricing schema not supported !')
}
}

View File

@ -1,5 +1,3 @@
import { LoggerInstance } from './Logger'
const PREDEFINED_ERRORS = {
datasets: {
invalid: 'Datasets is not a list, as expected'

View File

@ -1,5 +1,5 @@
import Decimal from 'decimal.js'
import { ethers, Signer, BigNumber } from 'ethers'
import { ethers, Signer } from 'ethers'
import { amountToUnits, unitsToAmount, minAbi, sendTx, LoggerInstance } from '.'
import { Config } from '../config'
import { ReceiptOrEstimate, ReceiptOrDecimal } from '../@types'

View File

@ -9,3 +9,4 @@ export * from './minAbi'
export * from './SignatureUtils'
export * from './TokenUtils'
export * from './ProviderErrors'
export * from './OrderUtils'

View File

@ -94,7 +94,6 @@ import {
Files,
FixedRateExchange,
FreCreationParams,
getHash,
Nft,
NftCreateData,
NftFactory,

View File

@ -473,6 +473,7 @@ describe('Compute flow tests', async () => {
delay(100000)
const jobFinished = await waitTillJobEnds()
console.log('Job finished: ', jobFinished)
// move to start orders with initial txid's and provider fees
it('should restart a computeJob without paying anything, because order is valid and providerFees are still valid', async () => {

View File

@ -8,7 +8,6 @@ import {
Aquarius,
NftFactory,
NftCreateData,
getHash,
ZERO_ADDRESS,
Nft,
approve,

View File

@ -1,8 +1,7 @@
import { assert, expect } from 'chai'
import { getTestConfig, provider, getAddresses } from '../config'
import { ethers, Signer, providers } from 'ethers'
import { provider, getAddresses } from '../config'
import { ethers, Signer } from 'ethers'
import {
Config,
NftFactory,
NftCreateData,
Datatoken,
@ -27,10 +26,8 @@ describe('Datatoken', () => {
let nftFactory: NftFactory
let nftAddress: string
let datatokenAddress: string
let fixedRateAddress: string
let exchangeId: string
let freParams: FreCreationParams
let config: Config
let addresses: any
const nftData: NftCreateData = {
@ -49,7 +46,6 @@ describe('Datatoken', () => {
user3 = (await provider.getSigner(3)) as Signer
datatokenDeployer = (await provider.getSigner(4)) as Signer
config = await getTestConfig(nftOwner as Signer)
addresses = await getAddresses()
freParams = {
@ -208,7 +204,7 @@ describe('Datatoken', () => {
assert(freCreatedEvent !== null)
// fixedRateAddress = freCreatedEvent.args.ad
exchangeId = freCreatedEvent.args.exchangeId
exchangeId = freCreatedEvent?.args?.exchangeId
})
it('#createFixedRate - should FAIL create FRE if NOT DatatokenDeployer', async () => {

View File

@ -1,6 +1,6 @@
import { assert, expect } from 'chai'
import { getTestConfig, provider, getAddresses } from '../config'
import { ethers, Signer, providers } from 'ethers'
import { provider, getAddresses } from '../config'
import { Signer } from 'ethers'
import {
NftFactory,
@ -9,7 +9,6 @@ import {
DispenserParams,
Dispenser,
ZERO_ADDRESS,
Config,
getEventFromTx
} from '../../src/'
import { DatatokenCreateParams } from '../../src/@types'
@ -23,7 +22,6 @@ describe('Dispenser flow', () => {
let datatoken: Datatoken
let dtAddress: string
let addresses
let config: Config
const nftData: NftCreateData = {
name: '72120Bundle',
@ -51,7 +49,6 @@ describe('Dispenser flow', () => {
user1 = (await provider.getSigner(3)) as Signer
user2 = (await provider.getSigner(4)) as Signer
config = await getTestConfig(factoryOwner as Signer)
addresses = await getAddresses()
nftData.owner = await factoryOwner.getAddress()

View File

@ -93,8 +93,8 @@ describe('Fixed Rate unit test', () => {
const freCreatedEvent = getEventFromTx(trxReceipt, 'NewFixedRate')
const tokenCreatedEvent = getEventFromTx(trxReceipt, 'TokenCreated')
dtAddress = tokenCreatedEvent.args.newTokenAddress
exchangeId = freCreatedEvent.args.exchangeId
dtAddress = tokenCreatedEvent?.args?.newTokenAddress
exchangeId = freCreatedEvent?.args?.exchangeId
// user1 has no dt1
expect(await balance(user1, dtAddress, await user1.getAddress())).to.equal('0.0')
@ -487,8 +487,8 @@ describe('Fixed Rate unit test', () => {
const freCreatedEvent = getEventFromTx(trxReceipt, 'NewFixedRate')
const tokenCreatedEvent = getEventFromTx(trxReceipt, 'TokenCreated')
dtAddress = tokenCreatedEvent.args.newTokenAddress
exchangeId = freCreatedEvent.args.exchangeId
dtAddress = tokenCreatedEvent?.args?.newTokenAddress
exchangeId = freCreatedEvent?.args?.exchangeId
// user1 has no dt1
expect(await balance(user1, dtAddress, await user1.getAddress())).to.equal('0.0')

View File

@ -1,7 +1,7 @@
import { assert } from 'chai'
import sha256 from 'crypto-js/sha256'
import { ethers, Signer } from 'ethers'
import { getAddresses, getTestConfig, provider } from '../config'
import { getAddresses, provider } from '../config'
import { NftFactory, NftCreateData, Nft, ZERO_ADDRESS, getEventFromTx } from '../../src'
import { MetadataAndTokenURI } from '../../src/@types'

View File

@ -1,6 +1,6 @@
import { assert, expect } from 'chai'
import { getTestConfig, provider, getAddresses } from '../config'
import { ethers, Signer, providers } from 'ethers'
import { ethers, Signer } from 'ethers'
import {
NftFactory,
NftCreateData,

View File

@ -1,6 +1,5 @@
import { assert, expect } from 'chai'
import { getTestConfig, provider, getAddresses } from '../config'
import MockERC20 from '@oceanprotocol/contracts/artifacts/contracts/utils/mock/MockERC20Decimals.sol/MockERC20Decimals.json'
import { ethers, Signer } from 'ethers'
import {
NftFactory,
@ -176,9 +175,8 @@ describe('Router unit test', () => {
ERC_PARAMS,
freParams
)
const trxReceipt2 = await tx.wait()
const trxReceipt2 = await tx2.wait()
// events have been emitted
const nftCreatedEvent2 = getEventFromTx(trxReceipt2, 'NFTCreated')
const TokenCreatedEvent2 = getEventFromTx(trxReceipt2, 'TokenCreated')
const NewFixedRateEvent2 = getEventFromTx(trxReceipt2, 'NewFixedRate')

View File

@ -4,11 +4,9 @@ import {
Config,
approve,
VeOcean,
VeFeeDistributor,
sendTx,
NftFactory,
VeAllocate,
VeFeeEstimate,
getEventFromTx,
amountToUnits
} from '../../src'
@ -18,8 +16,6 @@ describe('veOcean tests', () => {
let addresses: any
let nftFactory
let veOcean: VeOcean
let veFeeDistributor: VeFeeDistributor
let veFeeEstimate: VeFeeEstimate
let veAllocate: VeAllocate
let ownerAccount
let Alice
@ -36,7 +32,7 @@ describe('veOcean tests', () => {
})
it('initialize accounts', async () => {
chainId = (await Alice.provider.getNetwork()).chainId
chainId = (await Alice.provider.getNetwork())?.chainId
const minAbi = [
{
constant: false,
@ -73,9 +69,7 @@ describe('veOcean tests', () => {
amountToUnits(null, null, '1000', 18)
)
veOcean = new VeOcean(addresses.veOCEAN, Alice)
veFeeDistributor = new VeFeeDistributor(addresses.veFeeDistributor, Alice)
veAllocate = new VeAllocate(addresses.veAllocate, Alice)
veFeeEstimate = new VeFeeEstimate(addresses.veFeeEstimate, Alice)
nftFactory = new NftFactory(addresses.ERC721Factory, Alice)
})