Skip to content

Commit ab754e1

Browse files
Tweaks and simplifications
1 parent 98929d3 commit ab754e1

File tree

4 files changed

+92
-111
lines changed

4 files changed

+92
-111
lines changed

docs/tutorials/oracles/application.md

Lines changed: 68 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ title: "Part 4: Automating pricing decisions"
55
Now that your contract can use pricing data, you can act on that data to make trading decisions.
66
In this section, you set up a simple off-chain application to monitor prices and use the contract to buy and sell its simulated token.
77

8-
You can access the smart contract in many ways, but a simple way is to use Node.JS application because Pyth provides a Node SDK that simplifies getting pricing data from Hermes.
8+
You can access the smart contract in many ways, but a simple way is to use a Node.JS application because Pyth provides a Node SDK that simplifies getting pricing data from Hermes.
99
The application that you create in this section also uses the [Viem](https://viem.sh/) EVM toolkit to interact with Etherlink.
1010

1111
1. In the same directory as your `contracts` folder, create a directory named `app` to store your off-chain application.
@@ -41,7 +41,7 @@ This setting allows programs to import JSON files easily.
4141
```
4242

4343
These dependencies include the Pyth and Viem toolkits and the compiled ABI of your contract.
44-
You may need to change the path to your contract if you put it in a different place relative to this file.
44+
You may need to change the path to your compiled contract if you put the contract in a different place relative to this file.
4545

4646
1. Add these constants to access the environment variables you set, or edit this code to hard-code the values:
4747

@@ -116,7 +116,7 @@ Viem (in `view/chains`) has built-in objects that represent Etherlink Mainnet an
116116
const delaySeconds = (seconds: number) => new Promise(res => setTimeout(res, seconds*1000));
117117
```
118118

119-
1. Add this function to get current price data from Hermes, just like the `curl` command you used in previous sections:
119+
1. Add this function to get current price update data from Hermes, just like the `curl` command you used in previous sections:
120120

121121
```javascript
122122
// Utility function to call Hermes and return the current price of one XTZ in USD
@@ -147,7 +147,7 @@ Viem (in `view/chains`) has built-in objects that represent Etherlink Mainnet an
147147
}
148148
```
149149

150-
1. Add a`run` function to contain the main logic of the application:
150+
1. Add a `run` function to contain the main logic of the application:
151151

152152
```javascript
153153
const run = async () => {
@@ -165,11 +165,9 @@ Viem (in `view/chains`) has built-in objects that represent Etherlink Mainnet an
165165
// Check balance first
166166
let balance = await getBalance();
167167
console.log("Starting balance:", balance);
168-
let cash = await getCash();
169-
console.log("Starting cash in contract:", cash, "XTZ");
170168
// If not enough tokens, initialize balance with 5 tokens in the contract
171169
if (balance < 5) {
172-
console.log("Initializing account with 5 tez");
170+
console.log("Initializing account with 5 tokens");
173171
const initHash = await contract.write.initAccount([myAccount.address]);
174172
await publicClient.waitForTransactionReceipt({ hash: initHash });
175173
balance = await getBalance()
@@ -191,31 +189,34 @@ Viem (in `view/chains`) has built-in objects that represent Etherlink Mainnet an
191189
console.log("\n");
192190
console.log("Iteration", i++);
193191
let baselinePrice = await getPrice(connection);
194-
console.log("Baseline price:", baselinePrice);
192+
console.log("Baseline price:", baselinePrice, "USD to 1 XTZ");
193+
const oneUSDBaseline = Math.ceil((1/baselinePrice) * 10000) / 10000; // Round up to four decimals
194+
console.log("Or", oneUSDBaseline, "XTZ to 1 USD");
195195

196196
const updatedPrice = await alertOnPriceFluctuations(baselinePrice, connection);
197-
console.log("Price changed:", updatedPrice);
197+
console.log("Price changed:", updatedPrice, "USD to 1 XTZ");
198198
const priceFeedUpdateData = await connection.getLatestPriceUpdates([XTZ_USD_ID]);
199-
if (baselinePrice > updatedPrice) {
199+
const oneUSD = Math.ceil((1/updatedPrice) * 10000) / 10000; // Round up to four decimals
200+
201+
if (baselinePrice < updatedPrice) {
200202
// Buy
201-
console.log("Price went down; time to buy");
202-
const oneUSD = Math.ceil((1/updatedPrice) * 100) / 100; // Round up to two decimals
203+
console.log("Price of USD relative to XTZ went down; time to buy");
203204
console.log("Sending", oneUSD, "XTZ (about one USD)");
204205
const buyHash = await contract.write.buy(
205206
[[`0x${priceFeedUpdateData.binary.data[0]}`]] as any,
206207
{ value: parseEther(oneUSD.toString()), gas: 30000000n },
207208
);
208209
await publicClient.waitForTransactionReceipt({ hash: buyHash });
209-
console.log("Bought one token");
210-
} else if (baselinePrice < updatedPrice) {
211-
console.log("Price went up; time to sell");
210+
console.log("Bought one token for", oneUSD, "XTZ");
211+
} else if (baselinePrice > updatedPrice) {
212+
console.log("Price of USD relative to XTZ went up; time to sell");
212213
// Sell
213214
const sellHash = await contract.write.sell(
214215
[[`0x${priceFeedUpdateData.binary.data[0]}`]] as any,
215216
{ gas: 30000000n }
216217
);
217218
await publicClient.waitForTransactionReceipt({ hash: sellHash });
218-
console.log("Sold one token");
219+
console.log("Sold one token for", oneUSD, "XTZ");
219220
}
220221
balance = await getBalance();
221222
}
@@ -225,16 +226,7 @@ Viem (in `view/chains`) has built-in objects that represent Etherlink Mainnet an
225226
If the price of USD relative to XTZ went down, it's cheaper to buy the simulated token, so the code buys one.
226227
If the price of USD went up, it sells a token.
227228

228-
1. After the loop, add this code to cash out so you don't leave your sandbox XTZ locked in the contract:
229-
230-
```javascript
231-
// Cash out
232-
console.log("Cashing out");
233-
// Call the cashout function to retrieve the XTZ you've sent to the contract (for tutorial purposes)
234-
await contract.write.cashout();
235-
```
236-
237-
The complete application looks like this:
229+
The complete program looks like this:
238230

239231
```javascript
240232
import { HermesClient, PriceUpdate } from "@pythnetwork/hermes-client";
@@ -322,7 +314,7 @@ const run = async () => {
322314
console.log("Starting balance:", balance);
323315
// If not enough tokens, initialize balance with 5 tokens in the contract
324316
if (balance < 5) {
325-
console.log("Initializing account with 5 tez");
317+
console.log("Initializing account with 5 tokens");
326318
const initHash = await contract.write.initAccount([myAccount.address]);
327319
await publicClient.waitForTransactionReceipt({ hash: initHash });
328320
balance = await getBalance()
@@ -336,78 +328,93 @@ const run = async () => {
336328
console.log("\n");
337329
console.log("Iteration", i++);
338330
let baselinePrice = await getPrice(connection);
339-
console.log("Baseline price:", baselinePrice);
331+
console.log("Baseline price:", baselinePrice, "USD to 1 XTZ");
332+
const oneUSDBaseline = Math.ceil((1/baselinePrice) * 10000) / 10000; // Round up to four decimals
333+
console.log("Or", oneUSDBaseline, "XTZ to 1 USD");
340334

341335
const updatedPrice = await alertOnPriceFluctuations(baselinePrice, connection);
342-
console.log("Price changed:", updatedPrice);
336+
console.log("Price changed:", updatedPrice, "USD to 1 XTZ");
343337
const priceFeedUpdateData = await connection.getLatestPriceUpdates([XTZ_USD_ID]);
344-
if (baselinePrice > updatedPrice) {
338+
const oneUSD = Math.ceil((1/updatedPrice) * 10000) / 10000; // Round up to four decimals
339+
340+
if (baselinePrice < updatedPrice) {
345341
// Buy
346-
console.log("Price went down; time to buy");
347-
const oneUSD = Math.ceil((1/updatedPrice) * 100) / 100; // Round up to two decimals
342+
console.log("Price of USD relative to XTZ went down; time to buy");
348343
console.log("Sending", oneUSD, "XTZ (about one USD)");
349344
const buyHash = await contract.write.buy(
350345
[[`0x${priceFeedUpdateData.binary.data[0]}`]] as any,
351346
{ value: parseEther(oneUSD.toString()), gas: 30000000n },
352347
);
353348
await publicClient.waitForTransactionReceipt({ hash: buyHash });
354-
console.log("Bought one token");
355-
} else if (baselinePrice < updatedPrice) {
356-
console.log("Price went up; time to sell");
349+
console.log("Bought one token for", oneUSD, "XTZ");
350+
} else if (baselinePrice > updatedPrice) {
351+
console.log("Price of USD relative to XTZ went up; time to sell");
357352
// Sell
358353
const sellHash = await contract.write.sell(
359354
[[`0x${priceFeedUpdateData.binary.data[0]}`]] as any,
360355
{ gas: 30000000n }
361356
);
362357
await publicClient.waitForTransactionReceipt({ hash: sellHash });
363-
console.log("Sold one token");
358+
console.log("Sold one token for", oneUSD, "XTZ");
364359
}
365360
balance = await getBalance();
366361
}
367-
368-
// Cash out
369-
console.log("Cashing out");
370-
// Call the cashout function to retrieve the XTZ you've sent to the contract (for tutorial purposes)
371-
await contract.write.cashout();
372362
}
373363

374364
run();
365+
375366
```
376367

377368
To run the off-chain application, run the command `npx ts-node src/checkRate.ts`.
378369
The application calls the `buy` and `sell` function based on real-time data from Hermes.
379370
Here is the output from a sample run:
380371

381372
```
382-
Baseline price: 0.53016063
383-
Price changed: 0.53005698
384-
Price went down; time to buy
385-
Sending 1.89 XTZ (about one USD)
386-
Bought one more token
373+
Starting balance: 0
374+
Initializing account with 5 tez
375+
Initialized account. New balance is 5
376+
377+
378+
Iteration 0
379+
Baseline price: 0.5179437100000001 USD to 1 XTZ
380+
Or 1.9308 XTZ to 1 USD
381+
Price changed: 0.5177393 USD to 1 XTZ
382+
Price of USD relative to XTZ went up; time to sell
383+
Sold one token for 1.9315 XTZ
384+
385+
386+
Iteration 1
387+
Baseline price: 0.51764893 USD to 1 XTZ
388+
Or 1.9319 XTZ to 1 USD
389+
Price changed: 0.51743925 USD to 1 XTZ
390+
Price of USD relative to XTZ went up; time to sell
391+
Sold one token for 1.9326 XTZ
387392
388393
389394
Iteration 2
390-
Baseline price: 0.52988309
391-
Price changed: 0.53
392-
Price went up; time to sell
393-
Sold one token
395+
Baseline price: 0.51749921 USD to 1 XTZ
396+
Or 1.9324 XTZ to 1 USD
397+
Price changed: 0.51762153 USD to 1 XTZ
398+
Price of USD relative to XTZ went down; time to buy
399+
Sending 1.932 XTZ (about one USD)
400+
Bought one token for 1.932 XTZ
394401
395402
396403
Iteration 3
397-
Baseline price: 0.53
398-
Price changed: 0.53010189
399-
Price went up; time to sell
400-
Sold one token
404+
Baseline price: 0.51766628 USD to 1 XTZ
405+
Or 1.9318 XTZ to 1 USD
406+
Price changed: 0.51781075 USD to 1 XTZ
407+
Price of USD relative to XTZ went down; time to buy
408+
Sending 1.9313 XTZ (about one USD)
409+
Bought one token for 1.9313 XTZ
401410
402411
403412
Iteration 4
404-
Baseline price: 0.53015637
405-
Price changed: 0.52978122
406-
Price went down; time to buy
407-
Sending 1.89 XTZ (about one USD)
408-
Bought one token
409-
410-
Cashing out
413+
Baseline price: 0.51786312 USD to 1 XTZ
414+
Or 1.9311 XTZ to 1 USD
415+
Price changed: 0.51770622 USD to 1 XTZ
416+
Price of USD relative to XTZ went up; time to sell
417+
Sold one token for 1.9316 XTZ
411418
```
412419

413420
Now you can use the pricing data in the contract from off-chain applications.

docs/tutorials/oracles/environment.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,13 +81,13 @@ Before you begin, make sure that you have these programs installed:
8181
--fund $ADDRESS
8282
```
8383

84-
This command starts the node in sandbox mode and sends 10,000 to your address.
84+
This command starts the node in sandbox mode and sends 10,000 XTZ to your address.
8585
This sandbox state starts with the current state of Etherlink Testnet but is a separate environment, so you can't use it to deploy contracts or make transactions on Testnet.
8686

8787
1. Wait for the node to download teh snapshot of Etherlink Testnet and synchronize with the current state.
8888
This can take a few minutes depending on your connection and how old the most recent snapshot is.
8989

90-
The sandbox environment is ready when the EVM node's log logs the level of the new head block, as in this example:
90+
The sandbox environment is ready when the EVM node's log shows the level of the new head block, as in this example:
9191

9292
```
9393
Jun 16 14:26:32.041 NOTICE │ head is now 19809131, applied in 10.681ms
@@ -115,3 +115,5 @@ This can take a few minutes depending on your connection and how old the most re
115115
As with Ethereum, Etherlink records its native token (XTZ) in units of 10^18, also referred to as wei.
116116

117117
Now you can use Foundry to work with Etherlink in a local sandbox environment.
118+
In the next section, you will create a contract and deploy it to this sandbox.
119+
Continue to [Part 2: Getting information from the Pyth oracle](/tutorials/oracles/get_data).

docs/tutorials/oracles/get_data.md

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,18 @@ title: "Part 2: Getting information from the Pyth oracle"
44

55
Getting price information from the Pyth oracle takes a few steps:
66

7-
1. The off-chain caller gets current price data from Hermes, Pyth's service that listens for price updates and provides them to off-chain applications via a REST API.
7+
1. The off-chain caller gets price update data from Hermes, Pyth's service that listens for price updates and provides them to off-chain applications via a REST API.
8+
This data contains the information that Pyth needs to provide a current price to on-chain applications.
89

9-
1. The off-chain caller uses that price data to calculate the fee that Pyth charges to provide that price data to smart contracts.
10+
1. The off-chain caller sends that update data to the smart contract.
1011

11-
1. The off-chain caller sends that price data and the fee to the smart contract.
12+
1. Based on the update data, smart contract calculates the fee that Pyth charges to provide that price data to smart contracts.
1213

1314
1. The smart contract calls Pyth's on-chain application and pays the fee.
1415

1516
1. The Pyth on-chain application gets the price data from Hermes and provides it to the smart contract.
1617

17-
1. The smart contract stores the price data.
18+
1. The smart contract stores the updated price data.
1819

1920
## Getting oracle data in a contract
2021

@@ -23,13 +24,13 @@ Follow these steps to create a contract that uses the Pyth oracle in the way des
2324
1. Create a directory to store your work in:
2425

2526
```bash
26-
mkdir -p etherlink_pyth/contracts
27-
cd etherlink_pyth/contracts
27+
mkdir -p etherlink_defi/contracts
28+
cd etherlink_defi/contracts
2829
```
2930

30-
Later you will create a folder named `etherlink_pyth/app` to store the off-chain portion of the tutorial application.
31+
Later you will create a folder named `etherlink_defi/app` to store the off-chain portion of the tutorial application.
3132

32-
1. Create an empty Foundry project in the `etherlink_pyth/contracts` folder:
33+
1. Create an empty Foundry project in the `etherlink_defi/contracts` folder:
3334

3435
```bash
3536
forge init
@@ -95,7 +96,7 @@ Follow these steps to create a contract that uses the Pyth oracle in the way des
9596
}
9697
```
9798

98-
This function receives price data that an off-chain caller got from Hermes.
99+
This function receives price update data that an off-chain caller got from Hermes.
99100
It uses this data and the Pyth on-chain application to get the cost of the on-chain price update.
100101
Finally, it passes the fee and the price data to Pyth.
101102

@@ -186,7 +187,7 @@ contract TutorialContract {
186187
## Testing the data
187188

188189
To test the contract and how it gets data from Pyth, you can write Foundry tests that use a mocked version of Pyth.
189-
You set the exchange rate in the mocked version of Pyth and use tests to verify that the contract gets that exchange rate correctly.
190+
In these steps, you set the exchange rate in the mocked version of Pyth and use tests to verify that the contract gets that exchange rate correctly:
190191

191192
1. Create a test file named `test/TutorialContract.t.sol` and open it in any text editor.
192193

@@ -220,7 +221,7 @@ You set the exchange rate in the mocked version of Pyth and use tests to verify
220221
This stub imports your contract and creates an instance of it in the`setUp` function, which runs automatically before each test.
221222
It creates a mocked version of Pyth for the purposes of the test.
222223

223-
1. Replace the `// Test functions go here` with this utility function:
224+
1. Replace the `// Test functions go here` comment with this utility function:
224225

225226
```solidity
226227
// Utility function to create a mocked Pyth price update for the test
@@ -466,7 +467,7 @@ The addresses of Pyth applications are listed at https://docs.pyth.network/price
466467

467468
1. Set the `DEPLOYMENT_ADDRESS` environment variable to the address of the deployed contract.
468469

469-
1. Call the contract by getting the latest Hermes data, sending it and the update fee to the `updateAndGet` function, and then calling the `getPrice` function, as described in the next steps.
470+
1. Call the contract by getting update data from Hermes, sending it and the update fee to the `updateAndGet` function, and then calling the `getPrice` function, as described in the next steps.
470471

471472
Because the price data goes stale after 60 seconds, you need to run these commands within 60 seconds.
472473
You can put them in a single shell script to run at once or you can copy and paste them quickly.
@@ -512,9 +513,11 @@ The addresses of Pyth applications are listed at https://docs.pyth.network/price
512513
For example, assume that the response is `0x0000000000000000000000000000000000000000000000001950f85eb8a92984`.
513514
This hex number corresponds to 1824230934793759108 wei, or about 1.82 XTZ.
514515
This means that 1.82 XTZ equals 1 USD, so one XTZ is equal to 1 / 1.82 USD, or about 0.55 USD.
516+
You can paste the hex number that you get in response to a hex to decimal converter such as https://www.rapidtables.com/convert/number/hex-to-decimal.html.
515517

516518
If the commands failed, verify that the `curl` command to get the Hermes data succeeds; it should write a long string of hex code to the file `price_update.txt`.
517519
Also make sure that the environment variables are correct and that you are copying and pasting the commands into your terminal correctly.
518520

519521
Now you have a smart contract that can get up-to-date price information from Pyth.
520-
In the next section, you expand the smart contract to buy and sell based on that information.
522+
In the next section, you expand the smart contract to buy and sell based on that information.
523+
Continue to [Part 3: Using price data to buy and sell tokens](/tutorials/oracles/tokens).

0 commit comments

Comments
 (0)