[price-pusher] support for aptos (#815)

* aptos price listener

* price pusher aptos

* add comment

* update package lock

* remove eslint disable comments

* bump version

* npm i at root

* update readme

* address feedback

* update readme

* json fix
This commit is contained in:
Dev Kalra 2023-05-15 21:14:28 +05:30 committed by GitHub
parent 1dbc592836
commit 3fc996d6f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 425 additions and 118 deletions

227
package-lock.json generated
View File

@ -11514,6 +11514,10 @@
"resolved": "target_chains/cosmwasm/tools",
"link": true
},
"node_modules/@pythnetwork/eth-oracle-swap-example-frontend": {
"resolved": "target_chains/ethereum/examples/oracle_swap/app",
"link": true
},
"node_modules/@pythnetwork/price-pusher": {
"resolved": "price_pusher",
"link": true
@ -21067,9 +21071,9 @@
"dev": true
},
"node_modules/aptos": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/aptos/-/aptos-1.6.0.tgz",
"integrity": "sha512-5khjDwrDeNMDBFRcZAmETW20D+V2AqTdsgqkh6bvvl70BtRXdkitN0saM05gf1rK3atnO9PyUKO8iRaBDG5qtA==",
"version": "1.8.5",
"resolved": "https://registry.npmjs.org/aptos/-/aptos-1.8.5.tgz",
"integrity": "sha512-iQxliWesNHjGQ5YYXCyss9eg4+bDGQWqAZa73vprqGQ9tungK0cRjUI2fmnp63Ed6UG6rurHrL+b0ckbZAOZZQ==",
"dependencies": {
"@noble/hashes": "1.1.3",
"@scure/bip39": "1.1.0",
@ -50989,10 +50993,6 @@
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"node_modules/@pythnetwork/eth-oracle-swap-example-frontend": {
"resolved": "target_chains/ethereum/examples/oracle_swap/app",
"link": true
},
"node_modules/traverse-chain": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/traverse-chain/-/traverse-chain-0.1.0.tgz",
@ -55110,13 +55110,14 @@
},
"price_pusher": {
"name": "@pythnetwork/price-pusher",
"version": "5.0.0",
"version": "5.1.0",
"license": "Apache-2.0",
"dependencies": {
"@injectivelabs/sdk-ts": "1.10.72",
"@pythnetwork/price-service-client": "*",
"@pythnetwork/pyth-sdk-solidity": "*",
"@truffle/hdwallet-provider": "^2.1.3",
"aptos": "^1.8.5",
"joi": "^17.6.0",
"web3": "^1.8.1",
"web3-eth-contract": "^1.8.1",
@ -57475,6 +57476,7 @@
}
},
"target_chains/ethereum/examples/oracle_swap/app": {
"name": "@pythnetwork/eth-oracle-swap-example-frontend",
"version": "0.1.0",
"dependencies": {
"@pythnetwork/pyth-evm-js": "*",
@ -66433,6 +66435,107 @@
}
}
},
"@pythnetwork/eth-oracle-swap-example-frontend": {
"version": "file:target_chains/ethereum/examples/oracle_swap/app",
"requires": {
"@pythnetwork/pyth-evm-js": "*",
"@pythnetwork/pyth-sdk-solidity": "*",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"@types/jest": "^27.5.2",
"@types/node": "^16.11.64",
"@types/react": "^18.0.21",
"@types/react-dom": "^18.0.6",
"buffer": "^6.0.3",
"ethers": "^5.7.2",
"metamask-react": "^2.4.0",
"prettier": "^2.7.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"typescript": "^4.8.4",
"web-vitals": "^2.1.4",
"web3": "^1.8.0"
},
"dependencies": {
"@types/jest": {
"version": "27.5.2",
"resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.5.2.tgz",
"integrity": "sha512-mpT8LJJ4CMeeahobofYWIjFo0xonRS/HfxnVEPMPFSQdGUt1uHCnoPT7Zhb+sjDU2wz0oKV0OLUR0WzrHNgfeA==",
"requires": {
"jest-matcher-utils": "^27.0.0",
"pretty-format": "^27.0.0"
}
},
"@types/node": {
"version": "16.18.28",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.28.tgz",
"integrity": "sha512-SNMfiPqsiPoYfmyi+2qnDO4nZyMIOCab/CW+Slcml0lhIzkOizYzWtt/A7tgB3TSitd+YJKi8fSC2Cpm/VCp7A=="
},
"ansi-styles": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="
},
"buffer": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
"requires": {
"base64-js": "^1.3.1",
"ieee754": "^1.2.1"
}
},
"diff-sequences": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz",
"integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ=="
},
"jest-diff": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz",
"integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==",
"requires": {
"chalk": "^4.0.0",
"diff-sequences": "^27.5.1",
"jest-get-type": "^27.5.1",
"pretty-format": "^27.5.1"
}
},
"jest-get-type": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz",
"integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw=="
},
"jest-matcher-utils": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz",
"integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==",
"requires": {
"chalk": "^4.0.0",
"jest-diff": "^27.5.1",
"jest-get-type": "^27.5.1",
"pretty-format": "^27.5.1"
}
},
"pretty-format": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
"integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
"requires": {
"ansi-regex": "^5.0.1",
"ansi-styles": "^5.0.0",
"react-is": "^17.0.1"
}
},
"react-is": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
}
}
},
"@pythnetwork/price-pusher": {
"version": "file:price_pusher",
"requires": {
@ -66445,6 +66548,7 @@
"@types/yargs": "^17.0.10",
"@typescript-eslint/eslint-plugin": "^5.20.0",
"@typescript-eslint/parser": "^5.20.0",
"aptos": "^1.8.5",
"eslint": "^8.13.0",
"jest": "^27.5.1",
"joi": "^17.6.0",
@ -77292,9 +77396,9 @@
"dev": true
},
"aptos": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/aptos/-/aptos-1.6.0.tgz",
"integrity": "sha512-5khjDwrDeNMDBFRcZAmETW20D+V2AqTdsgqkh6bvvl70BtRXdkitN0saM05gf1rK3atnO9PyUKO8iRaBDG5qtA==",
"version": "1.8.5",
"resolved": "https://registry.npmjs.org/aptos/-/aptos-1.8.5.tgz",
"integrity": "sha512-iQxliWesNHjGQ5YYXCyss9eg4+bDGQWqAZa73vprqGQ9tungK0cRjUI2fmnp63Ed6UG6rurHrL+b0ckbZAOZZQ==",
"requires": {
"@noble/hashes": "1.1.3",
"@scure/bip39": "1.1.0",
@ -101582,107 +101686,6 @@
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"@pythnetwork/eth-oracle-swap-example-frontend": {
"version": "file:target_chains/ethereum/examples/oracle_swap/app",
"requires": {
"@pythnetwork/pyth-evm-js": "*",
"@pythnetwork/pyth-sdk-solidity": "*",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"@types/jest": "^27.5.2",
"@types/node": "^16.11.64",
"@types/react": "^18.0.21",
"@types/react-dom": "^18.0.6",
"buffer": "^6.0.3",
"ethers": "^5.7.2",
"metamask-react": "^2.4.0",
"prettier": "^2.7.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"typescript": "^4.8.4",
"web-vitals": "^2.1.4",
"web3": "^1.8.0"
},
"dependencies": {
"@types/jest": {
"version": "27.5.2",
"resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.5.2.tgz",
"integrity": "sha512-mpT8LJJ4CMeeahobofYWIjFo0xonRS/HfxnVEPMPFSQdGUt1uHCnoPT7Zhb+sjDU2wz0oKV0OLUR0WzrHNgfeA==",
"requires": {
"jest-matcher-utils": "^27.0.0",
"pretty-format": "^27.0.0"
}
},
"@types/node": {
"version": "16.18.28",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.28.tgz",
"integrity": "sha512-SNMfiPqsiPoYfmyi+2qnDO4nZyMIOCab/CW+Slcml0lhIzkOizYzWtt/A7tgB3TSitd+YJKi8fSC2Cpm/VCp7A=="
},
"ansi-styles": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="
},
"buffer": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
"requires": {
"base64-js": "^1.3.1",
"ieee754": "^1.2.1"
}
},
"diff-sequences": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz",
"integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ=="
},
"jest-diff": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz",
"integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==",
"requires": {
"chalk": "^4.0.0",
"diff-sequences": "^27.5.1",
"jest-get-type": "^27.5.1",
"pretty-format": "^27.5.1"
}
},
"jest-get-type": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz",
"integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw=="
},
"jest-matcher-utils": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz",
"integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==",
"requires": {
"chalk": "^4.0.0",
"jest-diff": "^27.5.1",
"jest-get-type": "^27.5.1",
"pretty-format": "^27.5.1"
}
},
"pretty-format": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
"integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
"requires": {
"ansi-regex": "^5.0.1",
"ansi-styles": "^5.0.0",
"react-is": "^17.0.1"
}
},
"react-is": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
}
}
},
"traverse-chain": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/traverse-chain/-/traverse-chain-0.1.0.tgz",

