window.dogesoft
PSBTs & the request() interface
Sign and push custom PSBTs for marketplaces and multi-party transactions, or use the generic request() interface.
Signing a PSBT
For anything the friendly methods don't cover β marketplace listings, multi-party trades, multi-input transactions β build a PSBT (Partially Signed Bitcoin Transaction) yourself and hand it to the wallet for signing. The user sees exactly what they're signing; you never see their key.
// unsignedPsbt: hex or base64, built by your backend.
// Every input the wallet signs must carry its previous transaction (nonWitnessUtxo).
const { psbtHex, txHex } = await dogesoft.signPsbt(unsignedPsbt, {
finalize: true
});
// psbtHex: the signed PSBT, base64-encoded (despite the name). hex is an alias.
// txHex: broadcast-ready raw transaction, only when finalize is true
// and every input in the PSBT is now signed.
// Or review + sign + broadcast in one call (PSBT as hex):
const { txid } = await dogesoft.pushPsbt(unsignedPsbtHex);
signPsbt() signs the inputs the connected account controls (or only the
ones you name in inputToSign) and leaves every other input untouched, so
several parties can sign the same PSBT in turn. Broadcast the final txHex
from your backend with POST https://explorer.dogesoft.io/api/tx/broadcast
(body {"hex": "β¦"}).
pushPsbt() takes a hex PSBT, shows the same review, signs every remaining
input and broadcasts. It fails if the transaction still isn't fully signed.
Marketplace flow β list, buy, cancel
A Doginals marketplace signs the listing, the purchase, and a self-send cancel as PSBTs through the same
signPsbt() / pushPsbt() pair above.
The listing stays a signed record. The purchase transaction carries one
Doge Soft marketplace tag
(BUY, AUCTION_SOLD,
OFFER_ACCEPT, GIFT,
BUNDLE, PARTIAL_FILL,
COLLECTION_TRANSFER).
- List β your backend builds an unsigned PSBT (inscription input + price output).
The seller signs it without
finalize. Store the signed PSBT; do not broadcast it. - Buy β your backend takes the stored listing PSBT, adds the buyer's payment
inputs/outputs and change, and returns an unsigned-for-buyer PSBT. The buyer signs with
finalize: true, and your backend broadcasts the resultingtxHex(or the buyer callspushPsbt()). - Cancel β your backend builds a PSBT that spends the listed inscription back to the seller. The seller signs it and you push it.
Signing a listing β ANYONECANPAY
A listing PSBT at step 1 has only the seller's inscription input β the buyer's payment input doesn't
exist yet. For the seller's signature to still be valid once your backend adds that payment input
later, the seller must sign with SIGHASH_SINGLE|ANYONECANPAY
(0x83), not the plain SIGHASH_ALL that signPsbt()
uses by default. Pass it per input via options.inputToSign:
// Seller signs only their own input, ANYONECANPAY so a buyer can add
// payment inputs later without invalidating this signature.
const { psbtHex } = await window.dogesoft.signPsbt(listingPsbtHex, {
inputToSign: [{ inputIndex: 0, sighashType: 0x83 }]
});
// Store psbtHex. Do not broadcast β it isn't a complete transaction yet.
| Value | Meaning |
|---|---|
0x01 | SIGHASH_ALL β the default when no sighashType is given. |
0x02 | SIGHASH_NONE |
0x03 | SIGHASH_SINGLE |
0x81 | SIGHASH_ALL | ANYONECANPAY |
0x82 | SIGHASH_NONE | ANYONECANPAY |
0x83 | SIGHASH_SINGLE | ANYONECANPAY β the listing value above. |
Any other value is rejected outright rather than silently signed as ALL. A single top-level
options.sighashType applies to every signed input that doesn't set
its own β useful for pushPsbt(), where the buyer's own new inputs
still sign as plain ALL by default.
// Batch a listing flow by looping signPsbt() once per item,
// sequentially (one approval each). Works in both hosts.
async function signPsbtsDogesoft(items) {
const out = [];
for (const item of items) {
const { psbtHex } = await window.dogesoft.signPsbt(item.psbtHex);
out.push({ ...item, signedPsbtHex: psbtHex });
}
return out;
}
Before treating a sale or cancellation as final, confirm the Doginal's output actually moved β
GET /api/explorer/tx/:txid returns the parsed
drc20_operations / inscriptions for
a transaction. The plain /api/tx/:txid only returns raw transaction
fields and won't tell you whether a carrier changed hands.
The request() interface
The provider also has a generic dispatcher, shaped like the EIP-1193 pattern many wallet adapters expect. These method strings behave the same in the extension and the mobile app:
| Method string | Equivalent to |
|---|---|
doge_requestAccounts | connect() |
doge_accounts | getAccounts() |
doge_getBalance | getBalance() |
doge_sendDoge | sendDoge(params), with params an object |
doge_sendDrc20 | sendDrc20(params), with params an object |
const result = await window.dogesoft.request({
method: "doge_requestAccounts"
});
const sent = await window.dogesoft.request({
method: "doge_sendDoge",
params: { to: "Dβ¦recipient", amount: 1 }
});
For signing (signMessage, signPsbt,
pushPsbt), call the methods directly as shown above. Their
request() parameter shapes aren't the same in both hosts yet. An unknown
method string rejects with Error('DogeSoft: unknown method "<method>"').
See Errors.