Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add basic tests for KetlCred #38

Merged
merged 1 commit into from
Jul 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import '@nomiclabs/hardhat-etherscan'
import '@nomiclabs/hardhat-waffle'
import '@openzeppelin/hardhat-upgrades'
import '@typechain/hardhat'
import 'hardhat-gas-reporter'
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"@ethersproject/providers": "^5.7.2",
"@nomiclabs/hardhat-ethers": "^2.2.3",
"@nomiclabs/hardhat-etherscan": "^3.1.7",
"@nomiclabs/hardhat-waffle": "^2.0.3",
"@opengsn/contracts": "^3.0.0-beta.6",
"@openzeppelin/contracts": "^4.8.3",
"@typechain/ethers-v5": "^10.2.1",
Expand All @@ -60,6 +61,7 @@
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-sort-imports-es6-autofix": "^0.6.0",
"ethereum-waffle": "^3.4.4",
"ethers": "^5.7.2",
"hardhat": "^2.14.0",
"hardhat-gas-reporter": "^1.0.9",
Expand Down
156 changes: 156 additions & 0 deletions test/OBSSStorage.ketlkred.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
import { Feeds, KetlCred, OBSSStorage, Profiles } from '../typechain'
import { MOCK_CID, zeroAddress } from './utils'
import { ethers, upgrades } from 'hardhat'
import { expect } from 'chai'
import { getFakeKetlAttestationContract } from './utils/fakes'
import { version } from '../package.json'

describe('OBSSStorage: KetlCred', () => {
before(async function () {
this.accounts = await ethers.getSigners()
this.owner = this.accounts[0]
this.user = this.accounts[1]

this.fakeKetlAttestationContract = await getFakeKetlAttestationContract(
this.owner
)
await this.fakeKetlAttestationContract.mock.balanceOf.returns(1)
await this.fakeKetlAttestationContract.mock.currentTokenId.returns(1)

this.profilesFactory = await ethers.getContractFactory('Profiles')
this.ketlCredFactory = await ethers.getContractFactory('KetlCred')
this.feedsFactory = await ethers.getContractFactory('Feeds')
this.obssStorageFactory = await ethers.getContractFactory('OBSSStorage')
})

describe('grantKetlCred: feedPosts', () => {
beforeEach(async function () {
this.profiles = (await upgrades.deployProxy(this.profilesFactory, [
this.fakeKetlAttestationContract.address,
0,
this.owner.address,
])) as Profiles
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This as is still needed because upgrades.deployProxy still doesn't support generics: OpenZeppelin/openzeppelin-upgrades#535

this.ketlCred = (await upgrades.deployProxy(
this.ketlCredFactory,
['Ketl', 'KETL', 0, this.owner.address],
{
initializer: 'initializeKetlCred',
}
)) as KetlCred
this.feeds = (await upgrades.deployProxy(this.feedsFactory, [
this.fakeKetlAttestationContract.address,
0,
this.owner.address,
])) as Feeds
this.obssStorage = (await upgrades.deployProxy(
this.obssStorageFactory,
[
zeroAddress,
version,
this.ketlCred.address,
this.profiles.address,
this.feeds.address,
],
{
initializer: 'initialize',
}
)) as OBSSStorage

await this.ketlCred.setAllowedCaller(this.obssStorage.address)
await this.profiles.setAllowedCaller(this.obssStorage.address)
await this.feeds.setAllowedCaller(this.obssStorage.address)

await this.feeds.addFeed(MOCK_CID)
await this.obssStorage.addFeedPost({
feedId: 0,
postMetadata: MOCK_CID,
})
})

it('should grant KetlCred when feedPost is upvoted by different user', async function () {
await this.obssStorage.connect(this.user).addFeedReaction({
feedId: 0,
postId: 0,
commentId: 0,
reactionType: 1,
})
expect(await this.ketlCred.balanceOf(this.owner.address)).to.equal(1)
})
it('should not grant KetlCred when feedPost is downvoted by user', async function () {
await this.obssStorage.connect(this.user).addFeedReaction({
feedId: 0,
postId: 0,
commentId: 0,
reactionType: 2,
})
expect(await this.ketlCred.balanceOf(this.owner.address)).to.equal(0)
})
it('should not grant KetlCred when feedPost is upvoted by author', async function () {
await this.obssStorage.connect(this.owner).addFeedReaction({
feedId: 0,
postId: 0,
commentId: 0,
reactionType: 1,
})
expect(await this.ketlCred.balanceOf(this.owner.address)).to.equal(0)
})
it('should not burn KetlCred when upvote is replaced with downvote', async function () {
await this.obssStorage.connect(this.user).addFeedReaction({
feedId: 0,
postId: 0,
commentId: 0,
reactionType: 1,
})
const reactionBefore = await this.feeds.usersToReactions(
0,
0,
0,
this.user.address
)
expect(reactionBefore.reactionType).to.equal(1)
await this.obssStorage.connect(this.user).addFeedReaction({
feedId: 0,
postId: 0,
commentId: 0,
reactionType: 2,
})
const reactionAfter = await this.feeds.usersToReactions(
0,
0,
0,
this.user.address
)
expect(reactionAfter.reactionType).to.equal(2)
expect(await this.ketlCred.balanceOf(this.owner.address)).to.equal(1)
})
it('should not burn KetlCred when upvote is removed', async function () {
await this.obssStorage.connect(this.user).addFeedReaction({
feedId: 0,
postId: 0,
commentId: 0,
reactionType: 1,
})
const reactionBefore = await this.feeds.usersToReactions(
0,
0,
0,
this.user.address
)
expect(reactionBefore.reactionType).to.equal(1)
await this.obssStorage.connect(this.user).removeFeedReaction({
feedId: 0,
postId: 0,
commentId: 0,
reactionId: reactionBefore.reactionId,
})
const reactionAfter = await this.feeds.usersToReactions(
0,
0,
0,
this.user.address
)
expect(reactionAfter.sender).to.equal(zeroAddress)
expect(await this.ketlCred.balanceOf(this.owner.address)).to.equal(1)
})
})
})
4 changes: 2 additions & 2 deletions test/OBSSStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ import { zeroAddress } from './utils'

