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

View File

@ -44,7 +44,7 @@
}, },
"dependencies": { "dependencies": {
"@injectivelabs/sdk-ts": "^1.0.457", "@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-evm-js": "^1.1.0",
"@pythnetwork/pyth-sdk-solidity": "^2.2.0", "@pythnetwork/pyth-sdk-solidity": "^2.2.0",
"@truffle/hdwallet-provider": "^2.1.3", "@truffle/hdwallet-provider": "^2.1.3",

View File

@ -103,11 +103,18 @@ async function injectiveRun() {
{ pollingFrequency: argv.pollingFrequency } { pollingFrequency: argv.pollingFrequency }
); );
const injectivePricePusher = new InjectivePricePusher(
connection,
argv.pythContract,
argv.endpoint,
fs.readFileSync(argv.mnemonicFile, "utf-8").trim()
);
const handler = new Controller( const handler = new Controller(
priceConfigs, priceConfigs,
pythPriceListener, pythPriceListener,
injectivePriceListener, injectivePriceListener,
new InjectivePricePusher(), injectivePricePusher,
{ {
cooldownDuration: argv.cooldownDuration, 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 { ChainPricePusher, PriceInfo, PriceListener } from "./interface";
import { DurationInSeconds } from "./utils"; import { DurationInSeconds } from "./utils";
import { PriceConfig } from "./price-config"; 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 = { type PriceQueryResponse = {
price_feed: { price_feed: {
@ -16,6 +26,11 @@ type PriceQueryResponse = {
}; };
}; };
type UpdateFeeResponse = {
denom: string;
amount: string;
};
// this use price without leading 0x // this use price without leading 0x
// FIXME: implement common methods in the parent class // FIXME: implement common methods in the parent class
export class InjectivePriceListener implements PriceListener { export class InjectivePriceListener implements PriceListener {
@ -103,10 +118,118 @@ export class InjectivePriceListener implements PriceListener {
} }
export class InjectivePricePusher implements ChainPricePusher { 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( async updatePriceFeed(
priceIds: string[], priceIds: string[],
pubTimesToPush: number[] pubTimesToPush: number[]
): Promise<void> { ): 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);
}
} }
} }