Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cleanup locker creation helpers #112

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Anchor.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
anchor_version = "0.22.0"
solana_version = "1.8.8"
solana_version = "1.8.16"

[scripts]
test = "yarn mocha -b"
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@
"@types/chai": "^4.3.0",
"@types/lodash": "^4.14.178",
"@types/mocha": "^9.1.0",
"@types/node": "^16.11.24",
"@types/node": "^16.11.25",
"@types/prettier": "^2.4.4",
"@yarnpkg/doctor": "^3.1.1-rc.2",
"bn.js": "^5.2.0",
"chai": "^4.3.4",
"chai": "=4.3.4",
"eslint": "^8.9.0",
"eslint-import-resolver-node": "^0.3.6",
"eslint-plugin-import": "^2.25.4",
Expand Down
27 changes: 27 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,30 @@ export const DEFAULT_LOCKER_PARAMS: LockerParams = {
maxStakeVoteMultiplier: 10,
whitelistEnabled: false,
};

/**
* Smart wallet creation parameters.
*/
export interface SmartWalletParameters {
/**
* Number of signers required to execute a smart wallet transaction. This is useful for testing.
*/
threshold: number;
/**
* Maximum number of owners on the smart wallet.
*/
maxOwners: number;
/**
* Timelock delay.
*/
delay: number;
}

/**
* Default parameters for the Governor smart wallet.
*/
export const DEFAULT_GOVERNOR_SMART_WALLET_PARAMS: SmartWalletParameters = {
threshold: 2,
maxOwners: 3,
delay: 0,
};
38 changes: 33 additions & 5 deletions src/sdk.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { GokiSDK } from "@gokiprotocol/client";
import type { BN } from "@project-serum/anchor";
import { newProgramMap } from "@saberhq/anchor-contrib";
import type { AugmentedProvider, Provider } from "@saberhq/solana-contrib";
Expand All @@ -15,19 +16,33 @@ import {
TRIBECA_IDLS,
} from "./constants";
import type { LockerParams } from "./programs/lockedVoter";
import { GovernWrapper } from "./wrappers";
import type { CreateLockerParams } from "./wrappers";
import { createLocker, GovernWrapper } from "./wrappers";
import { findLockerAddress } from "./wrappers/lockedVoter/pda";
import { findSimpleElectorateAddress } from "./wrappers/simpleVoter/pda";
import type { PendingElectorate } from "./wrappers/simpleVoter/types";

/**
* TribecaSDK.
* Tribeca protocol SDK.
*/
export class TribecaSDK {
/**
* The Goki SDK.
*/
readonly goki: GokiSDK;

constructor(
/**
* Provider.
*/
readonly provider: AugmentedProvider,
/**
* Programs.
*/
readonly programs: TribecaPrograms
) {}
) {
this.goki = GokiSDK.load({ provider });
}

/**
* Creates a new instance of the SDK with the given keypair.
Expand Down Expand Up @@ -58,14 +73,18 @@ export class TribecaSDK {
return new GovernWrapper(this);
}

/**
* Creates a new simple electorate.
* @returns
*/
async createSimpleElectorate({
proposalThreshold,
governor,
govTokenMint,
baseKP = Keypair.generate(),
}: {
proposalThreshold: BN;
baseKP?: Keypair;
baseKP?: Signer;
governor: PublicKey;
govTokenMint: PublicKey;
}): Promise<PendingElectorate> {
Expand Down Expand Up @@ -97,6 +116,15 @@ export class TribecaSDK {
};
}

/**
* Creates a new Locker and Governor.
* @param params
* @returns
*/
async createLockerAndGovernor(params: Omit<CreateLockerParams, "sdk">) {
return await createLocker({ ...params, sdk: this });
}

