namespace bdk {};

// ------------------------------------------------------------------------
// bdk crate - error module
// ------------------------------------------------------------------------

[Error]
interface AddressError {
  Base58();
  Bech32();
  WitnessVersion(string error_message);
  WitnessProgram(string error_message);
  UncompressedPubkey();
  ExcessiveScriptSize();
  UnrecognizedScript();
  NetworkValidation(Network required, Network found, string address);
  OtherAddressErr();
};

[Error]
interface Bip32Error {
    CannotDeriveFromHardenedKey();
    Secp256k1(string error_message);
    InvalidChildNumber(u32 child_number);
    InvalidChildNumberFormat();
    InvalidDerivationPathFormat();
    UnknownVersion(string version);
    WrongExtendedKeyLength(u32 length);
    Base58(string error_message);
    Hex(string error_message);
    InvalidPublicKeyHexLength(u32 length);
    UnknownError(string error_message);
};

[Error]
interface Bip39Error {
  BadWordCount(u64 word_count);
  UnknownWord(u64 index);
  BadEntropyBitCount(u64 bit_count);
  InvalidChecksum();
  AmbiguousLanguages(string languages);
};

[Error]
interface CalculateFeeError {
  MissingTxOut(sequence<OutPoint> out_points);
  NegativeFee(i64 fee);
};

[Error]
interface CannotConnectError {
  Include(u32 height);
};

[Error]
interface CreateTxError {
  Descriptor(string error_message);
  Persist(string error_message);
  Policy(string error_message);
  SpendingPolicyRequired(string kind);
  Version0();
  Version1Csv();
  LockTime(string requested, string required);
  RbfSequence();
  RbfSequenceCsv(string rbf, string csv);
  FeeTooLow(u64 required);
  FeeRateTooLow(string required);
  NoUtxosSelected();
  OutputBelowDustLimit(u64 index);
  ChangePolicyDescriptor();
  CoinSelection(string error_message);
  InsufficientFunds(u64 needed, u64 available);
  NoRecipients();
  Psbt(string error_message);
  MissingKeyOrigin(string key);
  UnknownUtxo(string outpoint);
  MissingNonWitnessUtxo(string outpoint);
  MiniscriptPsbt(string error_message);
};

[Error]
interface DescriptorError {
    InvalidHdKeyPath();
    InvalidDescriptorChecksum();
    HardenedDerivationXpub();
    MultiPath();
    Key(string error_message);
    Policy(string error_message);
    InvalidDescriptorCharacter(string char);
    Bip32(string error_message);
    Base58(string error_message);
    Pk(string error_message);
    Miniscript(string error_message);
    Hex(string error_message);
};

[Error]
interface DescriptorKeyError {
  Parse(string error_message);
  InvalidKeyType();
  Bip32(string error_message);
};

[Error]
interface ElectrumError {
  IOError(string error_message);
  Json(string error_message);
  Hex(string error_message);
  Protocol(string error_message);
  Bitcoin(string error_message);
  AlreadySubscribed();
  NotSubscribed();
  InvalidResponse(string error_message);
  Message(string error_message);
  InvalidDNSNameError(string domain);
  MissingDomain();
  AllAttemptsErrored();
  SharedIOError(string error_message);
  CouldntLockReader();
  Mpsc();
  CouldNotCreateConnection(string error_message);
  RequestAlreadyConsumed();
};

[Error]
interface EsploraError {
  Minreq(string error_message);
  HttpResponse(u16 status, string error_message);
  Parsing(string error_message);
  StatusCode(string error_message);
  BitcoinEncoding(string error_message);
  HexToArray(string error_message);
  HexToBytes(string error_message);
  TransactionNotFound();
  HeaderHeightNotFound(u32 height);
  HeaderHashNotFound();
  InvalidHttpHeaderName(string name);
  InvalidHttpHeaderValue(string value);
  RequestAlreadyConsumed();
};

