UNPKG

@surec/oracle

Version:

Typescript SDK for the Sure Oracle to be used to bring off-chain data on-chain

205 lines 7.16 kB
import { SHA3 } from 'sha3'; import randomBytes from 'randombytes'; import { SURE_MINT } from './constants.js'; import { getOrCreateAssociatedTokenAccountIx, validateKeys } from './utils.js'; import * as spl from '@solana/spl-token'; export const createVoteHash = ({ vote, salt, }) => { const hash = new SHA3(256); const voteCandidate = vote.toString() + salt.toString('utf8'); hash.update(voteCandidate); return hash.digest(); }; export const revealVote = ({ expectedVoteHash, vote, salt, }) => { const expectedVoteHashB = Buffer.from(expectedVoteHash); const voteHash = createVoteHash({ vote, salt }); return voteHash.equals(expectedVoteHashB); }; export class Vote { constructor(sdk) { this.sdk = sdk; this.program = sdk.program; } /** * submit a vote to a proposal * * @param mint - mint of proposal vault * @param proposal - the proposal to vote on * @param locker - locker used to lock tokens, see Tribeca * @param userEscrow - escrow that holds the locked tokens * @returns */ async submitVote({ vote, mint, proposal, locker, userEscrow, }) { const tokenMint = mint !== null && mint !== void 0 ? mint : SURE_MINT; validateKeys([ { v: tokenMint, n: 'tokenMint' }, { v: proposal, n: 'proposal' }, { v: locker, n: 'lcoker' }, { v: userEscrow, n: 'escrow' }, ]); const salt = randomBytes(16); const voteHash = createVoteHash({ vote, salt }); let ixs = []; const createATA = await getOrCreateAssociatedTokenAccountIx({ connection: this.sdk.provider.connection, payer: this.sdk.provider.wallet.payer, mint: tokenMint, owner: this.sdk.provider.walletKey, }); const [proposalVault] = await this.sdk.pda.findProposalVault({ proposal }); if (createATA.instruction) { ixs.push(createATA.instruction); } ixs.push(await this.program.methods .submitVote(voteHash) .accounts({ voterAccount: createATA.address, locker, userEscrow, proposal, proposalVault: proposalVault, proposalVaultMint: tokenMint, }) .instruction()); return { salt: salt, transactionEnvelope: this.sdk.provider.newTX(ixs), }; } /** * update vote * * @param mint - mint of proposal vault * @param proposal - the proposal to vote on * @returns */ async updateVote({ vote, proposal, }) { validateKeys([{ v: proposal, n: 'proposal' }]); const salt = randomBytes(16); const voteHash = createVoteHash({ vote, salt }); const voter = this.sdk.provider.wallet.publicKey; const [voteAccount] = await this.sdk.pda.findVoteAccount({ proposal, voter, }); let ixs = []; ixs.push(await this.program.methods .updateVote(voteHash) .accounts({ proposal, voteAccount, }) .instruction()); return { salt: salt, transactionEnvelope: this.sdk.provider.newTX(ixs), }; } /** * cancel vote * * @param voteAccout - the account used to vote with * @returns */ async cancelVote({ voteAccount }) { validateKeys([{ v: voteAccount, n: 'voteAccount' }]); const voter = this.sdk.provider.wallet.publicKey; const voteAccountLoaded = await this.program.account.voteAccount.fetch(voteAccount); const stakeMint = voteAccountLoaded.stakeMint; const proposal = voteAccountLoaded.proposal; const [proposalVault] = await this.sdk.pda.findProposalVault({ proposal }); const voterAccount = await spl.getAssociatedTokenAddress(voteAccountLoaded.tokenMint, voter); let ixs = []; ixs.push(await this.program.methods .cancelVote() .accounts({ voterAccount: voterAccount, proposalVault, proposalVaultMint: stakeMint, proposal: voteAccountLoaded.proposal, voteAccount, }) .instruction()); return this.sdk.provider.newTX(ixs); } /** * cancel vote * * @param voteAccount - the account used to vote with * @returns */ async revealVote({ voteAccount, vote, salt, }) { validateKeys([{ v: voteAccount, n: 'voteAccount' }]); const voteAccountLoaded = await this.program.account.voteAccount.fetch(voteAccount); const proposal = voteAccountLoaded.proposal; const [voteArray] = await this.sdk.pda.findRevealVoteArrayAddress({ proposal, }); let ixs = []; ixs.push(await this.program.methods .revealVote(salt.toString(), vote) .accounts({ proposal, revealVoteArray: voteArray, voteAccount, }) .instruction()); return this.sdk.provider.newTX(ixs); } /** * finalize vote * * @param voteAccount - the account used to vote with * @returns */ async finalizeVote({ voteAccount, }) { validateKeys([{ v: voteAccount, n: 'voteAccount' }]); const voteAccountLoaded = await this.program.account.voteAccount.fetch(voteAccount); const proposal = voteAccountLoaded.proposal; let ixs = []; ixs.push(await this.program.methods .finalizeVote() .accounts({ proposal, voteAccount, }) .instruction()); return this.sdk.provider.newTX(ixs); } /** * collect vote rewards * * @param voteAccount - the account used to vote with * @returns */ async collectRewards({ voteAccount, tokenMint, }) { validateKeys([{ v: voteAccount, n: 'voteAccount' }]); const voteAccountLoaded = await this.program.account.voteAccount.fetch(voteAccount); const proposal = voteAccountLoaded.proposal; const mint = voteAccountLoaded.stakeMint; const voterAccount = await getOrCreateAssociatedTokenAccountIx({ connection: this.sdk.provider.connection, payer: this.sdk.provider.wallet.payer, mint, owner: this.sdk.provider.walletKey, }); const [config] = this.sdk.pda.findOracleConfig({ tokenMint }); const [proposalVault] = this.sdk.pda.findProposalVault({ proposal }); let ixs = []; if (voterAccount.instruction) { ixs.push(voterAccount.instruction); } ixs.push(await this.program.methods .collectVoteReward() .accounts({ config, voterAccount: voterAccount.address, voteAccount, proposal, proposalVaultMint: mint, proposalVault, }) .instruction()); return this.sdk.provider.newTX(ixs); } } //# sourceMappingURL=vote.js.map