-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add a log triggered feed lookup upkeep (#9742)
- Loading branch information
1 parent
68e49f6
commit 58496ec
Showing
6 changed files
with
751 additions
and
0 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
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 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.16; | ||
|
||
// this struct is the same as LogTriggerConfig defined in KeeperRegistryLogicA2_1 contract | ||
struct LogTriggerConfig { | ||
address contractAddress; | ||
uint8 filterSelector; // denotes which topics apply to filter ex 000, 101, 111...only last 3 bits apply | ||
bytes32 topic0; | ||
bytes32 topic1; | ||
bytes32 topic2; | ||
bytes32 topic3; | ||
} | ||
|
||
contract DummyProtocol { | ||
event LimitOrderSent(uint256 indexed amount, uint256 indexed price, address indexed to); // keccak256(LimitOrderSent(uint256,uint256,address)) => 0x3e9c37b3143f2eb7e9a2a0f8091b6de097b62efcfe48e1f68847a832e521750a | ||
event LimitOrderWithdrawn(uint256 indexed amount, uint256 indexed price, address indexed from); // keccak256(LimitOrderWithdrawn(uint256,uint256,address)) => 0x0a71b8ed921ff64d49e4d39449f8a21094f38a0aeae489c3051aedd63f2c229f | ||
event LimitOrderExecuted(uint256 indexed orderId, uint256 indexed amount, address indexed exchange); // keccak(LimitOrderExecuted(uint256,uint256,address)) => 0xd1ffe9e45581c11d7d9f2ed5f75217cd4be9f8b7eee6af0f6d03f46de53956cd | ||
|
||
function sendLimitedOrder(uint256 amount, uint256 price, address to) public { | ||
// send an order to an exchange | ||
emit LimitOrderSent(amount, price, to); | ||
} | ||
|
||
function withdrawLimit(uint256 amount, uint256 price, address from) public { | ||
// withdraw an order from an exchange | ||
emit LimitOrderSent(amount, price, from); | ||
} | ||
|
||
function executeLimitOrder(uint256 orderId, uint256 amount, address exchange) public { | ||
// execute a limit order | ||
emit LimitOrderExecuted(orderId, amount, exchange); | ||
} | ||
|
||
/** | ||
* @notice this function generates bytes for a basic log trigger config with no filter selector. | ||
* @param targetContract the address of contract where events will be emitted from | ||
* @param t0 the signature of the event to listen to | ||
*/ | ||
function getBasicLogTriggerConfig( | ||
address targetContract, | ||
bytes32 t0 | ||
) external view returns (bytes memory logTrigger) { | ||
LogTriggerConfig memory cfg = LogTriggerConfig({ | ||
contractAddress: targetContract, | ||
filterSelector: 0, | ||
topic0: t0, | ||
topic1: 0x000000000000000000000000000000000000000000000000000000000000000, | ||
topic2: 0x000000000000000000000000000000000000000000000000000000000000000, | ||
topic3: 0x000000000000000000000000000000000000000000000000000000000000000 | ||
}); | ||
return abi.encode(cfg); | ||
} | ||
|
||
/** | ||
* @notice this function generates bytes for a customizable log trigger config. | ||
* @param targetContract the address of contract where events will be emitted from | ||
* @param selector the filter selector. this denotes which topics apply to filter ex 000, 101, 111....only last 3 bits apply | ||
* if 0, it won't filter based on topic 1, 2, 3. | ||
* if 1, it will filter based on topic 1, | ||
* if 2, it will filter based on topic 2, | ||
* if 3, it will filter based on topic 1 and topic 2, | ||
* if 4, it will filter based on topic 3, | ||
* if 5, it will filter based on topic 1 and topic 3.... | ||
* @param t0 the signature of the event to listen to. | ||
* @param t1 the topic 1 of the event. | ||
* @param t2 the topic 2 of the event. | ||
* @param t3 the topic 2 of the event. | ||
*/ | ||
function getAdvancedLogTriggerConfig( | ||
address targetContract, | ||
uint8 selector, | ||
bytes32 t0, | ||
bytes32 t1, | ||
bytes32 t2, | ||
bytes32 t3 | ||
) external view returns (bytes memory logTrigger) { | ||
LogTriggerConfig memory cfg = LogTriggerConfig({ | ||
contractAddress: targetContract, | ||
filterSelector: selector, | ||
topic0: t0, | ||
topic1: t1, | ||
topic2: t2, | ||
topic3: t3 | ||
}); | ||
return abi.encode(cfg); | ||
} | ||
} |
110 changes: 110 additions & 0 deletions
110
contracts/src/v0.8/dev/automation/tests/LogTriggeredFeedLookup.sol
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,110 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.16; | ||
|
||
import {ILogAutomation, Log} from "../2_1/interfaces/ILogAutomation.sol"; | ||
import "../2_1/interfaces/FeedLookupCompatibleInterface.sol"; | ||
import {ArbSys} from "../../vendor/@arbitrum/nitro-contracts/src/precompiles/ArbSys.sol"; | ||
|
||
interface IVerifierProxy { | ||
/** | ||
* @notice Verifies that the data encoded has been signed | ||
* correctly by routing to the correct verifier. | ||
* @param signedReport The encoded data to be verified. | ||
* @return verifierResponse The encoded response from the verifier. | ||
*/ | ||
function verify(bytes memory signedReport) external returns (bytes memory verifierResponse); | ||
} | ||
|
||
contract LogTriggeredFeedLookup is ILogAutomation, FeedLookupCompatibleInterface { | ||
event PerformingLogTriggerUpkeep( | ||
address indexed from, | ||
uint256 orderId, | ||
uint256 amount, | ||
address exchange, | ||
uint256 blockNumber, | ||
bytes blob, | ||
bytes verified | ||
); | ||
|
||
ArbSys internal constant ARB_SYS = ArbSys(0x0000000000000000000000000000000000000064); | ||
IVerifierProxy internal constant VERIFIER = IVerifierProxy(0x09DFf56A4fF44e0f4436260A04F5CFa65636A481); | ||
|
||
// for log trigger | ||
bytes32 constant sentSig = 0x3e9c37b3143f2eb7e9a2a0f8091b6de097b62efcfe48e1f68847a832e521750a; | ||
bytes32 constant withdrawnSig = 0x0a71b8ed921ff64d49e4d39449f8a21094f38a0aeae489c3051aedd63f2c229f; | ||
bytes32 constant executedSig = 0xd1ffe9e45581c11d7d9f2ed5f75217cd4be9f8b7eee6af0f6d03f46de53956cd; | ||
|
||
// for mercury config | ||
bool public useArbitrumBlockNum; | ||
string[] public feedsHex = ["0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"]; | ||
string public feedParamKey = "feedIdHex"; | ||
string public timeParamKey = "blockNumber"; | ||
|
||
constructor(bool _useArbitrumBlockNum) { | ||
useArbitrumBlockNum = _useArbitrumBlockNum; | ||
} | ||
|
||
function setTimeParamKey(string memory timeParam) external { | ||
timeParamKey = timeParam; | ||
} | ||
|
||
function setFeedParamKey(string memory feedParam) external { | ||
feedParamKey = feedParam; | ||
} | ||
|
||
function setFeedsHex(string[] memory newFeeds) external { | ||
feedsHex = newFeeds; | ||
} | ||
|
||
function checkLog(Log calldata log) external override returns (bool upkeepNeeded, bytes memory performData) { | ||
uint256 blockNum = getBlockNumber(); | ||
|
||
// filter by event signature | ||
if (log.topics[0] == executedSig) { | ||
// filter by indexed parameters | ||
bytes memory t1 = abi.encodePacked(log.topics[1]); // bytes32 to bytes | ||
uint256 orderId = abi.decode(t1, (uint256)); | ||
bytes memory t2 = abi.encodePacked(log.topics[2]); | ||
uint256 amount = abi.decode(t2, (uint256)); | ||
bytes memory t3 = abi.encodePacked(log.topics[3]); | ||
address exchange = abi.decode(t3, (address)); | ||
|
||
revert FeedLookup(feedParamKey, feedsHex, timeParamKey, blockNum, abi.encode(orderId, amount, exchange)); | ||
} | ||
revert("could not find matching event sig"); | ||
} | ||
|
||
function performUpkeep(bytes calldata performData) external override { | ||
(bytes[] memory values, bytes memory extraData) = abi.decode(performData, (bytes[], bytes)); | ||
(uint256 orderId, uint256 amount, address exchange) = abi.decode(extraData, (uint256, uint256, address)); | ||
|
||
bytes memory verifiedResponse; // = VERIFIER.verify(values[0]); | ||
|
||
emit PerformingLogTriggerUpkeep( | ||
tx.origin, | ||
orderId, | ||
amount, | ||
exchange, | ||
getBlockNumber(), | ||
values[0], | ||
verifiedResponse | ||
); | ||
} | ||
|
||
function checkCallback( | ||
bytes[] memory values, | ||
bytes memory extraData | ||
) external view override returns (bool upkeepNeeded, bytes memory performData) { | ||
// do sth about the chainlinkBlob data in values and extraData | ||
bytes memory performData = abi.encode(values, extraData); | ||
return (true, performData); | ||
} | ||
|
||
function getBlockNumber() internal view returns (uint256) { | ||
if (useArbitrumBlockNum) { | ||
return ARB_SYS.arbBlockNumber(); | ||
} else { | ||
return block.number; | ||
} | ||
} | ||
} |
Oops, something went wrong.