[Error]
interface ExtractTxError {
  AbsurdFeeRate(u64 fee_rate);
  MissingInputValue();
  SendingTooMuch();
  OtherExtractTxErr();
};

[Error]
enum FeeRateError {
  "ArithmeticOverflow"
};

[Error]
interface ParseAmountError {
  Negative();
  TooBig();
  TooPrecise();
  InvalidFormat();
  InputTooLarge();
  InvalidCharacter(string error_message);
  UnknownDenomination(string error_message);
  PossiblyConfusingDenomination(string error_message);
  OtherParseAmountErr();
};

[Error]
interface PersistenceError {
  Write(string error_message);
};

[Error]
interface PsbtParseError {
  PsbtEncoding(string error_message);
  Base64Encoding(string error_message);
};

[Error]
interface SignerError {
    MissingKey();
    InvalidKey();
    UserCanceled();
    InputIndexOutOfRange();
    MissingNonWitnessUtxo();
    InvalidNonWitnessUtxo();
    MissingWitnessUtxo();
    MissingWitnessScript();
    MissingHdKeypath();
    NonStandardSighash();
    InvalidSighash();
    SighashError(string error_message);
    MiniscriptPsbt(string error_message);
    External(string error_message);
};

[Error]
interface TransactionError {
  Io();
  OversizedVectorAllocation();
  InvalidChecksum(string expected, string actual);
  NonMinimalVarInt();
  ParseFailed();
  UnsupportedSegwitFlag(u8 flag);
  OtherTransactionErr();
};

[Error]
interface TxidParseError {
  InvalidTxid(string txid);
};

[Error]
interface WalletCreationError {
  Io(string error_message);
  InvalidMagicBytes(sequence<u8> got, sequence<u8> expected);
  Descriptor();
  Persist(string error_message);
  NotInitialized();
  LoadedGenesisDoesNotMatch(string expected, string got);
  LoadedNetworkDoesNotMatch(Network expected, Network? got);
  LoadedDescriptorDoesNotMatch(string got, KeychainKind keychain);
};

// ------------------------------------------------------------------------
// bdk crate - types module
// ------------------------------------------------------------------------

enum KeychainKind {
  "External",
  "Internal",
};

dictionary AddressInfo {
  u32 index;
  Address address;
  KeychainKind keychain;
};

dictionary Balance {
  Amount immature;

  Amount trusted_pending;

  Amount untrusted_pending;

  Amount confirmed;

  Amount trusted_spendable;

  Amount total;
};

dictionary LocalOutput {
  OutPoint outpoint;
  TxOut txout;
  KeychainKind keychain;
  boolean is_spent;
};

dictionary TxOut {
  u64 value;
  Script script_pubkey;
};

[Enum]
interface ChainPosition {
  Confirmed(u32 height, u64 timestamp);
  Unconfirmed(u64 timestamp);
};

dictionary CanonicalTx {
  Transaction transaction;
  ChainPosition chain_position;
};

interface FullScanRequest {};

interface SyncRequest {};

// ------------------------------------------------------------------------
// bdk crate - wallet module
// ------------------------------------------------------------------------

enum ChangeSpendPolicy {
  "ChangeAllowed",
  "OnlyChange",
  "ChangeForbidden"
};

interface Wallet {
  [Throws=WalletCreationError]
  constructor(Descriptor descriptor, Descriptor? change_descriptor, string persistence_backend_path, Network network);

  [Name=new_no_persist, Throws=DescriptorError]
  constructor(Descriptor descriptor, Descriptor? change_descriptor, Network network);

  [Throws=PersistenceError]
  AddressInfo reveal_next_address(KeychainKind keychain);

  Network network();

  Balance get_balance();

  [Throws=CannotConnectError]
  void apply_update(Update update);

  [Throws=PersistenceError]
  boolean commit();

  boolean is_mine([ByRef] Script script);

  [Throws=SignerError]
  boolean sign(Psbt psbt);

  SentAndReceivedValues sent_and_received([ByRef] Transaction tx);

  sequence<CanonicalTx> transactions();

