Skip to content
Open
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
41 changes: 28 additions & 13 deletions bapp-contracts/src/middleware/examples/ethPriceOracle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,22 @@ contract EthPriceOracle is OwnableBasedApp {
event NewTaskCreated(uint32 indexed taskIndex, bytes32 taskHash);
event TaskResponded(uint32 indexed taskIndex, bytes32 taskHash, address responder, uint256 ethPrice);
event BAppOptedInByStrategy(uint32 indexed strategyId, address indexed bApp, bytes data, address[] tokens, uint32[] obligationPercentages);
event DebugOptIn(uint32 indexed strategyId, address signer, address testOneAddress, address testTwoAddress);

// Structs
struct Task {
uint256 price;
uint32 taskNumber;
address responder;
}

// Storage
mapping(uint32 => bytes32) public allTaskHashes;
mapping(address => mapping(uint32 => bytes)) public allTaskResponses;
uint32 public latestTaskNum;
uint32 public latestTaskNum; // Tracks the current task
Copy link
Contributor

Choose a reason for hiding this comment

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

I would consider removing comments cause they are redundant. But it's ok.

uint32 public nextTaskNumber; // Tracks the next task to be created
uint256 public mostRecentPrice;
mapping(uint32 => address) public strategySigner;
Task public latestCompleteTask; // Stores the latest completed task details
ISSVBasedApps public immutable ssvBasedApps;

constructor(
Expand All @@ -46,9 +54,10 @@ contract EthPriceOracle is OwnableBasedApp {
bytes32 taskHash = keccak256(abi.encodePacked(block.number, msg.sender));

// store hash of task on-chain, emit event, and increase taskNum
allTaskHashes[latestTaskNum] = taskHash;
allTaskHashes[nextTaskNumber] = taskHash;
latestTaskNum = nextTaskNumber;
nextTaskNumber = nextTaskNumber + 1;
Copy link
Contributor

Choose a reason for hiding this comment

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

this could probably use ++ but that's ok for the example

emit NewTaskCreated(latestTaskNum, taskHash);
latestTaskNum = latestTaskNum + 1;

return taskHash;
}
Expand All @@ -59,26 +68,25 @@ contract EthPriceOracle is OwnableBasedApp {
uint256 ethPrice,
bytes[] calldata signatures,
address[] calldata signers,
uint32 strategyId
uint32[] calldata strategyIds
Copy link
Contributor

Choose a reason for hiding this comment

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

For the future these 3 params could go in a struct and then you would pass an array of these structs. So you don't have to check the length.

) external {
// check that the task is valid and hasn't been responded to yet
if (taskHash != allTaskHashes[taskNumber]) { revert TaskMismatch(); }
if (allTaskResponses[msg.sender][taskNumber].length != 0) { revert AlreadyResponded(); }
if (ethPrice <= 0) { revert InvalidPrice(); }
if (signatures.length != signers.length) { revert InvalidSignature(); }
if (signatures.length != signers.length || signatures.length != strategyIds.length) { revert InvalidSignature(); }

// Create the message that was signed (task num + price)
bytes32 messageHash = keccak256(abi.encodePacked(taskNumber, ethPrice));

// Get the strategy signer
address strategySignerAddress = strategySigner[strategyId];

// Verify each signature
for (uint i = 0; i < signatures.length; i++) {

for (uint256 i = 0; i < signatures.length; i++) {
// Recover the signer address from the signature
address recoveredSigner = messageHash.recover(signatures[i]);

// Get the strategy signer for this specific strategy
address strategySignerAddress = strategySigner[strategyIds[i]];

if (strategySignerAddress != address(0)) {
// if strategy has a signer set, verify this signer is the correct one
if (strategySignerAddress != signers[i]) {
Expand All @@ -87,7 +95,7 @@ contract EthPriceOracle is OwnableBasedApp {
} else {
// if strategy has no signer set, check the signer is the owner of the strategy
Copy link
Contributor

Choose a reason for hiding this comment

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

what happens here in the else if if (strategySignerAddress != signers[i])?

uint32 derivedStrategyId = IAccountBAppStrategy(address(ssvBasedApps)).accountBAppStrategy(recoveredSigner, address(this));
if (derivedStrategyId != strategyId) {
if (derivedStrategyId != strategyIds[i]) {
revert NotOptedIn();
}
}
Expand All @@ -96,6 +104,14 @@ contract EthPriceOracle is OwnableBasedApp {
// Store the response
allTaskResponses[msg.sender][taskNumber] = abi.encode(ethPrice);
mostRecentPrice = ethPrice;
latestTaskNum = taskNumber;

// Update the latest complete task
latestCompleteTask = Task({
price: ethPrice,
taskNumber: taskNumber,
responder: msg.sender
});

// Emit event with the ETH price
emit TaskResponded(taskNumber, taskHash, msg.sender, ethPrice);
Expand All @@ -112,7 +128,6 @@ contract EthPriceOracle is OwnableBasedApp {
// Store the address in the mapping
strategySigner[strategyId] = signer;

emit DebugOptIn(strategyId, signer, testOne[1], testTwo[2]);

return true;
}
Expand Down