Skip to content

Commit

Permalink
[auto-self-nominate] Implement repeating self nomination
Browse files Browse the repository at this point in the history
  • Loading branch information
HoOngEe committed Jun 14, 2019
1 parent 3d61896 commit adc70d5
Showing 1 changed file with 155 additions and 0 deletions.
155 changes: 155 additions & 0 deletions auto-self-nominate/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import { U64 } from "codechain-primitives/lib";
import { SDK } from "codechain-sdk";
import { PlatformAddress } from "codechain-sdk/lib/core/classes";
import { Custom } from "codechain-sdk/lib/core/transaction/Custom";

const RLP = require("rlp");

const ACTION_TAG_SELF_NOMINATE = 4;
const STAKE_ACTION_HANDLER_ID = 2;

function getConfig(field: string): string {
const c = process.env[field];
if (c == null) {
throw new Error(`${field} is not specified`);
}
return c;
}

function rpcUrl(server: string): string {
switch (server) {
case "corgi":
return "https://corgi-rpc.codechain.io/";
case "mainnet":
return "https://rpc.codechain.io/";
default:
throw Error("Invalid server configuration");
}
}

function networkId(server: string): string {
switch (server) {
case "beagle":
return "bc";
case "corgi":
return "wc";
case "mainnet":
return "cc";
default:
throw Error("Invalid server configuration");
}
}

const SERVER: string = (() => {
const server = process.env.SERVER || "beagle";
if (["beagle", "corgi", "mainnet"].indexOf(server) >= 0) {
return server;
} else {
throw Error("Invalid server configuration");
}
})();

const sdk = (() => {
console.log(`sdk ${SERVER} ${process.env.RPC_URL}`);
return new SDK({
server: process.env.RPC_URL || rpcUrl(SERVER),
networkId: networkId(SERVER),
});
})();

function decodePlatformAddressFromPubkey(buffer: Buffer): PlatformAddress {
const pubkey = buffer.toString("hex");
return PlatformAddress.fromPublic(pubkey, {
networkId: sdk.networkId,
});
}

function decodeNumber(buffer: Buffer): number {
return parseInt("0x" + buffer.toString("hex"), 16);
}

async function sendSelfNominateTransaction(
accountInfo: { accountAddress: string; passphrase: string },
params: { deposit: U64; metadata: string },
) {
const tx = createSelfNomination(params);
const { accountAddress, passphrase } = accountInfo;
await sdk.rpc.account.sendTransaction({
tx,
account: accountAddress,
passphrase,
});
}

function createSelfNomination(params: { deposit: U64; metadata: string }): Custom {
const { deposit, metadata } = params;
const handlerId = new U64(STAKE_ACTION_HANDLER_ID);
const actionTag = ACTION_TAG_SELF_NOMINATE;
const bytes = RLP.encode([actionTag, deposit, metadata]);
return new Custom(
{
handlerId,
bytes,
},
networkId(SERVER),
);
}

async function needsNomination(
address: string,
nominationFrequencyLevel: number,
): Promise<boolean> {
const bestBlockNumber = await sdk.rpc.chain.getBestBlockNumber()!;
const candidates: Map<string, number> = await (async () => {
const retval = new Map();
const data = (await sdk.rpc.engine.getCustomActionData(
2,
["Candidates"],
bestBlockNumber,
))!;
const list: Buffer[][] = RLP.decode(Buffer.from(data, "hex"));
list.map(([encodedPubkey, _, encodedNominationEnd]) =>
retval.set(
decodePlatformAddressFromPubkey(encodedPubkey).value,
decodeNumber(encodedNominationEnd),
),
);
return retval;
})();
const nominationEndAt = candidates.get(address);
if (nominationEndAt == null) {
throw new Error(`SelfNominate first with specific deposit vakue before repeating`);
} else {
const bestBlock = (await sdk.rpc.chain.getBlock(bestBlockNumber))!;
const currentTermId = Math.floor(bestBlock.timestamp / 3600);
return nominationEndAt - currentTermId < nominationFrequencyLevel;
}
}

async function main() {
const accountAddress = getConfig("ACCOUNT_ADDRESS");
const passphrase = getConfig("PASSPHRASE");
const metadata = getConfig("METADATA");
const repeatedAdditionalDeposit = new U64(parseInt(getConfig("ADDITIONAL_DEPOSIT"), 10) || 0);
const NEED_NOMINATION_UNDER_TERM_LEFT = 5;

setInterval(async () => {
if (await needsNomination(accountAddress, NEED_NOMINATION_UNDER_TERM_LEFT)) {
await sendSelfNominateTransaction(
{
accountAddress,
passphrase,
},
{
deposit: repeatedAdditionalDeposit,
metadata,
},
);
}
}, 600_000); // 10 minutes interval
}

main().catch(error => {
console.log({ error });
throw error;
});

0 comments on commit adc70d5

Please sign in to comment.