Governance

What is Cover Incident?

A cover incident is an event during when the terms (or rules) specified in the cover are fully met.

In the Neptune Mutual Protocol, a cover incident must undergo a governance process to reach to a resolution. Once an incident is submitted, the resolution can only be one of these two: Incident Occurred or False Reporting. The protocol intends to punish the users who try to cheat the governance system by getting all their stakes forfeited. To incentivize participation, the users who report in the governance system may earn some extra NEP rewards in a very short span of time (usually one week).

When a cover incident occurs, anyone can report it and earn a (20%) commission on fee earnings of the protocol. Before you submit any incident, ensure that you understand the following:

  • For the event to qualify as a cover incident, all terms and rules of the cover must be met.

  • The users who agree with the incident can add more votes/stakes or add attestatations to the report.

  • The users who disagree with the incident reporting can dispute or refute. Disputing allows anyone to mark the reported incident as False Reporting once. After that, the users who believe the incident reporting is a mistake can add more NEP votes/stakes by refuting.

  • There is a 7-day reporting period for users to participate in the governance process. The end of the reporting period is called Resolution Date.

  • The outcome of the cover incident will be achieved on the resolution date. The users who vote against the majority will lose all their stake to the majority.

Get Minimum Stake

Returns the minimum number of NEP tokens you need to stake to report an incident. Note that this number does not apply afterwards once a report has be submitted.

import { ChainId, governance } from '@neptunemutual/sdk'
import { getProvider } from './provider.js'
import { weiAsNep } from './bn.js'
const getMinStake = async () => {
const provider = getProvider()
const response = await governance.getMinStake(ChainId.Mumbai, provider)
console.info('Minimum Reporting Stake: %s', weiAsNep(response.result))
}
getMinStake()
/*****************************************************************************
Minimum Reporting Stake: 250.00 NEP
*****************************************************************************/

Report an Incident (Incident Happened)

The first user who reports a cover incident becomes the Cover Reporter. You will need to stake at least 250 NEP tokens to report an incident.

import { ChainId, governance } from '@neptunemutual/sdk'
import { info } from './info.js'
import { getProvider } from './provider.js'
import { ether } from './bn.js'
const payload = {
title: 'Test Exploit',
observed: new Date(),
proofOfIncident: 'https://etherscan.io/tokenholdings?a=0xA9AD3537C819ae0530623aFb458Fee8456C47d33',
description: 'DeFi protocol Learn Finance has reported that its vault was exploited by a hacker to the tune of $11 million on Dec 25.',
stake: ether(250)
}
const report = async () => {
const { key } = info
const provider = getProvider()
await governance.approveStake(ChainId.Mumbai, {}, provider)
const response = await governance.report(ChainId.Mumbai, key, payload, provider)
console.info(response)
}
report()
/*****************************************************************************
[info] {
status: 'Success',
result: {
storage: {
hashBytes32: '0xb09e406e9d065bca48b280b4c670c47d4e1b9107770a6280e3272a48773e24fe',
hash: 'QmaE6RV25JCwMB1ycYD7YRMdeCXmA58h1KC7v4NphqTs3s',
permalink: 'https://ipfs.infura.io/ipfs/QmaE6RV25JCwMB1ycYD7YRMdeCXmA58h1KC7v4NphqTs3s'
},
tx: {
nonce: 1,
gasPrice: [BigNumber],
gasLimit: [BigNumber],
to: '0x9A95A975a8f705806B5eF5D13B40a597bf8ab94f',
value: [BigNumber],
data: '0xeefd2cf770726f746f3a636f6e7472616374733a636f7665723a6366633a303100000002b09e406e9d065bca48b280b4c670c47d4e1b9107770a6280e3272a48773e24fe00000000000000000000000000000000000000000000000d8d726b7177a80000',
chainId: 80001,
v: 160038,
r: '0x67072717959337fbffae14f7eba3770c0250e7ac456087c6791fa16adf968dad',
s: '0x1bee01b72904e62c696bbc3c8378e90d22edc2cc2ce72a4f38e13e3ddf332355',
from: '0x076F91C0A411197e6Fce476F37c6385CCeacd26D',
hash: '0x0363d3abdf746ed66651a40bc8f53509d66c8f428ff527fddbbed51ac9d6ca3c',
type: null,
wait: [Function (anonymous)]
}
}
}
*****************************************************************************/

Dispute an Incident (False Reporting)

The first user who submits their NEP stake to disagree with a reported cover incident becomes the Candidate Cover Reporter. You will need to stake at least 250 NEP tokens to dispute a reported incident.