  [Throws=TxidParseError]
  CanonicalTx? get_tx(string txid);

  [Throws=CalculateFeeError]
  u64 calculate_fee([ByRef] Transaction tx);

  [Throws=CalculateFeeError]
  FeeRate calculate_fee_rate([ByRef] Transaction tx);

  sequence<LocalOutput> list_unspent();

  sequence<LocalOutput> list_output();

  FullScanRequest start_full_scan();

  SyncRequest start_sync_with_revealed_spks();
};

interface Update {};

interface TxBuilder {
  constructor();

  TxBuilder add_recipient([ByRef] Script script, Amount amount);

  TxBuilder set_recipients(sequence<ScriptAmount> recipients);

  TxBuilder add_unspendable(OutPoint unspendable);

  TxBuilder unspendable(sequence<OutPoint> unspendable);

  TxBuilder add_utxo(OutPoint outpoint);

  TxBuilder change_policy(ChangeSpendPolicy change_policy);

  TxBuilder do_not_spend_change();

  TxBuilder only_spend_change();

  TxBuilder manually_selected_only();

  TxBuilder fee_rate([ByRef] FeeRate fee_rate);

  TxBuilder fee_absolute(u64 fee);

  TxBuilder drain_wallet();

  TxBuilder drain_to([ByRef] Script script);

  TxBuilder enable_rbf();

  TxBuilder enable_rbf_with_sequence(u32 nsequence);

  [Throws=CreateTxError]
  Psbt finish([ByRef] Wallet wallet);
};

interface BumpFeeTxBuilder {
  constructor(string txid, FeeRate fee_rate);

  BumpFeeTxBuilder enable_rbf();

  BumpFeeTxBuilder enable_rbf_with_sequence(u32 nsequence);

  [Throws=CreateTxError]
  Psbt finish([ByRef] Wallet wallet);
};

// ------------------------------------------------------------------------
// bdk crate - descriptor module
// ------------------------------------------------------------------------

interface Mnemonic {
  constructor(WordCount word_count);

  [Name=from_string, Throws=Bip39Error]
  constructor(string mnemonic);

  [Name=from_entropy, Throws=Bip39Error]
  constructor(sequence<u8> entropy);

  string as_string();
};

interface DerivationPath {
  [Throws=Bip32Error]
  constructor(string path);
};

interface DescriptorSecretKey {
  constructor(Network network, [ByRef] Mnemonic mnemonic, string? password);

  [Name=from_string, Throws=DescriptorKeyError]
  constructor(string secret_key);

  [Throws=DescriptorKeyError]
  DescriptorSecretKey derive([ByRef] DerivationPath path);

  [Throws=DescriptorKeyError]
  DescriptorSecretKey extend([ByRef] DerivationPath path);

  DescriptorPublicKey as_public();

  sequence<u8> secret_bytes();

  string as_string();
};

interface DescriptorPublicKey {
  [Name=from_string, Throws=DescriptorKeyError]
  constructor(string public_key);

  [Throws=DescriptorKeyError]
  DescriptorPublicKey derive([ByRef] DerivationPath path);

  [Throws=DescriptorKeyError]
  DescriptorPublicKey extend([ByRef] DerivationPath path);

  string as_string();
};

interface Descriptor {
  [Throws=DescriptorError]
  constructor(string descriptor, Network network);

  [Name=new_bip44]
  constructor([ByRef] DescriptorSecretKey secret_key, KeychainKind keychain, Network network);

  [Name=new_bip44_public]
  constructor([ByRef] DescriptorPublicKey public_key, string fingerprint, KeychainKind keychain, Network network);

  [Name=new_bip49]
  constructor([ByRef] DescriptorSecretKey secret_key, KeychainKind keychain, Network network);

  [Name=new_bip49_public]
  constructor([ByRef] DescriptorPublicKey public_key, string fingerprint, KeychainKind keychain, Network network);

  [Name=new_bip84]
  constructor([ByRef] DescriptorSecretKey secret_key, KeychainKind keychain, Network network);

