Skip to content
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 Gelato web3 function deployment script for redstone oracles #208

Draft
wants to merge 5 commits into
base: LISK-1155-Set-up-RedStone-Push-Oracle-contracts
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .env.devnet
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ L1_RPC_URL=http://localhost:8545
# L2 RPC URL, e.g. Infura, Alchemy, or your own node
L2_RPC_URL=http://localhost:8546

# Provider url for testing web3 function with
PROVIDER_URLS=http://localhost:8546

Comment on lines +64 to +66
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this URL be different than what is L2_RPC_URL? Can we just use L2_RPC_URL without having a new one?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general it would be same. I am not sure where or which library picks this env var and we might have to change the lib code so maybe better to keep it separate (for now)

# *************** SMART CONTRACT VERIFICATION ***************

# Contract verifier - blockscout or etherscan. If not provided, verification will be skipped.
Expand Down
3 changes: 3 additions & 0 deletions .env.mainnet
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ L1_RPC_URL=https://eth.drpc.org
# L2 RPC URL, e.g. Infura, Alchemy, or your own node
L2_RPC_URL=https://rpc.api.lisk.com

# Provider url for testing web3 function with
PROVIDER_URLS=https://rpc.api.lisk.com

# *************** SMART CONTRACT VERIFICATION ***************

# Contract verifier - blockscout or etherscan. If not provided, verification will be skipped.
Expand Down
3 changes: 3 additions & 0 deletions .env.testnet
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ L1_RPC_URL=https://sepolia.drpc.org
# L2 RPC URL, e.g. Infura, Alchemy, or your own node
L2_RPC_URL=https://rpc.sepolia-api.lisk.com

# Provider url for testing web3 function with
PROVIDER_URLS=https://rpc.sepolia-api.lisk.com

# *************** SMART CONTRACT VERIFICATION ***************

# Contract verifier - blockscout or etherscan. If not provided, verification will be skipped.
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,7 @@ mutation_campaign
crytic-export/combined_solc.json
test/fuzzing/coverage/
test/fuzzing/covered.*

# Web3 Functions
node_modules
.tmp
50 changes: 50 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"name": "lens-ai-poc",
"version": "0.0.1",
"description": "Smart Oracle that pushes prices online every hour or when the price difference with the last price is greater or equal than 2%",
"scripts": {
"clean": "rm -rf node_modules",
"format": "prettier --write '*/**/*.*{js,json,md,ts}'",
"format:check": "prettier --check '*/**/*.*{js,json,md,ts}'",
"lint": "eslint --cache . && yarn lint:sol",
"lint:ts": "eslint -c .eslintrc.json --ext \"**/*.ts\" \"**/*.test.ts\"",
"postinstall": "yarn husky install",
"w3f:deploy": "npx w3f deploy web3-functions/index.ts",
"w3f:test": "npx w3f test web3-functions/index.ts --logs --chain-id=4202"
},
"license": "ISC",
"devDependencies": {
"@ethersproject/providers": "5.7.2",
"@gelatonetwork/automate-sdk": "^2.7.0-beta",
"@gelatonetwork/web3-functions-sdk": "^2.0.3",
"@tsconfig/recommended": "1.0.2",
"@typechain/ethers-v5": "^10.2.1",
"@types/chance": "1.1.3",
"@types/mocha": "^10.0.1",
"@types/node": "16.7.10",
"@types/uuid": "9.0.1",
"@typescript-eslint/eslint-plugin": "4.30.0",
"@typescript-eslint/parser": "4.30.0",
"chai": "4.3.7",
"dotenv": "10.0.0",
"eslint": "7.32.0",
"eslint-config-prettier": "8.3.0",
"eslint-plugin-prettier": "4.0.0",
"ethers": "5.7.2",
"husky": "8.0.3",
"lint-staged": "11.1.2",
"prettier": "2.8.8",
"prettier-plugin-solidity": "1.1.3",
"rxjs": "7.8.1",
"ts-node": "10.9.1",
"typechain": "^8.1.1",
"typescript": "5.0.4"
},
"lint-staged": {
"*.*{js,json,md,ts,yml,yaml}": "prettier --write",
"*.*{ts,js}": "eslint -c .eslintrc.json"
},
"dependencies": {
"@redstone-finance/evm-connector": "^0.0.22"
}
}
96 changes: 96 additions & 0 deletions web3-functions/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import {
Web3Function,
Web3FunctionContext,
} from "@gelatonetwork/web3-functions-sdk";
import { BigNumber, Contract } from "ethers";
import { formatBytes32String } from "ethers/lib/utils";
import { WrapperBuilder } from "@redstone-finance/evm-connector";

