[pice-pusher] add injective pusher (#633)

* add injective pusher

* remove cwPriceServiceConnection
This commit is contained in:
Dev Kalra 2023-02-27 17:05:12 +05:30 committed by GitHub
parent 7c728a5718
commit 20e8e15cef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 150 additions and 20 deletions

View File

@ -10,7 +10,7 @@
"license": "Apache-2.0",
"dependencies": {
"@injectivelabs/sdk-ts": "^1.0.457",
"@pythnetwork/pyth-common-js": "^1.2.0",
"@pythnetwork/pyth-common-js": "^1.4.0",
"@pythnetwork/pyth-evm-js": "^1.1.0",
"@pythnetwork/pyth-sdk-solidity": "^2.2.0",
"@truffle/hdwallet-provider": "^2.1.3",
@ -2501,11 +2501,11 @@
"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
},
"node_modules/@pythnetwork/pyth-common-js": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@pythnetwork/pyth-common-js/-/pyth-common-js-1.2.0.tgz",
"integrity": "sha512-GVBacwqMGcZC3H+Ol7DtK86HZlMvY3OujRnJs81WZGWEHWXJM5scot0ZGGqf7AC4U+LJbGLlN0uxR20Q/S7ixg==",
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@pythnetwork/pyth-common-js/-/pyth-common-js-1.4.0.tgz",
"integrity": "sha512-ilK+0/+tivMVPMIFmup+UfUHklhsS2fqofZxS2+XCn4WBJfI0lIKtiAaBVjV7WmzmC2mDjujcTCDn4RbqpLVqg==",
"dependencies": {
"@pythnetwork/pyth-sdk-js": "^1.1.0",
"@pythnetwork/pyth-sdk-js": "^1.2.0",
"@types/ws": "^8.5.3",
"axios": "^0.26.1",
"axios-retry": "^3.2.4",
@ -2547,9 +2547,9 @@
}
},
"node_modules/@pythnetwork/pyth-sdk-js": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@pythnetwork/pyth-sdk-js/-/pyth-sdk-js-1.1.0.tgz",
"integrity": "sha512-IfZI/D+7HiA01TfzuA7Fh0SMhsE+hZWoI1pt48G+XMbNkXhiZG4lSQJRsnquSEY06YAFcAX2D66cFtV6BHy8IA=="
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@pythnetwork/pyth-sdk-js/-/pyth-sdk-js-1.2.0.tgz",
"integrity": "sha512-grh6YCkp/nH73ACNu+Mew64lLVgz6egVBJm8JvdNkRggWkUn1PE4ZvV/6ceTIui5OhI369qzMCkldiAlIMBjnQ=="
},
"node_modules/@pythnetwork/pyth-sdk-solidity": {
"version": "2.2.0",
@ -14909,11 +14909,11 @@
"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
},
"@pythnetwork/pyth-common-js": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@pythnetwork/pyth-common-js/-/pyth-common-js-1.2.0.tgz",
"integrity": "sha512-GVBacwqMGcZC3H+Ol7DtK86HZlMvY3OujRnJs81WZGWEHWXJM5scot0ZGGqf7AC4U+LJbGLlN0uxR20Q/S7ixg==",
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@pythnetwork/pyth-common-js/-/pyth-common-js-1.4.0.tgz",
"integrity": "sha512-ilK+0/+tivMVPMIFmup+UfUHklhsS2fqofZxS2+XCn4WBJfI0lIKtiAaBVjV7WmzmC2mDjujcTCDn4RbqpLVqg==",
"requires": {
"@pythnetwork/pyth-sdk-js": "^1.1.0",
"@pythnetwork/pyth-sdk-js": "^1.2.0",
"@types/ws": "^8.5.3",
"axios": "^0.26.1",
"axios-retry": "^3.2.4",
@ -14943,9 +14943,9 @@
}
},
"@pythnetwork/pyth-sdk-js": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@pythnetwork/pyth-sdk-js/-/pyth-sdk-js-1.1.0.tgz",
"integrity": "sha512-IfZI/D+7HiA01TfzuA7Fh0SMhsE+hZWoI1pt48G+XMbNkXhiZG4lSQJRsnquSEY06YAFcAX2D66cFtV6BHy8IA=="
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@pythnetwork/pyth-sdk-js/-/pyth-sdk-js-1.2.0.tgz",
"integrity": "sha512-grh6YCkp/nH73ACNu+Mew64lLVgz6egVBJm8JvdNkRggWkUn1PE4ZvV/6ceTIui5OhI369qzMCkldiAlIMBjnQ=="
},
"@pythnetwork/pyth-sdk-solidity": {
"version": "2.2.0",

View File

@ -44,7 +44,7 @@
},
"dependencies": {
"@injectivelabs/sdk-ts": "^1.0.457",
"@pythnetwork/pyth-common-js": "^1.2.0",
"@pythnetwork/pyth-common-js": "^1.4.0",
"@pythnetwork/pyth-evm-js": "^1.1.0",
"@pythnetwork/pyth-sdk-solidity": "^2.2.0",
"@truffle/hdwallet-provider": "^2.1.3",

View File

@ -103,11 +103,18 @@ async function injectiveRun() {
{ pollingFrequency: argv.pollingFrequency }
);
const injectivePricePusher = new InjectivePricePusher(
connection,
argv.pythContract,
argv.endpoint,
fs.readFileSync(argv.mnemonicFile, "utf-8").trim()
);
const handler = new Controller(
priceConfigs,
pythPriceListener,
injectivePriceListener,
new InjectivePricePusher(),
injectivePricePusher,
{
cooldownDuration: argv.cooldownDuration,
}

View File

@ -1,8 +1,18 @@
import { HexString } from "@pythnetwork/pyth-common-js";
import { HexString, PriceServiceConnection } from "@pythnetwork/pyth-common-js";
import { ChainPricePusher, PriceInfo, PriceListener } from "./interface";
import { DurationInSeconds } from "./utils";
import { PriceConfig } from "./price-config";
import { ChainGrpcWasmApi } from "@injectivelabs/sdk-ts";
import {
ChainGrpcAuthApi,
ChainGrpcWasmApi,
DEFAULT_STD_FEE,
MsgExecuteContract,
Msgs,
PrivateKey,
TxGrpcClient,
TxResponse,
createTransactionFromMsg,
} from "@injectivelabs/sdk-ts";
type PriceQueryResponse = {
price_feed: {
@ -16,6 +26,11 @@ type PriceQueryResponse = {
};
};
type UpdateFeeResponse = {
denom: string;
amount: string;
};
// this use price without leading 0x
// FIXME: implement common methods in the parent class
export class InjectivePriceListener implements PriceListener {
@ -103,10 +118,118 @@ export class InjectivePriceListener implements PriceListener {
}
export class InjectivePricePusher implements ChainPricePusher {
private wallet: PrivateKey;
constructor(
private priceServiceConnection: PriceServiceConnection,
private pythContract: string,
private grpcEndpoint: string,
mnemonic: string
) {
this.wallet = PrivateKey.fromMnemonic(mnemonic);
}
private injectiveAddress(): string {
return this.wallet.toBech32();
}
private async signAndBroadcastMsg(
msg: Msgs,
fee = DEFAULT_STD_FEE
): Promise<TxResponse> {
const chainGrpcAuthApi = new ChainGrpcAuthApi(this.grpcEndpoint);
const account = await chainGrpcAuthApi.fetchAccount(
this.injectiveAddress()
);
const { signBytes, txRaw } = createTransactionFromMsg({
sequence: account.baseAccount.sequence,
accountNumber: account.baseAccount.accountNumber,
message: msg,
chainId: "injective-888",
fee,
pubKey: this.wallet.toPublicKey().toBase64(),
});
const sig = await this.wallet.sign(Buffer.from(signBytes));
/** Append Signatures */
txRaw.setSignaturesList([sig]);
const txService = new TxGrpcClient(this.grpcEndpoint);
const txResponse = await txService.broadcast(txRaw);
return txResponse;
}
async getPriceFeedUpdateObject(priceIds: string[]): Promise<any> {
const vaas = await this.priceServiceConnection.getLatestVaas(priceIds);
return {
update_price_feeds: {
data: vaas,
},
};
}
async updatePriceFeed(
priceIds: string[],
pubTimesToPush: number[]
): Promise<void> {
console.log("dummy pushed");
if (priceIds.length === 0) {
return;
}
if (priceIds.length !== pubTimesToPush.length)
throw new Error("Invalid arguments");
let priceFeedUpdateObject;
try {
// get the latest VAAs for updatePriceFeed and then push them
priceFeedUpdateObject = await this.getPriceFeedUpdateObject(priceIds);
} catch (e) {
console.error("Error fetching the latest vaas to push");
console.error(e);
return;
}
let updateFeeQueryResponse: UpdateFeeResponse;
try {
const api = new ChainGrpcWasmApi(this.grpcEndpoint);
const { data } = await api.fetchSmartContractState(
this.pythContract,
Buffer.from(
JSON.stringify({
get_update_fee: {
vaas: priceFeedUpdateObject.update_price_feeds.data,
},
})
).toString("base64")
);
const json = Buffer.from(data as string, "base64").toString();
updateFeeQueryResponse = JSON.parse(json);
} catch (e) {
console.error("Error fetching update fee");
console.error(e);
return;
}
// TODO: add specific error messages
try {
const executeMsg = MsgExecuteContract.fromJSON({
sender: this.injectiveAddress(),
contractAddress: this.pythContract,
msg: priceFeedUpdateObject,
funds: [updateFeeQueryResponse],
});
const rs = await this.signAndBroadcastMsg(executeMsg);
if (rs.code !== 0) throw new Error("Error: transaction failed");
console.log("Succesfully broadcasted txHash:", rs.txHash);
} catch (e) {
console.error("Error executing messages");
console.log(e);
}
}
}