From f1183047f01ee147108065784d38b0ae197ef4e0 Mon Sep 17 00:00:00 2001 From: Adam Wozniak <29418299+adamewozniak@users.noreply.github.com> Date: Fri, 22 Mar 2024 15:07:32 -0700 Subject: [PATCH] docs: update (#29) Co-authored-by: ryanbajollari <54822716+rbajollari@users.noreply.github.com> --- LICENSE | 9 --- README.md | 164 ++++++++++++++++++++++++++++++++++++++++++++++--- assets/ojo.png | Bin 0 -> 423300 bytes package.json | 2 +- 4 files changed, 156 insertions(+), 19 deletions(-) delete mode 100644 LICENSE create mode 100644 assets/ojo.png diff --git a/LICENSE b/LICENSE deleted file mode 100644 index f50dc9e..0000000 --- a/LICENSE +++ /dev/null @@ -1,9 +0,0 @@ -LIMITED ACCESS RIGHTS ONLY; NO USAGE OR OTHER LICENSE GRANTED - -Copyright 2024 Ojo - -Other than the right to read the software code or associated documentation files (the “Software”) provided by the copyright holder listed above, no permission or right of any kind is granted to any person obtaining a copy of this Software. You may obtain a commercial license to use the Software by entering into a separate commercial licensing agreement with Ojo. - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index 7be82e5..777ad5a 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,159 @@ -# Sample Hardhat Project +
+ +
-This project demonstrates a basic Hardhat use case. It comes with a sample contract, a test for that contract, and a script that deploys that contract. +Ojo-evm is a set of contracts which use Axelar's GMP to request data from the Ojo blockchain and relay it back to the EVM. It is the simplest way to implement pull-style price feeds for any protocol on EVM. -Try running some of the following tasks: +## Table of Contents -```shell -npx hardhat help -npx hardhat test -REPORT_GAS=true npx hardhat test -npx hardhat node -npx hardhat run scripts/deploy.ts +- [Table of Contents](#table-of-contents) +- [Flow](#flow) +- [Gas](#gas) +- [Integration](#integration) + - [Example](#example) + - [Alternate Example](#alternate-example) +- [Deployments](#deployments) + + +## Flow + +Ojo-evm is a pull-style oracle which executes DeFi transactions after oracle updates are successful. If they do not succeed or time out, the DeFi transaction will not go through. This design was created to stop tx-spam attacks on EVM, and to minimize the delta between DeFi transactions and oracle updates. + +1. User executes a DeFi transaction +2. The DeFi contract requests an Ojo update. During this request, the DeFi contract sends along the parameters and function to call after the oracle update goes through. +3. The oracle update request goes through Axelar's GMP +4. Axelar's GMP relays the message over IBC to the Ojo blockchain +5. The Ojo blockchain reaches into its KV store to read the current price data +6. The Ojo blockchain constructs an IBC message to Axelar to call GMP with the current price info +7. The GMP message is relayed to the Ojo EVM contract, which updates its state with current price info +8. If the oracle message did not time out, the Ojo evm contract executes the DeFi function + +## Gas + +Customers pay to use the Ojo oracle contract only in Axelar's GMP fees. These funds are relayed to the Ojo chain and then sent back to the EVM side in order to pay for gas fees. + +During transactions such as borrowing, non-gas funds are never sent to the Ojo blockchain; they remain on the local contract. + +## Integration + +Integrating with Ojo on EVM is very simple, thanks to Axelar's General Message Passing (GMP). + +During a transaction, a contract may request price data from the Ojo oracle prior to updating state. For example, in a lending protocol, this should be done during the execution of a borrow, collateralization, or liquidation. Each time a user transacts, they first pull oracle data into the contract, and then perform state changes according to the price data. + +### Example + +We are going to create the [MockOjo](./contracts/MockOjo.sol) contract, which is an example that integrates Ojo price feeds in a promise-based design. + +Add the necessary import headers: + +```solidity +import "@axelar-network/axelar-gmp-sdk-solidity/contracts/executable/AxelarExecutable.sol"; +import "@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGateway.sol"; +import "@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGasService.sol"; +import "@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IERC20.sol"; +import "@ojo-network/ojo-evm/contracts/IOjo.sol"; +import "@ojo-network/ojo-evm/contracts/OjoTypes.sol"; +``` + +Create an instance of Ojo in your contract & add a constructor: + +```solidity +contract MockOjo { + IOjo public immutable ojo; + + constructor(address ojo_) { + ojo = IOjo(ojo_); + } +} ``` + +Create a private DeFi function, which will *use* Ojo price data, but will not request it. This will be used in a later step: + +```solidity +function setBalance( + bytes32[] calldata assetNames, + bytes calldata commandParams +) internal { + (uint256 multiplier) = abi.decode(commandParams, (uint256)); + for(uint256 i = 0; i < assetNames.length; i++){ + OjoTypes.PriceData memory priceData = ojo.getPriceData(assetNames[i]); + + if (priceData.price > 0) { + Balance memory balance = Balance({ + assetName: assetNames[i], + amount: priceData.price * multiplier + }); + + balances.push(balance); + } + } +} +``` + +Finally, create the public function which will call an Ojo oracle update. Once the oracle update is finished, the private DeFi function will be called. + +```solidity +function setBalanceWithOjoPriceData( + bytes32[] calldata assetNames, + uint256 multiplier +) external payable { + bytes memory commandParams = abi.encodePacked(multiplier); + + ojo.callContractMethodWithOjoPriceData{value: msg.value}( + assetNames, + address(this), + MockOjo.setBalance.selector, + commandParams + ); +} +``` + +Please reference the [MockOjo](./contracts/MockOjo.sol) contract to test against Ojo, and see our [testnet deployments](https://docs.ojo.network/integrate/evm). + +### Alternate Example + +If your contract requires continual updates instead of performing pull-style updates, this is still possible. Please note that this is not advised for mainnet releases and can result in tx-spam attacks. + +Simply create a contract that will request oracle updates: + +```solidity + function relayOjoPriceData( + bytes32[] calldata assetNames + ) external payable { + bytes memory commandParams = "0x"; + + ojo.callContractMethodWithOjoPriceData{value: msg.value}( + assetNames, + address(this), + OjoTypes.EMPTY_COMMAND_SELECTOR, + commandParams + ); + } +``` + +Set up a chron job that continually performs these pull operations, and set your previously internal DeFi function to be external: + +```solidity +function setBalance( + bytes32[] calldata assetNames, + bytes calldata commandParams +) external { + (uint256 multiplier) = abi.decode(commandParams, (uint256)); + for(uint256 i = 0; i < assetNames.length; i++){ + OjoTypes.PriceData memory priceData = ojo.getPriceData(assetNames[i]); + + if (priceData.price > 0) { + Balance memory balance = Balance({ + assetName: assetNames[i], + amount: priceData.price * multiplier + }); + + balances.push(balance); + } + } +} +``` + +## Deployments + +These contracts are deployed everywhere listed [in our docs](https://docs.ojo.network/integrate/evm). Do not trust other addresses as they are not maintained by Ojo. diff --git a/assets/ojo.png b/assets/ojo.png new file mode 100644 index 0000000000000000000000000000000000000000..ca49711620ddd8c874f17b57c00da31c25854343 GIT binary patch literal 423300 zcmYgX1yCDIx5bLP6?b=cE$$A*-HN+waJM4G9g0JXQ`}qJ-5r8E?Xe0A{q~Mnz}>;y6P%;8whI{8hsgH_ zxSdt@6ti?6+e6*j{H8lb&T@;_QsOeNHHm@ b8p0dzn<|c0N_6up-CM1t
z8q%;{f=%ndwgQEo(hL81jGFfVq@*?5bd0vDN_&7wIVvJHqN&dpuOOuL1&KDmAZjO_
z%(6_LA=2jBFoIJ}6uw_zp@=TQ)=oiVdc%E;zE)rK+oy?&%~YV{6hG+%JN0?Cc=>qe
zMsYt~68I9YX)~MCXrF@Ls%dCko}LRF8vY71gxojEb&Enu`aG_$h4j?sbc2X6*?f{S
z%ysd_?cG@nRiOIE2KORd=xSb)K1%o)5;FzeWLhmLQb~r|@;1 @;Mik_LIN~J&-Jza>=mv2
zA#qNbCM)`ajPbh!PS)Pa;dy>w!yU;&*!(w5bNkZ|0Wf2QO{CfqUnom6%DVG{uFN&}
zjRoj<{C{S9eeHN=vdHyLv?^3@n4*b3SdIfhjY{TC2-?qQ&uqJMy{rvtH$vE=6dkQF
zK8C~?aE%>F>DosxSal&@{OTmXe5lQV_Iw)!JWmMiwE$l$CNC2h!2`-^q>v}KMb@ri
z647yaY8*u83q0~2gENycA)Ts3It7fMYHf4>&c^>+B{{b{F|?VGH+%0Ze@FY-uW**J
ze }kxROC9J7v}#y_tfwxsK`Hu1*yF3FOGwD_Y{BZWMMdj`Nvh^M3Oq_GQlUx1=i;h
z7-|4xG#$gd;;@ac37O&vg)gH!(G_)M9goJdlF8FJ9U>!)i$HEoy~UEsII3}Jh|}AB
zCQ;{0w38|qx-!N4{>{E04Mj2W7kf&DAw@D6HP}fDT#>7B)Nmyoyco
zYUc09a(aqQdj`9+^KhYB2w<}>qWo62=T3{^iJMYA!|aO{3DftwaJufg-!*e$hn078
zz{~l^g`LJhf3I_Vtu^p>iRys?MZ
zRbzA$GW&*@aSy#DGirufxgMcwN$_pMhq6Ed@N<)xiqHRy>fV)X4kz_jNCAA8_jj((
z(8d`PUkQeT6bK`cYJ*8CcpqSKQ+LSO6tg!G*m}gl6;IFi;=Nrxi@nsVT}e;gBaz^m+Gw
zy0ZH(EfFL6Z)S|7O>D~`On#!Tuh3P4N6nkaFdIQ=OY$g_WF@&p4jse^86Mh_OptKy
zLxV%bC63DqW4E
cSJhQ*BP@6~QB}**_sde3<9r@B
eF^y@I!%YV0!o?#C<>z0&15