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

Feature/basic ve ocean (#1595)

* bump contracts to 1.1.3

* add basic veOcean support

Co-authored-by: Bogdan Fazakas <bogdan.fazakas@gmail.com>
This commit is contained in:
Alex Coseru 2022-09-06 15:00:47 +03:00 committed by GitHub
parent 8a6f009290
commit f8f4b48243
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 650 additions and 11 deletions

View File

@ -46,7 +46,10 @@ jobs:
path: ~/.npm
key: ${{ runner.os }}-test-unit-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: ${{ runner.os }}-test-unit-${{ env.cache-name }}-
# Env var expansion workaround
# https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-environment-variable
- name: Set ADDRESS_FILE
run: echo "ADDRESS_FILE=${HOME}/.ocean/ocean-contracts/artifacts/address.json" >> $GITHUB_ENV
- name: Checkout Barge
uses: actions/checkout@v3
with:
@ -57,6 +60,8 @@ jobs:
working-directory: ${{ github.workspace }}/barge
run: |
bash -x start_ocean.sh --no-aquarius --no-elasticsearch --no-provider --no-dashboard 2>&1 > start_ocean.log &
env:
CONTRACTS_VERSION: v1.1.3
- run: npm ci
- name: Wait for contracts deployment
working-directory: ${{ github.workspace }}/barge

14
package-lock.json generated
View File

@ -9,7 +9,7 @@
"version": "1.1.8",
"license": "Apache-2.0",
"dependencies": {
"@oceanprotocol/contracts": "^1.0.0",
"@oceanprotocol/contracts": "^1.1.3",
"bignumber.js": "^9.0.2",
"cross-fetch": "^3.1.5",
"crypto-js": "^4.1.1",
@ -2589,9 +2589,9 @@
}
},
"node_modules/@oceanprotocol/contracts": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@oceanprotocol/contracts/-/contracts-1.0.0.tgz",
"integrity": "sha512-rDCIooe1WHipLejuGhx2Wv/88SB7bWrN3+XHCWxXyPKTmmSQsgxKZPPzbIVBQ0ESChQZqGSBBJyqErqwwW4eBw=="
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@oceanprotocol/contracts/-/contracts-1.1.3.tgz",
"integrity": "sha512-pn0rm4QKF8sVfDeJVlt18TV4Qj5oGgR/qQNO7O0GO2DQ3q8KHXRS15uRjmLTr5wW1kGcCHcTqEndXEEC7Elzkw=="
},
"node_modules/@octokit/auth-token": {
"version": "3.0.1",
@ -19327,9 +19327,9 @@
}
},
"@oceanprotocol/contracts": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@oceanprotocol/contracts/-/contracts-1.0.0.tgz",
"integrity": "sha512-rDCIooe1WHipLejuGhx2Wv/88SB7bWrN3+XHCWxXyPKTmmSQsgxKZPPzbIVBQ0ESChQZqGSBBJyqErqwwW4eBw=="
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@oceanprotocol/contracts/-/contracts-1.1.3.tgz",
"integrity": "sha512-pn0rm4QKF8sVfDeJVlt18TV4Qj5oGgR/qQNO7O0GO2DQ3q8KHXRS15uRjmLTr5wW1kGcCHcTqEndXEEC7Elzkw=="
},
"@octokit/auth-token": {
"version": "3.0.1",

View File

@ -49,7 +49,7 @@
"web3": "^1.7.4"
},
"dependencies": {
"@oceanprotocol/contracts": "^1.0.0",
"@oceanprotocol/contracts": "^1.1.3",
"bignumber.js": "^9.0.2",
"cross-fetch": "^3.1.5",
"crypto-js": "^4.1.1",

View File

@ -6,3 +6,6 @@ export * from './Router'
export * from './Datatoken'
export * from './NFT'
export * from './NFTFactory'
export * from './ve/VeOcean'
export * from './ve/VeFeeDistributor'
export * from './ve/VeAllocate'

View File

@ -0,0 +1,117 @@
import { AbiItem } from 'web3-utils'
import veAllocateABI from '@oceanprotocol/contracts/artifacts/contracts/ve/veAllocate.sol/veAllocate.json'
import { calculateEstimatedGas, sendTx } from '../../utils'
import { SmartContractWithAddress } from '../SmartContractWithAddress'
import { ReceiptOrEstimate } from '../../@types'
/**
* Provides an interface for veOcean contract
*/
export class VeAllocate extends SmartContractWithAddress {
getDefaultAbi(): AbiItem | AbiItem[] {
return veAllocateABI.abi as AbiItem[]
}
/**
* set a specific percentage of veOcean to a specific nft
* Maximum allocated percentage is 10000, so 1% is specified as 100
* @param {String} userAddress user address
* @param {String} amount Percentage used
* @param {String} nft NFT address to allocate to
* @param {String} chainId chainId of NFT
* @return {Promise<ReceiptOrEstimate>}
*/
public async setAllocation<G extends boolean = false>(
userAddress: string,
amount: string,
nft: string,
chainId: number,
estimateGas?: G
): Promise<ReceiptOrEstimate<G>> {
const estGas = await calculateEstimatedGas(
userAddress,
this.contract.methods.setAllocation,
amount,
nft,
chainId
)
if (estimateGas) return <ReceiptOrEstimate<G>>estGas
// Invoke function of the contract
const trxReceipt = await sendTx(
userAddress,
estGas + 1,
this.web3,
this.config?.gasFeeMultiplier,
this.contract.methods.setAllocation,
amount,
nft,
chainId
)
return <ReceiptOrEstimate<G>>trxReceipt
}
/**
* set specific percetage of veOcean to multiple nfts
* Maximum allocated percentage is 10000, so 1% is specified as 100
* @param {String} userAddress user address
* @param {String[]} amount Array of percentages used
* @param {String[]} nft Array of NFT addresses
* @param {String[]} chainId Array of chainIds
* @return {Promise<ReceiptOrEstimate>}
*/
public async setBatchAllocation<G extends boolean = false>(
userAddress: string,
amount: string[],
nft: string[],
chainId: number[],
estimateGas?: G
): Promise<ReceiptOrEstimate<G>> {
const estGas = await calculateEstimatedGas(
userAddress,
this.contract.methods.setBatchAllocation,
amount,
nft,
chainId
)
if (estimateGas) return <ReceiptOrEstimate<G>>estGas
// Invoke function of the contract
const trxReceipt = await sendTx(
userAddress,
estGas + 1,
this.web3,
this.config?.gasFeeMultiplier,
this.contract.methods.setBatchAllocation,
amount,
nft,
chainId
)
return <ReceiptOrEstimate<G>>trxReceipt
}
/** Get totalAllocation for address
* @param {String} userAddress user address
* @return {Promise<number>}
*/
public async getTotalAllocation(userAddress: string): Promise<number> {
const allocation = await this.contract.methods.getTotalAllocation(userAddress).call()
return allocation
}
/** Get getveAllocation for address, nft, chainId
* @param {String} userAddress user address
* @param {String} nft NFT address to allocate to
* @param {String} chainId chainId of NFT
* @return {Promise<number>}
*/
public async getVeAllocation(
userAddress: string,
nft: string,
chainId: string
): Promise<number> {
const allocation = await this.contract.methods
.getveAllocation(userAddress, nft, chainId)
.call()
return allocation
}
}

View File

@ -0,0 +1,74 @@
import { AbiItem } from 'web3-utils'
import veFeeABI from '@oceanprotocol/contracts/artifacts/contracts/ve/veFeeDistributor.vy/veFeeDistributor.json'
import { calculateEstimatedGas, sendTx } from '../../utils'
import { SmartContractWithAddress } from '../SmartContractWithAddress'
import { ReceiptOrEstimate } from '../../@types'
/**
* Provides an interface for veOcean contract
*/
export class VeFeeDistributor extends SmartContractWithAddress {
getDefaultAbi(): AbiItem | AbiItem[] {
return veFeeABI.abi as AbiItem[]
}
/**
* Claim fees for `userAddress`
* Each call to claim look at a maximum of 50 user veOCEAN points.
For accounts with many veOCEAN related actions, this function
may need to be called more than once to claim all available
fees. In the `Claimed` event that fires, if `claim_epoch` is
less than `max_epoch`, the account may claim again
* @param {String} userAddress user address
* @return {Promise<ReceiptOrEstimate>}
*/
public async claim<G extends boolean = false>(
userAddress: string,
estimateGas?: G
): Promise<ReceiptOrEstimate<G>> {
const estGas = await calculateEstimatedGas(userAddress, this.contract.methods.claim)
if (estimateGas) return <ReceiptOrEstimate<G>>estGas
// Invoke function of the contract
const trxReceipt = await sendTx(
userAddress,
estGas + 20000,
this.web3,
this.config?.gasFeeMultiplier,
this.contract.methods.claim
)
return <ReceiptOrEstimate<G>>trxReceipt
}
/**
* Make multiple fee claims in a single call
Used to claim for many accounts at once, or to make
multiple claims for the same address when that address
has significant veOCEAN history
* @param {String} fromUserAddress user address that sends the tx
* @param {String} addresses array of addresses to claim
* @return {Promise<ReceiptOrEstimate>}
*/
public async claimMany<G extends boolean = false>(
fromUserAddress: string,
addresses: string[],
estimateGas?: G
): Promise<ReceiptOrEstimate<G>> {
const estGas = await calculateEstimatedGas(
fromUserAddress,
this.contract.methods.claim_many,
addresses
)
if (estimateGas) return <ReceiptOrEstimate<G>>estGas
// Invoke function of the contract
const trxReceipt = await sendTx(
fromUserAddress,
estGas + 20000,
this.web3,
this.config?.gasFeeMultiplier,
this.contract.methods.claim_many,
addresses
)
return <ReceiptOrEstimate<G>>trxReceipt
}
}

222
src/contracts/ve/VeOcean.ts Normal file
View File

@ -0,0 +1,222 @@
import { AbiItem } from 'web3-utils'
import veOceanABI from '@oceanprotocol/contracts/artifacts/contracts/ve/veOCEAN.vy/veOCEAN.json'
import { calculateEstimatedGas, sendTx } from '../../utils'
import { SmartContractWithAddress } from '../SmartContractWithAddress'
import { ReceiptOrEstimate } from '../../@types'
/**
* Provides an interface for veOcean contract
*/
export class VeOcean extends SmartContractWithAddress {
getDefaultAbi(): AbiItem | AbiItem[] {
return veOceanABI.abi as AbiItem[]
}
/**
* Deposit `amount` tokens for `userAddress` and lock until `unlockTime`
* @param {String} userAddress user address
* @param {String} amount Amount of tokens to be locked
* @param {Number} unlockTime Timestamp for unlock
* @return {Promise<ReceiptOrEstimate>}
*/
public async lockTokens<G extends boolean = false>(
userAddress: string,
amount: string,
unlockTime: number,
estimateGas?: G
): Promise<ReceiptOrEstimate<G>> {
const amountFormatted = await this.amountToUnits(await this.getToken(), amount)
const estGas = await calculateEstimatedGas(
userAddress,
this.contract.methods.create_lock,
amountFormatted,
unlockTime
)
if (estimateGas) return <ReceiptOrEstimate<G>>estGas
// Invoke function of the contract
const trxReceipt = await sendTx(
userAddress,
estGas + 20000, // sometimes, it's not enough
this.web3,
this.config?.gasFeeMultiplier,
this.contract.methods.create_lock,
amountFormatted,
unlockTime
)
return <ReceiptOrEstimate<G>>trxReceipt
}
/**
* Deposit `amount` tokens for `toAddress` and add to the existing lock
* Anyone (even a smart contract) can deposit for someone else, but cannot extend their locktime and deposit for a brand new user
* @param {String} fromUserAddress user address that sends the tx
* @param {String} toAddress user address to deposit for
* @param {String} amount Amount of tokens to be locked
* @return {Promise<ReceiptOrEstimate>}
*/
public async depositFor<G extends boolean = false>(
fromUserAddress: string,
toAddress: string,
amount: string,
estimateGas?: G
): Promise<ReceiptOrEstimate<G>> {
const amountFormatted = await this.amountToUnits(await this.getToken(), amount)
const estGas = await calculateEstimatedGas(
fromUserAddress,
this.contract.methods.deposit_for,
toAddress,
amountFormatted
)
if (estimateGas) return <ReceiptOrEstimate<G>>estGas
// Invoke function of the contract
const trxReceipt = await sendTx(
fromUserAddress,
estGas + 20000, // sometimes, it's not enough
this.web3,
this.config?.gasFeeMultiplier,
this.contract.methods.deposit_for,
toAddress,
amountFormatted
)
return <ReceiptOrEstimate<G>>trxReceipt
}
/**
* Deposit `amount` additional tokens for `userAddress` without modifying the unlock time
* @param {String} userAddress user address that sends the tx
* @param {String} amount Amount of tokens to be locked
* @return {Promise<ReceiptOrEstimate>}
*/
public async increaseAmount<G extends boolean = false>(
userAddress: string,
amount: string,
estimateGas?: G
): Promise<ReceiptOrEstimate<G>> {
const amountFormatted = await this.amountToUnits(await this.getToken(), amount)
const estGas = await calculateEstimatedGas(
userAddress,
this.contract.methods.increase_amount,
amountFormatted
)
if (estimateGas) return <ReceiptOrEstimate<G>>estGas
// Invoke function of the contract
const trxReceipt = await sendTx(
userAddress,
estGas + 20000, // sometimes, it's not enough
this.web3,
this.config?.gasFeeMultiplier,
this.contract.methods.increase_amount,
amountFormatted
)
return <ReceiptOrEstimate<G>>trxReceipt
}
/**
* Extend the unlock time for `userAddress` to `unlockTime`
* @param {String} userAddress user address that sends the tx
* @param {Number} unlockTime Timestamp for new unlock time
* @return {Promise<ReceiptOrEstimate>}
*/
public async increaseUnlockTime<G extends boolean = false>(
userAddress: string,
unlockTime: number,
estimateGas?: G
): Promise<ReceiptOrEstimate<G>> {
const estGas = await calculateEstimatedGas(
userAddress,
this.contract.methods.increase_unlock_time,
unlockTime
)
if (estimateGas) return <ReceiptOrEstimate<G>>estGas
// Invoke function of the contract
const trxReceipt = await sendTx(
userAddress,
estGas + 20000, // sometimes, it's not enough
this.web3,
this.config?.gasFeeMultiplier,
this.contract.methods.increase_unlock_time,
unlockTime
)
return <ReceiptOrEstimate<G>>trxReceipt
}
/**
* Withdraw all tokens for `userAddress`
* @param {String} userAddress user address that sends the tx
* @return {Promise<ReceiptOrEstimate>}
*/
public async withdraw<G extends boolean = false>(
userAddress: string,
estimateGas?: G
): Promise<ReceiptOrEstimate<G>> {
const estGas = await calculateEstimatedGas(
userAddress,
this.contract.methods.withdraw
)
if (estimateGas) return <ReceiptOrEstimate<G>>estGas
// Invoke function of the contract
const trxReceipt = await sendTx(
userAddress,
estGas + 1,
this.web3,
this.config?.gasFeeMultiplier,
this.contract.methods.withdraw
)
return <ReceiptOrEstimate<G>>trxReceipt
}
/** Get voting power for address
* @param {String} userAddress user address
* @return {Promise<number>}
*/
public async getVotingPower(userAddress: string): Promise<number> {
const balance = await this.contract.methods.balanceOf(userAddress).call()
return balance
}
/** Get locked balance
* @param {String} userAddress user address
* @return {Promise<string>}
*/
public async getLockedAmount(userAddress: string): Promise<string> {
const balance = await this.contract.methods.locked(userAddress).call()
const balanceFormated = await this.unitsToAmount(
await this.getToken(),
balance.amount
)
return balanceFormated
}
/** Get untilLock for address
* @param {String} userAddress user address
* @return {Promise<number>}
*/
public async lockEnd(userAddress: string): Promise<number> {
const untilLock = await this.contract.methods.locked__end(userAddress).call()
return untilLock
}
/** Get total supply
* @return {Promise<number>}
*/
public async totalSupply(): Promise<string> {
const supplyFormated = await this.unitsToAmount(
await this.getToken(),
await this.contract.methods.totalSupply().call()
)
return supplyFormated
}
/** Get token
* @return {Promise<string>}
*/
public async getToken(): Promise<string> {
const tokenAddress = await this.contract.methods.token().call()
return tokenAddress
}
}

View File

@ -171,7 +171,7 @@ const algoDdoWithNoTimeout = {
image: 'ubuntu',
tag: 'latest',
checksum:
'sha256:42ba2dfce475de1113d55602d40af18415897167d47c2045ec7b6d9746ff148f'
'sha256:2d7ecc9c5e08953d586a6e50c29b91479a48f69ac1ba1f9dc0420d18a728dfc5'
}
}
},
@ -213,7 +213,7 @@ const algoDdoWith1mTimeout = {
image: 'ubuntu',
tag: 'latest',
checksum:
'sha256:42ba2dfce475de1113d55602d40af18415897167d47c2045ec7b6d9746ff148f'
'sha256:2d7ecc9c5e08953d586a6e50c29b91479a48f69ac1ba1f9dc0420d18a728dfc5'
}
}
},