/**
* Creates a Locker, which is an Electorate that supports vote locking.
* @returns
Expand All @@ -107,7 +135,7 @@ export class TribecaSDK {
baseKP = Keypair.generate(),
...providedLockerParams
}: {
baseKP?: Keypair;
baseKP?: Signer;
governor: PublicKey;
govTokenMint: PublicKey;
} & Partial<LockerParams>): Promise<{
Expand Down
4 changes: 2 additions & 2 deletions src/wrappers/govern/govern.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { TransactionEnvelope } from "@saberhq/solana-contrib";
import type { PublicKey } from "@solana/web3.js";
import type { PublicKey, Signer } from "@solana/web3.js";
import { Keypair, SystemProgram } from "@solana/web3.js";
import type BN from "bn.js";

Expand Down Expand Up @@ -33,7 +33,7 @@ export class GovernWrapper {
}: {
electorate: PublicKey;
smartWallet: PublicKey;
baseKP?: Keypair;
baseKP?: Signer;
quorumVotes?: BN;
votingDelay?: BN;
votingPeriod?: BN;
Expand Down
101 changes: 72 additions & 29 deletions src/wrappers/govern/setup.ts
Original file line number Diff line number Diff line change
@@ -1,43 +1,72 @@
import type { GokiSDK, SmartWalletWrapper } from "@gokiprotocol/client";
import type { SmartWalletWrapper } from "@gokiprotocol/client";
import type { TransactionEnvelope } from "@saberhq/solana-contrib";
import type { PublicKey } from "@solana/web3.js";
import type { PublicKey, Signer } from "@solana/web3.js";
import { Keypair } from "@solana/web3.js";
import BN from "bn.js";

import type { GovernanceParameters, TribecaSDK } from "../..";
import { DEFAULT_GOVERNANCE_PARAMETERS } from "../..";
import type {
GovernanceParameters,
SmartWalletParameters,
TribecaSDK,
} from "../..";
import {
DEFAULT_GOVERNANCE_PARAMETERS,
DEFAULT_GOVERNOR_SMART_WALLET_PARAMS,
} from "../..";
import type { GovernorWrapper } from "..";
import { findGovernorAddress } from "..";

/**
* Creates a Governor.
* @returns
* Parameters for the {@link createGovernorWithElectorate} function.
*/
export const createGovernorWithElectorate = async ({
createElectorate,
sdk,
gokiSDK,
owners = [sdk.provider.wallet.publicKey],
governanceParameters = DEFAULT_GOVERNANCE_PARAMETERS,
govBaseKP = Keypair.generate(),
smartWalletBaseKP = Keypair.generate(),
}: {
export interface CreateGovernorWithElectorateParams {
/**
* Function to create an electorate.
*/
createElectorate: (
governor: PublicKey
) => Promise<{ key: PublicKey; tx: TransactionEnvelope }>;
) => Promise<{ key: PublicKey; tx?: TransactionEnvelope }>;
/**
* Tribeca SDK.
*/
sdk: TribecaSDK;
gokiSDK: GokiSDK;
/**
* Additional owners on the governance smart wallet.
*
* For the Tribeca Trinity, this should be an owner invoker and an "emergency DAO" Smart Wallet.
*/
owners?: PublicKey[];
/**
* Additional governance parameters.
*/
governanceParameters?: Partial<GovernanceParameters>;
/**
* Base of the governor.
*/
govBaseKP?: Keypair;
governorBaseKP?: Signer;
/**
* Base of the smart wallet.
*/
smartWalletBaseKP?: Keypair;
}): Promise<{
/**
* Additional smart wallet parameters.
*/
smartWalletParameters?: Partial<SmartWalletParameters>;
}

