transfer100.pizza#71,490,003brc-20transfer100.pizza#71,190,790brc-20#67,166,229videoInscription #53822809#53,822,809html0#47,101,630text0#47,101,166text #47,098,843text #47,097,077text #47,096,690text #47,096,601text #47,096,423text #47,093,474text #47,092,156text #47,092,069text #47,092,042text #47,091,983text outpoint ), ); ord_server.assert_response_regex( format!("/inscription/{}", output.inscriptions[2].id), format!( r".*<dt>location</dt>.*<dd class=monospace>{}:20000</dd>.*", outpoint ), ); ord_server.assert_response_regex( format!("/output/{}", output.inscriptions[0].location.outpoint), format!(r".*<a href=/inscription/{}>.*</a>.*<a href=/inscription/{}>.*</a>.*<a href=/inscription/{}>.*</a>.*", output.inscriptions[0].id, output.inscriptions[1].id, output.inscriptions[2].id), ); } #[test] fn batch_in_same_output_with_non_default_postage() { let rpc_server = test_bitcoincore_rpc::spawn(); rpc_server.mine_blocks(1); create_wallet(&rpc_server); let output = CommandBuilder::new("wallet inscribe --fee-rate 1 --batch batch.yaml") .write("inscription.txt", "Hello World") .write("tulip.png", [0; 555]) .write("meow.wav", [0; 2048]) .write( "batch.yaml", "mode: shared-output\npostage: 777\ninscriptions:\n- file: inscription.txt\n- file: tulip.png\n- file: meow.wav\n" #45,160,776text CommandBuilder::new(format!( "wallet inscribe --satpoint {txid}:0:0 --file degenerate.png --fee-rate 0" )) .write("degenerate.png", [1; 100]) .rpc_server(&rpc_server) .run_and_deserialize_output::<Inscribe>(); let txid = rpc_server.mine_blocks_with_subsidy(1, 100)[0].txdata[0].txid(); CommandBuilder::new(format!( "wallet send --fee-rate 1 bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4 {txid}:0:0" )) .rpc_server(&rpc_server) .expected_exit_code(1) .expected_stderr("error: wallet does not contain enough cardinal UTXOs, please add additional funds to wallet.\n") .run_and_extract_stdout(); } #[test] fn do_not_send_within_dust_limit_of_an_inscription() { let rpc_server = test_bitcoincore_rpc::spawn(); create_wallet(&rpc_server); let (inscription, reveal) = inscribe(&rpc_server); rpc_server.mine_blocks(1); let output = OutPoint { txid: reveal, vout: 0, }; CommandBuilder::new(format!( "wallet send --fee-rate 1 bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4 {output}:329" #45,159,660text index: 1 }, InscriptionId { txid: reveal_txid, index: 2 }, ], runes: BTreeMap::new(), } ); // try and fail to send first CommandBuilder::new(format!( "wallet send --fee-rate 1 bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4 {}i0", reveal_txid, )) .rpc_server(&rpc_server) .expected_exit_code(1) .expected_stderr(format!( "error: cannot send {reveal_txid}:0:0 without also sending inscription {reveal_txid}i2 at {reveal_txid}:0:{}\n", 100 * COIN_VALUE )) .run_and_extract_stdout(); // splitting out last CommandBuilder::new(format!( "wallet send --fee-rate 1 bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4 {}i2", reveal_txid, )) .rpc_server(&rpc_server) .run_and_deserialize_output::<Output>(); rpc_server.mine_blocks(1); // splitting second to last CommandBuilder::new(format!( "wallet send --fee-rate 1 bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4 {}i1", reveal_txid, )) .rpc_server(&rpc_server) #45,159,659text .run_and_deserialize_output::<send::Output>() .transaction; rpc_server.mine_blocks(1); let output = CommandBuilder::new("wallet inscriptions") .rpc_server(&rpc_server) .run_and_deserialize_output::<Vec<inscriptions::Output>>(); assert_eq!(output.len(), 1); assert_eq!(output[0].inscription, inscription); assert_eq!(output[0].location, format!("{txid}:0:0").parse().unwrap()); } #[test] fn inscriptions_includes_locked_utxos() { let rpc_server = test_bitcoincore_rpc::spawn(); create_wallet(&rpc_server); rpc_server.mine_blocks(1); let (inscription, reveal) = inscribe(&rpc_server); rpc_server.mine_blocks(1); rpc_server.lock(OutPoint { txid: reveal, vout: 0, }); let output = CommandBuilder::new("wallet inscriptions") .rpc_server(&rpc_server) .run_and_deserialize_output::<Vec<inscriptions::Output>>(); assert_eq!(output.len(), 1); assert_eq!(output[0].inscription, inscription); assert_eq!(output[0].location, format!("{reveal}:0:0").parse().unwrap()); #45,023,648textuse {super::*, ord::subcommand::wallet::balance::Output}; #[test] fn wallet_balance() { let rpc_server = test_bitcoincore_rpc::spawn(); create_wallet(&rpc_server); assert_eq!( CommandBuilder::new("wallet balance") .rpc_server(&rpc_server) .run_and_deserialize_output::<Output>() .cardinal, 0 ); rpc_server.mine_blocks(1); assert_eq!( CommandBuilder::new("wallet balance") .rpc_server(&rpc_server) .run_and_deserialize_output::<Output>() .cardinal, 50 * COIN_VALUE ); } #[test] fn wallet_balance_only_counts_cardinal_utxos() { let rpc_server = test_bitcoincore_rpc::spawn(); create_wallet(&rpc_server); assert_eq!( CommandBuilder::new("wallet balance") .rpc_server(&rpc_server) .run_and_deserialize_output::<Output>() .cardinal, 0 ); inscribe(&rpc_server); assert_eq!( CommandBuilder::new("wallet balance") .rpc_server(&rpc_server) .run_and_deserialize_output::<Output>() .cardinal, 100 * COIN_VALUE - 10_000 #45,023,643text }) } fn get_blockchain_info(&self) -> Result<GetBlockchainInfoResult, jsonrpc_core::Error> { Ok(GetBlockchainInfoResult { chain: String::from(match self.network { Network::Bitcoin => "main", Network::Testnet => "test", Network::Signet => "signet", Network::Regtest => "regtest", _ => panic!(), }), blocks: 0, headers: 0, best_block_hash: self.state().hashes[0], difficulty: 0.0, median_time: 0, verification_progress: 0.0, initial_block_download: false, chain_work: Vec::new(), size_on_disk: 0, pruned: false, prune_height: None, automatic_pruning: None, prune_target_size: None, softforks: HashMap::new(), warnings: String::new(), }) } fn get_network_info(&self) -> Result<GetNetworkInfoResult, jsonrpc_core::Error> { Ok(GetNetworkInfoResult { version: self.state().version, subversion: String::new(), protocol_version: 0, local_services: String::new(), #44,995,180text 0xA2, 0x63, b'f', b'o', b'o', 0x63, b'b', b'a', b'r', 0x63, b'b', b'a', b'z', 0x01, ], ) .rpc_server(&rpc_server) .run_and_deserialize_output(); let inscription = inscriptions[0].id; rpc_server.mine_blocks(1); let ord_server = TestServer::spawn_with_args(&rpc_server, &[]); ord_server.assert_response_regex( format!("/inscription/{inscription}"), ".*<dt>metadata</dt>.*<dl><dt>foo</dt><dd>bar</dd><dt>baz</dt><dd>1</dd></dl>.*", ); } #[test] fn error_message_when_parsing_json_metadata_is_reasonable() { CommandBuilder::new( "wallet inscribe --fee-rate 1 --json-metadata metadata.json --file content.png", ) .write("content.png", [1; 520]) .write("metadata.json", "{") .stderr_regex(".*failed to parse JSON metadata.*") .expected_exit_code(1) .run_and_extract_stdout(); } #[test] fn error_message_when_parsing_cbor_metadata_is_reasonable() { CommandBuilder::new( "wallet inscribe --fee-rate 1 --cbor-metadata metadata.cbor --file content.png", ) .write("content.png", [1; 520]) #44,994,778text .run_and_deserialize_output::<send::Output>() .transaction; rpc_server.mine_blocks(1); let output = CommandBuilder::new("wallet inscriptions") .rpc_server(&rpc_server) .run_and_deserialize_output::<Vec<inscriptions::Output>>(); assert_eq!(output.len(), 1); assert_eq!(output[0].inscription, inscription); assert_eq!(output[0].location, format!("{txid}:0:0").parse().unwrap()); } #[test] fn inscriptions_includes_locked_utxos() { let rpc_server = test_bitcoincore_rpc::spawn(); create_wallet(&rpc_server); rpc_server.mine_blocks(1); let (inscription, reveal) = inscribe(&rpc_server); rpc_server.mine_blocks(1); rpc_server.lock(OutPoint { txid: reveal, vout: 0, }); let output = CommandBuilder::new("wallet inscriptions") .rpc_server(&rpc_server) .run_and_deserialize_output::<Vec<inscriptions::Output>>(); assert_eq!(output.len(), 1); assert_eq!(output[0].inscription, inscription); assert_eq!(output[0].location, format!("{reveal}:0:0").parse().unwrap()); #44,991,649text let ord_server = TestServer::spawn_with_args(&rpc_server, &[]); ord_server.assert_response_regex( format!("/inscription/{inscription}"), format!( ".*<h1>Inscription 0</h1>.*<dt>location</dt>.*<dd class=monospace>{send_txid}:0:0</dd>.*", ), ); } #[test] fn send_on_mainnnet_works_with_wallet_named_foo() { let rpc_server = test_bitcoincore_rpc::spawn(); let txid = rpc_server.mine_blocks(1)[0].txdata[0].txid(); CommandBuilder::new("--wallet foo wallet create") .rpc_server(&rpc_server) .run_and_deserialize_output::<ord::subcommand::wallet::create::Output>(); CommandBuilder::new(format!( "--wallet foo wallet send --fee-rate 1 bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4 {txid}:0:0" )) .rpc_server(&rpc_server) .run_and_deserialize_output::<Output>(); } #[test] fn send_addresses_must_be_valid_for_network() { let rpc_server = test_bitcoincore_rpc::builder().build(); let txid = rpc_server.mine_blocks_with_subsidy(1, 1_000)[0].txdata[0].txid(); create_wallet(&rpc_server); #44,990,338text )) .rpc_server(&rpc_server) .expected_exit_code(1) .expected_stderr(format!( "error: cannot send {output}:329 without also sending inscription {inscription} at {output}:0\n" )) .run_and_extract_stdout(); } #[test] fn can_send_after_dust_limit_from_an_inscription() { let rpc_server = test_bitcoincore_rpc::spawn(); create_wallet(&rpc_server); let (_, reveal) = inscribe(&rpc_server); rpc_server.mine_blocks(1); let output = OutPoint { txid: reveal, vout: 0, }; CommandBuilder::new(format!( "wallet send --fee-rate 1 bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4 {output}:330" )) .rpc_server(&rpc_server) .run_and_deserialize_output::<Output>(); } #[test] fn splitting_merged_inscriptions_is_possible() { let rpc_server = test_bitcoincore_rpc::spawn(); create_wallet(&rpc_server); rpc_server.mine_blocks(3); let inscription = envelope(&[b"ord", &[1], b"text/plain;charset=utf-8", &[], b"bar"]); // merging 3 inscriptions into one utxo let reveal_txid = rpc_server.broadcast_tx(TransactionTemplate { #44,990,330text"unlocking new classes of collector." msgstr "" "Ces bitcoiners pourraient être plus intéressés par les inscriptions que par " "les NFTs Ethereum, ce qui ouvrirait la porte à d’autres types de " "collectionneurs." #: src\faq.md:204 msgid "_Inscriptions have a richer data model._" msgstr "_Les inscriptions disposent d’un modèle de données plus riche._" #: src\faq.md:206 msgid "" "Inscriptions consist of a content type, also known as a MIME type, and " "content, which is an arbitrary byte string. This is the same data model used " "by the web, and allows inscription content to evolve with the web, and come " "to support any kind of content supported by web browsers, without requiring " "changes to the underlying protocol." msgstr "" "Une entrée se compose du type de contenu, appelé type MIME, et d’une chaîne " "d’octets arbitraire constituant le contenu. Il s’agit du même modèle de " "données que celui utilisé par le web, qui permet au contenu de l’inscription " "d’évoluer avec le web et de prendre en charge tout type de contenu supporté " #44,986,762textuse {super::*, ord::subcommand::list::Output}; #[test] fn output_found() { let rpc_server = test_bitcoincore_rpc::spawn(); let output = CommandBuilder::new( "--index-sats list 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0", ) .rpc_server(&rpc_server) .run_and_deserialize_output::<Vec<Output>>(); assert_eq!( output, vec![Output { output: "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0" .parse() .unwrap(), start: 0, end: 50 * COIN_VALUE, size: 50 * COIN_VALUE, offset: 0, rarity: "mythic".parse().unwrap(), name: "nvtdijuwxlp".into(), }] ); } #[test] fn output_not_found() { let rpc_server = test_bitcoincore_rpc::spawn(); CommandBuilder::new( "--index-sats list 0000000000000000000000000000000000000000000000000000000000000000:0", ) .rpc_server(&rpc_server) .expected_exit_code(1) .expected_stderr("error: output not found\n") .run_and_extract_stdout(); } #[test] fn no_satoshi_index() { #44,986,642textimport { marked } from 'https://cdn.jsdelivr.net/npm/marked@9/+esm' const inscription = document.documentElement.dataset.inscription; const response = await fetch(`/content/${inscription}`); const markdown = await response.text(); document.body.innerHTML = marked.parse(markdown); #44,981,487textuse super::*; #[derive(Debug, PartialEq, Serialize, Deserialize)] pub struct Output { pub supply: u64, pub first: u64, pub last: u64, pub last_mined_in_block: u32, } pub(crate) fn run() -> SubcommandResult { let mut last = 0; loop { if Height(last + 1).subsidy() == 0 { break; } last += 1; } Ok(Box::new(Output { supply: Sat::SUPPLY, first: 0, last: Sat::SUPPLY - 1, last_mined_in_block: last, })) } #44,981,420textmsgstr "序数理论有什么用?" #: src/faq.md:23 msgid "" "Collecting, trading, and scheming. Ordinal theory assigns identities to " "individual satoshis, allowing them to be individually tracked and traded, as " "curios and for numismatic value." msgstr "" "收集、交易和策划。序数理论将身份分配给单个聪,允许它们作为古玩和钱币价值被单" "独跟踪和交易。" #: src/faq.md:27 msgid "" "Ordinal theory also enables inscriptions, a protocol for attaching arbitrary " "content to individual satoshis, turning them into bitcoin-native digital " "artifacts." msgstr "" "序数理论还赋能铭文,这是一种将任意内容附加到单个聪的协议,将它们变成比特币原" "生的数字文物。" #: src/faq.md:31 msgid "How does ordinal theory work?" msgstr "序数理论是如何运作的?" #: src/faq.md:34 msgid "" "Ordinal numbers are assigned to satoshis in the order in which they are " "mined. The first satoshi in the first block has ordinal number 0, the second " "has ordinal number 1, and the last satoshi of the first block has ordinal " "number 4,999,999,999." msgstr "" "序数是按照挖矿的顺序分配给聪的。第一个区块的首聪序数为0,第二个聪的序数为1," "第一个区块的最后一个聪的序数为4,999,999,999。" #: src/faq.md:39 msgid "" #44,979,347texttransfer171.opnp#44,745,702brc-20transfer85.opnp#44,229,467brc-20transfer42.opnp#43,009,136brc-20dmt-mint.nat#42,586,409tapdmt-mint.nat#42,586,236tapdmt-mint.nat#42,569,895tapdmt-mint.nat#42,569,883tapdmt-mint.nat#42,569,839tapdmt-mint.nat#42,569,835tapdmt-mint.nat#42,569,800tapdmt-mint.nat#42,569,767tapdmt-mint.nat#42,569,746tapdmt-mint.nat#42,569,728tapdmt-mint.nat#42,569,706tapdmt-mint.nat#42,569,655tapdmt-mint.nat#42,569,648tapdmt-mint.nat#42,569,623tapdmt-mint.nat#42,569,622taptransfer42.opnp#42,566,712brc-20dmt-mint.nat#42,515,352tapdmt-mint.nat#42,515,317tapdmt-mint.nat#42,515,169tapdmt-mint.nat#42,515,085tapdmt-mint.nat#42,515,084tapdmt-mint.nat#42,503,020tapdmt-mint.nat#42,502,747tapdmt-mint.nat#42,502,697taptransfer42.opnp#42,462,427brc-20Inscription #41761808#41,761,808png