Skip to content

Commit

Permalink
Sync
Browse files Browse the repository at this point in the history
  • Loading branch information
AmitPr committed Oct 7, 2024
1 parent 456c9a6 commit 330c32c
Show file tree
Hide file tree
Showing 11 changed files with 454 additions and 324 deletions.
6 changes: 6 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# flyctl launch added from .gitignore
**/node_modules
**/bin
**/.env
**/.DS_Store
fly.toml
18 changes: 18 additions & 0 deletions .github/workflows/fly-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# See https://fly.io/docs/app-guides/continuous-deployment-with-github-actions/

name: Fly Deploy
on:
push:
branches:
- main
jobs:
deploy:
name: Deploy app
runs-on: ubuntu-latest
concurrency: deploy-group # optional: ensure only one action runs at a time
steps:
- uses: actions/checkout@v4
- uses: superfly/flyctl-actions/setup-flyctl@master
- run: flyctl deploy --remote-only
env:
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
12 changes: 12 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
FROM oven/bun:latest

WORKDIR /app

COPY . .

RUN apt-get -y update
RUN apt-get install -y procps && rm -rf /var/lib/apt/lists/*

RUN bun install --verbose

ENTRYPOINT ["sh", "-c", "bun run --bun start"]
Binary file modified bun.lockb
Binary file not shown.
16 changes: 10 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
{
"name": "quark-crank",
"scripts": {
"start": "bun --bun run ./src/app.ts"
"start": "bun run ./src/app.ts"
},
"type": "module",
"dependencies": {
"@cosmjs/crypto": "^0.31.1",
"@cosmjs/proto-signing": "^0.31.1",
"@cosmjs/utils": "^0.31.1",
"@cosmjs/crypto": "^0.32.4",
"@cosmjs/proto-signing": "^0.32.4",
"@cosmjs/utils": "^0.32.4",
"@cosmjs/tendermint-rpc": "^0.32.4",
"@cosmjs/stargate": "^0.32.4",
"@cosmjs/encoding": "^0.32.4",
"@entropic-labs/quark.js": "^0.0.34",
"@types/node": "^18.11.9",
"cosmjs-types": "^0.7.2",
"kujira.js": "^0.9.33",
"cosmjs-types": "^0.9.0",
"kujira.js": "^1.0.61",
"protobufjs": "^7.1.2",
"text-encoding": "^0.7.0"
}
Expand Down
2 changes: 1 addition & 1 deletion src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { createGrant, getGrant } from "./workers/index.js";
import * as hub from "./workers/hub.js";
import * as unifier from "./workers/unifier.js";

const ENABLED = [...unifier.contracts,];// ...hub.contracts,];
const ENABLED = [...unifier.contracts, ...hub.contracts,];

const run = async () => {
await Promise.all(
Expand Down
18 changes: 9 additions & 9 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,22 @@ export const NETWORK = process.env.NETWORK === "mainnet" ? MAINNET : TESTNET;

export enum Contract {
HUB = "hub",
ICA_HUB = "ica_hub",
UNIFIER = "unifier",
}

const RPCS = {
[MAINNET]: [
"https://kujira-rpc.polkachu.com",
"https://rpc-kujira.starsquid.io",
"https://kujira-rpc.polkachu.com",
"https://rpc-kujira.mintthemoon.xyz",
],
[TESTNET]:
[
"https://kujira-testnet-rpc.polkachu.com",
"https://test-rpc-kujira.mintthemoon.xyz",
"https://dev-rpc-kujira.mintthemoon.xyz",
]
}
[TESTNET]: [
"https://kujira-testnet-rpc.polkachu.com",
"https://test-rpc-kujira.mintthemoon.xyz",
"https://dev-rpc-kujira.mintthemoon.xyz",
],
};

const RPC_DEFAULT =
process.env.NETWORK === "mainnet" ? RPCS[MAINNET][0] : RPCS[TESTNET][0];
Expand All @@ -29,4 +29,4 @@ export const PREFIX = process.env.PREFIX || "kujira";
export const RPC_ENDPOINT = process.env.RPC_ENDPOINT || RPC_DEFAULT;
export const GAS_PRICE = GasPrice.fromString(
process.env.GAS_PRICE || "0.0034ukuji"
);
);
4 changes: 2 additions & 2 deletions src/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ export const getAllContractState = async (
const pageRequest = pageResponse
? PageRequest.fromPartial({
key: pageResponse.nextKey,
limit: Long.fromNumber(100000),
limit: 100000n,
})
: PageRequest.fromPartial({
limit: Long.fromNumber(100000),
limit: 100000n,
});

const res = await client.wasm.getAllContractState(address, pageRequest);
Expand Down
54 changes: 29 additions & 25 deletions src/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ import { DeliverTxResponse, SigningStargateClient } from "@cosmjs/stargate";
import { registry } from "kujira.js";
import { GAS_PRICE, PREFIX, RPC_ENDPOINT } from "./config.js";

export const wallet = (account: number) => {
export const wallet = (account: number, prefix = PREFIX) => {
if (!process.env.MNEMONIC) throw new Error("MNEMONIC not set");

return DirectSecp256k1HdWallet.fromMnemonic(process.env.MNEMONIC, {
prefix: PREFIX,
prefix,
hdPaths: [
[
Slip10RawIndex.hardened(44),
Expand All @@ -30,22 +30,26 @@ export const wallet = (account: number) => {

export type Client = [SigningStargateClient, string];

export const client = async (account: number): Promise<Client> => {
const signer = await wallet(account);
export const client = async (
account: number,
rpc = RPC_ENDPOINT,
gasPrice = GAS_PRICE,
prefix?: string
): Promise<Client> => {
const signer = await wallet(account, prefix);

const [acc] = await signer.getAccounts();
const c = await SigningStargateClient.connectWithSigner(
RPC_ENDPOINT,
signer,
{ registry, gasPrice: GAS_PRICE }
);
const c = await SigningStargateClient.connectWithSigner(rpc, signer, {
registry,
gasPrice,
});

return [c, acc.address];
};

export const ORCHESTRATOR = client(0);

export function calculateFee(gasLimit: number, granter: string): StdFee {
export function calculateFee(gasLimit: number, granter?: string): StdFee {
const { denom, amount: gasPriceAmount } = GAS_PRICE;
// Note: Amount can exceed the safe integer range (https://github.com/cosmos/cosmjs/issues/1134),
// which we handle by converting from Decimal to string without going through number.
Expand All @@ -63,34 +67,34 @@ export function calculateFee(gasLimit: number, granter: string): StdFee {
export async function signAndBroadcast(
account: Client,
messages: readonly EncodeObject[],
memo = ""
memo = "",
granter?: string | null
): Promise<DeliverTxResponse> {
const gasEstimation = await account[0].simulate(account[1], messages, memo);
const multiplier = 1.5;
const orchestrator = await ORCHESTRATOR;
const fee = calculateFee(
Math.round(gasEstimation * multiplier),
orchestrator[1]
);
const multiplier = 2.0;
if (granter === null) {
granter = undefined;
} else {
granter = granter || (await ORCHESTRATOR)[1];
}
const fee = calculateFee(Math.round(gasEstimation * multiplier), granter);

return account[0].signAndBroadcast(account[1], messages, fee, memo);
}

/// Uses the ORACLE_KEY to sign arbitrary data
export async function oracleSignArbitrary(
data: Uint8Array
): Promise<{ signature: Uint8Array, pubkey: Uint8Array }> {
): Promise<{ signature: Uint8Array; pubkey: Uint8Array }> {
if (!process.env.ORACLE_KEY) throw new Error("ORACLE_KEY not set");
// convert ORACLE_KEY to Uint8Array private key
const privateKey = new Uint8Array(
Buffer.from(process.env.ORACLE_KEY, "hex")
);
const privateKey = new Uint8Array(Buffer.from(process.env.ORACLE_KEY, "hex"));
const { pubkey } = await Secp256k1.makeKeypair(privateKey);
const compressedPubkey = await Secp256k1.compressPubkey(pubkey);
const extendedSignature = (await Secp256k1.createSignature(data, privateKey));
const extendedSignature = await Secp256k1.createSignature(data, privateKey);
const signature = new Uint8Array([
...extendedSignature.r(32),
...extendedSignature.s(32)
...extendedSignature.r(32),
...extendedSignature.s(32),
]);
return { signature, pubkey: compressedPubkey };
}
}
82 changes: 41 additions & 41 deletions src/workers/hub.ts
Original file line number Diff line number Diff line change
@@ -1,60 +1,60 @@
import { Contract, NETWORK } from "config.js";
import { client, signAndBroadcast } from "wallet.js";
import { msg } from "kujira.js";
import { HUBS } from "@entropic-labs/quark.js";

export const registry = {
"kaiyo-1": [
{ address: "kujira1eulxny0ffvhkkec9l2s44tg9a868ly0fgg86raduypku735zyeyqv7lsun", interval: 86400 },
{ address: "kujira17nsll5xs4ak8lsguqelhh0etvvfe2cw6lmhg0jpja28zedunddkq0d4jv4", interval: 86400 },
{ address: "kujira1y52rf2kv6t9yvev7g3s5jvxutw7jxj3a87p3yydrh4dxtdglkssq06sjy2", interval: 86400 }
],
"harpoon-4": [
{ address: "kujira1jhmfj3avt2dlswrqlgx7fssvgrqfqzyj9m5cvgavuwekquxhu27ql88enu", interval: 60 },
{ address: "kujira16t7wlfluk27c7emzvxfcqxzged7tkne9p7rrwexzc7gdg6dvk4psxm5waf", interval: 60 }
]
"kaiyo-1": Object.values(HUBS["kaiyo-1"]).map((x) => ({
address: x!.address,
interval: 86400,
})),
"harpoon-4": Object.keys(HUBS["harpoon-4"]).map((address) => ({
address,
interval: 60,
})),
};

export const contracts = [
...registry[NETWORK].map(({ address }) => ({
address,
contract: Contract.HUB,
})),
...registry[NETWORK].map(({ address }) => ({
address,
contract: Contract.HUB,
})),
];

/// We need to run the "{ crank: {} }" message on the hub to:
/// 1. Claim and redistribute rewards
/// 2. Vote on proposals
/// 3. Queue unbondings, etc.
export async function run(address: string, idx: number) {
const config = registry[NETWORK].find((x) => x.address === address);
if (!config) throw new Error(`${address} hub not found`);
const config = registry[NETWORK].find((x) => x.address === address);
if (!config) throw new Error(`${address} hub not found`);

try {
const w = await client(idx);
try {
const w = await client(idx);

const msgs = [
msg.wasm.msgExecuteContract({
sender: w[1],
contract: address,
msg: Buffer.from(
JSON.stringify({
crank: {},
})
),
funds: [],
}),
];
try {
console.debug(`[HUB:${address}] Cranking...`);
const res = await signAndBroadcast(w, msgs, "auto");
console.info(`[HUB:${address}] Cranked: ${res.transactionHash}`);
} catch (e: any) {
console.error(`[HUB:${address}] ${e}`);
}
} catch (error: any) {
console.error(`[HUB:${address}] ${error.message}`);
} finally {
await new Promise((resolve) => setTimeout(resolve, config.interval * 1000));
await run(address, idx);
const msgs = [
msg.wasm.msgExecuteContract({
sender: w[1],
contract: address,
msg: Buffer.from(
JSON.stringify({
crank: "empty",
})
),
funds: [],
}),
];
try {
console.debug(`[HUB:${address}] Cranking...`);
const res = await signAndBroadcast(w, msgs, "auto");
console.info(`[HUB:${address}] Cranked: ${res.transactionHash}`);
} catch (e: any) {
console.error(`[HUB:${address}] ${e}`);
}
} catch (error: any) {
console.error(`[HUB:${address}] ${error.message}`);
} finally {
await new Promise((resolve) => setTimeout(resolve, config.interval * 1000));
await run(address, idx);
}
}
Loading

0 comments on commit 330c32c

Please sign in to comment.