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:
parent
2724e63bff
commit
faa7de3601
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
204
src/utils/OrderUtils.ts
Normal 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 !')
|
||||
}
|
||||
}
|
@ -1,5 +1,3 @@
|
||||
import { LoggerInstance } from './Logger'
|
||||
|
||||
const PREDEFINED_ERRORS = {
|
||||
datasets: {
|
||||
invalid: 'Datasets is not a list, as expected'
|
||||
|
@ -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'
|
||||
|
@ -9,3 +9,4 @@ export * from './minAbi'
|
||||
export * from './SignatureUtils'
|
||||
export * from './TokenUtils'
|
||||
export * from './ProviderErrors'
|
||||
export * from './OrderUtils'
|
||||
|
@ -94,7 +94,6 @@ import {
|
||||
Files,
|
||||
FixedRateExchange,
|
||||
FreCreationParams,
|
||||
getHash,
|
||||
Nft,
|
||||
NftCreateData,
|
||||
NftFactory,
|
||||
|
@ -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 () => {
|
||||
|
@ -8,7 +8,6 @@ import {
|
||||
Aquarius,
|
||||
NftFactory,
|
||||
NftCreateData,
|
||||
getHash,
|
||||
ZERO_ADDRESS,
|
||||
Nft,
|
||||
approve,
|
||||
|
@ -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 () => {
|
||||
|
@ -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()
|
||||
|
@ -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')
|
||||
|
@ -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'
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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')
|
||||
|
||||
|
@ -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)
|
||||
})
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user