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.3/gn>
- Goldsky: <https://api.goldsky.com/api/public/project_clus2fndawbcc01w31192938i/subgraphs/amoy-managed-optimistic-oracle-v2/1.0.5/gn>
- Polygon
- TheGraph:
- Goldsky: <https://api.goldsky.com/api/public/project_clus2fndawbcc01w31192938i/subgraphs/polygon-managed-optimistic-oracle-v2/1.0.1/gn>
- Goldsky: <https://api.goldsky.com/api/public/project_clus2fndawbcc01w31192938i/subgraphs/polygon-managed-optimistic-oracle-v2/1.0.2/gn>

## Financial Contract Events

Expand Down
21 changes: 21 additions & 0 deletions packages/managed-oracle-v2/src/mappings/optimisticOracleV2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,27 @@ export function handleOptimisticProposePrice(event: ProposePrice): void {
event.params.ancillaryData
);

// 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);
if (customBond !== null) {
const bond = customBond.customBond;
const currency = customBond.currency;
log.debug("custom bond of {} of currency {} was set for request Id: {}", [
bond.toString(),
currency.toHexString(),
requestId,
]);
request.bond = bond;
request.currency = currency;
}

let customLiveness = getCustomLiveness(event.params.requester, event.params.identifier, event.params.ancillaryData);
if (customLiveness !== null) {
const liveness = customLiveness.customLiveness;
log.debug("custom liveness of {} was set for request Id: {}", [liveness.toString(), requestId]);
request.customLiveness = customLiveness.customLiveness;
}

