From 2f071eb75e449f3b717f704407d556b68fded3e7 Mon Sep 17 00:00:00 2001 From: De Facto Date: Thu, 25 Feb 2021 10:52:20 +0800 Subject: [PATCH] work on reward faucet --- src/Deployer.ts | 49 +++++++++++++++- src/Submitter.ts | 16 ++++- src/json.ts | 23 ++++++++ test.ts | 148 +++++++++++++++++++++++++++++++++++------------ 4 files changed, 196 insertions(+), 40 deletions(-) diff --git a/src/Deployer.ts b/src/Deployer.ts index ab01c0e..4949d7a 100644 --- a/src/Deployer.ts +++ b/src/Deployer.ts @@ -20,15 +20,25 @@ import FluxAggregator from "./FluxAggregator" import { AggregatorConfig, IAggregatorConfig } from "./schema" import { jsonReplacer, jsonReviver } from "./json" import { log } from "./log" +import { config } from "dotenv/types" interface OracleDeployInfo { pubkey: PublicKey owner: PublicKey } + +interface FaucetInfo { + pubkey: PublicKey + // program account public key + owner: PublicKey + ownerSeed: Buffer +} + interface AggregatorDeployInfo { pubkey: PublicKey owner: PublicKey config: IAggregatorConfig + faucet: FaucetInfo oracles: { [key: string]: OracleDeployInfo @@ -124,6 +134,34 @@ export class Deployer { return new FluxAggregator(this.wallet, this.state.programID) } + async createRewardFaucet( + aggregatorInfo: AggregatorDeployInfo + ): Promise { + if (aggregatorInfo.faucet) { + return aggregatorInfo.faucet + } + + const seed = Buffer.from(aggregatorInfo.config.description) + + const faucetOwner = await ProgramAccount.forSeed(seed, this.state.programID) + + const spltoken = new SPLToken(this.wallet) + + const faucet = await spltoken.initializeAccount({ + // TODO: check if rewardTokenAccount is null + token: aggregatorInfo.config.rewardTokenAccount, + owner: faucetOwner.pubkey, + }) + + aggregatorInfo.faucet = { + pubkey: faucet.publicKey, + owner: faucetOwner.pubkey, + ownerSeed: seed, + } + + return aggregatorInfo.faucet + } + async createOracle( aggregatorInfo: AggregatorDeployInfo, name: string, @@ -164,11 +202,18 @@ export class Deployer { owner: this.wallet.account, }) - return { + const info: AggregatorDeployInfo = { pubkey: account.publicKey, owner: this.wallet.pubkey, config, + // to be set by `createRewardFaucet` + faucet: undefined, oracles: {}, - } + } as any + + // will set + await this.createRewardFaucet(info) + + return info } } diff --git a/src/Submitter.ts b/src/Submitter.ts index 6a8c265..097eee1 100644 --- a/src/Submitter.ts +++ b/src/Submitter.ts @@ -36,6 +36,7 @@ export class Submitter { public aggregatorPK: PublicKey, public oraclePK: PublicKey, private oracleOwnerWallet: Wallet, + private priceFeed: IPriceFeed, private cfg: SubmitterConfig ) { @@ -58,7 +59,20 @@ export class Submitter { await Promise.all([this.observeAggregatorState(), this.observePriceFeed()]) } - public async withdrawRewards() {} + public async withdrawRewards() { + // if (this.oracle.withdrawable.isZero()) { + // return + // } + + // // + + // this.program.withdraw({ + // accounts: { + // aggregator: this.aggregatorPK, + // // faucet + // } + // }) + } private async reloadState(loadAggregator = true) { if (loadAggregator) { diff --git a/src/json.ts b/src/json.ts index d93cdc5..4e05949 100644 --- a/src/json.ts +++ b/src/json.ts @@ -7,18 +7,41 @@ export function jsonReviver(_key: string, val: any) { if (val["type"] == "PublicKey") { return new PublicKey(val.base58) } + + if (val["type"] == "Buffer") { + return Buffer.from(val.hex, "hex") + } } return val } export function jsonReplacer(key: string, value: any) { if (value && typeof value == "object") { + console.log("jsonReplacer", key, value) if (value.constructor == PublicKey) { return { type: "PublicKey", base58: value.toBase58(), } } + + // The Buffer class defines a `toJSON` method that returns: + // + // { + // type: 'Buffer', + // data: [ + // 100, 101, 97, 100, + // 98, 101, 97, 102 + // ] + // } + // + // Convert this to an hex string + if (value.type == "Buffer") { + return { + type: "Buffer", + hex: Buffer.from(value).toString("hex"), + } + } } return value diff --git a/test.ts b/test.ts index ebc4f19..b46ea49 100644 --- a/test.ts +++ b/test.ts @@ -1,67 +1,141 @@ import dotenv from "dotenv" +import { ProgramAccount, PublicKey, SPLToken, Wallet } from "solray" dotenv.config() import { AppContext, conn, network } from "./src/context" import { AggregatorDeployFile, Deployer } from "./src/Deployer" import { coinbase } from "./src/feeds" -import { loadJSONFile } from "./src/json" +import { jsonReplacer, jsonReviver, loadJSONFile } from "./src/json" import { log } from "./src/log" import { PriceFeeder } from "./src/PriceFeeder" +import { stateFromJSON } from "./src/state" + +interface State { + rewardTokenPK: PublicKey + faucetPK: PublicKey + isMinted: boolean +} + +class TestHarness { + public state: State + constructor( + stateFile: string, + private wallet: Wallet, + ) { + this.state = stateFromJSON(stateFile, {} as State, { + replacer: jsonReplacer, + reviver: jsonReviver, + }) + // this.state = stateFromJSON(`state.${network}.json`, {} as State) + } + + // async setup() { + // // setup reward token plus mint + // await this.setupRewardTokenPK() + // await this.setupFaucet() + // await this.mintToFaucet(1e6 * 1e9) + // } + + get spltoken() { + return new SPLToken(this.wallet) + } + + // async mintToFaucet(amount: number) { + // if (this.state.isMinted) { + // return + // } + + // await this.spltoken.mintTo({ + // token: this.state.rewardTokenPK, + // to: await this.faucetOwnerPK(), + // amount: BigInt(amount), // 1M + // authority: this.wallet.pubkey, + // }) + // } + + // async faucetOwnerPK(): Promise { + // const rewardTokenOwner = await ProgramAccount.forSeed( + // Buffer.from("solink"), + // this.aggregatorProgramID + // ) + + // return rewardTokenOwner.pubkey + // } + + async setupFaucet(aggregatorProgramID: PublicKey): Promise { + if (this.state.faucetPK) { + return this.state.faucetPK + } + + const faucetOwner = await ProgramAccount.forSeed( + Buffer.from("solink"), + aggregatorProgramID + ) + + const faucet = await this.spltoken.initializeAccount({ + token: this.state.rewardTokenPK, + owner: faucetOwner.pubkey, + }) + + await this.spltoken.mintTo({ + token: this.state.rewardTokenPK, + to: faucet.publicKey, + amount: BigInt(1e6*1e9), // 1M + authority: this.wallet.pubkey, + }) + + this.state.faucetPK = faucet.publicKey + return faucet.publicKey + } + + async setupRewardTokenPK(): Promise { + if (this.state.rewardTokenPK) { + return this.state.rewardTokenPK + } + + log.info("setup reward token") + const token = await this.spltoken.initializeMint({ + mintAuthority: this.wallet.pubkey, + decimals: 9, + // account: this.wallet.deriveAccount("0") + }) + + this.state.rewardTokenPK = token.publicKey + return token.publicKey + } +} async function main() { + // persistent JSON state for test script + + const setupFile = `config/setup.${network}.json` const deployFile = `deploy.${network}.json` const feederConfigFile = "feeder.json" let ctx = new AppContext() let adminWallet = await ctx.adminWallet() let oracleWallet = await ctx.oracleWallet() - await conn.requestAirdrop(adminWallet.pubkey, 10 * 1e9) await conn.requestAirdrop(oracleWallet.pubkey, 10 * 1e9) - const deployer = new Deployer(deployFile, setupFile, adminWallet) + const t = new TestHarness(`test.${network}.json`, adminWallet) + await t.setupRewardTokenPK() + // return + + const deployer = new Deployer(deployFile, setupFile, adminWallet) await deployer.runAll() + // TODO: actually, creating the faucet should be in the deployer + // await t.setupFaucet(deployer.state.programID) + const deploy = loadJSONFile(deployFile) const feeder = new PriceFeeder(deploy, oracleWallet) feeder.start() + // TODO: try to to harvest rewards + return - - // const spltoken = new SPLToken(adminWallet) - // const rewardToken = await deployer.ensure("create reward token", async () => { - // return spltoken.initializeMint({ - // mintAuthority: adminWallet.pubkey, - // decimals: 8, - // }) - // }) - - // const rewardTokenOwner = await ProgramAccount.forSeed( - // Buffer.from("solink"), - // aggregatorProgram.publicKey - // ) - - // const rewardTokenAccount = await deployer.ensure( - // "initialize reward token account", - // async () => { - // const vault = await spltoken.initializeAccount({ - // token: rewardToken.publicKey, - // owner: rewardTokenOwner.pubkey, - // }) - - // await spltoken.mintTo({ - // token: rewardToken.publicKey, - // to: vault.publicKey, - // amount: BigInt(1e6 * 1e8), // 1M - // authority: adminWallet.pubkey, - // }) - - // return vault - // } - // ) - - // console.log(await spltoken.mintInfo(rewardToken.publicKey)) } main().catch((err) => console.log(err))