forked from solana-labs/governance-ui
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Realm wizard creator (solana-labs#165)
* feat: realm-wizard creator * chore: removed unecessary code * fix: mismatch arguments * fix: removed unused variabled * chore: removed .lock files * feat: readded yarn.lock * fix: yarn lock file * updated gitignore * chore: use default instance in examples * fix: remove unnecessary signers from councilMembersSignersChunks * chore: remove unused var * chore: remove unused mint functions * chore: remove unused oyster artefacts * chore: rename create-realm-validator * fix: Update realm creation options description * chore: update realm description text Co-authored-by: Sebastian.Bor <[email protected]>
- Loading branch information
1 parent
110f0c2
commit f870cc7
Showing
31 changed files
with
1,907 additions
and
419 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,6 @@ | ||
# Run in context of one realm: starts with default realm and disables realms page navigation | ||
# REALM=MNGO | ||
MAINNET_RPC=https://mango.rpcpool.com | ||
DEVNET_RPC=https://mango.devnet.rpcpool.com | ||
DEVNET_RPC=https://mango.devnet.rpcpool.com | ||
|
||
DEFAULT_GOVERNANCE_PROGRAM_ID=GTesTBiEWE32WHXXE2S4XbZvA5CrEc4xs6ZgRe895dP |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,7 +18,6 @@ | |
# misc | ||
.DS_Store | ||
*.pem | ||
.env | ||
|
||
# debug | ||
npm-debug.log* | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,231 @@ | ||
import { | ||
GovernanceConfig, | ||
MintMaxVoteWeightSource, | ||
VoteThresholdPercentage, | ||
VoteWeightSource, | ||
} from '@models/accounts' | ||
import { ProgramVersion } from '@models/registry/constants' | ||
import { withCreateMintGovernance } from '@models/withCreateMintGovernance' | ||
import { withCreateRealm } from '@models/withCreateRealm' | ||
import { withDepositGoverningTokens } from '@models/withDepositGoverningTokens' | ||
import { withSetRealmAuthority } from '@models/withSetRealmAuthority' | ||
import { BN } from '@project-serum/anchor' | ||
import { | ||
Connection, | ||
Keypair, | ||
PublicKey, | ||
TransactionInstruction, | ||
} from '@solana/web3.js' | ||
|
||
import { withCreateAssociatedTokenAccount } from '@tools/sdk/splToken/withCreateAssociatedTokenAccount' | ||
import { withCreateMint } from '@tools/sdk/splToken/withCreateMint' | ||
import { withMintTo } from '@tools/sdk/splToken/withMintTo' | ||
import { | ||
getMintNaturalAmountFromDecimal, | ||
getTimestampFromDays, | ||
} from '@tools/sdk/units' | ||
import { | ||
getWalletPublicKey, | ||
sendTransactions, | ||
SequenceType, | ||
WalletSigner, | ||
} from 'utils/sendTransactions' | ||
import { chunks } from '@utils/helpers' | ||
|
||
/// Creates multisig realm with community mint with 0 supply | ||
/// and council mint used as multisig token | ||
export const createMultisigRealm = async ( | ||
connection: Connection, | ||
programId: PublicKey, | ||
programVersion: ProgramVersion, | ||
|
||
name: string, | ||
yesVoteThreshold: number, | ||
councilWalletPks: PublicKey[], | ||
|
||
wallet: WalletSigner | ||
) => { | ||
const walletPk = getWalletPublicKey(wallet) | ||
|
||
const mintsSetupInstructions: TransactionInstruction[] = [] | ||
const councilMembersInstructions: TransactionInstruction[] = [] | ||
|
||
const mintsSetupSigners: Keypair[] = [] | ||
|
||
// Default to 100% supply | ||
const communityMintMaxVoteWeightSource = | ||
MintMaxVoteWeightSource.FULL_SUPPLY_FRACTION | ||
|
||
// The community mint is going to have 0 supply and we arbitrarily set it to 1m | ||
const minCommunityTokensToCreate = 1000000 | ||
|
||
// Community mint decimals | ||
const communityMintDecimals = 6 | ||
|
||
// Create community mint | ||
const communityMintPk = await withCreateMint( | ||
connection, | ||
mintsSetupInstructions, | ||
mintsSetupSigners, | ||
walletPk, | ||
null, | ||
communityMintDecimals, | ||
walletPk | ||
) | ||
|
||
// Create council mint | ||
const councilMintPk = await withCreateMint( | ||
connection, | ||
mintsSetupInstructions, | ||
mintsSetupSigners, | ||
walletPk, | ||
null, | ||
0, | ||
walletPk | ||
) | ||
|
||
let walletAtaPk: PublicKey | undefined | ||
|
||
for (const teamWalletPk of councilWalletPks) { | ||
const ataPk = await withCreateAssociatedTokenAccount( | ||
councilMembersInstructions, | ||
councilMintPk, | ||
teamWalletPk, | ||
walletPk | ||
) | ||
// Mint 1 council token to each team member | ||
await withMintTo( | ||
councilMembersInstructions, | ||
councilMintPk, | ||
ataPk, | ||
walletPk, | ||
1 | ||
) | ||
|
||
if (teamWalletPk.equals(walletPk)) { | ||
walletAtaPk = ataPk | ||
} | ||
} | ||
|
||
// Create realm | ||
const realmInstructions: TransactionInstruction[] = [] | ||
const realmSigners: Keypair[] = [] | ||
|
||
// Convert to mint natural amount | ||
const minCommunityTokensToCreateAsMintValue = new BN( | ||
getMintNaturalAmountFromDecimal( | ||
minCommunityTokensToCreate, | ||
communityMintDecimals | ||
) | ||
) | ||
|
||
const realmPk = await withCreateRealm( | ||
realmInstructions, | ||
programId, | ||
programVersion, | ||
name, | ||
walletPk, | ||
communityMintPk, | ||
walletPk, | ||
councilMintPk, | ||
communityMintMaxVoteWeightSource, | ||
minCommunityTokensToCreateAsMintValue, | ||
undefined | ||
) | ||
|
||
let tokenOwnerRecordPk: PublicKey | ||
|
||
// If the current wallet is in the team then deposit the council token | ||
if (walletAtaPk) { | ||
tokenOwnerRecordPk = await withDepositGoverningTokens( | ||
realmInstructions, | ||
programId, | ||
realmPk, | ||
walletAtaPk, | ||
councilMintPk, | ||
walletPk, | ||
walletPk, | ||
walletPk | ||
) | ||
} else { | ||
// Let's throw for now if the current wallet isn't in the team | ||
// TODO: To fix it we would have to make it temp. as part of the team and then remove after the realm is created | ||
throw new Error('Current wallet must be in the team') | ||
} | ||
|
||
// Put community and council mints under the realm governance with default config | ||
const config = new GovernanceConfig({ | ||
voteThresholdPercentage: new VoteThresholdPercentage({ | ||
value: yesVoteThreshold, | ||
}), | ||
minCommunityTokensToCreateProposal: minCommunityTokensToCreateAsMintValue, | ||
// Do not use instruction hold up time | ||
minInstructionHoldUpTime: 0, | ||
// max voting time 3 days | ||
maxVotingTime: getTimestampFromDays(3), | ||
voteWeightSource: VoteWeightSource.Deposit, | ||
proposalCoolOffTime: 0, | ||
minCouncilTokensToCreateProposal: new BN(1), | ||
}) | ||
|
||
const { | ||
governanceAddress: communityMintGovPk, | ||
} = await withCreateMintGovernance( | ||
realmInstructions, | ||
programId, | ||
realmPk, | ||
communityMintPk, | ||
config, | ||
walletPk, | ||
walletPk, | ||
tokenOwnerRecordPk, | ||
walletPk | ||
) | ||
|
||
await withCreateMintGovernance( | ||
realmInstructions, | ||
programId, | ||
realmPk, | ||
councilMintPk, | ||
config, | ||
walletPk, | ||
walletPk, | ||
tokenOwnerRecordPk, | ||
walletPk | ||
) | ||
|
||
// Set the community governance as the realm authority | ||
withSetRealmAuthority( | ||
realmInstructions, | ||
programId, | ||
realmPk, | ||
walletPk, | ||
communityMintGovPk | ||
) | ||
|
||
try { | ||
const councilMembersChunks = chunks(councilMembersInstructions, 10) | ||
// only walletPk needs to sign the minting instructions and it's a signer by default and we don't have to include any more signers | ||
const councilMembersSignersChunks = Array(councilMembersChunks.length).fill( | ||
[] | ||
) | ||
|
||
const tx = await sendTransactions( | ||
connection, | ||
wallet, | ||
[mintsSetupInstructions, ...councilMembersChunks, realmInstructions], | ||
[mintsSetupSigners, ...councilMembersSignersChunks, realmSigners], | ||
SequenceType.Sequential | ||
) | ||
|
||
return { | ||
tx, | ||
realmPk, | ||
communityMintPk, | ||
councilMintPk, | ||
} | ||
} catch (ex) { | ||
console.error(ex) | ||
throw ex | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.