-
Notifications
You must be signed in to change notification settings - Fork 187
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
feat: add candy machine gpa builders #95
Merged
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
d060555
chore: export config types
thlorenz ad216bb
chore: replace `instanceof` with `is` as that works across web3.js ve…
thlorenz 5d4cf41
chore: remove 'try' prefix from conversion methods
thlorenz 273e339
chore: spread candy machine data fields
thlorenz c2b8f28
chore: UnreachableCase Error is now an SDK Error
thlorenz dace887
chore: findCandyMachine now uses metaplex rpc
thlorenz ee1b364
chore: unreachable case error includes value in message
thlorenz 2a7f066
chore: expose candy machine client as `candyMachines`
thlorenz db19409
feat: candyMachine GPA including tests
thlorenz db661f6
chore: gpa operation handlers and using those in test
thlorenz 93e6a10
chore: upgrade to `candyMachines` renaming
thlorenz 8de5bff
Merge branch 'main' into thlorenz/feat/cm-gpa-builder
thlorenz ecf5f6f
chore: Given, When, Then in tests to make Loris happy
thlorenz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
52 changes: 52 additions & 0 deletions
52
src/plugins/candyMachineModule/findCandyMachinesByPublicKeyField.ts
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,52 @@ | ||
import { PublicKey } from '@solana/web3.js'; | ||
import { Operation, OperationHandler, useOperation } from '@/types'; | ||
import { Metaplex } from '@/Metaplex'; | ||
import { CandyMachine } from './CandyMachine'; | ||
import { CandyMachineAccount, CandyMachineProgram } from '../../programs'; | ||
import { UnreachableCaseError } from '../../errors'; | ||
|
||
// ----------------- | ||
// Operation | ||
// ----------------- | ||
const Key = 'FindCandyMachinesByPublicKeyOperation' as const; | ||
|
||
export const findCandyMachinesByPublicKeyFieldOperation = | ||
useOperation<FindCandyMachinesByPublicKeyFieldOperation>(Key); | ||
|
||
export type FindCandyMachinesByPublicKeyFieldInput = { | ||
type: 'authority' | 'wallet'; | ||
publicKey: PublicKey; | ||
}; | ||
export type FindCandyMachinesByPublicKeyFieldOperation = Operation< | ||
typeof Key, | ||
FindCandyMachinesByPublicKeyFieldInput, | ||
CandyMachine[] | ||
>; | ||
|
||
// ----------------- | ||
// Handler | ||
// ----------------- | ||
export const findCandyMachinesByPublicKeyFieldOnChainOperationHandler: OperationHandler<FindCandyMachinesByPublicKeyFieldOperation> = | ||
{ | ||
handle: async ( | ||
operation: FindCandyMachinesByPublicKeyFieldOperation, | ||
metaplex: Metaplex | ||
): Promise<CandyMachine[]> => { | ||
const { type, publicKey } = operation.input; | ||
const accounts = CandyMachineProgram.accounts(metaplex); | ||
let candyMachineQuery; | ||
switch (type) { | ||
case 'authority': | ||
candyMachineQuery = accounts.candyMachineAccountsForAuthority(publicKey); | ||
break; | ||
case 'wallet': | ||
candyMachineQuery = accounts.candyMachineAccountsForWallet(publicKey); | ||
break; | ||
default: | ||
throw new UnreachableCaseError(type); | ||
} | ||
|
||
const candyMachineUnparseds = await candyMachineQuery.get(); | ||
return candyMachineUnparseds.map(CandyMachineAccount.from).map(CandyMachine.fromAccount); | ||
}, | ||
}; |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { PROGRAM_ID } from '@metaplex-foundation/mpl-candy-machine'; | ||
import { CandyMachineGpaBuilder } from './gpaBuilders'; | ||
import { Metaplex } from '@/Metaplex'; | ||
|
||
export const CandyMachineProgram = { | ||
publicKey: PROGRAM_ID, | ||
|
||
accounts(metaplex: Metaplex) { | ||
return new CandyMachineGpaBuilder(metaplex, this.publicKey); | ||
}, | ||
}; |
29 changes: 29 additions & 0 deletions
29
src/programs/candyMachine/gpaBuilders/CandyMachineGpaBuilder.ts
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,29 @@ | ||
import { GpaBuilder } from '@/utils'; | ||
import { PublicKey } from '@solana/web3.js'; | ||
|
||
type AccountDiscriminator = [number, number, number, number, number, number, number, number]; | ||
// TODO(thlorenz): copied from candy machine SDK | ||
// SDK should either provide a GPA builder or expose this discriminator | ||
const candyMachineDiscriminator: AccountDiscriminator = [51, 173, 177, 113, 25, 241, 109, 189]; | ||
|
||
const AUTHORITY = candyMachineDiscriminator.length; | ||
const WALLET = AUTHORITY + PublicKey.default.toBytes().byteLength; | ||
|
||
export class CandyMachineGpaBuilder extends GpaBuilder { | ||
whereDiscriminator(discrimator: AccountDiscriminator) { | ||
return this.where(0, Buffer.from(discrimator)); | ||
} | ||
|
||
candyMachineAccounts() { | ||
return this.whereDiscriminator(candyMachineDiscriminator); | ||
} | ||
|
||
// wallet same as solTreasury | ||
candyMachineAccountsForWallet(wallet: PublicKey) { | ||
return this.candyMachineAccounts().where(WALLET, wallet.toBase58()); | ||
} | ||
|
||
candyMachineAccountsForAuthority(authority: PublicKey) { | ||
return this.candyMachineAccounts().where(AUTHORITY, authority.toBase58()); | ||
} | ||
} |
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 @@ | ||
export * from './CandyMachineGpaBuilder'; |
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,2 +1,4 @@ | ||
export * from './accounts'; | ||
export * from './CandyMachineProgram'; | ||
export * from './gpaBuilders'; | ||
export * from './transactionBuilders'; |
85 changes: 85 additions & 0 deletions
85
test/plugins/candyMachineModule/findCandyMachinesByPublicKeyField.test.ts
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,85 @@ | ||
import test from 'tape'; | ||
import spok from 'spok'; | ||
import { killStuckProcess, metaplex, spokSamePubkey } from '../../helpers'; | ||
import { createCandyMachineWithMinimalConfig } from './helpers'; | ||
|
||
killStuckProcess(); | ||
|
||
// ----------------- | ||
// Wallet | ||
// ----------------- | ||
test('candyMachineGPA: candyMachineAccountsForWallet for wallet with one candy machine created', async (t) => { | ||
// Given I create one candy machine with a wallet | ||
const mx = await metaplex(); | ||
const { candyMachineSigner, authorityAddress, walletAddress } = | ||
await createCandyMachineWithMinimalConfig(mx); | ||
|
||
// When I get the candy machines for the wallet | ||
const candyMachines = await mx.candyMachines().findCandyMachinesByWallet(walletAddress); | ||
|
||
// It returns that candy machine | ||
t.equal(candyMachines.length, 1, 'returns one account'); | ||
const cm = candyMachines[0]; | ||
spok(t, cm, { | ||
$topic: 'candyMachine', | ||
authorityAddress: spokSamePubkey(authorityAddress), | ||
walletAddress: spokSamePubkey(walletAddress), | ||
}); | ||
t.ok( | ||
candyMachineSigner.publicKey.toBase58().startsWith(cm.uuid), | ||
'candy machine uuid matches candyMachineSigner' | ||
); | ||
}); | ||
|
||
test('candyMachineGPA: candyMachineAccountsForWallet for wallet with two candy machines created for that wallet and one for another', async (t) => { | ||
// Given I create one candy machine with wallet1 and two with wallet2 | ||
|
||
// Other wallet | ||
{ | ||
const mx = await metaplex(); | ||
await createCandyMachineWithMinimalConfig(mx); | ||
} | ||
|
||
const mx = await metaplex(); | ||
// This wallet | ||
{ | ||
await createCandyMachineWithMinimalConfig(mx); | ||
await createCandyMachineWithMinimalConfig(mx); | ||
} | ||
|
||
// When I get the candy machines for the wallet | ||
const candyMachines = await mx.candyMachines().findCandyMachinesByWallet(mx.identity().publicKey); | ||
|
||
// It returns the two candy machine of wallet2 | ||
t.equal(candyMachines.length, 2, 'returns two machines'); | ||
|
||
for (const cm of candyMachines) { | ||
t.ok(cm.walletAddress.equals(mx.identity().publicKey), 'wallet matches'); | ||
} | ||
}); | ||
|
||
// ----------------- | ||
// Authority | ||
// ----------------- | ||
test('candyMachineGPA: candyMachineAccountsForAuthority for authority with one candy machine created', async (t) => { | ||
// Given I create a candy machine with a specific auhority | ||
const mx = await metaplex(); | ||
const { candyMachineSigner, authorityAddress, walletAddress } = | ||
await createCandyMachineWithMinimalConfig(mx); | ||
|
||
// When I get the candy machines for that authority | ||
const candyMachines = await mx.candyMachines().findCandyMachinesByAuthority(authorityAddress); | ||
|
||
// It returns that one candy machine for that authority | ||
t.equal(candyMachines.length, 1, 'returns one account'); | ||
const cm = candyMachines[0]; | ||
spok(t, cm, { | ||
$topic: 'candyMachine', | ||
authorityAddress: spokSamePubkey(authorityAddress), | ||
walletAddress: spokSamePubkey(walletAddress), | ||
}); | ||
t.ok( | ||
candyMachineSigner.publicKey.toBase58().startsWith(cm.uuid), | ||
'candy machine uuid matches candyMachineSigner' | ||
); | ||
}); |
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,59 @@ | ||
import { Keypair } from '@solana/web3.js'; | ||
import { amman, SKIP_PREFLIGHT } from '../../../helpers'; | ||
import { CandyMachineConfigWithoutStorage } from '@/plugins/candyMachineModule/config'; | ||
import { Metaplex } from '@/Metaplex'; | ||
|
||
/** | ||
* Creates a candy machine using the mx.identity as signer as well as | ||
* solTreasurySigner aka wallet. | ||
*/ | ||
export async function createCandyMachineWithMinimalConfig(mx: Metaplex) { | ||
const payer = mx.identity(); | ||
|
||
const solTreasurySigner = payer; | ||
await amman.airdrop(mx.connection, solTreasurySigner.publicKey, 100); | ||
|
||
const config: CandyMachineConfigWithoutStorage = { | ||
price: 1.0, | ||
number: 10, | ||
sellerFeeBasisPoints: 0, | ||
solTreasuryAccount: solTreasurySigner.publicKey.toBase58(), | ||
goLiveDate: '25 Dec 2021 00:00:00 GMT', | ||
retainAuthority: true, | ||
isMutable: false, | ||
}; | ||
|
||
const opts = { | ||
candyMachine: Keypair.generate(), | ||
confirmOptions: SKIP_PREFLIGHT, | ||
}; | ||
await amman.addr.addLabels({ ...config, ...opts, payer }); | ||
|
||
const cm = mx.candyMachines(); | ||
const { | ||
transactionId, | ||
confirmResponse, | ||
candyMachine, | ||
payerSigner, | ||
candyMachineSigner, | ||
authorityAddress, | ||
walletAddress, | ||
} = await cm.createCandyMachineFromConfig(config, opts); | ||
|
||
await amman.addr.addLabel('create: candy-machine', transactionId); | ||
|
||
return { | ||
cm, | ||
|
||
transactionId, | ||
confirmResponse, | ||
candyMachine, | ||
config, | ||
|
||
solTreasurySigner, | ||
payerSigner, | ||
candyMachineSigner, | ||
authorityAddress, | ||
walletAddress, | ||
}; | ||
} |
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 +1,2 @@ | ||
export * from './asserts'; | ||
export * from './create'; |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remind me to have a chat with you about this. I have recently been creating GpaBuilder classes for each account type (that extend a program GpaBuild when needed) where the constructor enforces the account constraint. I think this is good for now but something to discuss when we think about auto-generating them.