kleros/kleros-v2

View on GitHub
subgraph/core/src/entities/Dispute.ts

Summary

Maintainability
A
2 hrs
Test Coverage
import { BigInt, ByteArray, crypto, dataSource, ethereum } from "@graphprotocol/graph-ts";
import { KlerosCore, DisputeCreation } from "../../generated/KlerosCore/KlerosCore";
import { Court, Dispute } from "../../generated/schema";
import { ZERO } from "../utils";
import { getAndIncrementPeriodCounter } from "./PeriodIndexCounter";

export function createDisputeFromEvent(event: DisputeCreation): void {
  const disputeID = event.params._disputeID;
  const disputeContractState = KlerosCore.bind(event.address).disputes(disputeID);
  const dispute = new Dispute(disputeID.toString());
  const courtID = disputeContractState.value0.toString();
  dispute.court = courtID;
  dispute.disputeID = disputeID;
  dispute.createdAt = event.block.timestamp;
  dispute.arbitrated = event.params._arbitrable.toHexString();
  dispute.period = "evidence";
  dispute.ruled = false;
  dispute.currentRuling = ZERO;
  dispute.tied = true;
  dispute.overridden = false;
  dispute.lastPeriodChange = event.block.timestamp;
  dispute.lastPeriodChangeBlockNumber = event.block.number;
  dispute.periodNotificationIndex = getAndIncrementPeriodCounter(dispute.period);
  const court = Court.load(courtID);
  if (!court) return;
  dispute.periodDeadline = event.block.timestamp.plus(court.timesPerPeriod[0]);
  dispute.currentRoundIndex = ZERO;
  const roundID = `${disputeID.toString()}-${ZERO.toString()}`;
  dispute.currentRound = roundID;
  dispute.save();

  updateDisputeRequestData(event);
}

// source: contracts/src/arbitration/interfaces/IArbitrableV2.sol
const DisputeRequest = "DisputeRequest(address,uint256,uint256,uint256,string)";
const DisputeRequestSignature = crypto.keccak256(ByteArray.fromUTF8(DisputeRequest));

// note : we are using bytes32 in place of string as strings cannot be decoded and it breaks the function.
// It is okay for us, as we are only interested in the uint256 in frontend.
const DisputeRequestTypestring = "(uint256,uint256,bytes32)"; // _externalDisputeId,_templateId,_templateUri

// source: contracts/src/gateway/interfaces/IHomeGateway.sol
const CrossChainDisputeIncoming =
  "CrossChainDisputeIncoming(address,uint256,address,uint256,uint256,uint256,uint256,string)";
const CrossChainDisputeIncomingSignature = crypto.keccak256(ByteArray.fromUTF8(CrossChainDisputeIncoming));

// note : arbitrable is an indexed arg, so it will topic[1]
const CrossChainDisputeIncomingTypestring = "(address,uint256,uint256,uint256,string)"; // arbitrator, _arbitrableChainId, _externalDisputeId, _templateId, _templateUri

export const updateDisputeRequestData = (event: DisputeCreation): void => {
  const dispute = Dispute.load(event.params._disputeID.toString());
  if (!dispute) return;

  const receipt = event.receipt;
  if (!receipt) return;

  const logs = receipt.logs;

  // note that the topic at 0th index is always the event signature
  const disputeRequestEventIndex = logs.findIndex((log) => log.topics[0] == DisputeRequestSignature);
  const crossChainDisputeEventIndex = logs.findIndex((log) => log.topics[0] == CrossChainDisputeIncomingSignature);

  if (crossChainDisputeEventIndex !== -1) {
    const crossChainDisputeEvent = logs[crossChainDisputeEventIndex];

    const decoded = ethereum.decode(CrossChainDisputeIncomingTypestring, crossChainDisputeEvent.data);
    if (!decoded) return;
    dispute.isCrossChain = true;
    dispute.arbitrableChainId = decoded.toTuple()[1].toBigInt();
    dispute.externalDisputeId = decoded.toTuple()[2].toBigInt();
    dispute.templateId = decoded.toTuple()[3].toBigInt();
    dispute.save();
    return;
  } else if (disputeRequestEventIndex !== -1) {
    const disputeRequestEvent = logs[disputeRequestEventIndex];

    const decoded = ethereum.decode(DisputeRequestTypestring, disputeRequestEvent.data);
    if (!decoded) return;
    dispute.isCrossChain = false;
    dispute.arbitrableChainId = getHomeChainId(dataSource.network());
    dispute.externalDisputeId = decoded.toTuple()[0].toBigInt();
    dispute.templateId = decoded.toTuple()[1].toBigInt();
    dispute.save();
    return;
  }
};

// workaround, since hashmap don't work in subgraphs.
// https://thegraph.com/docs/en/developing/supported-networks/
function getHomeChainId(name: string): BigInt {
  if (name == "arbitrum-one") return BigInt.fromI32(42161);
  else if (name == "arbitrum-sepolia") return BigInt.fromI32(421614);
  else return BigInt.fromI32(1);
}