Skip to content

Commit

Permalink
add DataFarming contract support (#1596)
Browse files Browse the repository at this point in the history
* add DataFarming contract support
  • Loading branch information
alexcos20 authored Sep 6, 2022
1 parent 647096a commit dd383ec
Show file tree
Hide file tree
Showing 4 changed files with 308 additions and 0 deletions.
106 changes: 106 additions & 0 deletions src/contracts/df/DfRewards.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import { AbiItem } from 'web3-utils'
import dfRewardsABI from '@oceanprotocol/contracts/artifacts/contracts/df/DFRewards.sol/DFRewards.json'
import { calculateEstimatedGas, sendTx } from '../../utils'
import { SmartContractWithAddress } from '../SmartContractWithAddress'
import { ReceiptOrEstimate } from '../../@types'

/**
* Provides an interface for DFRewards contract
*/
export class DfRewards extends SmartContractWithAddress {
getDefaultAbi(): AbiItem | AbiItem[] {
return dfRewardsABI.abi as AbiItem[]
}

/** Get available DF Rewards for a token
* @param {String} userAddress user address
* @param {String} tokenAddress token address
* @return {Promise<string>}
*/
public async getAvailableRewards(
userAddress: string,
tokenAddress: string
): Promise<string> {
const rewards = await this.contract.methods
.claimable(userAddress, tokenAddress)
.call()
const rewardsFormated = await this.unitsToAmount(tokenAddress, rewards)

return rewardsFormated
}

/**
* claim rewards for any address
* @param {String} fromUserAddress user that generates the tx
* @param {String} userAddress user address to claim
* @param {String} tokenAddress token address
* @return {Promise<ReceiptOrEstimate>}
*/
public async claimRewards<G extends boolean = false>(
fromUserAddress: string,
userAddress: string,
tokenAddress: string,
estimateGas?: G
): Promise<ReceiptOrEstimate<G>> {
const estGas = await calculateEstimatedGas(
fromUserAddress,
this.contract.methods.claimFor,
userAddress,
tokenAddress
)
if (estimateGas) return <ReceiptOrEstimate<G>>estGas

// Invoke function of the contract
const trxReceipt = await sendTx(
fromUserAddress,
estGas + 1,
this.web3,
this.config?.gasFeeMultiplier,
this.contract.methods.claimFor,
userAddress,
tokenAddress
)
return <ReceiptOrEstimate<G>>trxReceipt
}

/**
* allocate rewards to address. An approve must exist before calling this function.
* @param {String} fromUserAddress user that generates the tx
* @param {String[]} userAddresses array of users that will receive rewards
* @param {String[]} amounts array of amounts
* @param {String} tokenAddress token address
* @return {Promise<ReceiptOrEstimate>}
*/
public async allocateRewards<G extends boolean = false>(
fromUserAddress: string,
userAddresses: string[],
amounts: string[],
tokenAddress: string,
estimateGas?: G
): Promise<ReceiptOrEstimate<G>> {
for (let i = 0; i < amounts.length; i++) {
amounts[i] = await this.amountToUnits(tokenAddress, amounts[i])
}
const estGas = await calculateEstimatedGas(
fromUserAddress,
this.contract.methods.allocate,
userAddresses,
amounts,
tokenAddress
)
if (estimateGas) return <ReceiptOrEstimate<G>>estGas

// Invoke function of the contract
const trxReceipt = await sendTx(
fromUserAddress,
estGas + 1,
this.web3,
this.config?.gasFeeMultiplier,
this.contract.methods.allocate,
userAddresses,
amounts,
tokenAddress
)
return <ReceiptOrEstimate<G>>trxReceipt
}
}
67 changes: 67 additions & 0 deletions src/contracts/df/DfStrategyV1.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { AbiItem } from 'web3-utils'
import dfStrategyV1ABI from '@oceanprotocol/contracts/artifacts/contracts/df/DFStrategyV1.sol/DFStrategyV1.json'
import { calculateEstimatedGas, sendTx } from '../../utils'
import { SmartContractWithAddress } from '../SmartContractWithAddress'
import { ReceiptOrEstimate } from '../../@types'

/**
* Provides an interface for dfStrategyV1 contract
*/
export class DfStrategyV1 extends SmartContractWithAddress {
getDefaultAbi(): AbiItem | AbiItem[] {
return dfStrategyV1ABI.abi as AbiItem[]
}

/** Get available DF Rewards for multiple tokens
* @param {String} userAddress user address
* @param {String} tokenAddresses array of tokens
* @return {Promise<string[]>}
*/
public async getMultipleAvailableRewards(
userAddress: string,
tokenAddresses: string[]
): Promise<string[]> {
const rewards = await this.contract.methods
.claimables(userAddress, tokenAddresses)
.call()
const rewardsFormated: string[] = []
for (let i = 0; i < rewards.length; i++) {
rewardsFormated.push(await this.unitsToAmount(tokenAddresses[i], rewards[i]))
}
return rewardsFormated
}

/**
* claim multiple token rewards for any address
* @param {String} fromUserAddress user that generates the tx
* @param {String} userAddress user address to claim
* @param {String} tokenAddresses array of tokens
* @return {Promise<ReceiptOrEstimate>}
*/
public async claimMultipleRewards<G extends boolean = false>(
fromUserAddress: string,
userAddress: string,
tokenAddresses: string[],
estimateGas?: G
): Promise<ReceiptOrEstimate<G>> {
const estGas = await calculateEstimatedGas(
fromUserAddress,
this.contract.methods.claimMultiple,
userAddress,
tokenAddresses
)
if (estimateGas) return <ReceiptOrEstimate<G>>estGas

// Invoke function of the contract
const trxReceipt = await sendTx(
fromUserAddress,
estGas + 1,
this.web3,
this.config?.gasFeeMultiplier,
this.contract.methods.claimMultiple,
userAddress,
tokenAddresses
)
return <ReceiptOrEstimate<G>>trxReceipt
}
}
2 changes: 2 additions & 0 deletions src/contracts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ export * from './NFTFactory'
export * from './ve/VeOcean'
export * from './ve/VeFeeDistributor'
export * from './ve/VeAllocate'
export * from './df/DfRewards'
export * from './df/DfStrategyV1'
133 changes: 133 additions & 0 deletions test/unit/DFRewards.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import { assert } from 'chai'
import { AbiItem } from 'web3-utils'
import { web3, getTestConfig, getAddresses } from '../config'
import {
Config,
approve,
DfRewards,
DfStrategyV1,
sendTx,
calculateEstimatedGas
} from '../../src'

describe('veOcean tests', async () => {
let config: Config
let addresses: any
let nftFactory
let dfRewards: DfRewards
let dfStrategy: DfStrategyV1
let ownerAccount: string
let Alice: string
let Bob: string
let nft1, nft2, nft3
let tokenContract
let chainId

before(async () => {
config = await getTestConfig(web3)
})

it('initialize accounts', async () => {
addresses = getAddresses()
const accounts = await web3.eth.getAccounts()
chainId = await web3.eth.getChainId()
ownerAccount = accounts[0]
Alice = accounts[1]
Bob = accounts[2]
const minAbi = [
{
constant: false,
inputs: [
{ name: 'to', type: 'address' },
{ name: 'value', type: 'uint256' }
],
name: 'mint',
outputs: [{ name: '', type: 'bool' }],
payable: false,
stateMutability: 'nonpayable',
type: 'function'
},
{
constant: true,
inputs: [{ name: 'owner', type: 'address' }],
name: 'balanceOf',
outputs: [{ name: '', type: 'uint256' }],
payable: false,
stateMutability: 'view',
type: 'function'
}
] as AbiItem[]
tokenContract = new web3.eth.Contract(minAbi, addresses.Ocean)
const estGas = await calculateEstimatedGas(
ownerAccount,
tokenContract.methods.mint,
ownerAccount,
web3.utils.toWei('10000')
)
// mint some Oceans
await sendTx(
ownerAccount,
estGas,
web3,
1,
tokenContract.methods.mint,
ownerAccount,
web3.utils.toWei('1000')
)
dfRewards = new DfRewards(addresses.DFRewards, web3)
dfStrategy = new DfStrategyV1(addresses.DFStrategyV1, web3)
})

it('Generous owner should allocate some DF Rewards', async () => {
const dfOceanBalance = web3.utils.fromWei(
await tokenContract.methods.balanceOf(addresses.DFRewards).call()
)
// approve 500 tokens
await approve(web3, config, ownerAccount, addresses.Ocean, addresses.DFRewards, '300')
// fund DFRewards
await dfRewards.allocateRewards(
ownerAccount,
[Alice, Bob],
['100', '200'],
addresses.Ocean
)
const newDfOceanBalance = web3.utils.fromWei(
await tokenContract.methods.balanceOf(addresses.DFRewards).call()
)
const expected = parseInt(dfOceanBalance) + 300
assert(parseInt(newDfOceanBalance) === expected, 'DFRewards allocate failed')
})

it('Alice should check for rewards', async () => {
const rewards = await dfRewards.getAvailableRewards(Alice, addresses.Ocean)
assert(parseInt(rewards) >= 100, 'Alice reward missmatch, got only ' + rewards)
const multipleRewards = await dfStrategy.getMultipleAvailableRewards(Alice, [
addresses.Ocean
])
assert(parseInt(multipleRewards[0]) >= 100, 'Alice reward missmatch')
})

it('Alice should claim the rewards using DFRewards claim', async () => {
const aliceOceanBalance = web3.utils.fromWei(
await tokenContract.methods.balanceOf(Alice).call()
)
await dfRewards.claimRewards(Alice, Alice, addresses.Ocean)
const newAliceOceanBalance = web3.utils.fromWei(
await tokenContract.methods.balanceOf(Alice).call()
)
const expected = parseInt(aliceOceanBalance) + 100
assert(parseInt(newAliceOceanBalance) >= expected, 'Alice failed to claim')
})

it('Bob should claim the rewards using DFStrategy claim', async () => {
const bobOceanBalance = web3.utils.fromWei(
await tokenContract.methods.balanceOf(Bob).call()
)
await dfStrategy.claimMultipleRewards(Bob, Bob, [addresses.Ocean])
const newBobOceanBalance = web3.utils.fromWei(
await tokenContract.methods.balanceOf(Bob).call()
)
const expected = parseInt(bobOceanBalance) + 200
assert(parseInt(newBobOceanBalance) >= expected, 'Bob failed to claim')
})
})

0 comments on commit dd383ec

Please sign in to comment.