import { ChainId, governance } from '@neptunemutual/sdk'
import { info } from './info.js'
import { getProvider } from './provider.js'
import { ether } from './bn.js'
const dispute = async () => {
const { key } = info
const provider = getProvider(true)
const stake = ether(250)
await governance.approveStake(ChainId.Mumbai, {}, provider)
const response = await governance.dispute(ChainId.Mumbai, key, stake, provider)
console.info(response)
}
dispute()
/*****************************************************************************
[info] {
status: 'Success',
result: {
nonce: 1,
gasPrice: BigNumber { _hex: '0x06fc23ac00', _isBigNumber: true },
gasLimit: BigNumber { _hex: '0x040341', _isBigNumber: true },
to: '0x9A95A975a8f705806B5eF5D13B40a597bf8ab94f',
value: BigNumber { _hex: '0x00', _isBigNumber: true },
data: '0x1386012570726f746f3a636f6e7472616374733a636f7665723a6366633a3031000000020000000000000000000000000000000000000000000000000000000060f6c262000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d8d726b7177a80000',
chainId: 80001,
v: 160038,
r: '0xd38c21cacfb4fa35e7b7293037fb71690c999547db178571b2a804966c904c1f',
s: '0x7f122b5ee3b88cccfbae388a5abfb23fb88231475e6d90fb46b248e9e1adc42b',
from: '0xA3dEE71417e31C0A09F33690cA55052018041a94',
hash: '0xe9c510d5c78df270ab0b1c9ba29b14397710008597d28d24a129ff642579433b',
type: null,
wait: [Function (anonymous)]
}
}
*****************************************************************************/

Add an Attestation (Incident Occurred)

Adding an attestation means that you believe and support the reported incident. You can stake any number of NEP tokens and vote for the support of the Incident Occurred side.

import { ChainId, governance } from '@neptunemutual/sdk'
import { info } from './info.js'
import { getProvider } from './provider.js'
import { ether, weiAsNep } from './bn.js'
const attest = async () => {
const { key, coverName } = info
const provider = getProvider()
const stake = ether(100)
const incidentDate = (await governance.getIncidentDate(ChainId.Mumbai, key, provider)).result
let response = await governance.getStakes(ChainId.Mumbai, key, incidentDate, provider)
console.info('[%s Reporting Stake: Yes] Before: %s', coverName, weiAsNep(response.result.yes))
await governance.approveStake(ChainId.Mumbai, {}, provider)
response = await governance.attest(ChainId.Mumbai, key, stake, provider)
console.info(response)
await response.result.wait()
response = await governance.getStakes(ChainId.Mumbai, key, incidentDate, provider)
console.info('[%s Reporting Stake: Yes] After: %s', coverName, weiAsNep(response.result.yes))
}
attest()
/*****************************************************************************
[info] [Compound Finance Cover Reporting Stake: Yes] Before: 250.00 NEP
[info] {
status: 'Success',
result: {
nonce: 1,
gasPrice: BigNumber { _hex: '0x06fc23ac00', _isBigNumber: true },
gasLimit: BigNumber { _hex: '0x02d10b', _isBigNumber: true },
to: '0x9A95A975a8f705806B5eF5D13B40a597bf8ab94f',
value: BigNumber { _hex: '0x00', _isBigNumber: true },
data: '0x789c846770726f746f3a636f6e7472616374733a636f7665723a6366633a3031000000020000000000000000000000000000000000000000000000000000000060f6c2620000000000000000000000000000000000000000000000056bc75e2d63100000',
chainId: 80001,
v: 160037,
r: '0xbfd3235a892e061456aa89afc52c6c73d3fd16a5ceac4c02e931c464869d3b16',
s: '0x4988dece2b1202ae7394d6e1b380e5dca6f44ac3278f4d80e5cb61d1db6927fb',
from: '0x076F91C0A411197e6Fce476F37c6385CCeacd26D',
hash: '0xbaf310d9a9ea1a39fae97ebe6c98f30e005aede879b7750a3abdabbae4d0e6c0',
type: null,
wait: [Function (anonymous)]
}
}
[info] [Compound Finance Cover Reporting Stake: Yes] After: 350.00 NEP
*****************************************************************************/

Add a Refutation

By refuting, you prove your support for the side who disagree with the reported incident. You can stake any number of NEP tokens and vote to support the False Reporting side.

import { ChainId, governance } from '@neptunemutual/sdk'
import { info } from './info.js'
import { getProvider } from './provider.js'
import { ether, weiAsNep } from './bn.js'
const refute = async () => {
const { key, coverName } = info
const provider = getProvider()
const stake = ether(100)
const incidentDate = (await governance.getIncidentDate(ChainId.Mumbai, key, provider)).result
let response = await governance.getStakes(ChainId.Mumbai, key, incidentDate, provider)
console.info('[%s Reporting Stake: No] Before: %s', coverName, weiAsNep(response.result.no))
await governance.approveStake(ChainId.Mumbai, {}, provider)
response = await governance.refute(ChainId.Mumbai, key, stake, provider)
console.info(response)
await response.result.wait()
response = await governance.getStakes(ChainId.Mumbai, key, incidentDate, provider)
console.info('[%s Reporting Stake: No] After: %s', coverName, weiAsNep(response.result.no))
}
refute()
/*****************************************************************************
[info] [Compound Finance Cover Reporting Stake: No] Before: 250.00 NEP
[info] {
status: 'Success',
result: {
nonce: 1,
gasPrice: BigNumber { _hex: '0x06fc23ac00', _isBigNumber: true },
gasLimit: BigNumber { _hex: '0x0313c0', _isBigNumber: true },
to: '0x9A95A975a8f705806B5eF5D13B40a597bf8ab94f',
value: BigNumber { _hex: '0x00', _isBigNumber: true },
data: '0xf1a4115070726f746f3a636f6e7472616374733a636f7665723a6366633a3031000000020000000000000000000000000000000000000000000000000000000060f6c2620000000000000000000000000000000000000000000000056bc75e2d63100000',
chainId: 80001,
v: 160038,
r: '0x07d9aaa8a4479d472563fbe07eb328ebdf3ea8e7c19e2816457a4f1ce12d8da6',
s: '0x258d5210785bdbd3c80c3c9afe10df28131320e4ca191e58a6fb9f67f4494e8e',
from: '0x076F91C0A411197e6Fce476F37c6385CCeacd26D',
hash: '0x8e1c0ae87be7b4bbc758759ce10113b6e1f46399b2690b1298ea9e06d2d5965a',
type: null,
wait: [Function (anonymous)]
}
}
[info] [Compound Finance Cover Reporting Stake: No] After: 350.00 NEP
*****************************************************************************/

