quasvel
Version:
Access and interact with Aragon Organizations and their apps.
432 lines (361 loc) • 17.1 kB
text/typescript
import { ethereum, BigInt, Address } from '@graphprotocol/graph-ts'
import { ERC20 } from '../generated/schema'
import { ERC20 as ERC20Contract } from '../generated/templates/Agreement/ERC20'
import { Staking as StakingContract } from '../generated/templates/Agreement/Staking'
import { StakingFactory as StakingFactoryContract } from '../generated/templates/Agreement/StakingFactory'
import { Agreement, Action, Signature, Version, Disputable, Challenge, Dispute, Evidence, Signer, CollateralRequirement, ArbitratorFee, StakingMovement, Staking } from '../generated/schema'
import {
Agreement as AgreementContract,
ActionSubmitted,
ActionChallenged,
ActionSettled,
ActionDisputed,
ActionAccepted,
ActionVoided,
ActionRejected,
ActionClosed,
EvidenceSubmitted,
SettingChanged,
Signed,
DisputableAppActivated,
DisputableAppDeactivated,
CollateralRequirementChanged
} from '../generated/templates/Agreement/Agreement'
/* eslint-disable @typescript-eslint/no-use-before-define */
export function handleSettingChanged(event: SettingChanged): void {
const agreementApp = AgreementContract.bind(event.address)
const settingData = agreementApp.getSetting(event.params.settingId)
const agreement = loadOrCreateAgreement(event.address)
const currentVersionId = buildVersionId(event.address, event.params.settingId)
const version = new Version(currentVersionId)
version.agreement = event.address.toHexString()
version.versionId = event.params.settingId
version.arbitrator = settingData.value0
version.appFeesCashier = settingData.value1
version.title = settingData.value2
version.content = settingData.value3
version.effectiveFrom = event.block.timestamp
version.save()
agreement.currentVersion = currentVersionId
agreement.save()
}
export function handleSigned(event: Signed): void {
const signer = loadOrCreateSigner(event.address, event.params.signer)
signer.save()
const signature = new Signature(event.transaction.hash.toHexString())
signature.signer = buildSignerId(event.address, event.params.signer)
signature.version = buildVersionId(event.address, event.params.settingId)
signature.createdAt = event.block.timestamp
signature.save()
}
export function handleDisputableAppActivated(event: DisputableAppActivated): void {
const agreementApp = AgreementContract.bind(event.address)
const disputableData = agreementApp.getDisputableInfo(event.params.disputable)
const disputable = loadOrCreateDisputable(event.address, event.params.disputable)
disputable.activated = true
disputable.currentCollateralRequirement = buildCollateralRequirementId(event.address, event.params.disputable, disputableData.value1)
disputable.save()
updateCollateralRequirement(event.address, event.params.disputable, disputableData.value1)
}
export function handleDisputableAppDeactivated(event: DisputableAppDeactivated): void {
const disputable = loadOrCreateDisputable(event.address, event.params.disputable)
disputable.activated = false
disputable.save()
}
export function handleCollateralRequirementChanged(event: CollateralRequirementChanged): void {
updateCollateralRequirement(event.address, event.params.disputable, event.params.collateralRequirementId)
}
export function handleActionSubmitted(event: ActionSubmitted): void {
const actionId = buildActionId(event.address, event.params.actionId)
const agreementApp = AgreementContract.bind(event.address)
const action = new Action(actionId)
const actionData = agreementApp.getAction(event.params.actionId)
action.agreement = event.address.toHexString()
action.actionId = event.params.actionId
action.disputable = buildDisputableId(event.address, actionData.value0)
action.disputableActionId = actionData.value1
action.collateralRequirement = buildCollateralRequirementId(event.address, actionData.value0, actionData.value2)
action.version = buildVersionId(event.address, actionData.value3)
action.submitter = buildSignerId(event.address, actionData.value4)
action.closed = actionData.value5
action.context = actionData.value6
action.createdAt = event.block.timestamp
action.save()
createStakingMovement(event.address, event.params.actionId, 'new', event)
}
export function handleActionClosed(event: ActionClosed): void {
const action = Action.load(buildActionId(event.address, event.params.actionId))!
action.closed = true
action.save()
createStakingMovement(event.address, event.params.actionId, 'closed', event)
}
export function handleActionChallenged(event: ActionChallenged): void {
const actionId = buildActionId(event.address, event.params.actionId)
const challengeId = buildChallengeId(event.address, event.params.challengeId)
const agreementApp = AgreementContract.bind(event.address)
const action = Action.load(actionId)!
action.lastChallenge = challengeId
action.save()
const challenge = new Challenge(challengeId)
const challengeData = agreementApp.getChallenge(event.params.challengeId)
challenge.action = buildActionId(event.address, event.params.actionId)
challenge.challengeId = event.params.challengeId
challenge.challenger = challengeData.value1
challenge.endDate = challengeData.value2
challenge.context = challengeData.value3
challenge.settlementOffer = challengeData.value4
challenge.state = castChallengeState(challengeData.value5)
challenge.createdAt = event.block.timestamp
const challengerArbitratorFeeId = challengeId + 'challenger-arbitrator-fee'
const challengeArbitratorFeesData = agreementApp.getChallengeArbitratorFees(event.params.challengeId)
createArbitratorFee(event.address, challengerArbitratorFeeId, challengeArbitratorFeesData.value2, challengeArbitratorFeesData.value3)
challenge.challengerArbitratorFee = challengerArbitratorFeeId
challenge.save()
createStakingMovement(event.address, event.params.actionId, 'challenged', event)
}
export function handleActionSettled(event: ActionSettled): void {
updateChallengeState(event.address, event.params.challengeId)
createStakingMovement(event.address, event.params.actionId, 'settled', event)
}
export function handleActionDisputed(event: ActionDisputed): void {
updateChallengeState(event.address, event.params.challengeId)
const dispute = loadOrCreateDispute(event.address, event.params.challengeId, event)
dispute.save()
const challengeId = buildChallengeId(event.address, event.params.challengeId)
const agreementApp = AgreementContract.bind(event.address)
const challengeArbitratorFeesData = agreementApp.getChallengeArbitratorFees(event.params.challengeId)
const submitterArbitratorFeeId = challengeId + 'submitter-arbitrator-fee'
createArbitratorFee(event.address, submitterArbitratorFeeId, challengeArbitratorFeesData.value0, challengeArbitratorFeesData.value1)
const challenge = Challenge.load(challengeId)!
challenge.submitterArbitratorFee = submitterArbitratorFeeId
challenge.save()
}
export function handleActionAccepted(event: ActionAccepted): void {
updateChallengeState(event.address, event.params.challengeId)
updateDisputeState(event.address, event.params.challengeId, event)
}
export function handleActionVoided(event: ActionVoided): void {
updateChallengeState(event.address, event.params.challengeId)
updateDisputeState(event.address, event.params.challengeId, event)
}
export function handleActionRejected(event: ActionRejected): void {
updateChallengeState(event.address, event.params.challengeId)
updateDisputeState(event.address, event.params.challengeId, event)
createStakingMovement(event.address, event.params.actionId, 'rejected', event)
}
export function handleEvidenceSubmitted(event: EvidenceSubmitted): void {
const evidenceId = buildId(event)
const evidence = new Evidence(evidenceId)
evidence.data = event.params.evidence
evidence.dispute = buildDisputeId(event.address, event.params.disputeId)
evidence.submitter = event.params.submitter
evidence.createdAt = event.block.timestamp
evidence.save()
}
function loadOrCreateAgreement(agreementAddress: Address): Agreement {
let agreement = Agreement.load(agreementAddress.toHexString())
if (agreement === null) {
const agreementApp = AgreementContract.bind(agreementAddress)
const stakingFactoryAddress = agreementApp.stakingFactory()
agreement = new Agreement(agreementAddress.toHexString())
agreement.dao = agreementApp.kernel()
agreement.stakingFactory = stakingFactoryAddress
}
return agreement!
}
function loadOrCreateSigner(agreement: Address, signerAddress: Address): Signer {
const signerId = buildSignerId(agreement, signerAddress)
let signer = Signer.load(signerId)
if (signer === null) {
signer = new Signer(signerId)
signer.agreement = agreement.toHexString()
signer.address = signerAddress
}
return signer!
}
function loadOrCreateDisputable(agreement: Address, disputableAddress: Address): Disputable {
const disputableId = buildDisputableId(agreement, disputableAddress)
let disputable = Disputable.load(disputableId)
if (disputable === null) {
disputable = new Disputable(disputableId)
disputable.agreement = agreement.toHexString()
disputable.address = disputableAddress
}
return disputable!
}
function loadOrCreateDispute(agreement: Address, challengeId: BigInt, event: ethereum.Event): Dispute {
const agreementApp = AgreementContract.bind(agreement)
const challengeData = agreementApp.getChallenge(challengeId)
const disputeId = buildDisputeId(agreement, challengeData.value8)
let dispute = Dispute.load(disputeId)
if (dispute === null) {
dispute = new Dispute(disputeId)
dispute.ruling = challengeData.value9
dispute.disputeId = challengeData.value8
dispute.challenge = buildChallengeId(agreement, challengeId)
dispute.submitterFinishedEvidence = challengeData.value6
dispute.challengerFinishedEvidence = challengeData.value7
dispute.createdAt = event.block.timestamp
}
return dispute!
}
function updateChallengeState(agreement: Address, challengeId: BigInt): void {
const agreementApp = AgreementContract.bind(agreement)
const challengeData = agreementApp.getChallenge(challengeId)
const challenge = Challenge.load(buildChallengeId(agreement, challengeId))!
challenge.state = castChallengeState(challengeData.value5)
challenge.save()
}
function updateDisputeState(agreement: Address, challengeId: BigInt, event: ethereum.Event): void {
const agreementApp = AgreementContract.bind(agreement)
const challengeData = agreementApp.getChallenge(challengeId)
const dispute = loadOrCreateDispute(agreement, challengeId, event)
dispute.ruling = challengeData.value9
dispute.submitterFinishedEvidence = challengeData.value6
dispute.challengerFinishedEvidence = challengeData.value7
dispute.save()
}
function updateCollateralRequirement(agreement: Address, disputable: Address, collateralRequirementId: BigInt): void {
const agreementApp = AgreementContract.bind(agreement)
const requirementId = buildCollateralRequirementId(agreement, disputable, collateralRequirementId)
const requirement = new CollateralRequirement(requirementId)
const requirementData = agreementApp.getCollateralRequirement(disputable, collateralRequirementId)
requirement.disputable = buildDisputableId(agreement, disputable)
requirement.token = buildERC20(agreement, requirementData.value0)
requirement.challengeDuration = requirementData.value1
requirement.actionAmount = requirementData.value2
requirement.challengeAmount = requirementData.value3
requirement.save()
}
function createStakingMovement(agreement: Address, actionId: BigInt, type: string, event: ethereum.Event): void {
const agreementApp = AgreementContract.bind(agreement)
const actionData = agreementApp.getAction(actionId)
const collateralData = agreementApp.getCollateralRequirement(actionData.value0, actionData.value2)
const user = actionData.value4
const token = collateralData.value0
const collateralAmount = collateralData.value2
if (collateralAmount.equals(BigInt.fromI32(0))) {
return
}
const factory = StakingFactoryContract.bind(agreementApp.stakingFactory())
const stakingAddress = factory.getInstance(token)
const staking = updateStaking(stakingAddress, token, user)
const id = buildStakingMovementId(token, user, buildId(event))
const movement = new StakingMovement(id)
movement.staking = staking.id
movement.agreement = agreement.toHexString()
movement.action = buildActionId(agreement, actionId)
movement.createdAt = event.block.timestamp
if (type == 'new') {
movement.amount = collateralAmount
movement.actionState = 'Scheduled'
movement.collateralState = 'Locked'
} else if (type == 'challenged') {
movement.amount = collateralAmount
movement.actionState = 'Challenged'
movement.collateralState = 'Challenged'
staking.challenged = staking.challenged.plus(collateralAmount)
} else if (type == 'settled') {
const challengeData = agreementApp.getChallenge(actionData.value7)
movement.amount = challengeData.value4
movement.actionState = 'Settled'
movement.collateralState = 'Slashed'
staking.challenged = staking.challenged.minus(collateralAmount)
} else if (type == 'rejected') {
movement.amount = collateralAmount
movement.actionState = 'Cancelled'
movement.collateralState = 'Slashed'
staking.challenged = staking.challenged.minus(collateralAmount)
} else { // closed
movement.amount = collateralAmount
movement.actionState = 'Completed'
movement.collateralState = 'Available'
staking.challenged = staking.challenged.minus(collateralAmount)
}
staking.save()
movement.save()
}
function updateStaking(stakingAddress: Address, token: Address, user: Address): Staking {
const stakingApp = StakingContract.bind(stakingAddress)
const balance = stakingApp.getBalancesOf(user)
const staking = loadOrCreateStaking(token, user)
staking.total = balance.value0
staking.locked = balance.value1
staking.available = staking.total.minus(staking.locked)
staking.save()
return staking
}
function loadOrCreateStaking(token: Address, user: Address): Staking {
const id = buildStakingId(token, user)
let staking = Staking.load(id)
if (staking === null) {
staking = new Staking(id)
staking.user = user
staking.token = token.toHexString()
staking.total = BigInt.fromI32(0)
staking.locked = BigInt.fromI32(0)
staking.available = BigInt.fromI32(0)
staking.challenged = BigInt.fromI32(0)
}
return staking!
}
function createArbitratorFee(agreement: Address, id: string, feeToken: Address, feeAmount: BigInt): void {
const arbitratorFee = new ArbitratorFee(id)
arbitratorFee.amount = feeAmount
arbitratorFee.token = buildERC20(agreement, feeToken)
arbitratorFee.save()
}
export function buildERC20(agreement: Address, address: Address): string {
const id = address.toHexString()
let token = ERC20.load(id)
if (token === null) {
const tokenContract = ERC20Contract.bind(address)
token = new ERC20(id)
token.name = tokenContract.name()
token.symbol = tokenContract.symbol()
token.decimals = tokenContract.decimals()
token.save()
}
return token.id
}
function buildSignerId(agreement: Address, signer: Address): string {
return agreement.toHexString() + "-signer-" + signer.toHexString()
}
function buildDisputableId(agreement: Address, disputable: Address): string {
return agreement.toHexString() + "-disputable-" + disputable.toHexString()
}
export function buildActionId(agreement: Address, actionId: BigInt): string {
return agreement.toHexString() + "-action-" + actionId.toString()
}
function buildChallengeId(agreement: Address, challengeId: BigInt): string {
return agreement.toHexString() + "-challenge-" + challengeId.toString()
}
function buildDisputeId(agreement: Address, disputeId: BigInt): string {
return agreement.toHexString() + "-dispute-" + disputeId.toString()
}
function buildVersionId(agreement: Address, versionId: BigInt): string {
return agreement.toHexString() + "-version-" + versionId.toString()
}
function buildCollateralRequirementId(agreement: Address, disputable: Address, collateralRequirementId: BigInt): string {
return buildDisputableId(agreement, disputable) + "-collateral-requirement-" + collateralRequirementId.toString()
}
function buildStakingId(token: Address, user: Address): string {
return token.toHexString() + "-staking-" + user.toHexString()
}
function buildStakingMovementId(token: Address, user: Address, id: string): string {
return buildStakingId(token, user) + "-movement-" + id
}
function buildId(event: ethereum.Event): string {
return event.transaction.hash.toHexString() + event.logIndex.toString()
}
function castChallengeState(state: i32): string {
switch (state) {
case 0: return 'Waiting'
case 1: return 'Settled'
case 2: return 'Disputed'
case 3: return 'Rejected'
case 4: return 'Accepted'
case 5: return 'Voided'
default: return 'Unknown'
}
}