request.save();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { describe, test, clearStore, afterAll, assert, log, afterEach } from "matchstick-as/assembly/index";
import { handleCustomLivenessSet, handleCustomBondSet } from "../../src/mappings/managedOracleV2";
import { handleOptimisticRequestPrice } from "../../src/mappings/optimisticOracleV2";
import { handleOptimisticProposePrice, handleOptimisticRequestPrice } from "../../src/mappings/optimisticOracleV2";
import {
createCustomLivenessSetEvent,
createCustomBondSetEvent,
createProposePriceEvent,
createRequestPriceEvent,
mockGetState,
State,
Expand All @@ -26,6 +27,9 @@ namespace Constants {
export const reward = 1000000;
export const finalFee = 500000;
export const timestamp = 1757284669;
export const customLiveness_2 = 123456;
export const customBond_2 = 3000000;
export const currency_2 = "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48";
}

describe("Managed OOv2", () => {
Expand Down Expand Up @@ -120,7 +124,7 @@ describe("Managed OOv2", () => {
log.info("Custom Bond: {}", [customBondEntity.customBond.toString()]);
});

test("Custom bond and liveness are applied to RequestPrice entity", () => {
test("Custom bond and liveness are applied to RequestPrice entity at REQUEST time", () => {
mockGetState(
Constants.requester,
Constants.identifierHex,
Expand Down Expand Up @@ -210,6 +214,108 @@ describe("Managed OOv2", () => {
log.info("Created OptimisticPriceRequest entity: {}", [priceRequestEntity.id]);
log.info("Custom Liveness: {}", [priceRequestEntity.customLiveness!.toString()]);
log.info("Custom Bond: {}", [priceRequestEntity.bond!.toString()]);
log.info("Custom Bond Currency: {}", [priceRequestEntity.currency!.toHexString()]);
log.info("State: {}", [priceRequestEntity.state!]);
});

test("Custom bond and liveness are applied to RequestPrice entity at PROPOSE time", () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we also test custom bond updates?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

mockGetState(
Constants.requester,
Constants.identifierHex,
Constants.timestamp,
Constants.ancillaryData,
State.Requested
);
// Step 1: Create RequestPrice event
const requestPriceEvent = createRequestPriceEvent(
Constants.requester,
Constants.identifierHex,
Constants.timestamp,
Constants.ancillaryData,
Constants.currency,
Constants.reward,
Constants.finalFee
);
handleOptimisticRequestPrice(requestPriceEvent);

// Step 2: Set custom liveness
const customLivenessEvent = createCustomLivenessSetEvent(
Constants.managedRequestId,
Constants.requester,
Constants.identifierHex,
Constants.ancillaryData,
Constants.customLiveness
);
handleCustomLivenessSet(customLivenessEvent);
// Step 3: Set custom bond
const customBondEvent = createCustomBondSetEvent(
Constants.managedRequestId,
Constants.requester,
Constants.identifierHex,
Constants.ancillaryData,
Constants.currency_2,
Constants.customBond_2
);
handleCustomBondSet(customBondEvent);

mockGetState(
Constants.requester,
Constants.identifierHex,
Constants.timestamp,
Constants.ancillaryData,
State.Proposed
);

// Step 4: Create ProposePrice event
const proposePriceEvent = createProposePriceEvent(
Constants.requester,
Constants.requester,
Constants.identifierHex,
Constants.timestamp,
Constants.ancillaryData,
1,
Constants.timestamp + 3600,
Constants.currency
);
handleOptimisticProposePrice(proposePriceEvent);

const requestId = Constants.identifierString
.concat("-")
.concat(Constants.timestamp.toString())
.concat("-")
.concat(Constants.ancillaryData);

const priceRequestEntity = OptimisticPriceRequest.load(requestId);

assert.assertTrue(priceRequestEntity !== null, "OptimisticPriceRequest entity should be created");

if (priceRequestEntity === null) {
return;
}

// Assert custom values are applied
assert.addressEquals(
Address.fromBytes(priceRequestEntity.currency),
Address.fromString(Constants.currency_2),
"Currency should match"
);

assert.bigIntEquals(
priceRequestEntity.bond!,
BigInt.fromI32(Constants.customBond_2),
"Custom bond should be applied to RequestPrice"
);

assert.bigIntEquals(
priceRequestEntity.customLiveness!,
BigInt.fromI32(Constants.customLiveness),
"Custom liveness should be applied to RequestPrice"
);

log.info("Created OptimisticPriceRequest entity: {}", [priceRequestEntity.id]);
log.info("Custom Liveness: {}", [priceRequestEntity.customLiveness!.toString()]);
log.info("State: {}", [priceRequestEntity.state!]);
log.info("Custom Bond: {}", [priceRequestEntity.bond!.toString()]);
log.info("Custom Bond Currency: {}", [priceRequestEntity.currency!.toHexString()]);
});
});
60 changes: 59 additions & 1 deletion packages/managed-oracle-v2/tests/managed-oracle-v2/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { createMockedFunction, newMockEvent } from "matchstick-as";
import { ethereum, BigInt, Address, Bytes } from "@graphprotocol/graph-ts";
import { CustomBondSet, CustomLivenessSet, RequestPrice } from "../../generated/ManagedOracleV2/ManagedOracleV2";
import {
CustomBondSet,
CustomLivenessSet,
ProposePrice,
RequestPrice,
} from "../../generated/ManagedOracleV2/ManagedOracleV2";

export const contractAddress = Address.fromString("0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7"); // Default test contract address

Expand Down Expand Up @@ -122,6 +127,59 @@ export function createRequestPriceEvent(
return requestPriceEvent;
}

export function createProposePriceEvent(
requester: string, // Address,
proposer: string, // Address,
identifier: string, // Bytes,
timestamp: i32, // BigInt,
ancillaryData: string, // Bytes,
proposedPrice: i32, // BigInt,
expirationTimestamp: i32, // BigInt,
currency: string // Address
): ProposePrice {
let proposePriceEvent = changetype<ProposePrice>(newMockEvent());
proposePriceEvent.address = contractAddress;
proposePriceEvent.parameters = new Array();

// requester
proposePriceEvent.parameters.push(
new ethereum.EventParam("requester", ethereum.Value.fromAddress(Address.fromString(requester)))
);
// proposer
proposePriceEvent.parameters.push(
new ethereum.EventParam("proposer", ethereum.Value.fromAddress(Address.fromString(proposer)))
);
// identifier
proposePriceEvent.parameters.push(
new ethereum.EventParam("identifier", ethereum.Value.fromBytes(Bytes.fromHexString(identifier)))
);
// timestamp
proposePriceEvent.parameters.push(
new ethereum.EventParam("timestamp", ethereum.Value.fromUnsignedBigInt(BigInt.fromI32(timestamp)))
);
// ancillaryData
proposePriceEvent.parameters.push(
new ethereum.EventParam("ancillaryData", ethereum.Value.fromBytes(Bytes.fromHexString(ancillaryData)))
);
// proposedPrice
proposePriceEvent.parameters.push(
new ethereum.EventParam("proposedPrice", ethereum.Value.fromSignedBigInt(BigInt.fromI32(proposedPrice)))
);
// expirationTimestamp
proposePriceEvent.parameters.push(
new ethereum.EventParam(
"expirationTimestamp",
ethereum.Value.fromUnsignedBigInt(BigInt.fromI32(expirationTimestamp))
)
);
// currency
proposePriceEvent.parameters.push(
new ethereum.EventParam("currency", ethereum.Value.fromAddress(Address.fromString(currency)))
);

return proposePriceEvent;
}

// https://github.com/UMAprotocol/protocol/blob/99b96247d27ec8a5ea9dbf3eef1dcd71beb0dc41/packages/core/contracts/optimistic-oracle-v2/interfaces/OptimisticOracleV2Interface.sol#L51
export namespace State {
export const Invalid = 0; // Never requested
Expand Down