View File

@ -71,6 +71,14 @@ npm run start -- injective --grpc-endpoint https://grpc-endpoint.com \
[--pushing-frequency 10] \
[--polling-frequency 5] \
# For Aptos
npm run start -- aptos --endpoint https://fullnode.testnet.aptoslabs.com/v1 \
--pyth-contract-address 0x7e783b349d3e89cf5931af376ebeadbfab855b3fa239b7ada8f5a92fbea6b387 --price-service-endpoint "https://xc-testnet.pyth.network" \
--price-config-file "./price-config.testnet.sample.yaml" \
--mnemonic-file "path/to/mnemonic.txt" \
[--pushing-frequency 10] \
[--polling-frequency 5] \
# Or, run the price pusher docker image instead of building from the source
docker run public.ecr.aws/pyth-network/xc-price-pusher:v<version> -- <above-arguments>

View File

@ -0,0 +1,7 @@
{
"endpoint": "https://fullnode.testnet.aptoslabs.com/v1",
"pyth-contract-address": "0x7e783b349d3e89cf5931af376ebeadbfab855b3fa239b7ada8f5a92fbea6b387",
"price-service-endpoint": "https://xc-testnet.pyth.network",
"mnemonic-file": "./mnemonic",
"price-config-file": "./price-config.testnet.sample.yaml"
}