218
test/unit/veOcean.test.ts Normal file
View File

@ -0,0 +1,218 @@
import { assert } from 'chai'
import { AbiItem } from 'web3-utils'
import { web3, getTestConfig, getAddresses } from '../config'
import {
Config,
approve,
VeOcean,
VeFeeDistributor,
sendTx,
calculateEstimatedGas,
NftFactory,
VeAllocate
} from '../../src'
describe('veOcean tests', async () => {
let config: Config
let addresses: any
let nftFactory
let veOcean: VeOcean
let veFeeDistributor: VeFeeDistributor
let veAllocate: VeAllocate
let ownerAccount: string
let Alice: string
let Bob: string
let nft1, nft2, nft3
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'
}
] as AbiItem[]
const tokenContract = new web3.eth.Contract(minAbi, addresses.Ocean)
const estGas = await calculateEstimatedGas(
ownerAccount,
tokenContract.methods.mint,
Alice,
web3.utils.toWei('1000')
)
await sendTx(
ownerAccount,
estGas,
web3,
1,
tokenContract.methods.mint,
Alice,
web3.utils.toWei('1000')
)
await sendTx(
ownerAccount,
estGas,
web3,
1,
tokenContract.methods.mint,
Bob,
web3.utils.toWei('1000')
)
veOcean = new VeOcean(addresses.veOCEAN, web3)
veFeeDistributor = new VeFeeDistributor(addresses.veFeeDistributor, web3)
veAllocate = new VeAllocate(addresses.veAllocate, web3)
nftFactory = new NftFactory(addresses.ERC721Factory, web3)
})
it('Alice should lock 100 Ocean', async () => {
// since we can only lock once, we test if tx fails or not
// so if there is already a lock, skip it
const currentBalance = await veOcean.getLockedAmount(Alice)
const currentLock = await veOcean.lockEnd(Alice)
const amount = '100'
await approve(web3, config, Alice, addresses.Ocean, addresses.veOCEAN, amount)
const timestamp = Math.floor(Date.now() / 1000)
const unlockTime = timestamp + 7 * 86400
if (parseInt(currentBalance) > 0 || currentLock > 0) {
// we already have some locked tokens, so our transaction should fail
try {
await veOcean.lockTokens(Alice, amount, unlockTime)
assert(false, 'This should fail!')
} catch (e) {
// do nothing
}
} else {
const estGas = await veOcean.lockTokens(Alice, amount, unlockTime, true)
console.log('Estimate gas for lockTokens:' + estGas)
const tx = await veOcean.lockTokens(Alice, amount, unlockTime)
// check events
assert(tx.events.Deposit.returnValues[0] === Alice)
assert(tx.events.Deposit.returnValues[1] === web3.utils.toWei(amount))
assert(tx.events.Deposit.returnValues[2] > 0) // we cannot compare it to the actual untiLock, because contract will round it to weeks
assert(tx.events.Supply.returnValues[1] > tx.events.Supply.returnValues[0]) // supply has increased
}
})
it('Alice should increase the lock time', async () => {
const currentLock = await veOcean.lockEnd(Alice)
const newLock = parseInt(String(currentLock)) + 7 * 86400
await veOcean.increaseUnlockTime(Alice, newLock)
const newCurrentLock = await veOcean.lockEnd(Alice)
assert(newCurrentLock > currentLock, 'Lock time should change"')
})
it('Alice should increase the locked amount', async () => {
const currentBalance = await veOcean.getLockedAmount(Alice)
const currentLock = await veOcean.lockEnd(Alice)
const amount = '200'
await approve(web3, config, Alice, addresses.Ocean, addresses.veOCEAN, amount)
await veOcean.increaseAmount(Alice, amount)
const newCurrentBalance = await veOcean.getLockedAmount(Alice)
const newCurrentLock = await veOcean.lockEnd(Alice)
assert(newCurrentLock === currentLock, 'Lock time should not change')
assert(
newCurrentBalance > currentBalance,
'Amount error:' + newCurrentBalance + ' shoud be > than ' + currentBalance
)
})
it('Alice should publish 3 NFTs', async () => {
// publish 3 nfts
nft1 = await nftFactory.createNFT(Alice, {
name: 'testNft1',
symbol: 'TSTF1',
templateIndex: 1,
tokenURI: '',
transferable: true,
owner: Alice
})
nft2 = await nftFactory.createNFT(Alice, {
name: 'testNft2',
symbol: 'TSTF2',
templateIndex: 1,
tokenURI: '',
transferable: true,
owner: Alice
})
nft3 = await nftFactory.createNFT(Alice, {
name: 'testNft3',
symbol: 'TSTF3',
templateIndex: 1,
tokenURI: '',
transferable: true,
owner: Alice
})
})
it('Alice should allocate 10% to NFT1', async () => {
const totalAllocation = await veAllocate.getTotalAllocation(Alice)
const tx = await veAllocate.setAllocation(Alice, '1000', nft1, chainId)
assert(tx.events.AllocationSet.returnValues[0] === Alice)
assert(tx.events.AllocationSet.returnValues[1] === nft1)
assert(parseInt(tx.events.AllocationSet.returnValues[2]) === parseInt(chainId))
assert(tx.events.AllocationSet.returnValues[3] === '1000')
const newTotalAllocation = await veAllocate.getTotalAllocation(Alice)
const expectedAllocation = parseInt(String(totalAllocation)) + 1000
assert(
parseInt(String(newTotalAllocation)) === parseInt(String(expectedAllocation)),
'NewAllocation (' + newTotalAllocation + ') should be ' + expectedAllocation
)
const nftAllocation = await veAllocate.getVeAllocation(Alice, nft1, chainId)
assert(
parseInt(String(nftAllocation)) === parseInt('1000'),
nftAllocation + ' should be 1000'
)
})
it('Alice should allocate 10% to NFT2 and 20% to NFT3', async () => {
const totalAllocation = await veAllocate.getTotalAllocation(Alice)
const tx = await veAllocate.setBatchAllocation(
Alice,
['1000', '2000'],
[nft2, nft3],
[chainId, chainId]
)
assert(tx.events.AllocationSetMultiple.returnValues[0] === Alice)
assert(tx.events.AllocationSetMultiple.returnValues[1][0] === nft2)
assert(tx.events.AllocationSetMultiple.returnValues[1][1] === nft3)
assert(
parseInt(tx.events.AllocationSetMultiple.returnValues[2][0]) === parseInt(chainId)
)
assert(tx.events.AllocationSetMultiple.returnValues[3][0] === '1000')
assert(tx.events.AllocationSetMultiple.returnValues[3][1] === '2000')
const newTotalAllocation = await veAllocate.getTotalAllocation(Alice)
const expectedAllocation = parseInt(String(totalAllocation)) + 3000
assert(
parseInt(String(newTotalAllocation)) === parseInt(String(expectedAllocation)),
'NewAllocation (' + newTotalAllocation + ') should be ' + expectedAllocation
)
let nftAllocation = await veAllocate.getVeAllocation(Alice, nft2, chainId)
assert(
parseInt(String(nftAllocation)) === parseInt('1000'),
nftAllocation + ' should be 1000'
)
nftAllocation = await veAllocate.getVeAllocation(Alice, nft3, chainId)
assert(
parseInt(String(nftAllocation)) === parseInt('2000'),
nftAllocation + ' should be 2000'
)
})
})