Skip to content

Commit

Permalink
Tasks: Support off-chain oracle queries (#82)
Browse files Browse the repository at this point in the history
  • Loading branch information
facuspagnuolo committed Jul 29, 2023
1 parent 271cec9 commit c0bef46
Show file tree
Hide file tree
Showing 5 changed files with 253 additions and 88 deletions.
6 changes: 2 additions & 4 deletions packages/price-oracle/test/PriceOracle.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1551,10 +1551,8 @@ describe('PriceOracle', () => {
})

describe('getPrice (off-chain)', () => {
let base: Contract,
quote: Contract,
feed: Contract,
data = '0x'
let data = '0x'
let base: Contract, quote: Contract, feed: Contract

const OFF_CHAIN_ORACLE_PRICE = fp(5)
const SMART_VAULT_ORACLE_PRICE = fp(10)
Expand Down
33 changes: 31 additions & 2 deletions packages/tasks/contracts/base/BaseTask.sol
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,12 @@ abstract contract BaseTask is IBaseTask, Authorized {
*/
function _getPrice(address base, address quote) internal view virtual returns (uint256) {
address priceOracle = ISmartVault(smartVault).priceOracle();
if (priceOracle == address(0)) revert TaskSmartVaultPriceOracleNotSet(base, quote);
return IPriceOracle(priceOracle).getPrice(_wrappedIfNative(base), _wrappedIfNative(quote));
if (priceOracle == address(0)) revert TaskSmartVaultPriceOracleNotSet(smartVault);
bytes memory extraCallData = _decodeExtraCallData();
return
extraCallData.length == 0
? IPriceOracle(priceOracle).getPrice(_wrappedIfNative(base), _wrappedIfNative(quote))
: IPriceOracle(priceOracle).getPrice(_wrappedIfNative(base), _wrappedIfNative(quote), extraCallData);
}

/**
Expand All @@ -172,4 +176,29 @@ abstract contract BaseTask is IBaseTask, Authorized {
function _wrappedNativeToken() internal view returns (address) {
return ISmartVault(smartVault).wrappedNativeToken();
}

/**
* @dev Decodes any potential extra calldata stored in the calldata space. Tasks relying on the extra calldata
* pattern, assume that the last word of the calldata stores the extra calldata length so it can be decoded. Note
* that tasks relying on this pattern must contemplate this function may return bogus data if no extra calldata
* was given.
*/
function _decodeExtraCallData() private pure returns (bytes memory data) {
uint256 length = uint256(_decodeLastCallDataWord());
if (msg.data.length < length) return new bytes(0);
data = new bytes(length);
assembly {
calldatacopy(add(data, 0x20), sub(sub(calldatasize(), length), 0x20), length)
}
}

/**
* @dev Returns the last calldata word. This function returns zero if the calldata is not long enough.
*/
function _decodeLastCallDataWord() private pure returns (bytes32 result) {
if (msg.data.length < 36) return bytes32(0);
assembly {
result := calldataload(sub(calldatasize(), 0x20))
}
}
}
2 changes: 1 addition & 1 deletion packages/tasks/contracts/interfaces/base/IBaseTask.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ interface IBaseTask is IAuthorized {
/**
* @dev The smart vault's price oracle is not set
*/
error TaskSmartVaultPriceOracleNotSet(address base, address quote);
error TaskSmartVaultPriceOracleNotSet(address smartVault);

/**
* @dev Emitted every time a task is executed
Expand Down
1 change: 1 addition & 0 deletions packages/tasks/test/base/BaseTask.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ describe('BaseTask', () => {

context('when there is not enough balance in the connector', () => {
it('reverts', async () => {
// TODO: Hardhat does not decode smart vault error properly
await expect(task.call(token, amount)).to.be.reverted
})
})
Expand Down
Loading

0 comments on commit c0bef46

Please sign in to comment.