const ORACLE_ABI = [
"function updateDataFeedsValuesPartial(bytes32[]) public",
"function getValueForDataFeed(bytes32) public view returns (uint256)",
"function getDataTimestampFromLatestUpdate(bytes32) external view returns (uint256)",
"function getLivePrice(bytes32[]) public view returns (uint256[], uint256)",
];

Web3Function.onRun(async (context: Web3FunctionContext) => {
const { userArgs, multiChainProvider } = context;

const provider = multiChainProvider.default();

const oracleAddressPrimaryProd = "0x1038999DCf0A302Cc8Eed72fAeCbf0eEBfC476b0";
const oraclePrimaryProd = new Contract(oracleAddressPrimaryProd, ORACLE_ABI, provider);

const dataFeedIdEth = formatBytes32String("ETH");
const dataFeedIdUsdt = formatBytes32String("USDT");

// Wrap contract with redstone data service
const wrappedOraclePrimaryProd = WrapperBuilder.wrap(oraclePrimaryProd).usingDataService(
{
dataServiceId: "redstone-primary-prod",
uniqueSignersCount: 2,
dataFeeds: ["ETH", "USDT"],
disablePayloadsDryRun: true,
},
["https://oracle-gateway-1.a.redstone.finance"]
);

// Retrieve stored & live prices
const decimals = BigNumber.from(8);
const { livePrices, liveTimestamp } = await wrappedOraclePrimaryProd.getLivePrice([dataFeedIdEth, dataFeedIdUsdt]);
const liveEthPrice: BigNumber = livePrices[0];
const liveUsdtPrice: BigNumber = livePrices[1];
const storedEthPrice: BigNumber = await wrappedOraclePrimaryProd.getValueForDataFeed(dataFeedIdEth);
const storedUsdtPrice: BigNumber = await wrappedOraclePrimaryProd.getValueForDataFeed(dataFeedIdUsdt);
console.log(`Live ETH price: ${liveEthPrice.toString()}`);
console.log(`Live USDT price: ${liveUsdtPrice.toString()}`);
console.log(`Stored ETH price: ${storedEthPrice.toString()}`);
console.log(`Stored USDT price: ${storedUsdtPrice.toString()}`);

// Check price deviation
const priceDeviationEth = computePriceDeviation(liveEthPrice, storedEthPrice, decimals);
const deviationPrct = (priceDeviationEth.toNumber() / 10 ** 8) * 100;
console.log(`Deviation: ${deviationPrct.toFixed(2)}%`);

// Check update time interval
const currentTimestamp = Date.now();
const timeElapsed = (currentTimestamp - liveTimestamp) / (1000 * 60 * 60)

// Only update price if deviation is above 0.5% or last update is more than 6 hours ago
const minDeviation = 0.5;
if (deviationPrct < minDeviation && timeElapsed <= 6) {
return {
canExec: false,
message: `No update: price deviation too small or time elapsed since last update is less than 6 hours`,
};
}

// Craft transaction to update the price on-chain
console.log(`Start price update for ETH`);
const { data } = await wrappedOraclePrimaryProd.populateTransaction.updateDataFeedsValuesPartial(
[dataFeedIdEth]
);
console.log(`Stop price update`);
console.log(`Data: ${data}`);

return {
canExec: true,
callData: [{ to: oracleAddressPrimaryProd, data: data as string }],
};
});

function computePriceDeviation(
newPrice: BigNumber,
oldPrice: BigNumber,
decimals: BigNumber
) {
const zero = BigNumber.from(0);
const ten = BigNumber.from(10);
if (zero.eq(oldPrice)) {
return ten.mul(decimals);
} else if (newPrice.gt(oldPrice)) {
return ((newPrice.sub(oldPrice)).mul(ten).mul(decimals)).div(oldPrice);
} else {
return ((oldPrice.sub(newPrice)).mul(ten).mul(decimals)).div(oldPrice);
}
}
10 changes: 10 additions & 0 deletions web3-functions/schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"web3FunctionVersion": "2.0.0",
"runtime": "js-1.0",
"memory": 128,
"timeout": 30,
"userArgs": {
"currency": "string",
"oracleAddress": "string"
}
}
4 changes: 4 additions & 0 deletions web3-functions/userArgs.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"currency":"LSK",
"oracleAddress":"0x198549B829ba2Cc8c203247f25c3b3bC33df6304"
}
Loading