Get Status

Gets the status of a given cover.

import { ChainId, governance } from '@neptunemutual/sdk'
import { info } from './info.js'
import { getProvider } from './provider.js'
const getStatus = async () => {
const { key, coverName } = info
const provider = getProvider()
const response = await governance.getStatus(ChainId.Mumbai, key, provider)
console.info('[%s] Status: %s', coverName, response.result)
}
getStatus()
/*****************************************************************************
[info] [Compound Finance Cover] Status: { key: 'IncidentHappened', value: 2 }
*****************************************************************************/

Get Incident Date

Gets the incident date by the given cover key.

import { ChainId, governance } from '@neptunemutual/sdk'
import { info } from './info.js'
import { getProvider } from './provider.js'
import { toDate } from './bn.js'
const getIncidentDate = async () => {
const { key, coverName } = info
const provider = getProvider()
const response = await governance.getIncidentDate(ChainId.Mumbai, key, provider)
console.info('[%s] Incident Date: %s', coverName, toDate(response.result).toUTCString())
}
getIncidentDate()
/*****************************************************************************
[info] [Compound Finance Cover] Incident Date: Tue, 20 Jul 2021 12:32:34 GMT
*****************************************************************************/

Get Reporter

Gets the reporter of the given cover (if any).

import { ChainId, governance } from '@neptunemutual/sdk'
import { info } from './info.js'
import { getProvider } from './provider.js'
const getReporter = async () => {
const { key, coverName } = info
const provider = getProvider()
const incidentDate = (await governance.getIncidentDate(ChainId.Mumbai, key, provider)).result
const response = await governance.getReporter(ChainId.Mumbai, key, incidentDate, provider)
console.info('[%s] Reporter: %s', coverName, response.result)
}
getReporter()
/*****************************************************************************
[info] [Compound Finance Cover] Reporter: 0x076F91C0A411197e6Fce476F37c6385CCeacd26D
*****************************************************************************/

Based on the stakes of each side, the returned value is either the original cover reporter or the candidate cover reporter.

Get Stakes

Returns the stakes submitted by the users on each side.

import { ChainId, governance } from '@neptunemutual/sdk'
import { info } from './info.js'
import { getProvider } from './provider.js'
import { weiAsNep } from './bn.js'
const getStakes = async () => {
const { key, coverName } = info
const provider = getProvider()
const incidentDate = (await governance.getIncidentDate(ChainId.Mumbai, key, provider)).result
const response = await governance.getStakes(ChainId.Mumbai, key, incidentDate, provider)
const { yes, no } = response.result
console.info('[%s Stakes] Yes: %s. No: %s', coverName, weiAsNep(yes), weiAsNep(no))
}
getStakes()
/*****************************************************************************
[info] [Compound Finance Cover Stakes] Yes: 350.00 NEP. No: 350.00 NEP
*****************************************************************************/

Get Stakes of an Account

Returns the stakes submitted by the given account on each side.

import { ChainId, governance } from '@neptunemutual/sdk'
import { info } from './info.js'
import { getProvider } from './provider.js'
import { weiAsNep } from './bn.js'
const getStakesOf = async () => {
const { key, coverName } = info
const provider = getProvider()
const account = provider.address
const incidentDate = (await governance.getIncidentDate(ChainId.Mumbai, key, provider)).result
const response = await governance.getStakesOf(ChainId.Mumbai, key, incidentDate, account, provider)
const { yes, no } = response.result
console.info('[%s Stakes Of %s] Yes: %s. No: %s', coverName, account, weiAsNep(yes), weiAsNep(no))
}
getStakesOf()
/*****************************************************************************
[info] [Compound Finance Cover Stakes Of 0x076F91C0A411197e6Fce476F37c6385CCeacd26D]
Yes: 350.00 NEP. No: 100.00 NEP
*****************************************************************************/

Finalize the Reporting

A report can be finalized after the claim expiry period. Once finalized, policies for the cover in question can be purchased again.

await governance.finalize(<ChainId>, <key>, <incidentDate>, <provider>)

This feature is only accessible to the governance system or the protocol admins.

Always refer to the Protocol Fee document for the latest information since the fees are configurable and can change.