Skip to content
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
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,10 +146,10 @@ This subgraph indexes events and function calls by the "Managed Optimistic Oracl

- Amoy
- TheGraph:
- Goldsky: <https://api.goldsky.com/api/public/project_clus2fndawbcc01w31192938i/subgraphs/amoy-managed-optimistic-oracle-v2/1.0.5/gn>
- Goldsky: <https://api.goldsky.com/api/public/project_clus2fndawbcc01w31192938i/subgraphs/amoy-managed-optimistic-oracle-v2/1.0.6/gn>
- Polygon
- TheGraph:
- Goldsky: <https://api.goldsky.com/api/public/project_clus2fndawbcc01w31192938i/subgraphs/polygon-managed-optimistic-oracle-v2/1.0.2/gn>
- Goldsky: <https://api.goldsky.com/api/public/project_clus2fndawbcc01w31192938i/subgraphs/polygon-managed-optimistic-oracle-v2/1.0.3/gn>

## Financial Contract Events

Expand Down
4 changes: 3 additions & 1 deletion packages/managed-oracle-v2/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,11 @@ type OptimisticPriceRequest @entity {
}

type CustomBond @entity {
"ID is managedRequestId, ie. the hash of requester, identifier, ancillaryData"
"ID is the hash of requester, identifier, ancillaryData, currency"
id: ID!

managedRequestId: String!

currency: Bytes!

requester: Bytes!
Expand Down
18 changes: 15 additions & 3 deletions packages/managed-oracle-v2/src/mappings/managedOracleV2.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,27 @@
import { log } from "@graphprotocol/graph-ts";
import { CustomBond, CustomLiveness } from "../../generated/schema";
import { CustomBondSet, CustomLivenessSet } from "../../generated/ManagedOracleV2/ManagedOracleV2";

import { createCustomBondIdFromEvent } from "../utils/helpers/managedOracleV2";

/**
* Handles CustomBondSet events from the ManagedOracleV2 contract.
*
* Creates or updates a CustomBond entity with a unique ID that includes the currency.
* This ensures that custom bonds are tied to specific currencies and can only be
* found when the request currency matches the custom bond currency.
*/
export function handleCustomBondSet(event: CustomBondSet): void {
const managedRequestId = event.params.managedRequestId.toHexString();
log.debug("Custom Bond set event. Loading entity with managedRequestId, {}", [managedRequestId]);

let entity = CustomBond.load(managedRequestId);
// Generate unique ID that includes currency - this ensures currency matching
const id = createCustomBondIdFromEvent(event);

let entity = CustomBond.load(id);

if (entity == null) {
entity = new CustomBond(managedRequestId);
entity = new CustomBond(id);
entity.managedRequestId = managedRequestId;
entity.requester = event.params.requester;
entity.identifier = event.params.identifier.toString();
entity.ancillaryData = event.params.ancillaryData.toHex();
Expand Down
46 changes: 39 additions & 7 deletions packages/managed-oracle-v2/src/mappings/optimisticOracleV2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,31 @@ import { getManagedRequestId, getOrCreateOptimisticPriceRequest } from "../utils
import { CustomBond, CustomLiveness } from "../../generated/schema";

import { Address, BigInt, Bytes, dataSource, log } from "@graphprotocol/graph-ts";
import { createCustomBondId } from "../utils/helpers/managedOracleV2";

let network = dataSource.network();

let isMainnet = network == "mainnet";
let isGoerli = network == "goerli";

function getCustomBond(requester: Address, identifier: Bytes, ancillaryData: Bytes): CustomBond | null {
const managedRequestId = getManagedRequestId(requester, identifier, ancillaryData).toHexString();
let customBondEntity = CustomBond.load(managedRequestId);
/**
* Retrieves a custom bond entity if one exists for the given parameters.
*
* IMPORTANT: Custom bonds are stored with a unique ID that includes the currency.
* This means we can only find custom bonds that match the EXACT currency used in the request.
* If a custom bond was set for a different currency, it will NOT be found here.
*
* This ensures that custom bonds are only applied when the currency matches,
* preventing incorrect bond amounts from being applied to requests with different currencies.
*/
function getCustomBond(
requester: Address,
identifier: Bytes,
ancillaryData: Bytes,
currency: Bytes
): CustomBond | null {
const id = createCustomBondId(requester, identifier, ancillaryData, currency);
let customBondEntity = CustomBond.load(id);
return customBondEntity ? customBondEntity : null;
}

Expand Down Expand Up @@ -118,7 +134,14 @@ export function handleOptimisticRequestPrice(event: RequestPrice): void {
}

// Look up custom bond and liveness values that may have been set before the request
let customBond = getCustomBond(event.params.requester, event.params.identifier, event.params.ancillaryData);
// Custom bonds are stored with a unique ID that includes the currency, so we only find
// custom bonds that match the exact currency used in this request
let customBond = getCustomBond(
event.params.requester,
event.params.identifier,
event.params.ancillaryData,
event.params.currency
);
if (customBond !== null) {
const bond = customBond.customBond;
const currency = customBond.currency;
Expand All @@ -127,8 +150,9 @@ export function handleOptimisticRequestPrice(event: RequestPrice): void {
currency.toHexString(),
requestId,
]);
// Apply the custom bond amount - the currency is guaranteed to match since
// the custom bond ID includes the currency and we looked it up using the request's currency
request.bond = bond;
request.currency = currency;
}

let customLiveness = getCustomLiveness(event.params.requester, event.params.identifier, event.params.ancillaryData);
Expand Down Expand Up @@ -187,7 +211,14 @@ export function handleOptimisticProposePrice(event: ProposePrice): void {
);

// Look up custom bond and liveness values that may have been set before the request
let customBond = getCustomBond(event.params.requester, event.params.identifier, event.params.ancillaryData);
// Custom bonds are stored with a unique ID that includes the currency, so we only find
// custom bonds that match the exact currency used in this request
let customBond = getCustomBond(
event.params.requester,
event.params.identifier,
event.params.ancillaryData,
event.params.currency
);
if (customBond !== null) {
const bond = customBond.customBond;
const currency = customBond.currency;
Expand All @@ -196,8 +227,9 @@ export function handleOptimisticProposePrice(event: ProposePrice): void {
currency.toHexString(),
requestId,
]);
// Apply the custom bond amount - the currency is guaranteed to match since
// the custom bond ID includes the currency and we looked it up using the request's currency
request.bond = bond;
request.currency = currency;
}

let customLiveness = getCustomLiveness(event.params.requester, event.params.identifier, event.params.ancillaryData);
Expand Down
30 changes: 30 additions & 0 deletions packages/managed-oracle-v2/src/utils/helpers/managedOracleV2.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,36 @@
import { Address, ByteArray, Bytes, crypto } from "@graphprotocol/graph-ts";
import { CustomBondSet } from "../../../generated/ManagedOracleV2/ManagedOracleV2";

export function getManagedRequestId(requester: Address, identifier: Bytes, ancillaryData: Bytes): ByteArray {
let packed = requester.concat(identifier).concat(ancillaryData);
return crypto.keccak256(packed);
}

/**
* Creates a unique ID for a custom bond entity.
*
* Including the currency in the ID ensures that custom bonds are tied to specific currencies.
* This means that custom bonds set for different currencies will have different IDs,
* even if all other parameters (requester, identifier, ancillary data) are the same.
*
* This is crucial for the currency matching logic - we can only find custom bonds
* that match the exact currency used in a request.
*/
export function createCustomBondId(requester: Bytes, identifier: Bytes, ancillaryData: Bytes, currency: Bytes): string {
let packed = requester.concat(identifier).concat(ancillaryData).concat(currency);
return crypto.keccak256(packed).toHexString();
}

/**
* Creates a custom bond ID from a CustomBondSet event.
* This is a convenience function that extracts the parameters from the event
* and passes them to createCustomBondId.
*/
export function createCustomBondIdFromEvent(event: CustomBondSet): string {
return createCustomBondId(
event.params.requester,
event.params.identifier,
event.params.ancillaryData,
event.params.currency
);
}
Loading