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

Merge pull request #289 from oceanprotocol/feature/statstics_history

add stats/history
This commit is contained in:
Alex Coseru 2020-09-30 15:32:41 +03:00 committed by GitHub
commit 9d33417b7c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 297 additions and 30 deletions

View File

@ -2,6 +2,28 @@ import Web3 from 'web3'
import { AbiItem } from 'web3-utils/types'
import { TransactionReceipt } from 'web3-core'
import { Pool } from './Pool'
import { EventData, Filter } from 'web3-eth-contract'
declare type PoolTransactionType = 'swap' | 'join' | 'exit'
export interface PoolDetails {
poolAddress: string
tokens: string[]
}
export interface PoolTransaction {
poolAddress: string
dtAddress: string
caller: string
transactionHash: string
blockNumber: number
timestamp: number
tokenIn?: string
tokenOut?: string
tokenAmountIn?: string
tokenAmountOut?: string
type: PoolTransactionType
}
/**
* Ocean Pools submodule exposed under ocean.pool
@ -82,9 +104,9 @@ export class OceanPool extends Pool {
* @param {String} poolAddress
* @return {string}
*/
public async getDTAddress(account: string, poolAddress: string): Promise<string> {
public async getDTAddress(poolAddress: string): Promise<string> {
this.dtAddress = null
const tokens = await this.getCurrentTokens(account, poolAddress)
const tokens = await this.getCurrentTokens(poolAddress)
let token: string
for (token of tokens) {
@ -115,7 +137,7 @@ export class OceanPool extends Pool {
* @return {String}
*/
public async getDTReserve(account: string, poolAddress: string): Promise<string> {
await this.getDTAddress(account, poolAddress)
await this.getDTAddress(poolAddress)
return super.getReserve(account, poolAddress, this.dtAddress)
}
@ -139,7 +161,7 @@ export class OceanPool extends Pool {
console.error('oceanAddress is not defined')
return null
}
await this.getDTAddress(account, poolAddress)
await this.getDTAddress(poolAddress)
// TODO - check balances first
await super.approve(
@ -180,7 +202,7 @@ export class OceanPool extends Pool {
console.error('oceanAddress is not defined')
return null
}
await this.getDTAddress(account, poolAddress)
await this.getDTAddress(poolAddress)
return this.swapExactAmountOut(
account,
poolAddress,
@ -204,7 +226,7 @@ export class OceanPool extends Pool {
poolAddress: string,
amount: string
): Promise<TransactionReceipt> {
await this.getDTAddress(account, poolAddress)
await this.getDTAddress(poolAddress)
await super.approve(
account,
this.dtAddress,
@ -234,7 +256,7 @@ export class OceanPool extends Pool {
amount: string,
maximumPoolShares: string
): Promise<TransactionReceipt> {
await this.getDTAddress(account, poolAddress)
await this.getDTAddress(poolAddress)
// TODO Check balance of PoolShares before doing exit
return this.exitswapExternAmountOut(
account,
@ -335,10 +357,7 @@ export class OceanPool extends Pool {
toBlock: 'latest'
})
for (let i = 0; i < events.length; i++) {
const constituents = await super.getCurrentTokens(
account,
events[i].returnValues[0]
)
const constituents = await super.getCurrentTokens(events[i].returnValues[0])
if (constituents.includes(dtAddress)) result.push(events[i].returnValues[0])
}
return result
@ -349,7 +368,7 @@ export class OceanPool extends Pool {
poolAddress: string,
dtRequired: string
): Promise<string> {
await this.getDTAddress(account, poolAddress)
await this.getDTAddress(poolAddress)
const tokenBalanceIn = await this.getReserve(account, poolAddress, this.oceanAddress)
const tokenWeightIn = await this.getDenormalizedWeight(
account,
@ -372,4 +391,154 @@ export class OceanPool extends Pool {
swapFee
)
}
/**
* Search all pools created by an address
* @param {String} account If empty, will return all pools ever created by anybody
* @return {PoolDetails[]}
*/
public async getPoolsbyCreator(account?: string): Promise<PoolDetails[]> {
const result: PoolDetails[] = []
const factory = new this.web3.eth.Contract(this.factoryABI, this.factoryAddress)
const events = await factory.getPastEvents('BPoolRegistered', {
filter: account ? { registeredBy: account } : {},
fromBlock: 0,
toBlock: 'latest'
})
for (let i = 0; i < events.length; i++) {
if (!account || events[i].returnValues[1].toLowerCase() === account.toLowerCase())
result.push(await this.getPoolDetails(events[i].returnValues[0]))
}
return result
}
/**
* Get pool details
* @param {String} poolAddress Pool address
* @return {PoolDetails}
*/
public async getPoolDetails(poolAddress: string): Promise<PoolDetails> {
const tokens = await super.getFinalTokens(poolAddress)
const details: PoolDetails = { poolAddress, tokens }
return details
}
/**
* Get all actions from a pool (join,exit,swap)
* @param {String} poolAddress Pool address
* @param {String} account
* @return {PoolTransaction[]}
*/
public async getPoolLogs(
poolAddress: string,
account?: string
): Promise<PoolTransaction[]> {
const results: PoolTransaction[] = []
const pool = new this.web3.eth.Contract(this.poolABI, poolAddress)
const dtAddress = await this.getDTAddress(poolAddress)
const filter: Filter = account ? { caller: account } : {}
let events: EventData[]
events = await pool.getPastEvents('LOG_SWAP', {
filter,
fromBlock: 0,
toBlock: 'latest'
})
for (let i = 0; i < events.length; i++) {
if (!account || events[i].returnValues[0].toLowerCase() === account.toLowerCase())
results.push(await this.getEventData('swap', poolAddress, dtAddress, events[i]))
}
events = await pool.getPastEvents('LOG_JOIN', {
filter,
fromBlock: 0,
toBlock: 'latest'
})
for (let i = 0; i < events.length; i++) {
if (!account || events[i].returnValues[0].toLowerCase() === account.toLowerCase())
results.push(await this.getEventData('join', poolAddress, dtAddress, events[i]))
}
events = await pool.getPastEvents('LOG_EXIT', {
filter,
fromBlock: 0,
toBlock: 'latest'
})
for (let i = 0; i < events.length; i++) {
if (!account || events[i].returnValues[0].toLowerCase() === account.toLowerCase())
results.push(await this.getEventData('exit', poolAddress, dtAddress, events[i]))
}
return results
}
/**
* Get all logs on all pools for a specific address
* @param {String} account
* @return {PoolTransaction[]}
*/
public async getAllPoolLogs(account: string): Promise<PoolTransaction[]> {
const results: PoolTransaction[] = []
const factory = new this.web3.eth.Contract(this.factoryABI, this.factoryAddress)
const events = await factory.getPastEvents('BPoolRegistered', {
filter: {},
fromBlock: 0,
toBlock: 'latest'
})
for (let i = 0; i < events.length; i++) {
const logs = await this.getPoolLogs(events[i].returnValues[0], account)
for (let j = 0; j < logs.length; j++) results.push(logs[j])
}
return results
}
private async getEventData(
type: PoolTransactionType,
poolAddress: string,
dtAddress: string,
data: EventData
): Promise<PoolTransaction> {
const blockDetails = await this.web3.eth.getBlock(data.blockNumber)
let result: PoolTransaction = {
poolAddress,
dtAddress,
caller: data.returnValues[0],
transactionHash: data.transactionHash,
blockNumber: data.blockNumber,
timestamp: parseInt(String(blockDetails.timestamp)),
type
}
switch (type) {
case 'swap':
result = {
...result,
tokenIn: data.returnValues[1],
tokenOut: data.returnValues[2],
tokenAmountIn: this.web3.utils.fromWei(data.returnValues[3]),
tokenAmountOut: this.web3.utils.fromWei(data.returnValues[4])
}
break
case 'join':
result = {
...result,
tokenIn: data.returnValues[1],
tokenAmountIn: this.web3.utils.fromWei(data.returnValues[2])
}
break
case 'exit':
result = {
...result,
tokenOut: data.returnValues[1],
tokenAmountOut: this.web3.utils.fromWei(data.returnValues[2])
}
break
}
return result
}
}

View File

@ -15,7 +15,7 @@ export interface TokensToAdd {
}
export class Pool extends PoolFactory {
private poolABI: AbiItem | AbiItem[]
public poolABI: AbiItem | AbiItem[]
constructor(
web3: Web3,
@ -275,14 +275,11 @@ export class Pool extends PoolFactory {
/**
* Get tokens composing this pool
* @param {String} account
* @param {String} poolAddress
* @return {String[]}
*/
async getCurrentTokens(account: string, poolAddress: string): Promise<string[]> {
const pool = new this.web3.eth.Contract(this.poolABI, poolAddress, {
from: account
})
async getCurrentTokens(poolAddress: string): Promise<string[]> {
const pool = new this.web3.eth.Contract(this.poolABI, poolAddress)
let result = null
try {
result = await pool.methods.getCurrentTokens().call()
@ -294,14 +291,11 @@ export class Pool extends PoolFactory {
/**
* Get the final tokens composing this pool
* @param {String} account
* @param {String} poolAddress
* @return {String[]}
*/
async getFinalTokens(account: string, poolAddress: string): Promise<string[]> {
const pool = new this.web3.eth.Contract(this.poolABI, poolAddress, {
from: account
})
async getFinalTokens(poolAddress: string): Promise<string[]> {
const pool = new this.web3.eth.Contract(this.poolABI, poolAddress)
let result = null
try {
result = await pool.methods.getFinalTokens().call()

View File

@ -1,11 +1,11 @@
import defaultFixedRateExchangeABI from '@oceanprotocol/contracts/artifacts/FixedRateExchange.json'
import BigNumber from 'bignumber.js'
import { TransactionReceipt } from 'web3-core'
import { Contract } from 'web3-eth-contract'
import { Contract, EventData } from 'web3-eth-contract'
import { AbiItem } from 'web3-utils/types'
import Web3 from 'web3'
export interface FixedPricedExchange {
export interface FixedPriceExchange {
exchangeID?: string
exchangeOwner: string
dataToken: string
@ -15,6 +15,12 @@ export interface FixedPricedExchange {
supply: string
}
export interface FixedPriceSwap {
exchangeID: string
caller: string
baseTokenAmount: string
dataTokenAmount: string
}
const DEFAULT_GAS_LIMIT = 300000
export class OceanFixedRateExchange {
@ -292,8 +298,8 @@ export class OceanFixedRateExchange {
* @param {String} exchangeId ExchangeId
* @return {Promise<FixedPricedExchange>} Exchange details
*/
public async getExchange(exchangeId: string): Promise<FixedPricedExchange> {
const result: FixedPricedExchange = await this.contract.methods
public async getExchange(exchangeId: string): Promise<FixedPriceExchange> {
const result: FixedPriceExchange = await this.contract.methods
.getExchange(exchangeId)
.call()
return result
@ -337,8 +343,8 @@ export class OceanFixedRateExchange {
public async searchforDT(
dataTokenAddress: string,
minSupply: string
): Promise<FixedPricedExchange[]> {
const result: FixedPricedExchange[] = []
): Promise<FixedPriceExchange[]> {
const result: FixedPriceExchange[] = []
const events = await this.contract.getPastEvents('ExchangeCreated', {
filter: { datatoken: dataTokenAddress },
fromBlock: 0,
@ -357,4 +363,80 @@ export class OceanFixedRateExchange {
}
return result
}
/**
* Get all exchanges, filtered by creator(if any)
* @param {String} account
* @return {Promise<FixedPricedExchange[]>}
*/
public async getExchangesbyCreator(account?: string): Promise<FixedPriceExchange[]> {
const result: FixedPriceExchange[] = []
const events = await this.contract.getPastEvents('ExchangeCreated', {
filter: {},
fromBlock: 0,
toBlock: 'latest'
})
for (let i = 0; i < events.length; i++) {
if (!account || events[i].returnValues[3].toLowerCase() === account.toLowerCase())
result.push(await this.getExchange(events[i].returnValues[0]))
}
return result
}
/**
* Get all swaps for an exchange, filtered by account(if any)
* @param {String} exchangeId
* @param {String} account
* @return {Promise<FixedPricedSwap[]>}
*/
public async getExchangeSwaps(
exchangeId: string,
account?: string
): Promise<FixedPriceSwap[]> {
const result: FixedPriceSwap[] = []
const events = await this.contract.getPastEvents('Swapped', {
filter: { exchangeId: exchangeId },
fromBlock: 0,
toBlock: 'latest'
})
for (let i = 0; i < events.length; i++) {
if (!account || events[i].returnValues[1].toLowerCase() === account.toLowerCase())
result.push(this.getEventData(events[i]))
}
return result
}
/**
* Get all swaps for an account
* @param {String} account
* @return {Promise<FixedPricedSwap[]>}
*/
public async getAllExchangesSwaps(account: string): Promise<FixedPriceSwap[]> {
const result: FixedPriceSwap[] = []
const events = await this.contract.getPastEvents('ExchangeCreated', {
filter: {},
fromBlock: 0,
toBlock: 'latest'
})
for (let i = 0; i < events.length; i++) {
const swaps: FixedPriceSwap[] = await this.getExchangeSwaps(
events[i].returnValues[0],
account
)
swaps.forEach((swap) => {
result.push(swap)
})
}
return result
}
private getEventData(data: EventData): FixedPriceSwap {
const result: FixedPriceSwap = {
exchangeID: data.returnValues[0],
caller: data.returnValues[1],
baseTokenAmount: data.returnValues[2],
dataTokenAmount: data.returnValues[3]
}
return result
}
}

View File

@ -122,7 +122,7 @@ describe('Balancer flow', () => {
assert(String(n) === '2', 'unexpected num tokens: ' + n)
})
it('Get pool information', async () => {
const currentTokens = await Pool.getCurrentTokens(alice, alicePoolAddress)
const currentTokens = await Pool.getCurrentTokens(alicePoolAddress)
assert(currentTokens.length === 2)
assert(currentTokens.includes(tokenAddress))
assert(currentTokens.includes(oceanTokenAddress))
@ -270,4 +270,18 @@ describe('Balancer flow', () => {
assert(parseFloat(bobDtBalance) < parseFloat(newbobDtBalance))
assert(parseFloat(poolShares) > parseFloat(newpoolShares))
})
it('ALice should get all the pools that she created', async () => {
const alicePools = await Pool.getPoolsbyCreator(alice)
assert(alicePools.length > 0)
})
it('ALice should get the logs for her pool', async () => {
const poolLogs = await Pool.getPoolLogs(greatPool, null)
assert(poolLogs.length > 0)
})
it('Bob should get the logs for all his activities', async () => {
const poolLogs = await Pool.getAllPoolLogs(bob)
assert(poolLogs.length > 0)
})
})

View File

@ -226,4 +226,12 @@ describe('FixedRateExchange flow', () => {
const exchangeDetails = await FixedRateClass.searchforDT(tokenAddress, tokenAmount)
assert(exchangeDetails.length === 0)
})
it('Bob should find all the exchanges created by Alice', async () => {
const exchangeDetails = await FixedRateClass.getExchangesbyCreator(alice)
assert(exchangeDetails.length > 0)
})
it('Bob should find all his swaps', async () => {
const exchangeDetails = await FixedRateClass.getAllExchangesSwaps(bob)
assert(exchangeDetails.length > 0)
})
})