  [Name=new_bip84_public]
  constructor([ByRef] DescriptorPublicKey public_key, string fingerprint, KeychainKind keychain, Network network);

  [Name=new_bip86]
  constructor([ByRef] DescriptorSecretKey secret_key, KeychainKind keychain, Network network);

  [Name=new_bip86_public]
  constructor([ByRef] DescriptorPublicKey public_key, string fingerprint, KeychainKind keychain, Network network);

  string as_string();

  string as_string_private();
};

// ------------------------------------------------------------------------
// bdk_esplora crate
// ------------------------------------------------------------------------

interface EsploraClient {
  constructor(string url);

  [Throws=EsploraError]
  Update full_scan(FullScanRequest full_scan_request, u64 stop_gap, u64 parallel_requests);

  [Throws=EsploraError]
  Update sync(SyncRequest sync_request, u64 parallel_requests);

  [Throws=EsploraError]
  void broadcast([ByRef] Transaction transaction);
};

// ------------------------------------------------------------------------
// bdk_electrum crate
// ------------------------------------------------------------------------

interface ElectrumClient {
  [Throws=ElectrumError]
  constructor(string url);

  [Throws=ElectrumError]
  Update full_scan(FullScanRequest full_scan_request, u64 stop_gap, u64 batch_size, boolean fetch_prev_txouts);

  [Throws=ElectrumError]
  Update sync(SyncRequest sync_request, u64 batch_size, boolean fetch_prev_txouts);

  [Throws=ElectrumError]
  string broadcast([ByRef] Transaction transaction);
};

// ------------------------------------------------------------------------
// bdk-ffi-defined types
// ------------------------------------------------------------------------

dictionary ScriptAmount {
  Script script;
  Amount amount;
};

dictionary SentAndReceivedValues {
    Amount sent;
    Amount received;
};

// ------------------------------------------------------------------------
// bdk crate - bitcoin re-exports
// ------------------------------------------------------------------------

interface Script {
  constructor(sequence<u8> raw_output_script);

  sequence<u8> to_bytes();
};

[NonExhaustive]
enum Network {
  "Bitcoin",
  "Testnet",
  "Signet",
  "Regtest",
};

enum WordCount {
  "Words12",
  "Words15",
  "Words18",
  "Words21",
  "Words24",
};

interface Address {
  [Throws=AddressError]
  constructor(string address, Network network);

  Network network();

  Script script_pubkey();

  string to_qr_uri();

  string as_string();

  boolean is_valid_for_network(Network network);
};

interface Transaction {
  [Throws=TransactionError]
  constructor(sequence<u8> transaction_bytes);

  string txid();

  u64 total_size();

  u64 vsize();

  boolean is_coinbase();

  boolean is_explicitly_rbf();

  boolean is_lock_time_enabled();

  i32 version();

  sequence<u8> serialize();

  u64 weight();

  sequence<TxIn> input();

  sequence<TxOut> output();

  u32 lock_time();
};

interface Psbt {
  [Throws=PsbtParseError]
  constructor(string psbt_base64);

  string serialize();

  [Throws=ExtractTxError]
  Transaction extract_tx();
};

dictionary OutPoint {
  string txid;
  u32 vout;
};

interface Amount {
  [Name=from_sat]
  constructor(u64 from_sat);

  [Name=from_btc, Throws=ParseAmountError]
  constructor(f64 from_btc);

  u64 to_sat();

  f64 to_btc();
};

interface FeeRate {
  [Name=from_sat_per_vb, Throws=FeeRateError]
  constructor(u64 sat_per_vb);

  [Name=from_sat_per_kwu]
  constructor(u64 sat_per_kwu);

  u64 to_sat_per_vb_ceil();

  u64 to_sat_per_vb_floor();

  u64 to_sat_per_kwu();
};

dictionary TxIn {
  OutPoint previous_output;
  Script script_sig;
  u32 sequence;
  sequence<sequence<u8>> witness;
};
