[pice-pusher] add injective pusher (#633)
* add injective pusher * remove cwPriceServiceConnection
This commit is contained in:
parent
7c728a5718
commit
20e8e15cef
|
@ -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",
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue