-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add price feed rounds #64
Merged
Merged
Changes from 10 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
ee46aa4
add price feed rounds
iFrostizz 795fb11
remove unused state var
iFrostizz 5980093
fmt and lint
iFrostizz 228272a
add round unit tests
iFrostizz 214c219
fix tests
iFrostizz 095342a
lint
iFrostizz 231d37b
update bindings
iFrostizz cd56a7d
pass oracle info for bindings
iFrostizz f1c442a
update bindings
iFrostizz a6cd1fc
update bin
iFrostizz c827e2e
remove unused constants
iFrostizz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 |
---|---|---|
|
@@ -7,3 +7,6 @@ | |
[submodule "contracts/lib/solidity-merkle-trees"] | ||
path = contracts/lib/solidity-merkle-trees | ||
url = [email protected]:michaelkaplan13/solidity-merkle-trees.git | ||
[submodule "contracts/lib/chainlink"] | ||
path = contracts/lib/chainlink | ||
url = https://github.com/smartcontractkit/chainlink |
201 changes: 156 additions & 45 deletions
201
abi-bindings/go/PriceFeedImporter/PriceFeedImporter.go
Large diffs are not rendered by default.
Oops, something went wrong.
2 changes: 1 addition & 1 deletion
2
abi-bindings/go/mocks/MockPriceFeedAggregator/MockPriceFeedAggregator.go
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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,2 +1,3 @@ | ||
@solidity-merkle-trees=lib/solidity-merkle-trees/src/ | ||
@subnet-evm=lib/teleporter/contracts/lib/subnet-evm/contracts/ | ||
@chainlink=lib/chainlink/contracts/src/v0.8/shared/ |
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 |
---|---|---|
|
@@ -12,7 +12,6 @@ import {RLPReader} from "@solidity-merkle-trees/trie/ethereum/RLPReader.sol"; | |
* THIS IS AN EXAMPLE LIBRARY THAT USES UN-AUDITED CODE. | ||
* DO NOT USE THIS CODE IN PRODUCTION. | ||
*/ | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This happened when formatting |
||
library RLPUtils { | ||
using RLPReader for bytes; | ||
using RLPReader for RLPReader.RLPItem; | ||
|
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,82 @@ | ||
// (c) 2024, Ava Labs, Inc. All rights reserved. | ||
// See the file LICENSE for licensing terms. | ||
|
||
// SPDX-License-Identifier: Ecosystem | ||
|
||
pragma solidity 0.8.18; | ||
|
||
import {Test} from "forge-std/Test.sol"; | ||
import {WarpBlockHash, IWarpMessenger} from "@subnet-evm/contracts/interfaces/IWarpMessenger.sol"; | ||
import {PriceFeedImporter} from "../src/PriceFeedImporter.sol"; | ||
|
||
contract EventImporterTest is Test { | ||
address public constant WARP_PRECOMPILE_ADDRESS = 0x0200000000000000000000000000000000000005; | ||
bytes32 public constant DEFAULT_BLOCKCHAIN_ID = | ||
bytes32(hex"55e1fcfdde01f9f6d4c16fa2ed89ce65a8669120a86f321eef121891cab61241"); | ||
address public constant SOURCE_ORACLE_AGGREGATOR = 0x154baB1FC1D87fF641EeD0E9Bc0f8a50D880D2B6; | ||
|
||
uint8 public constant DECIMALS = 18; | ||
string public description = "WarpETHUSDAggregator"; | ||
uint256 public constant VERSION = 1; | ||
|
||
PriceFeedImporter public priceFeedImporter; | ||
|
||
event AnswerUpdated(int256 currentAnswer, uint80 roundID, uint256 updatedAt); | ||
event EventImported( | ||
bytes32 indexed sourceBlockchainID, | ||
bytes32 indexed sourceBlockHash, | ||
address indexed loggerAddress, | ||
uint256 txIndex, | ||
uint256 logIndex | ||
); | ||
|
||
function setUp() public virtual { | ||
priceFeedImporter = new PriceFeedImporter(DEFAULT_BLOCKCHAIN_ID, SOURCE_ORACLE_AGGREGATOR, DECIMALS, description, VERSION); | ||
} | ||
|
||
function testImportEvent() public { | ||
// Mock the Warp precompile returning a valid WarpBlockHash. | ||
bytes32 blockHash = 0x2d9215bce478eb82bfd35f7e9bdc9d76e1814e8d7b5aa10ab05e2f17d145c0cf; | ||
bytes memory encodedBlockHeader = | ||
hex"f9027ba05e92b0416d56a052ea29c5267627d489290dd2f87bae4887c56084452349598ca01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940100000000000000000000000000000000000000a0425ff44c06b858d5ea72ce4261f8174d1a6d729a2ffdadddaa94abe58b37597da000d275e4cce63b7fe0facd8f477d3cf879b7992c3fed522e01ec5bc6b05345f7a07149d37617782b645919054a607d47ffc590e8c8827c616e792b22caf8fb527fb90100202000000000000000000000801000a120020004000080002184810040000008002050000000004000500400200c1004084000000103010200200e02000808000090c0000024800204802009006020200008000081000000000050808002080000210011021008000000000100000800000000400000082000000010000007010800000400000000000014010000000802020490040002094020004800404010000000401008000401000600002000124000180008008008800001800400000002040002000600000000002001020050004018000000007080002024000020008200000020000081000100040000400000020000000000020000020001000000018402b60ce083e4e1c0831ca6e38466452e8db8560000000000095c3f0000000000000000000000000010c6a90000000000000000000000000004ee9900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000880000000000000000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218505d21dba008080"; | ||
assertEq(blockHash, keccak256(encodedBlockHeader)); | ||
vm.mockCall( | ||
WARP_PRECOMPILE_ADDRESS, | ||
abi.encodeCall(IWarpMessenger.getVerifiedWarpBlockHash, (0)), | ||
abi.encode(WarpBlockHash({blockHash: blockHash, sourceChainID: DEFAULT_BLOCKCHAIN_ID}), true) | ||
); | ||
|
||
// Assemble the Merkle proof against the receipts root of the block header. | ||
bytes[] memory proof = new bytes[](3); | ||
proof[0] = | ||
hex"f901d180a0cb5cc5565987800aeba057b0af7a83c7d46c3e16d08a0b2e5e97c663af8c0249a091ca9b1a8700045443e3cebc160679c2a8443dafd8f3bd33797836b401f5c0daa0f334d4c8361313ace856c4cd2f762c7954b0e280635e21cf7c5d8a0365b229f7a05a7dda2d8aa8908be6452e5ea4f2176d02c6c59418e8ade5d49cee1b1dab43e7a0ed2f24945ae33093877231e08d6cfc4584151642e49c59ad4cc7b6c6a9be30e3a09a1e4d23e6722be8df80f8e0b0a6978f868e2d09f9a8999c69349012425cb1a8a0d4639be4cfb077205fe324498b3b82165e4f26680b257b402aaf844287986d7ba02bf31869288dd26d1524809068622f88b2d8a7d4ba41e6b3d71103a72fbf81cfa0c8a339bcdd687538e2d6428ec10a9b763d8803c47b58796813fad9325bce9583a0853e20adc93f1f305cae89c704b98dd6ea5ebd2725cbd334a254c496fa25874fa0c2dc37de20dfd81248b7c7373e3858c935cb1377ce96c861fddfe3c6498b22b9a00592cdc2487293d7f933bac6750638a20ce822e652abe776ed20c69f354cd9dba0d472513604ab02f424f3a737de868348662e9caedf883b4213d0b76dbc7c9ae3a043d6dd9e9b84b58f3d23e0dc2c1fbdef9c99e6307431b849fe666696be6345c78080"; | ||
proof[1] = | ||
hex"f905ab20b905a7f905a40183162ae9b9010000000000000000000000000000000000000000000000000000000100000000000000100000000000000000000000000000000000000200000000000000000000000000000000000000000001002000000000000001000000000000000000000000000000020000000000000000000800000000000000000000000000000001000000000000000000000000000000000000000480000000000000000000400000000000001000000000000200000000000000000008000008000000000000000000000000000000000000000000000000004010000000000000000000000020000000000000000000000000000000000000000000000000000000000001000000f90499f9035c94154bab1fc1d87ff641eed0e9bc0f8a50d880d2b6f842a0f6a97944f31ea060dfde0566e4167c1a1082551e64b60ecb14d599a9d023d451a0000000000000000000000000000000000000000000000000000000000002be00b90300000000000000000000000000000000000000000000000000000006010e05e000000000000000000000000000e5b37dc608c73852f9c0f56e30f8d74d89b51c5500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000002c00000000000000000000000f4fc72042f23c3a2b6da6ebfecf0b6e30001538902000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000600bc7bda0000000000000000000000000000000000000000000000000000000600bc8b1c4000000000000000000000000000000000000000000000000000000600c0b0c17000000000000000000000000000000000000000000000000000000600d9b39e5000000000000000000000000000000000000000000000000000000600f2e28c6000000000000000000000000000000000000000000000000000000600f9c1e30000000000000000000000000000000000000000000000000000000600f9c1e3000000000000000000000000000000000000000000000000000000060105dd20a8000000000000000000000000000000000000000000000000000006010e05e000000000000000000000000000000000000000000000000000000006010e05e000000000000000000000000000000000000000000000000000000006010e05e000000000000000000000000000000000000000000000000000000006013c1415ba000000000000000000000000000000000000000000000000000006014367c00800000000000000000000000000000000000000000000000000000601bf96ddf600000000000000000000000000000000000000000000000000000601bf96ddf6000000000000000000000000000000000000000000000000000006023b6e36e00000000000000000000000000000000000000000000000000000000000000010010f0d0e0c040903080a000b0607020500000000000000000000000000000000f89b94154bab1fc1d87ff641eed0e9bc0f8a50d880d2b6f863a00109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271a0000000000000000000000000000000000000000000000000000000000002be00a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000066452e8df89b94154bab1fc1d87ff641eed0e9bc0f8a50d880d2b6f863a00559884fd3a460db3073b7fc896cc77986f16e378210ded43186175bf646fc5fa0000000000000000000000000000000000000000000000000000006010e05e000a0000000000000000000000000000000000000000000000000000000000002be00a00000000000000000000000000000000000000000000000000000000066452e8d"; | ||
proof[2] = | ||
hex"f851a016195dc5b5fc0021cbfee701b341d49721eb17357a1b354ecf55a61cab521b5c80808080808080a085f248d30b0ce90e5d44a50650a12dffc585c1cc2cb9474050891fa23e5306ac8080808080808080"; | ||
|
||
// Current answer should revert since no event has been imported yet. | ||
vm.expectRevert("No data"); | ||
priceFeedImporter.latestRoundData(); | ||
|
||
// Import the event. | ||
vm.expectEmit(true, true, true, true); | ||
emit AnswerUpdated(6_601_600_000_000, 179_712, 1_715_809_933); | ||
vm.expectEmit(true, true, true, true); | ||
emit EventImported(DEFAULT_BLOCKCHAIN_ID, blockHash, 0x154baB1FC1D87fF641EeD0E9Bc0f8a50D880D2B6, 8, 2); | ||
priceFeedImporter.importEvent(bytes32(0), encodedBlockHeader, 8, proof, 2); | ||
|
||
// Verify the latest round data. | ||
(uint80 roundID, int256 currentAnswer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) = | ||
priceFeedImporter.latestRoundData(); | ||
assertEq(roundID, 179_712); | ||
assertEq(currentAnswer, 6_601_600_000_000); | ||
assertEq(startedAt, 1_715_809_933); | ||
assertEq(updatedAt, 1_715_809_933); | ||
assertEq(answeredInRound, 179_712); | ||
|
||
assertEq(priceFeedImporter.latestSourceBlockNumber(), 45_485_280); | ||
assertEq(priceFeedImporter.latestSourceTxIndex(), 8); | ||
assertEq(priceFeedImporter.latestSourceLogIndex(), 2); | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Events should be published monotonically increasingly. This is not true apparently on startup because the blocks catch-up operation is done asynchronously to the tip following one, thanks @cam-schultz !
We may want to modify this logic because of the catch-up so that it can accept any height, but not allow overwrites.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An issue arising from that is that there might be some missing rounds although the last one is saved. Some smart contracts relying on this information to calculate i.e. the median price may get surprised by this behavior.
If we assume that any gap can only happen at the startup and that it would be filled quickly, we could save them in a "buffer" and only respond with the
getRoundData
method if none of the previous round is missing.