Managing Sales
Sales are identified by a SaleKey and configured with a SaleState.
Key details:
- The
SaleKeyis the immutable identity of a sale. Changing any field creates a newsaleKeyId. UseupdateSaleonly when theSaleKeystays the same, and usenonceto create multiple sales for the same token. startTimeandendTimeare Unix timestamps (seconds).startTimemust be non-zero;0nis treated as "uninitialized" onchain.priceis expressed in the smallest unit of the sale currency (use the ERC20's decimals).
Registering a Sale
import { Gatekeeper, Factory, gatekeeperAddress } from '@sceneinfrastructure/sdk'
const chainId = 8453 // Base
const saleKey = {
token: '0x2345678901234567890123456789012345678901', // Your deployed contract
tokenId: 1n,
currency: '0x1111111111111111111111111111111111111111',
fundsRecipient: '0x4567890123456789012345678901234567890123',
vendor: '0x5678901234567890123456789012345678901234',
vendorFeeBps: 0,
referralFeeBps: 0,
salesTaxBps: 0,
nonce: 1n,
} as const
const saleState = {
startTime: 1n,
endTime: 9999999999n,
quantity: 100,
price: 1000000n,
approvers: [],
}
// Encode the registerSale call
const registerData = Gatekeeper.encodeRegisterSale({
saleKey,
saleState,
})
// Wrap in callGatekeeper (for use during deployment)
const callData = Factory.encodeCallGatekeeper({
gatekeeper: gatekeeperAddress[chainId],
data: registerData,
})If you're registering or updating sales after deployment, call Gatekeeper1155.callGatekeeper directly (requires ADMIN_ROLE or owner on the token contract):
import { gatekeeper1155Abi, Gatekeeper, gatekeeperAddress } from '@sceneinfrastructure/sdk'
import { createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { base } from 'viem/chains'
const account = privateKeyToAccount('0x...' as `0x${string}`)
const walletClient = createWalletClient({
account,
chain: base,
transport: http(),
})
const chainId = 8453 // Base
const tokenContract = '0x2345678901234567890123456789012345678901'
const saleKey = {
token: tokenContract,
tokenId: 1n,
currency: '0x1111111111111111111111111111111111111111',
fundsRecipient: '0x4567890123456789012345678901234567890123',
vendor: '0x5678901234567890123456789012345678901234',
vendorFeeBps: 0,
referralFeeBps: 0,
salesTaxBps: 0,
nonce: 1n,
} as const
const saleState = {
startTime: 1n,
endTime: 9999999999n,
quantity: 100,
price: 1000000n,
approvers: [],
}
const registerData = Gatekeeper.encodeRegisterSale({ saleKey, saleState })
// await walletClient.writeContract({
// address: tokenContract,
// abi: gatekeeper1155Abi,
// functionName: 'callGatekeeper',
// args: [gatekeeperAddress[chainId], registerData],
// })Approval-Gated Sales
For sales requiring approval signatures, add approver addresses:
import { Gatekeeper } from '@sceneinfrastructure/sdk'
const chainId = 8453 // Base
const saleKey = {
token: '0x1234567890123456789012345678901234567890', // Your deployed contract
tokenId: 1n,
currency: '0x1111111111111111111111111111111111111111',
fundsRecipient: '0x3456789012345678901234567890123456789012',
vendor: '0x4567890123456789012345678901234567890123',
vendorFeeBps: 0,
referralFeeBps: 0,
salesTaxBps: 0,
nonce: 1n,
} as const
const registerData = Gatekeeper.encodeRegisterSale({
saleKey,
saleState: {
startTime: 1n,
endTime: 9999999999n,
quantity: 100,
price: 1000000n,
approvers: [
'0x5678901234567890123456789012345678901234',
'0x6789012345678901234567890123456789012345',
],
},
})When approvers are set, purchases require a valid EIP-712 signature from one of the approvers. See Executing Purchases for details.
Updating a Sale
Update an existing sale's configuration:
import { Gatekeeper, Factory, gatekeeperAddress } from '@sceneinfrastructure/sdk'
const chainId = 8453 // Base
const saleKey = {
token: '0x2345678901234567890123456789012345678901', // Your deployed contract
tokenId: 1n,
currency: '0x1111111111111111111111111111111111111111',
fundsRecipient: '0x4567890123456789012345678901234567890123',
vendor: '0x5678901234567890123456789012345678901234',
vendorFeeBps: 0,
referralFeeBps: 0,
salesTaxBps: 0,
nonce: 1n,
} as const
// End the sale by setting endTime to now
const updateData = Gatekeeper.encodeUpdateSale({
saleKey,
saleState: {
startTime: 1n,
endTime: BigInt(Math.floor(Date.now() / 1000)),
quantity: 0,
price: 0n,
approvers: [],
},
})
// Wrap in callGatekeeper
const callData = Factory.encodeCallGatekeeper({
gatekeeper: gatekeeperAddress[chainId],
data: updateData,
})Generating Sale Key IDs
The SaleKey is hashed to create a unique identifier:
import { SaleKey } from '@sceneinfrastructure/sdk'
const chainId = 8453 // Base
const saleKey = {
token: '0x1234567890123456789012345678901234567890', // Your deployed contract
tokenId: 1n,
currency: '0x1111111111111111111111111111111111111111',
fundsRecipient: '0x3456789012345678901234567890123456789012',
vendor: '0x4567890123456789012345678901234567890123',
vendorFeeBps: 0,
referralFeeBps: 0,
salesTaxBps: 0,
nonce: 1n,
} as const
const saleKeyId = SaleKey.generateId(saleKey)
console.log('Sale Key ID:', saleKeyId)Converting Sale to SaleKey
If you have a full Sale object from the indexer, convert it to a SaleKey:
import { Client, Sale } from '@sceneinfrastructure/sdk'
const client = Client.create({ url: '...' })
// Get a sale from the indexer
const saleKeyId = '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef' as const
const sale = await client.sale.get({ saleKeyId })
if (sale) {
// Convert to SaleKey for contract calls
const saleKey = Sale.toSaleKey(sale)
console.log('SaleKey:', saleKey)
}Next Steps
- Execute purchases from your registered sales
- API Reference: Gatekeeper for complete function documentation
- API Reference: Sale for type definitions