describe('OBSSStorage contract tests', () => {
before(async function () {
this.factory = await ethers.getContractFactory('OBSSStorage')
this.obssStorageFactory = await ethers.getContractFactory('OBSSStorage')
})

describe('Constructor', function () {
it('should deploy the contract with the correct fields', async function () {
const version = 'v0.0.1'
const contract = await upgrades.deployProxy(
this.factory,
this.obssStorageFactory,
[zeroAddress, version, zeroAddress, zeroAddress, zeroAddress],
{
initializer: 'initialize',
Expand Down
30 changes: 28 additions & 2 deletions test/types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,33 @@
import type { OBSSStorage__factory } from '../typechain'
import { MockContract } from 'ethereum-waffle'
import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'
import type {
Feeds,
Feeds__factory,
KetlCred,
KetlCred__factory,
OBSSStorage,
OBSSStorage__factory,
Profiles,
Profiles__factory,
} from '../typechain'

declare module 'mocha' {
export interface Context {
factory: OBSSStorage__factory
// Factories for contracts
profilesFactory: Profiles__factory
feedsFactory: Feeds__factory
ketlCredFactory: KetlCred__factory
obssStorageFactory: OBSSStorage__factory
// Contract instances
profiles: Profiles
feeds: Feeds
ketlCred: KetlCred
obssStorage: OBSSStorage
// Mock contracts
fakeKetlAttestationContract: MockContract
// Signers
accounts: SignerWithAddress[]
owner: SignerWithAddress
user: SignerWithAddress
}
}
39 changes: 39 additions & 0 deletions test/utils/fakes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'
import { allowMapInput } from '.'
import { deployMockContract } from 'ethereum-waffle'

export async function getFakeCommitmentProof() {
return {
a: [1, 2],
b: [
[1, 2],
[3, 4],
],
c: [1, 2],
input: await allowMapInput(),
}
}

export async function getFakeKetlAttestationContract(
signer: SignerWithAddress
) {
return await deployMockContract(signer, [
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider importing contract ABI from ketl-attestation-contract

{
inputs: [
{ internalType: 'address', name: 'account', type: 'address' },
{ internalType: 'uint256', name: 'id', type: 'uint256' },
],
name: 'balanceOf',
outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
stateMutability: 'view',
type: 'function',
},
{
inputs: [],
name: 'currentTokenId',
outputs: [{ internalType: 'uint32', name: '', type: 'uint32' }],
stateMutability: 'view',
type: 'function',
},
])
}
14 changes: 1 addition & 13 deletions test/utils.ts → test/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,7 @@ function generateRandomBytes32(): string {
return `0x${crypto.randomBytes(32).toString('hex')}`
}

export async function getFakeCommitmentProof() {
return {
a: [1, 2],
b: [
[1, 2],
[3, 4],
],
c: [1, 2],
input: await allowMapInput(),
}
}

async function allowMapInput() {
export async function allowMapInput() {
const randomUint256 = () => BigNumber.from(randomBytes(32)).toBigInt()
const thousandRandomUint256 = Array.from({ length: 1000 }, randomUint256)
const leaf = thousandRandomUint256[0]
Expand Down
Loading