-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: added DataEdge contract with OracleConfiguration (#2)
* feat: added DataEdge contract with OracleConfiguration * fix: keep oracle history by using address as the ID * chore: changed to use subgraph ids * chore: use subgraphs deployment id and use version instead of commit hash
- Loading branch information
Showing
15 changed files
with
430 additions
and
533 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,4 +13,5 @@ config/addresses.ts | |
config/generatedAddresses.json | ||
tests/.bin | ||
.vscode | ||
.latest.json | ||
.latest.json | ||
.docker |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
[ | ||
{ | ||
"anonymous": false, | ||
"inputs": [ | ||
{ | ||
"indexed": false, | ||
"internalType": "bytes", | ||
"name": "data", | ||
"type": "bytes" | ||
} | ||
], | ||
"name": "Log", | ||
"type": "event" | ||
}, | ||
{ "stateMutability": "payable", "type": "fallback" } | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,45 +1,42 @@ | ||
type NewOwnership @entity(immutable: true) { | ||
id: Bytes! | ||
from: Bytes! # address | ||
to: Bytes! # address | ||
blockNumber: BigInt! | ||
blockTimestamp: BigInt! | ||
transactionHash: Bytes! | ||
type GlobalState @entity { | ||
id: ID! | ||
oracles: [Oracle!]! @derivedFrom(field: "state") | ||
activeOracles: [Oracle!]! | ||
} | ||
|
||
type NewPendingOwnership @entity(immutable: true) { | ||
id: Bytes! | ||
from: Bytes! # address | ||
to: Bytes! # address | ||
blockNumber: BigInt! | ||
blockTimestamp: BigInt! | ||
transactionHash: Bytes! | ||
} | ||
|
||
type OracleSet @entity(immutable: true) { | ||
id: Bytes! | ||
index: BigInt! # uint256 | ||
oracle: Bytes! # address | ||
blockNumber: BigInt! | ||
blockTimestamp: BigInt! | ||
transactionHash: Bytes! | ||
type Oracle @entity { | ||
id: Bytes! # address | ||
index: String! # oracle_index | ||
state: GlobalState! | ||
latestConfig: OracleConfiguration! | ||
configurations: [OracleConfiguration!]! @derivedFrom(field: "oracle") | ||
votes: [OracleVote!]! @derivedFrom(field: "oracle") | ||
active: Boolean! | ||
activeSince: BigInt! | ||
activeUntil: BigInt! # 0 means active | ||
} | ||
|
||
type OracleVote @entity(immutable: true) { | ||
id: Bytes! | ||
id: ID! | ||
oracle: Oracle! | ||
subgraphDeploymentID: Bytes! # bytes32 | ||
deny: Boolean! # bool | ||
oracleIndex: BigInt! # uint256 | ||
timestamp: BigInt! # uint256 | ||
blockNumber: BigInt! | ||
blockTimestamp: BigInt! | ||
transactionHash: Bytes! | ||
} | ||
|
||
type VoteTimeLimitSet @entity(immutable: true) { | ||
id: Bytes! | ||
voteTimeLimit: BigInt! # uint256 | ||
blockNumber: BigInt! | ||
blockTimestamp: BigInt! | ||
transactionHash: Bytes! | ||
} | ||
type OracleConfiguration @entity(immutable: true) { | ||
id: ID! | ||
oracle: Oracle! | ||
version: String! | ||
ipfsConcurrency: String! | ||
ipfsTimeout: String! | ||
minSignal: String! | ||
period: String! | ||
gracePeriod: String! | ||
supportedDataSourceKinds: String! | ||
networkSubgraphDeploymentId: String! | ||
epochBlockOracleSubgraphDeploymentId: String! | ||
subgraphAvailabilityManagerContract: String! | ||
oracleIndex: String! | ||
createdAt: BigInt! | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export let ORACLE_CONFIGURATION_ABI = | ||
"(string,(string,string,string,string,string,string,string,string,string,string))" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import { log, BigInt, Bytes } from "@graphprotocol/graph-ts"; | ||
import { StoreCache } from "./store-cache"; | ||
|
||
export function parseCalldata(calldata: Bytes): Bytes { | ||
// Remove function signature | ||
let dataWithoutSignature = calldata.toHexString().slice(10); | ||
|
||
// ethabi expects a tuple offset if your tuple contains dynamic data | ||
// https://medium.com/@r2d2_68242/indexing-transaction-input-data-in-a-subgraph-6ff5c55abf20 | ||
let hexStringToDecode = '0x0000000000000000000000000000000000000000000000000000000000000020' + | ||
dataWithoutSignature; | ||
return Bytes.fromHexString(hexStringToDecode); | ||
} | ||
|
||
export function isSubmitterAllowed( | ||
cache: StoreCache, | ||
oracleIndex: String, | ||
submitter: Bytes | ||
): boolean { | ||
let oracle = cache.getOracle(submitter); | ||
return oracle.active && oracle.index == oracleIndex; | ||
} | ||
|
||
|
||
export function getOracleVoteId( | ||
subgraphDeploymentID: String, | ||
oracleAddress: String, | ||
timestamp: String | ||
): string { | ||
return [subgraphDeploymentID, oracleAddress, timestamp].join("-") as string; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import { log, ethereum, Bytes } from "@graphprotocol/graph-ts"; | ||
import { Log as LogEvent } from "../generated/SAODataEdge/SAODataEdge" | ||
import { parseCalldata, isSubmitterAllowed } from "./helpers" | ||
import { StoreCache } from "./store-cache"; | ||
import { ORACLE_CONFIGURATION_ABI } from "./constants"; | ||
|
||
export function handleLog(event: LogEvent): void { | ||
let submitter = event.transaction.from; | ||
processPayload(submitter, event.params.data, event.transaction.hash.toHexString(), event.block); | ||
} | ||
|
||
export function processPayload( | ||
submitter: Bytes, | ||
payload: Bytes, | ||
txHash: string, | ||
block: ethereum.Block | ||
): void { | ||
let submitterAddress = submitter.toHexString(); | ||
log.warning("Processing payload. Submitter: {}", [submitterAddress]); | ||
|
||
let cache = new StoreCache(); | ||
|
||
let parsedCalldata = parseCalldata(payload); | ||
let decoded = ethereum.decode(ORACLE_CONFIGURATION_ABI, parsedCalldata)!.toTuple(); | ||
let decodedConfig = decoded[1].toTuple(); | ||
let decodedOracleIndex = decodedConfig[9].toString(); | ||
|
||
if (!isSubmitterAllowed(cache, decodedOracleIndex, submitter)) { | ||
log.error("Submitter not allowed: {}", [submitterAddress]); | ||
return; | ||
} | ||
|
||
log.info("Submitter allowed", []); | ||
|
||
let oracle = cache.getOracle(submitter); | ||
let config = cache.getOracleConfiguration(txHash); | ||
config.oracle = oracle.id; | ||
config.version = decoded[0].toString(); | ||
config.ipfsConcurrency = decodedConfig[0].toString(); | ||
config.ipfsTimeout = decodedConfig[1].toString(); | ||
config.minSignal = decodedConfig[2].toString(); | ||
config.period = decodedConfig[3].toString(); | ||
config.gracePeriod = decodedConfig[4].toString(); | ||
config.supportedDataSourceKinds = decodedConfig[5].toString(); | ||
config.networkSubgraphDeploymentId = decodedConfig[6].toString(); | ||
config.epochBlockOracleSubgraphDeploymentId = decodedConfig[7].toString(); | ||
config.subgraphAvailabilityManagerContract = decodedConfig[8].toString(); | ||
config.oracleIndex = decodedOracleIndex; | ||
config.createdAt = block.timestamp; | ||
|
||
oracle.latestConfig = config.id; | ||
|
||
cache.commitChanges(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import { GlobalState, Oracle, OracleConfiguration, OracleVote } from "../generated/schema" | ||
import { log, Bytes } from "@graphprotocol/graph-ts" | ||
|
||
export class SafeMap<K, V> extends Map<K, V> { | ||
safeGet(id: K): V | null { | ||
return this.has(id) ? this.get(id) : null; | ||
} | ||
} | ||
|
||
export class StoreCache { | ||
state: GlobalState; | ||
oracles: SafeMap<Bytes, Oracle>; | ||
oraclesConfigs: SafeMap<String, OracleConfiguration>; | ||
oracleVotes: SafeMap<String, OracleVote>; | ||
|
||
constructor() { | ||
let state = GlobalState.load("0"); | ||
if (state == null) { | ||
state = new GlobalState("0"); | ||
state.activeOracles = []; | ||
state.save(); | ||
} | ||
|
||
this.state = state; | ||
this.oracles = new SafeMap<Bytes, Oracle>(); | ||
this.oraclesConfigs = new SafeMap<String, OracleConfiguration>(); | ||
this.oracleVotes = new SafeMap<String, OracleVote>(); | ||
} | ||
|
||
getGlobalState(): GlobalState { | ||
return this.state; | ||
} | ||
|
||
getOracle(id: Bytes): Oracle { | ||
if (this.oracles.safeGet(id) == null) { | ||
let oracle = Oracle.load(id); | ||
if (oracle == null) { | ||
oracle = new Oracle(id); | ||
oracle.state = this.state.id; | ||
oracle.index = ""; | ||
} | ||
this.oracles.set(id, oracle); | ||
} | ||
return this.oracles.safeGet(id)!; | ||
} | ||
|
||
getOracleConfiguration(id: String): OracleConfiguration { | ||
if (this.oraclesConfigs.safeGet(id) == null) { | ||
let config = OracleConfiguration.load(id); | ||
if (config == null) { | ||
config = new OracleConfiguration(id); | ||
} | ||
this.oraclesConfigs.set(id, config); | ||
} | ||
return this.oraclesConfigs.safeGet(id)!; | ||
} | ||
|
||
getOracleVote(id: String): OracleVote { | ||
if (this.oracleVotes.safeGet(id) == null) { | ||
let vote = OracleVote.load(id); | ||
if (vote == null) { | ||
vote = new OracleVote(id); | ||
} | ||
this.oracleVotes.set(id, vote); | ||
} | ||
return this.oracleVotes.safeGet(id)!; | ||
} | ||
|
||
commitChanges(): void { | ||
this.state.save(); | ||
|
||
let oracles = this.oracles.values(); | ||
for (let i = 0; i < oracles.length; i++) { | ||
oracles[i].save(); | ||
} | ||
|
||
let configs = this.oraclesConfigs.values(); | ||
for (let i = 0; i < configs.length; i++) { | ||
configs[i].save(); | ||
} | ||
|
||
let votes = this.oracleVotes.values(); | ||
for (let i = 0; i < votes.length; i++) { | ||
votes[i].save(); | ||
} | ||
} | ||
} |
Oops, something went wrong.