Integrate your dApp with Spooky Doge wallet for Dogecoin payments and Doginal transfers
Spooky Doge wallet is available on:
window.dogecoin provider, so you can support all users with a single codebase.
// Check if Spooky Doge wallet is available
function isSpookyWalletAvailable() {
return typeof window.dogecoin !== 'undefined' && window.dogecoin.isSpookyWallet;
}
// Wait for wallet to be ready (it injects after page load)
window.addEventListener('dogecoin#initialized', () => {
console.log('Spooky Doge wallet detected!');
});
async function connectWallet() {
if (!isSpookyWalletAvailable()) {
alert('Please install Spooky Doge wallet or open in the Spooky Doge app browser');
return null;
}
try {
// Opens approval popup for user
const result = await window.dogecoin.connect();
console.log('Connected! Address:', result.address);
return result.address;
} catch (error) {
console.error('Connection rejected:', error.message);
return null;
}
}
// Get connected address
const address = await window.dogecoin.getAddress();
// Get wallet balance in koinu (1 DOGE = 100,000,000 koinu)
const balance = await window.dogecoin.getBalance();
const dogeBalance = balance / 100000000;
// Check if currently connected
const connected = window.dogecoin.isConnected();
// Get all connected accounts
const accounts = await window.dogecoin.getAccounts();
// Simple single-output transaction
async function sendPayment(recipientAddress, amountInDoge) {
try {
// Opens transaction approval popup
const result = await window.dogecoin.sendTransaction({
to: recipientAddress,
amount: amountInDoge // Amount in DOGE (not koinu)
});
console.log('Transaction sent! TXID:', result.txid);
return result.txid;
} catch (error) {
console.error('Transaction failed:', error.message);
throw error;
}
}
// Advanced: Multi-output transaction (e.g., with marketplace fee)
async function sendPaymentWithFee(recipientAddress, amount, marketplaceFeeAddress, feeAmount) {
try {
const result = await window.dogecoin.sendTransaction({
outputs: [
{ address: recipientAddress, amount: amount },
{ address: marketplaceFeeAddress, amount: feeAmount }
]
});
console.log('Transaction sent! TXID:', result.txid);
return result.txid;
} catch (error) {
console.error('Transaction failed:', error.message);
throw error;
}
}
// Example: Send 100 DOGE to seller + 5 DOGE marketplace fee
await sendPaymentWithFee('DSellerAddress...', 100, 'DMarketplaceFeeAddress...', 5);
// Get all doginals in the wallet
const doginals = await window.dogecoin.getDoginals();
doginals.forEach(d => {
console.log('Inscription:', d.inscriptionId);
console.log('Image URL:', d.imageUrl);
console.log('Content Type:', d.contentType);
});
// Transfer a single doginal
async function transferDoginal(inscriptionId, recipientAddress) {
try {
const result = await window.dogecoin.sendDoginal({
inscriptionId: inscriptionId, // Single inscription ID
to: recipientAddress
});
console.log('Doginal transferred! TXID:', result.txid);
return result.txid;
} catch (error) {
console.error('Transfer failed:', error.message);
throw error;
}
}
// Transfer MULTIPLE doginals in one transaction
async function transferMultipleDoginals(inscriptionIds, recipientAddress) {
try {
const result = await window.dogecoin.sendDoginal({
inscriptionId: inscriptionIds, // Array of inscription IDs
to: recipientAddress
});
console.log('Doginals transferred! TXID:', result.txid);
return result.txid;
} catch (error) {
console.error('Transfer failed:', error.message);
throw error;
}
}
// Example: Send 3 doginals at once
const myDoginals = ['abc123i0', 'def456i0', 'ghi789i0'];
await transferMultipleDoginals(myDoginals, 'DRecipientAddress...');
// Request a message signature (no cost, requires user approval)
async function signMessage(message) {
try {
const result = await window.dogecoin.signMessage(message);
console.log('Signature:', result.signature);
console.log('Signed by:', result.address);
return result;
} catch (error) {
console.error('Signing failed:', error.message);
throw error;
}
}
// Get DRC-20 token balances
async function getDrc20Balances() {
const balances = await window.dogecoin.request({
method: 'doge_getDrc20Balances'
});
// Returns: [{ tick: 'DOGI', available: '1000', transferable: '500', total: '1500' }, ...]
return balances;
}
// Send DRC-20 tokens
async function sendDrc20(tick, amount, recipient) {
const result = await window.dogecoin.request({
method: 'doge_sendDrc20',
params: {
tick: tick, // Token ticker (e.g., 'DOGI')
amount: amount, // Amount as string
to: recipient // Recipient address
}
});
return result.txid;
}
Fee: 0.03 DOGE per transfer (0.02 network + 0.01 wallet)
// Get Dunes token balances
async function getDunesBalances() {
const balances = await window.dogecoin.request({
method: 'doge_getDunesBalances'
});
// Returns: [{ name: 'COOL•DUNE', symbol: 'COOLDUNE', balance: '5000', divisibility: 0 }, ...]
return balances;
}
// Send Dunes tokens
async function sendDune(duneName, amount, recipient) {
const result = await window.dogecoin.request({
method: 'doge_sendDune',
params: {
duneName: duneName, // Dune name (e.g., 'COOL•DUNE')
amount: amount, // Amount as string
to: recipient // Recipient address
}
});
return result.txid;
}
Fee: Variable (0.02 DOGE for single-dune UTXO, 0.20 DOGE for multi-dune auto-split)
// Send Dunes to MULTIPLE recipients in one transaction (up to 50)
async function sendDuneToMany(duneName, recipients) {
try {
const result = await window.dogecoin.sendDuneMulti({
duneName: duneName,
outputs: recipients // [{ address: 'D...', amount: '100' }, ...]
});
console.log('Multi-dune transfer sent! TXID:', result.txid);
return result.txid;
} catch (error) {
console.error('Multi-dune transfer failed:', error.message);
throw error;
}
}
// Example: Distribute dune rewards to 3 stakers
await sendDuneToMany('SPOOKY.DOGE', [
{ address: 'DStaker1Address...', amount: '500' },
{ address: 'DStaker2Address...', amount: '250' },
{ address: 'DStaker3Address...', amount: '1000' },
]);
Fee: Base 0.20 DOGE + scaling per input/output + 0.01 DOGE wallet fee. Max 50 recipients per transaction.
Send a DRC-20 token to up to 500 recipients in one operation. Designed for airdrop tools and staking reward distribution. Each recipient can receive a different amount.
// Batch send DRC-20 tokens to many recipients
async function batchSendDrc20(tick, recipients) {
try {
const result = await window.dogecoin.request({
method: 'doge_batchSendDrc20',
params: {
tick: tick, // DRC-20 token ticker (e.g., 'SLIME')
recipients: recipients // [{ address: 'D...', amount: '1000' }, ...]
}
});
console.log('Batch complete!');
console.log('Distribution TXIDs:', result.distributionTxids);
console.log('Completed:', result.completedRecipients, '/', result.totalRecipients);
return result;
} catch (error) {
if (error.message === 'User rejected') {
console.log('User declined the batch send');
} else {
console.error('Batch failed:', error.message);
}
throw error;
}
}
// Example: Airdrop SLIME to 5 holders
await batchSendDrc20('SLIME', [
{ address: 'DHolder1...', amount: '1000' },
{ address: 'DHolder2...', amount: '500' },
{ address: 'DHolder3...', amount: '2500' },
{ address: 'DHolder4...', amount: '750' },
{ address: 'DHolder5...', amount: '1200' },
]);
Limits: Maximum 500 recipients per call. Distribution transactions auto-split if they exceed ~95KB.
Fee: 0.02 DOGE per inscription tx (2 per recipient = 0.04/recipient) + distribution fee (0.02 base + 0.01 per recipient dust penalty) + 0.01 DOGE dev fee. Example: 50 recipients ≈ 2.54 DOGE total.
// Account changes (user switches address)
window.dogecoin.on('accountsChanged', (accounts) => {
if (accounts.length === 0) {
console.log('Wallet disconnected');
} else {
console.log('Active account:', accounts[0]);
}
});
// Connection events
window.dogecoin.on('connect', ({ address }) => {
console.log('Connected:', address);
});
window.dogecoin.on('disconnect', () => {
console.log('Wallet disconnected');
});
Available at window.dogecoin or window.spookyWallet
| Property | Type | Description |
|---|---|---|
isSpookyWallet |
boolean |
Always true - identifies the wallet |
isConnected() |
function |
Returns true if site is connected |
connect()Request wallet connection. Opens approval popup.
Returns: Promise<{ address: string }>
disconnect()Disconnect the dApp from the wallet.
Returns: Promise<void>
getAddress()Get the currently connected address.
Returns: Promise<string | null> - Null if not connected
getAccounts()Get all connected accounts.
Returns: Promise<string[]>
getBalance()Get wallet balance in koinu.
Returns: Promise<number> - Balance in koinu (divide by 100,000,000 for DOGE)
getDoginals()Get all doginals (inscriptions) in the wallet.
Returns: Promise<Doginal[]>
interface Doginal {
inscriptionId: string; // Unique inscription identifier
output: string; // UTXO reference (txid:vout)
contentType: string; // MIME type (e.g., 'image/png', 'text/html')
imageUrl: string; // CDN URL for the content
value?: number; // UTXO value in DOGE (optional)
}
sendTransaction(params)Request a DOGE transaction. Opens approval popup. Supports both simple single-output and advanced multi-output formats.
Parameters (Simple):
{
to: string; // Recipient Dogecoin address
amount: number; // Amount in DOGE (not koinu)
}
Parameters (Multi-Output):
{
outputs: Array<{
address: string; // Recipient Dogecoin address
amount: number; // Amount in DOGE
}>;
}
Returns: Promise<{ txid: string }>
sendDoginal(params)Request a doginal transfer. Opens approval popup. Supports both single and multiple inscription transfers.
Parameters:
{
inscriptionId: string | string[]; // Single ID or array of inscription IDs
to: string; // Recipient Dogecoin address
}
Returns: Promise<{ txid: string }>
signMessage(message)Request a message signature. Opens approval popup. Free - no DOGE cost
Parameters: message (string) - The message to sign
Returns: Promise<{ signature: string, address: string }>
The signature is in Bitcoin/Dogecoin signed message format (base64-encoded, 65 bytes), compatible with verifymessage in Dogecoin Core.
signPsbt(params)Request signing of a partially signed transaction (PSBT). Opens approval popup. Marketplace Integration
This method enables marketplaces to request partial transaction signing for trading Doginals, DRC-20 tokens, and Dunes. The wallet signs only the specified inputs, returning the signed hex to the marketplace for finalization and broadcast.
Accepted formats: Both BIP174 PSBT format (industry standard, starts with magic bytes 70736274ff) and raw transaction hex are supported. If BIP174 is provided, the wallet returns a signed BIP174 PSBT with partial signatures added. If raw hex is provided, the wallet returns a signed raw transaction hex.
Parameters:
{
psbtHex: string; // BIP174 PSBT hex or raw transaction hex
signInputs?: number[]; // Input indices to sign (default: all)
sighashTypes?: number[]; // Per-input sighash types (default: [0x01] SIGHASH_ALL)
message?: string; // Optional message to display to user (e.g. "Buy Doginal #1234 for 500 DOGE")
imageUrl?: string; // Optional image URL to display in approval popup (e.g. doginal thumbnail)
}
Returns: Promise<{ signedPsbtHex: string }>
Supported sighash types:
| Type | Value | Use Case |
|---|---|---|
SIGHASH_ALL | 0x01 | Default — signs all inputs and outputs (buyer purchases) |
SIGHASH_NONE | 0x02 | Signs inputs but no outputs |
SIGHASH_SINGLE | 0x03 | Signs only the output at the same index as the input |
SIGHASH_ALL|ANYONECANPAY | 0x81 | Signs one input and all outputs |
SIGHASH_NONE|ANYONECANPAY | 0x82 | Signs one input, no outputs |
SIGHASH_SINGLE|ANYONECANPAY | 0x83 | Marketplace listings — seller signs their input + matching output, buyer can add inputs/outputs later |
SIGHASH_SINGLE|ANYONECANPAY (0x83) when listing. This lets the buyer add their payment inputs and change outputs without invalidating the seller's signature. Buyers should use SIGHASH_ALL (0x01) to finalize the transaction.
message parameter to enhance the approval popup:
sighashTypes includes 0x83, the title shows "List for Sale" and the button says "List"."List [Item Name] for [amount] DOGE" or "Buy [Item Name] for [amount] DOGE""List Spook #34 for 500 DOGE", "Buy CoolDoge #12 for 100 DOGE"signPsbts), the wallet sums up all DOGE amounts and shows a total at the bottom of the approval popup.async function listDoginal(psbtHex, inputsToSign, doginalInfo) {
try {
const result = await window.dogecoin.signPsbt({
psbtHex: psbtHex,
signInputs: inputsToSign,
message: `List ${doginalInfo.name} for ${doginalInfo.price} DOGE`,
imageUrl: doginalInfo.thumbnailUrl
});
// Store the signed PSBT as an active listing on your marketplace
return result.signedPsbtHex;
} catch (error) {
console.error('Listing failed:', error.message);
throw error;
}
}
async function buyDoginal(psbtHex, buyerInputs, doginalInfo) {
try {
const result = await window.dogecoin.signPsbt({
psbtHex: psbtHex,
signInputs: buyerInputs,
message: `Buy ${doginalInfo.name} for ${doginalInfo.price} DOGE`,
imageUrl: doginalInfo.thumbnailUrl
});
// PSBT is now fully signed (seller + buyer), finalize and broadcast
return result.signedPsbtHex;
} catch (error) {
console.error('Purchase failed:', error.message);
throw error;
}
}
signPsbts(params) Batch MarketplaceRequest batch signing of multiple PSBTs at once. Opens a single approval popup showing all transactions. Used for batch marketplace operations.
This method enables marketplaces to request signing of multiple transactions in a single user interaction. Ideal for listing multiple Doginals, DRC-20 tokens, or Dunes at once. Each PSBT is signed independently, so buyers can purchase individual listings separately.
Parameters:
{
psbts: Array<{
psbtHex: string; // BIP174 PSBT hex or raw transaction hex
signInputs?: number[]; // Input indices to sign (default: all)
sighashTypes?: number[]; // Per-input sighash types (default: [0x01] SIGHASH_ALL)
message?: string; // Optional message for this transaction (e.g. "List Doginal #1234 for 500 DOGE")
imageUrl?: string; // Optional image URL for this transaction (e.g. doginal thumbnail)
}>
}
Returns: Promise<{ signedPsbts: Array<{ signedPsbtHex: string }> }>
The returned signedPsbts array matches the order of the input psbts array.
async function batchListDoginals(listings) {
try {
const result = await window.dogecoin.signPsbts({
psbts: listings.map(listing => ({
psbtHex: listing.psbtHex,
signInputs: listing.inputsToSign,
message: `List ${listing.name} for ${listing.price} DOGE`,
imageUrl: listing.thumbnailUrl
}))
});
// Each signed PSBT is independent - store each as a separate listing
result.signedPsbts.forEach((signed, index) => {
console.log(`Listed ${listings[index].name}:`, signed.signedPsbtHex);
});
return result.signedPsbts;
} catch (error) {
console.error('Batch listing failed:', error.message);
throw error;
}
}
request() Methodconst result = await window.dogecoin.request({
method: 'doge_signPsbts',
params: {
psbts: [
{ psbtHex: '...', message: 'List Doginal #1 for 100 DOGE', imageUrl: 'https://...' },
{ psbtHex: '...', message: 'List Doginal #2 for 200 DOGE', imageUrl: 'https://...' }
]
}
});
batchSendDune(params) Batch / AirdropBatch send a Dunes token to up to 1000 recipients in one operation. The wallet automatically splits recipients into batches that fit within Dogecoin's 80-byte OP_RETURN relay limit (~10-12 per transaction depending on amounts). Opens a single approval popup showing all recipients, amounts, batch count, and fee breakdown. Designed for airdrop tools and staking reward distribution.
Parameters:
{
duneName: string; // Dune name (e.g., "MY.DUNE")
duneId: string; // Dune ID (e.g., "5000000:42")
divisibility: number; // Token divisibility (e.g., 8)
recipients: Array<{
address: string; // Recipient Dogecoin address
amount: string; // Amount as string (e.g., "100")
}>;
}
Returns:
Promise<{
txids: string[]; // Transaction IDs for each batch
totalRecipients: number; // Total recipients processed
}>
Limits: Maximum 1000 recipients per call. Each batch contains ~10-12 recipients (calculated dynamically based on OP_RETURN payload size). The wallet chains change UTXOs between batches automatically.
| Fee Component | Amount | Notes |
|---|---|---|
| Size-based network fee | ~0.005 DOGE | Per batch, scales with actual tx size (0.01 DOGE/KB) |
| Dust penalty | 0.01 DOGE | Per dust output (recipients + dune change) |
| Dev fee | 0.01 DOGE | Per batch |
Example fee calculations (assuming 10 recipients per batch):
const result = await window.dogecoin.request({
method: 'doge_batchSendDune',
params: {
duneName: 'MY.DUNE',
duneId: '5000000:42',
divisibility: 8,
recipients: [
{ address: 'DAddr1...', amount: '100' },
{ address: 'DAddr2...', amount: '250' },
{ address: 'DAddr3...', amount: '500' },
// ... up to 1000 recipients
]
}
});
console.log('Batch TXIDs:', result.txids);
console.log('Total recipients:', result.totalRecipients);
batchSendDrc20(params) Batch / AirdropBatch send a DRC-20 token to up to 500 recipients in one operation. Opens approval popup showing all recipients with amounts and fee breakdown. Designed for airdrop tools and staking reward distribution.
Parameters:
{
tick: string; // DRC-20 token ticker (e.g., "SLIME")
recipients: Array<{
address: string; // Recipient Dogecoin address
amount: string; // Amount as string (e.g., "1000")
}>;
}
Returns:
Promise<{
distributionTxids: string[]; // Distribution transaction IDs
inscriptionTxids: string[]; // All commit+reveal transaction IDs
completedRecipients: number; // Recipients successfully processed
totalRecipients: number; // Total requested
}>
Limits: Maximum 500 recipients per call. Distribution auto-splits at ~95KB.
Example: 50 recipients ≈ 2.54 DOGE total. 500 recipients ≈ 25.04 DOGE total.
const result = await window.dogecoin.request({
method: 'doge_batchSendDrc20',
params: {
tick: 'SLIME',
recipients: [
{ address: 'DAddr1...', amount: '1000' },
{ address: 'DAddr2...', amount: '500' },
{ address: 'DAddr3...', amount: '2500' },
]
}
});
console.log('Distribution TXIDs:', result.distributionTxids);
request(args)EIP-1193 style request method for compatibility.
// Examples
const accounts = await window.dogecoin.request({ method: 'doge_requestAccounts' });
const balance = await window.dogecoin.request({ method: 'doge_getBalance' });
const doginals = await window.dogecoin.request({ method: 'doge_getDoginals' });
const result = await window.dogecoin.request({
method: 'doge_sendTransaction',
params: { to: 'DAddress...', amount: 10 }
});
Supported Methods:
| Method | Description |
|---|---|
doge_requestAccounts | Request wallet connection |
doge_accounts | Get connected accounts |
doge_getBalance | Get wallet balance |
doge_getDoginals | Get doginals in wallet (supports pagination) |
doge_sendTransaction | Send DOGE (single or multi-output) |
doge_sendDoginal | Transfer doginals (single or batch) |
doge_getDrc20Balances | Get DRC-20 token balances |
doge_sendDrc20 | Send DRC-20 tokens |
doge_getDunesBalances | Get Dunes token balances |
doge_sendDune | Send Dunes tokens |
doge_sendDuneMulti | Send Dunes tokens to multiple recipients in one tx |
doge_batchSendDune | Batch send Dunes tokens to up to 1000 recipients (airdrop/rewards) |
doge_batchSendDrc20 | Batch send DRC-20 tokens to up to 500 recipients (airdrop/rewards) |
doge_signMessage | Sign a message (free, no DOGE cost) |
doge_signPsbt | Sign a partially signed transaction (marketplace integration) |
doge_signPsbts | Batch sign multiple PSBTs at once (marketplace batch listing) |
doge_chainId | Get chain identifier ("dogecoin:mainnet") |
on(event, callback)Subscribe to wallet events.
Events:
connect - Fired when connected, receives { address: string }disconnect - Fired when disconnectedaccountsChanged - Fired when active address changes, receives string[]removeListener(event, callback)Unsubscribe from wallet events.
| Transaction Type | Network Fee | Dev Fee | Total |
|---|---|---|---|
| Regular DOGE send | Dynamic (based on tx size) | 0.01 DOGE | Variable |
| Doginal transfer | 0.02 DOGE | 0.01 DOGE | 0.03 DOGE |
| Multi-doginal transfer | 0.02 DOGE x count | 0.01 DOGE | Variable |
| DRC-20 transfer | 0.02 DOGE | 0.01 DOGE | 0.03 DOGE |
| Dune transfer | 0.02 DOGE | 0.01 DOGE | 0.03 DOGE |
| Multi-dune transfer | 0.20 DOGE | 0.01 DOGE | 0.21 DOGE |
| Batch Dune airdrop | ~0.005 DOGE/batch + 0.01 DOGE per dust output | 0.01 DOGE/batch | ~0.125 DOGE (10 recipients), ~12.5 DOGE (1000 recipients) |
| Batch DRC-20 airdrop | 0.02 DOGE x 2 per recipient + distribution fee (0.02 + 0.01/recipient dust penalty) | 0.01 DOGE | ~2.54 DOGE (50 recipients) |
| Error Message | Cause |
|---|---|
"Connection rejected by user" | User declined connection request |
"Site not connected" | dApp not connected to wallet |
"Wallet not unlocked" | User hasn't unlocked the wallet |
"Transaction rejected by user" | User declined transaction |
"Doginal transfer rejected by user" | User declined doginal transfer |
"Message signing rejected by user" | User declined signature request |
"DRC-20 transfer rejected by user" | User declined DRC-20 transfer |
"Dune transfer rejected by user" | User declined Dune transfer |
"PSBT signing rejected by user" | User declined PSBT signing request |
"Batch PSBT signing rejected by user" | User declined batch PSBT signing request |
"Invalid PSBT params: psbtHex is required" | Missing psbtHex parameter |
"Invalid batch PSBT params: psbts array is required" | Missing or empty psbts array parameter |
"Insufficient funds" | Not enough DOGE for transaction + fees |
"Inscription not found in wallet" | Requested inscription not in wallet |
"Batch DRC-20 send rejected by user" | User declined batch DRC-20 airdrop |
"Batch Dune send rejected by user" | User declined batch Dune airdrop |
"Not enough DOGE for batch fees" | Insufficient DOGE to cover inscription + distribution fees |
dist-extension folderif (!isSpookyWalletAvailable()) {
// Show a banner or modal
showModal({
title: 'Use Spooky Doge Wallet',
message: 'For the best experience, open this site in the Spooky Doge app browser.',
buttons: [
{ text: 'Get the App', url: 'https://spooksociety.xyz' },
{ text: 'Continue Anyway', action: 'dismiss' }
]
});
}
For integration support or questions: