import type { MsgExecuteContractEncodeObject, SigningCosmWasmClient } from '@cosmjs/cosmwasm-stargate' import { toUtf8 } from '@cosmjs/encoding' import type { Coin } from '@cosmjs/proto-signing' import { coin } from '@cosmjs/proto-signing' import type { logs } from '@cosmjs/stargate' import type { Timestamp } from '@stargazezone/types/contracts/minter/shared-types' import { MsgExecuteContract } from 'cosmjs-types/cosmwasm/wasm/v1/tx' import type { AirdropAllocation } from 'utils/isValidAccountsFile' export interface InstantiateResponse { readonly contractAddress: string readonly transactionHash: string readonly logs: readonly logs.Log[] } export interface MigrateResponse { readonly transactionHash: string readonly logs: readonly logs.Log[] } export interface RoyaltyInfo { payment_address: string share: string } export interface VendingMinterInstance { readonly contractAddress: string //Query getConfig: () => Promise getMintableNumTokens: () => Promise getStartTime: () => Promise getMintPrice: () => Promise getMintCount: (address: string) => Promise //Execute mint: (senderAddress: string) => Promise purge: (senderAddress: string) => Promise updateMintPrice: (senderAddress: string, price: string) => Promise setWhitelist: (senderAddress: string, whitelist: string) => Promise updateStartTime: (senderAddress: string, time: Timestamp) => Promise updateStartTradingTime: (senderAddress: string, time?: Timestamp) => Promise updatePerAddressLimit: (senderAddress: string, perAddressLimit: number) => Promise mintTo: (senderAddress: string, recipient: string) => Promise mintFor: (senderAddress: string, recipient: string, tokenId: number) => Promise batchMintFor: (senderAddress: string, recipient: string, tokenIds: string) => Promise batchMint: (senderAddress: string, recipient: string, batchNumber: number) => Promise shuffle: (senderAddress: string) => Promise withdraw: (senderAddress: string) => Promise airdrop: (senderAddress: string, recipients: string[]) => Promise airdropSpecificTokens: (senderAddress: string, tokenRecipients: AirdropAllocation[]) => Promise burnRemaining: (senderAddress: string) => Promise updateDiscountPrice: (senderAddress: string, price: string) => Promise removeDiscountPrice: (senderAddress: string) => Promise } export interface VendingMinterMessages { mint: () => MintMessage purge: () => PurgeMessage updateMintPrice: (price: string) => UpdateMintPriceMessage setWhitelist: (whitelist: string) => SetWhitelistMessage updateStartTime: (time: Timestamp) => UpdateStartTimeMessage updateStartTradingTime: (time: Timestamp) => UpdateStartTradingTimeMessage updatePerAddressLimit: (perAddressLimit: number) => UpdatePerAddressLimitMessage mintTo: (recipient: string) => MintToMessage mintFor: (recipient: string, tokenId: number) => MintForMessage batchMintFor: (recipient: string, tokenIds: string) => BatchMintForMessage batchMint: (recipient: string, batchNumber: number) => CustomMessage shuffle: () => ShuffleMessage withdraw: () => WithdrawMessage airdrop: (recipients: string[]) => CustomMessage airdropSpecificTokens: (recipients: AirdropAllocation[]) => CustomMessage burnRemaining: () => BurnRemainingMessage updateDiscountPrice: (price: string) => UpdateDiscountPriceMessage removeDiscountPrice: () => RemoveDiscountPriceMessage } export interface MintMessage { sender: string contract: string msg: { mint: Record } funds: Coin[] } export interface PurgeMessage { sender: string contract: string msg: { purge: Record } funds: Coin[] } export interface UpdateMintPriceMessage { sender: string contract: string msg: { update_mint_price: { price: string } } funds: Coin[] } export interface UpdateDiscountPriceMessage { sender: string contract: string msg: { update_discount_price: { price: string } } funds: Coin[] } export interface RemoveDiscountPriceMessage { sender: string contract: string msg: { remove_discount_price: Record } funds: Coin[] } export interface SetWhitelistMessage { sender: string contract: string msg: { set_whitelist: { whitelist: string } } funds: Coin[] } export interface UpdateStartTimeMessage { sender: string contract: string msg: { update_start_time: string } funds: Coin[] } export interface UpdateStartTradingTimeMessage { sender: string contract: string msg: { update_start_trading_time: string } funds: Coin[] } export interface UpdatePerAddressLimitMessage { sender: string contract: string msg: { update_per_address_limit: { per_address_limit: number } } funds: Coin[] } export interface MintToMessage { sender: string contract: string msg: { mint_to: { recipient: string } } funds: Coin[] } export interface MintForMessage { sender: string contract: string msg: { mint_for: { recipient: string token_id: number } } funds: Coin[] } export interface BatchMintForMessage { sender: string contract: string msg: Record[] funds: Coin[] } export interface CustomMessage { sender: string contract: string msg: Record[] funds: Coin[] } export interface ShuffleMessage { sender: string contract: string msg: { shuffle: Record } funds: Coin[] } export interface WithdrawMessage { sender: string contract: string msg: { withdraw: Record } funds: Coin[] } export interface BurnRemainingMessage { sender: string contract: string msg: { burn_remaining: Record } funds: Coin[] } export interface MintPriceMessage { public_price: { denom: string amount: string } airdrop_price: { denom: string amount: string } whitelist_price?: { denom: string amount: string } current_price: { denom: string amount: string } } export interface VendingMinterContract { instantiate: ( senderAddress: string, codeId: number, initMsg: Record, label: string, admin?: string, funds?: Coin[], ) => Promise migrate: ( senderAddress: string, contractAddress: string, codeId: number, migrateMsg: Record, ) => Promise use: (contractAddress: string) => VendingMinterInstance messages: (contractAddress: string) => VendingMinterMessages } export const vendingMinter = (client: SigningCosmWasmClient, txSigner: string): VendingMinterContract => { const use = (contractAddress: string): VendingMinterInstance => { //Query const getConfig = async (): Promise => { const res = await client.queryContractSmart(contractAddress, { config: {}, }) return res } const getMintableNumTokens = async (): Promise => { const res = await client.queryContractSmart(contractAddress, { mintable_num_tokens: {}, }) return res } const getStartTime = async (): Promise => { const res = await client.queryContractSmart(contractAddress, { start_time: {}, }) return res } const getMintPrice = async (): Promise => { const res = await client.queryContractSmart(contractAddress, { mint_price: {}, }) return res } const getMintCount = async (address: string): Promise => { const res = await client.queryContractSmart(contractAddress, { mint_count: { address }, }) return res } //Execute const mint = async (senderAddress: string): Promise => { const price = (await getMintPrice()).public_price.amount const res = await client.execute( senderAddress, contractAddress, { mint: {}, }, 'auto', '', [coin(price, 'ustars')], ) return res.transactionHash } const purge = async (senderAddress: string): Promise => { const res = await client.execute( senderAddress, contractAddress, { purge: {}, }, 'auto', '', ) return res.transactionHash } const updateMintPrice = async (senderAddress: string, price: string): Promise => { const res = await client.execute( senderAddress, contractAddress, { update_mint_price: { price: (Number(price) * 1000000).toString(), }, }, 'auto', '', ) return res.transactionHash } const updateDiscountPrice = async (senderAddress: string, price: string): Promise => { const res = await client.execute( senderAddress, contractAddress, { update_discount_price: { price: (Number(price) * 1000000).toString(), }, }, 'auto', '', ) return res.transactionHash } const removeDiscountPrice = async (senderAddress: string): Promise => { const res = await client.execute( senderAddress, contractAddress, { remove_discount_price: {}, }, 'auto', '', ) return res.transactionHash } const setWhitelist = async (senderAddress: string, whitelist: string): Promise => { const res = await client.execute( senderAddress, contractAddress, { set_whitelist: { whitelist }, }, 'auto', '', ) return res.transactionHash } const updateStartTime = async (senderAddress: string, time: Timestamp): Promise => { const res = await client.execute( senderAddress, contractAddress, { update_start_time: time, }, 'auto', '', ) return res.transactionHash } const updateStartTradingTime = async (senderAddress: string, time?: Timestamp): Promise => { const res = await client.execute( senderAddress, contractAddress, { update_start_trading_time: time || null, }, 'auto', '', ) return res.transactionHash } const updatePerAddressLimit = async (senderAddress: string, perAddressLimit: number): Promise => { const res = await client.execute( senderAddress, contractAddress, { update_per_address_limit: { per_address_limit: perAddressLimit }, }, 'auto', '', ) return res.transactionHash } const mintTo = async (senderAddress: string, recipient: string): Promise => { const res = await client.execute( senderAddress, contractAddress, { mint_to: { recipient }, }, 'auto', '', ) return res.transactionHash } const mintFor = async (senderAddress: string, recipient: string, tokenId: number): Promise => { const res = await client.execute( senderAddress, contractAddress, { mint_for: { token_id: tokenId, recipient }, }, 'auto', '', ) return res.transactionHash } const batchMintFor = async (senderAddress: string, recipient: string, tokenIds: string): Promise => { const executeContractMsgs: MsgExecuteContractEncodeObject[] = [] if (tokenIds.includes(':')) { const [start, end] = tokenIds.split(':').map(Number) for (let i = start; i <= end; i++) { const msg = { mint_for: { token_id: i, recipient }, } const executeContractMsg: MsgExecuteContractEncodeObject = { typeUrl: '/cosmwasm.wasm.v1.MsgExecuteContract', value: MsgExecuteContract.fromPartial({ sender: txSigner, contract: contractAddress, msg: toUtf8(JSON.stringify(msg)), }), } executeContractMsgs.push(executeContractMsg) } } else { const tokenNumbers = tokenIds.split(',').map(Number) for (let i = 0; i < tokenNumbers.length; i++) { const msg = { mint_for: { token_id: tokenNumbers[i], recipient }, } const executeContractMsg: MsgExecuteContractEncodeObject = { typeUrl: '/cosmwasm.wasm.v1.MsgExecuteContract', value: MsgExecuteContract.fromPartial({ sender: txSigner, contract: contractAddress, msg: toUtf8(JSON.stringify(msg)), }), } executeContractMsgs.push(executeContractMsg) } } const res = await client.signAndBroadcast(txSigner, executeContractMsgs, 'auto', 'batch mint for') return res.transactionHash } const batchMint = async (senderAddress: string, recipient: string, batchNumber: number): Promise => { const executeContractMsgs: MsgExecuteContractEncodeObject[] = [] for (let i = 0; i < batchNumber; i++) { const msg = { mint_to: { recipient }, } const executeContractMsg: MsgExecuteContractEncodeObject = { typeUrl: '/cosmwasm.wasm.v1.MsgExecuteContract', value: MsgExecuteContract.fromPartial({ sender: senderAddress, contract: contractAddress, msg: toUtf8(JSON.stringify(msg)), }), } executeContractMsgs.push(executeContractMsg) } const res = await client.signAndBroadcast(senderAddress, executeContractMsgs, 'auto', 'batch mint') return res.transactionHash } const airdrop = async (senderAddress: string, recipients: string[]): Promise => { const executeContractMsgs: MsgExecuteContractEncodeObject[] = [] for (let i = 0; i < recipients.length; i++) { const msg = { mint_to: { recipient: recipients[i] }, } const executeContractMsg: MsgExecuteContractEncodeObject = { typeUrl: '/cosmwasm.wasm.v1.MsgExecuteContract', value: MsgExecuteContract.fromPartial({ sender: senderAddress, contract: contractAddress, msg: toUtf8(JSON.stringify(msg)), }), } executeContractMsgs.push(executeContractMsg) } const res = await client.signAndBroadcast(senderAddress, executeContractMsgs, 'auto', 'airdrop') return res.transactionHash } const airdropSpecificTokens = async (senderAddress: string, recipients: AirdropAllocation[]): Promise => { const executeContractMsgs: MsgExecuteContractEncodeObject[] = [] for (let i = 0; i < recipients.length; i++) { const msg = { mint_for: { recipient: recipients[i].address, token_id: Number(recipients[i].tokenId) }, } const executeContractMsg: MsgExecuteContractEncodeObject = { typeUrl: '/cosmwasm.wasm.v1.MsgExecuteContract', value: MsgExecuteContract.fromPartial({ sender: senderAddress, contract: contractAddress, msg: toUtf8(JSON.stringify(msg)), }), } executeContractMsgs.push(executeContractMsg) } const res = await client.signAndBroadcast(senderAddress, executeContractMsgs, 'auto', 'airdrop_specific_tokens') return res.transactionHash } const shuffle = async (senderAddress: string): Promise => { const res = await client.execute( senderAddress, contractAddress, { shuffle: {}, }, 'auto', '', [coin(500000000, 'ustars')], ) return res.transactionHash } const withdraw = async (senderAddress: string): Promise => { const res = await client.execute( senderAddress, contractAddress, { withdraw: {}, }, 'auto', '', ) return res.transactionHash } const burnRemaining = async (senderAddress: string): Promise => { const res = await client.execute( senderAddress, contractAddress, { burn_remaining: {}, }, 'auto', '', ) return res.transactionHash } return { contractAddress, getConfig, getMintableNumTokens, getStartTime, getMintPrice, getMintCount, mint, purge, updateMintPrice, updateDiscountPrice, removeDiscountPrice, setWhitelist, updateStartTime, updateStartTradingTime, updatePerAddressLimit, mintTo, mintFor, batchMintFor, batchMint, airdrop, airdropSpecificTokens, shuffle, withdraw, burnRemaining, } } const migrate = async ( senderAddress: string, contractAddress: string, codeId: number, migrateMsg: Record, ): Promise => { const result = await client.migrate(senderAddress, contractAddress, codeId, migrateMsg, 'auto') return { transactionHash: result.transactionHash, logs: result.logs, } } const instantiate = async ( senderAddress: string, codeId: number, initMsg: Record, label: string, ): Promise => { const result = await client.instantiate(senderAddress, codeId, initMsg, label, 'auto', { funds: [coin('3000000000', 'ustars')], }) return { contractAddress: result.contractAddress, transactionHash: result.transactionHash, logs: result.logs, } } const messages = (contractAddress: string) => { const mint = (): MintMessage => { return { sender: txSigner, contract: contractAddress, msg: { mint: {}, }, funds: [], } } const purge = (): PurgeMessage => { return { sender: txSigner, contract: contractAddress, msg: { purge: {}, }, funds: [], } } const updateMintPrice = (price: string): UpdateMintPriceMessage => { return { sender: txSigner, contract: contractAddress, msg: { update_mint_price: { price: (Number(price) * 1000000).toString(), }, }, funds: [], } } const updateDiscountPrice = (price: string): UpdateDiscountPriceMessage => { return { sender: txSigner, contract: contractAddress, msg: { update_discount_price: { price: (Number(price) * 1000000).toString(), }, }, funds: [], } } const removeDiscountPrice = (): RemoveDiscountPriceMessage => { return { sender: txSigner, contract: contractAddress, msg: { remove_discount_price: {}, }, funds: [], } } const setWhitelist = (whitelist: string): SetWhitelistMessage => { return { sender: txSigner, contract: contractAddress, msg: { set_whitelist: { whitelist, }, }, funds: [], } } const updateStartTime = (startTime: string): UpdateStartTimeMessage => { return { sender: txSigner, contract: contractAddress, msg: { update_start_time: startTime, }, funds: [], } } const updateStartTradingTime = (startTime: string): UpdateStartTradingTimeMessage => { return { sender: txSigner, contract: contractAddress, msg: { update_start_trading_time: startTime, }, funds: [], } } const updatePerAddressLimit = (limit: number): UpdatePerAddressLimitMessage => { return { sender: txSigner, contract: contractAddress, msg: { update_per_address_limit: { per_address_limit: limit, }, }, funds: [], } } const mintTo = (recipient: string): MintToMessage => { return { sender: txSigner, contract: contractAddress, msg: { mint_to: { recipient, }, }, funds: [], } } const mintFor = (recipient: string, tokenId: number): MintForMessage => { return { sender: txSigner, contract: contractAddress, msg: { mint_for: { recipient, token_id: tokenId, }, }, funds: [], } } const batchMintFor = (recipient: string, tokenIds: string): BatchMintForMessage => { const msg: Record[] = [] if (tokenIds.includes(':')) { const [start, end] = tokenIds.split(':').map(Number) for (let i = start; i <= end; i++) { msg.push({ mint_for: { token_id: i.toString(), recipient }, }) } } else { const tokenNumbers = tokenIds.split(',').map(Number) for (let i = 0; i < tokenNumbers.length; i++) { msg.push({ mint_for: { token_id: tokenNumbers[i].toString(), recipient } }) } } return { sender: txSigner, contract: contractAddress, msg, funds: [], } } const batchMint = (recipient: string, batchNumber: number): CustomMessage => { const msg: Record[] = [] for (let i = 0; i < batchNumber; i++) { msg.push({ mint_to: { recipient } }) } return { sender: txSigner, contract: contractAddress, msg, funds: [], } } const airdrop = (recipients: string[]): CustomMessage => { const msg: Record[] = [] for (let i = 0; i < recipients.length; i++) { msg.push({ mint_to: { recipient: recipients[i] } }) } return { sender: txSigner, contract: contractAddress, msg, funds: [], } } const airdropSpecificTokens = (recipients: AirdropAllocation[]): CustomMessage => { const msg: Record[] = [] for (let i = 0; i < recipients.length; i++) { msg.push({ mint_for: { recipient: recipients[i].address, token_id: recipients[i].tokenId } }) } return { sender: txSigner, contract: contractAddress, msg, funds: [], } } const shuffle = (): ShuffleMessage => { return { sender: txSigner, contract: contractAddress, msg: { shuffle: {}, }, funds: [], } } const withdraw = (): WithdrawMessage => { return { sender: txSigner, contract: contractAddress, msg: { withdraw: {}, }, funds: [], } } const burnRemaining = (): BurnRemainingMessage => { return { sender: txSigner, contract: contractAddress, msg: { burn_remaining: {}, }, funds: [], } } return { mint, purge, updateMintPrice, updateDiscountPrice, removeDiscountPrice, setWhitelist, updateStartTime, updateStartTradingTime, updatePerAddressLimit, mintTo, mintFor, batchMintFor, batchMint, airdrop, airdropSpecificTokens, shuffle, withdraw, burnRemaining, } } return { use, instantiate, migrate, messages } }