/**
* Creates a Governor.
* @returns
*/
export const createGovernorWithElectorate = async ({
createElectorate,
sdk,
owners = [sdk.provider.wallet.publicKey],
governanceParameters = DEFAULT_GOVERNANCE_PARAMETERS,
governorBaseKP = Keypair.generate(),
smartWalletBaseKP = Keypair.generate(),
smartWalletParameters = DEFAULT_GOVERNOR_SMART_WALLET_PARAMS,
}: CreateGovernorWithElectorateParams): Promise<{
governorWrapper: GovernorWrapper;
smartWalletWrapper: SmartWalletWrapper;
electorate: PublicKey;
Expand All @@ -46,17 +75,29 @@ export const createGovernorWithElectorate = async ({
tx: TransactionEnvelope;
}[];
}> => {
const [governor] = await findGovernorAddress(govBaseKP.publicKey);
const [governor] = await findGovernorAddress(governorBaseKP.publicKey);

const createTXs: {
title: string;
tx: TransactionEnvelope;
}[] = [];

const { smartWalletWrapper, tx: tx1 } = await gokiSDK.newSmartWallet({
owners: [...owners, governor],
threshold: new BN(2),
numOwners: 3,
if (owners.find((owner) => owner.equals(governor))) {
throw new Error("governor should not be provided in owners list");
}

const allOwners = [...owners, governor];
const smartWalletParams: SmartWalletParameters = {
...DEFAULT_GOVERNOR_SMART_WALLET_PARAMS,
...smartWalletParameters,
maxOwners: allOwners.length,
};

const { smartWalletWrapper, tx: tx1 } = await sdk.goki.newSmartWallet({
owners: allOwners,
threshold: new BN(smartWalletParams.threshold),
numOwners: smartWalletParams.maxOwners,
delay: new BN(smartWalletParams.delay),
base: smartWalletBaseKP,
});
createTXs.push({
Expand All @@ -71,7 +112,7 @@ export const createGovernorWithElectorate = async ({
const { wrapper: governorWrapper, tx: tx2 } = await sdk.govern.createGovernor(
{
...governanceParameters,
baseKP: govBaseKP,
baseKP: governorBaseKP,
electorate,
smartWallet: smartWalletWrapper.key,
}
Expand All @@ -81,10 +122,12 @@ export const createGovernorWithElectorate = async ({
tx: tx2,
});

createTXs.push({
title: "Create Electorate",
tx: createElectorateTX,
});
if (createElectorateTX) {
createTXs.push({
title: "Create Electorate",
tx: createElectorateTX,
});
}

return {
governorWrapper,
Expand Down
66 changes: 24 additions & 42 deletions src/wrappers/lockedVoter/setup.ts
Original file line number Diff line number Diff line change
@@ -1,55 +1,41 @@
import type { GokiSDK, SmartWalletWrapper } from "@gokiprotocol/client";
import type { SmartWalletWrapper } from "@gokiprotocol/client";
import type { TransactionEnvelope } from "@saberhq/solana-contrib";
import type { PublicKey } from "@solana/web3.js";
import type { PublicKey, Signer } from "@solana/web3.js";
import { Keypair } from "@solana/web3.js";

import type {
GovernanceParameters,
GovernorWrapper,
LockerParams,
} from "../..";
import {
DEFAULT_GOVERNANCE_PARAMETERS,
DEFAULT_LOCKER_PARAMS,
} from "../../constants";
import type { TribecaSDK } from "../../sdk";
import type { GovernorWrapper, LockerParams } from "../..";
import { DEFAULT_LOCKER_PARAMS } from "../../constants";
import type { CreateGovernorWithElectorateParams } from "../govern/setup";
import { createGovernorWithElectorate } from "../govern/setup";
import { LockerWrapper } from "./locker";

export interface CreateLockerParams
extends Omit<CreateGovernorWithElectorateParams, "createElectorate"> {
/**
* Mint of the token staked for veTokens.
*/
govTokenMint: PublicKey;
/**
* Parameters for the locker.
*/
lockerParams?: Partial<LockerParams>;
/**
* Base of the locker.
*/
lockerBaseKP?: Signer;
}

/**
* Creates a new Locker.
* @returns
*/
export const createLocker = async ({
sdk,
gokiSDK,
govTokenMint,
owners = [sdk.provider.wallet.publicKey],
governanceParameters = DEFAULT_GOVERNANCE_PARAMETERS,
lockerParams = DEFAULT_LOCKER_PARAMS,
governorBaseKP = Keypair.generate(),
lockerBaseKP = Keypair.generate(),
smartWalletBaseKP = Keypair.generate(),
}: {
sdk: TribecaSDK;
gokiSDK: GokiSDK;
govTokenMint: PublicKey;
owners?: PublicKey[];
governanceParameters?: Partial<GovernanceParameters>;
lockerParams?: Partial<LockerParams>;
/**
* Base of the governor.
*/
governorBaseKP?: Keypair;
/**
* Base of the governor.
*/
lockerBaseKP?: Keypair;
/**
* Base of the smart wallet.
*/
smartWalletBaseKP?: Keypair;
}): Promise<{
...createGovernorParams
}: CreateLockerParams): Promise<{
governorWrapper: GovernorWrapper;
smartWalletWrapper: SmartWalletWrapper;
lockerWrapper: LockerWrapper;
Expand All @@ -72,11 +58,7 @@ export const createLocker = async ({
};
},
sdk,
gokiSDK,
owners,
governanceParameters,
govBaseKP: governorBaseKP,
smartWalletBaseKP,
...createGovernorParams,
});
return {
...governor,
Expand Down
Loading