95 lines
3.3 KiB
TypeScript
95 lines
3.3 KiB
TypeScript
import { address, type Account, type Address, type Rpc } from '@solana/kit'
|
|
import { type GetProgramAccountsApi } from '@solana/rpc-api'
|
|
import { type GetAccountInfoApi } from '@solana/rpc-api'
|
|
import type { Base64EncodedBytes, Lamports } from '@solana/rpc-types'
|
|
import {
|
|
decodeSolistingStateOrderAccount,
|
|
fetchSolistingStateOrderAccount,
|
|
getSolistingStateOrderAccountDiscriminatorBytes,
|
|
type SolistingStateOrderAccount,
|
|
} from './generated/solisting/src/generated/index'
|
|
import { deriveEscrowId } from './pda'
|
|
|
|
const PROGRAM_ADDRESS = address('9uF64swnFqo34oFJtv8Qx9JDyXXJz73eDFF4cKRBfQBZ')
|
|
|
|
export type OrderAccountWithPda = Account<SolistingStateOrderAccount>
|
|
type GpaRpc = Rpc<GetProgramAccountsApi>
|
|
type GetRpc = Rpc<GetAccountInfoApi>
|
|
|
|
// OrderAccount byte layout (Sol-currency variant, the only one currently implemented):
|
|
// 0: discriminator (8)
|
|
// 8: listing (32)
|
|
// 40: buyer (32)
|
|
// 72: seller (32)
|
|
// 104: resolver Option<Pubkey> = 1 byte tag + 32 bytes = 33 bytes
|
|
// 137: paymentCurrency — Sol variant = 1 byte tag + 0 data = 1 byte total
|
|
// 138: amount (8)
|
|
// 146: escrowAccount (32)
|
|
const LISTING_OFFSET = 8n
|
|
const BUYER_OFFSET = 40n
|
|
// escrowAccount offset is only valid for Sol-currency orders.
|
|
// SPL orders (currently rejected by the program with SplNotImplemented) would sit at offset 179.
|
|
const ESCROW_ACCOUNT_OFFSET = 146n
|
|
|
|
type RawGpaResult = Array<{
|
|
pubkey: Address
|
|
account: {
|
|
executable: boolean
|
|
lamports: bigint
|
|
owner: Address
|
|
space: bigint
|
|
data: [string, 'base64']
|
|
}
|
|
}>
|
|
|
|
const DISC_BASE64 = Buffer.from(
|
|
getSolistingStateOrderAccountDiscriminatorBytes(),
|
|
).toString('base64') as Base64EncodedBytes
|
|
|
|
async function gpa(
|
|
rpc: GpaRpc,
|
|
addressFilter: { offset: bigint; addr: Address },
|
|
): Promise<OrderAccountWithPda[]> {
|
|
const results = await rpc
|
|
.getProgramAccounts(PROGRAM_ADDRESS, {
|
|
encoding: 'base64',
|
|
filters: [
|
|
{ memcmp: { offset: 0n, bytes: DISC_BASE64, encoding: 'base64' } },
|
|
{ memcmp: { offset: addressFilter.offset, bytes: addressFilter.addr as never, encoding: 'base58' } },
|
|
],
|
|
})
|
|
.send()
|
|
|
|
return (results as RawGpaResult).map((r) => {
|
|
const data = new Uint8Array(Buffer.from(r.account.data[0], 'base64'))
|
|
return decodeSolistingStateOrderAccount({
|
|
address: r.pubkey,
|
|
data,
|
|
executable: r.account.executable,
|
|
lamports: r.account.lamports as unknown as Lamports,
|
|
programAddress: r.account.owner,
|
|
space: r.account.space,
|
|
exists: true,
|
|
}) as OrderAccountWithPda
|
|
})
|
|
}
|
|
|
|
export function fetchOrdersForListing(rpc: GpaRpc, listingPk: Address): Promise<OrderAccountWithPda[]> {
|
|
return gpa(rpc, { offset: LISTING_OFFSET, addr: listingPk })
|
|
}
|
|
|
|
export function fetchOrdersByBuyer(rpc: GpaRpc, buyer: Address): Promise<OrderAccountWithPda[]> {
|
|
return gpa(rpc, { offset: BUYER_OFFSET, addr: buyer })
|
|
}
|
|
|
|
export async function fetchOrderByEscrow(rpc: GpaRpc, escrowPda: Address): Promise<OrderAccountWithPda | null> {
|
|
const results = await gpa(rpc, { offset: ESCROW_ACCOUNT_OFFSET, addr: escrowPda })
|
|
return results[0] ?? null
|
|
}
|
|
|
|
export async function fetchOrder(rpc: GetRpc, addr: Address): Promise<OrderAccountWithPda | null> {
|
|
return fetchSolistingStateOrderAccount(rpc, addr).catch(() => null)
|
|
}
|
|
|
|
export { deriveEscrowId }
|