View File

@ -1,6 +1,6 @@
{
"name": "@pythnetwork/price-pusher",
"version": "5.0.0",
"version": "5.1.0",
"description": "Pyth Price Pusher",
"homepage": "https://pyth.network",
"main": "lib/index.js",
@ -55,6 +55,7 @@
"@pythnetwork/price-service-client": "*",
"@pythnetwork/pyth-sdk-solidity": "*",
"@truffle/hdwallet-provider": "^2.1.3",
"aptos": "^1.8.5",
"joi": "^17.6.0",
"web3": "^1.8.1",
"web3-eth-contract": "^1.8.1",

View File

@ -0,0 +1,190 @@
import {
ChainPriceListener,
IPricePusher,
PriceInfo,
PriceItem,
} from "../interface";
import { AptosAccount, AptosClient, TxnBuilderTypes } from "aptos";
import { DurationInSeconds } from "../utils";
import { PriceServiceConnection } from "@pythnetwork/price-service-client";
import { PushAttempt } from "../common";
export class AptosPriceListener extends ChainPriceListener {
constructor(
private pythModule: string,
private endpoint: string,
priceItems: PriceItem[],
config: {
pollingFrequency: DurationInSeconds;
}
) {
super("aptos", config.pollingFrequency, priceItems);
}
async getOnChainPriceInfo(priceId: string): Promise<PriceInfo | undefined> {
try {
const client = new AptosClient(this.endpoint);
const res = await client.getAccountResource(
this.pythModule,
`${this.pythModule}::state::LatestPriceInfo`
);
// This depends upon the pyth contract storage on Aptos and should not be undefined.
// If undefined, there has been some change and we would need to update accordingly.
const handle = (res.data as any).info.handle;
const priceItemRes = await client.getTableItem(handle, {
key_type: `${this.pythModule}::price_identifier::PriceIdentifier`,
value_type: `${this.pythModule}::price_info::PriceInfo`,
key: {
bytes: priceId,
},
});
const multiplier =
priceItemRes.price_feed.price.price.negative === true ? -1 : 1;
const price =
multiplier * Number(priceItemRes.price_feed.price.price.magnitude);
console.log(
`Polled an Aptos on-chain price for feed ${this.priceIdToAlias.get(
priceId
)} (${priceId}).`
);
return {
price: price.toString(),
conf: priceItemRes.price_feed.price.conf,
publishTime: Number(priceItemRes.price_feed.price.timestamp),
};
} catch (e) {
console.error(
`Polling Aptos on-chain price for ${priceId} failed. Error:`
);
console.error(e);
return undefined;
}
}
}
export class AptosPricePusher implements IPricePusher {
private lastPushAttempt: PushAttempt | undefined;
private readonly accountHDPath = "m/44'/637'/0'/0'/0'";
constructor(
private priceServiceConnection: PriceServiceConnection,
private pythContractAddress: string,
private endpoint: string,
private mnemonic: string,
private overrideGasPriceMultiplier: number
) {}
/**
* Gets price update data which then can be submitted to the Pyth contract to update the prices.
* This will throw an axios error if there is a network problem or the price service returns a non-ok response (e.g: Invalid price ids)
*
* @param priceIds Array of hex-encoded price ids.
* @returns Array of price update data.
*/
async getPriceFeedsUpdateData(priceIds: string[]): Promise<number[][]> {
// Fetch the latest price feed update VAAs from the price service
const latestVaas = await this.priceServiceConnection.getLatestVaas(
priceIds
);
return latestVaas.map((vaa) => Array.from(Buffer.from(vaa, "base64")));
}
async updatePriceFeed(
priceIds: string[],
pubTimesToPush: number[]
): Promise<void> {
if (priceIds.length === 0) {
return;
}
if (priceIds.length !== pubTimesToPush.length)
throw new Error("Invalid arguments");
let priceFeedUpdateData;
try {
// get the latest VAAs for updatePriceFeed and then push them
priceFeedUpdateData = await this.getPriceFeedsUpdateData(priceIds);
} catch (e) {
console.error("Error fetching the latest vaas to push");
console.error(e);
return;
}
try {
const account = AptosAccount.fromDerivePath(
this.accountHDPath,
this.mnemonic
);
const client = new AptosClient(this.endpoint);
const rawTx = await client.generateTransaction(account.address(), {
function: `${this.pythContractAddress}::pyth::update_price_feeds_if_fresh_with_funder`,
type_arguments: [],
arguments: [
priceFeedUpdateData,
priceIds.map((priceId) => Buffer.from(priceId, "hex")),
pubTimesToPush,
],
});
const simulation = await client.simulateTransaction(account, rawTx, {
estimateGasUnitPrice: true,
estimateMaxGasAmount: true,
estimatePrioritizedGasUnitPrice: true,
});
// Transactions on Aptos can be prioritized by paying a higher gas unit price.
// We are storing the gas unit price paid for the last transaction.
// If that transaction is not added to the block, we are increasing the gas unit price
// by multiplying the old gas unit price with `this.overrideGasPriceMultiplier`.
// After which we are sending a transaction with the same sequence number as the last
// transaction. Since they have the same sequence number only one of them will be added to
// the block and we won't be paying fees twice.
let gasUnitPrice = Number(simulation[0].gas_unit_price);
if (
this.lastPushAttempt !== undefined &&
Number(simulation[0].sequence_number) === this.lastPushAttempt.nonce
) {
const newGasUnitPrice = Number(
this.lastPushAttempt.gasPrice * this.overrideGasPriceMultiplier
);
if (gasUnitPrice < newGasUnitPrice) gasUnitPrice = newGasUnitPrice;
}
const gasUsed = Number(simulation[0].gas_used) * 1.5;
const maxGasAmount = Number(gasUnitPrice * gasUsed);
const rawTxWithFee = new TxnBuilderTypes.RawTransaction(
rawTx.sender,
rawTx.sequence_number,
rawTx.payload,
BigInt(maxGasAmount.toFixed()),
BigInt(gasUnitPrice.toFixed()),
rawTx.expiration_timestamp_secs,
rawTx.chain_id
);
const signedTx = await client.signTransaction(account, rawTxWithFee);
const pendingTx = await client.submitTransaction(signedTx);
console.log("Succesfully broadcasted txHash:", pendingTx.hash);
// Update lastAttempt
this.lastPushAttempt = {
nonce: Number(pendingTx.sequence_number),
gasPrice: gasUnitPrice,
};
return;
} catch (e: any) {
console.error("Error executing messages");
console.log(e);
return;
}
}
}

View File

@ -0,0 +1,96 @@
import { PriceServiceConnection } from "@pythnetwork/price-service-client";
import * as options from "../options";
import { readPriceConfigFile } from "../price-config";
import fs from "fs";
import { PythPriceListener } from "../pyth-price-listener";
import { Controller } from "../controller";
import { Options } from "yargs";
import { AptosPriceListener, AptosPricePusher } from "./aptos";
export default {
command: "aptos",
describe: "run price pusher for aptos",
builder: {
endpoint: {
description:
"RPC endpoint endpoint URL for aptos. The pusher will periodically" +
"poll for updates. The polling interval is configurable via the " +
"`polling-frequency` command-line argument.",
type: "string",
required: true,
} as Options,
"override-gas-price-multiplier": {
description:
"Multiply the gas price by this number if the transaction is not landing to override it. Default 2",
type: "number",
required: false,
default: 2,
} as Options,
...options.priceConfigFile,
...options.priceServiceEndpoint,
...options.mnemonicFile,
...options.pythContractAddress,
...options.pollingFrequency,
...options.pushingFrequency,
},
handler: function (argv: any) {
// FIXME: type checks for this
const {
endpoint,
priceConfigFile,
priceServiceEndpoint,
mnemonicFile,
pythContractAddress,
pushingFrequency,
pollingFrequency,
overrideGasPriceMultiplier,
} = argv;
const priceConfigs = readPriceConfigFile(priceConfigFile);
const priceServiceConnection = new PriceServiceConnection(
priceServiceEndpoint,
{
logger: {
// Log only warnings and errors from the price service client
info: () => undefined,
warn: console.warn,
error: console.error,
debug: () => undefined,
trace: () => undefined,
},
}
);
const mnemonic = fs.readFileSync(mnemonicFile, "utf-8").trim();
const priceItems = priceConfigs.map(({ id, alias }) => ({ id, alias }));
const pythListener = new PythPriceListener(
priceServiceConnection,
priceItems
);
const aptosListener = new AptosPriceListener(
pythContractAddress,
endpoint,
priceItems,
{ pollingFrequency }
);
const aptosPusher = new AptosPricePusher(
priceServiceConnection,
pythContractAddress,
endpoint,
mnemonic,
overrideGasPriceMultiplier
);
const controller = new Controller(
priceConfigs,
pythListener,
aptosListener,
aptosPusher,
{ pushingFrequency }
);
controller.start();
},
};

View File

@ -0,0 +1,4 @@
export type PushAttempt = {
nonce: number;
gasPrice: number;
};

View File

@ -18,6 +18,7 @@ import {
} from "@pythnetwork/price-service-client";
import { CustomGasStation } from "./custom-gas-station";
import { Provider } from "web3/providers";
import { PushAttempt } from "../common";
export class EvmPriceListener extends ChainPriceListener {
private pythContractFactory: PythContractFactory;
@ -117,11 +118,6 @@ export class EvmPriceListener extends ChainPriceListener {
}
}
type PushAttempt = {
nonce: number;
gasPrice: number;
};
export class EvmPricePusher implements IPricePusher {
private customGasStation?: CustomGasStation;
private pythContract: Contract;

View File

@ -3,10 +3,12 @@ import yargs from "yargs";
import { hideBin } from "yargs/helpers";
import injective from "./injective/command";
import evm from "./evm/command";
import aptos from "./aptos/command";
yargs(hideBin(process.argv))
.config("config")
.global("config")
.command(evm)
.command(injective)
.command(aptos)
.help().argv;