# Agenda (please add / remove anything is wrong) - [x] Install local node and connect both on testnet or regtest. - [x] Install ord and create a wallet - [x] Inscribe an NFT - [x] See the NFT on the ord server - [x] Create a common PSBT transaction - [x] Run local stacks connected to the testnet. - [x] Connect XVerse to localnode, with testnet. - [x] Figure out how to select exactly the sat wich has the NFT to send. (insc_id[output_pos][sat_pos]) - [ ] Create an PSBT half-signed transaction of the NFT specifieng the sat where the NFT is. - [ ] Try the same, now from elixir code using the library. ## Resources Ordinals mnemonic ```json { “mnemonic”: “kitchen multiply wage typical side isolate other enough library together extend eagle”, “passphrase”: “” } ``` ## Bicoin Node Setup ### Install bitcoin-core *bitcoin.conf for testnet* ```txt datadir=<path-to-bitcoin-core>/data prune=0 txindex=1 printtoconsole=1 rpcallowip=127.0.0.1 rpcwallet=ord blocksonly=0 debug=mempool debug=rpc server=1 #Speed up sync options maxconnections=15 minrelaytxfee=0.0001 maxmempool=200 maxreceiverbuffer=2500 maxsendbuffer=500 dbcache=16000 addresstype=bech32 testnet=1 [test] fallbackfee=0.0003 wallet=ord rpcwallet=cli rpcbind=127.0.0.1 rpcport=18443 addnode=104.237.131.138 addnode=151.80.205.132 addnode=192.155.82.123 addnode=74.220.255.190 addnode=80.100.203.151 ``` *bitcoin.conf for regtest* ``` datadir=<path-to-bitcoin-core>/data prune=0 txindex=1 printtoconsole=1 rpcallowip=127.0.0.1 rpcwallet=ord debug=mempool debug=rpc server=1 regtest=1 [regtest] rpcbind=127.0.0.1 rpcport=18443 wallet=ord ``` ### Download from Bitcoin.org: * Get version 24.0.1 from [here](https://bitcoincore.org/en/download/). Download the .tar.gz, not the .dmg file. If you're on MacOS, it may be necessary to codesign bitcoind in order to be able to run `./bin/bitcoind -conf=$(pwd)/data/bitcoin.conf`. 1. Open Keychain Access. 2. Choose Keychain Access > Certificate Assistant > Create Certificate ... 3. Enter a name 4. Set 'Certificate Type' to 'Code Signing' Then, your command should look like this, if your certificate name is my-new-cert: codesign -fs my-new-cert /<path-to-bitcoin-core>/bin/bitcoind ### Download with package manager: #### MacOs: If you have brew installed, simply do: ``` brew install bitcoin ``` It should install version 24.0.1 or greater, you can check it with: ``` bitcoind --version ``` #### Ubuntu: There's a snap available, you can install it with: `sudo snap install bitcoin-core` ### Config Now, with bitcoind installed: * Create a data directory * Copy the *bitcoin.conf* file inside a data directory * Run `./bin/bitcoind -conf=$(pwd)/data/bitcoin.conf` * Wait until the sync finished * If, for some reason, you need to stop and rerun the execution, add the flag `-reindex` to the previous command. ### Create wallet, an address and found it. 1. Create the wallet `bitcoin-cli createwallet cli` 2. Generate a new address: `bitcoin-cli -rpcwallet="cli" getnewaddress` 3. Check balance `bitcoin-cli -rpcwallet="cli" getbalance` 4. To show your current address you can run this command `bitcoin-cli listaddressgroupings` ** If you put "cli" wallet on bitcoin.conf you don't have to secify -rpcwallet on every command.** # Simple PSBT transactions ## Dependencies Install jq with brew or apt ## Some words to get familiarized - UTXO: Unspent Transaction Output. It refers to the unspent amount of bitcoin that result from a completed transaction. - VOUT: Short for "transaction output," is a term used in the context of cryptocurrencies to describe the destination addresses and amounts sent in a transaction. Each transaction can have multiple outputs (VOUTs), representing the various recipients and the corresponding amounts of cryptocurrency being sent to them. VOUTs are then used as inputs (UTXOs) in subsequent transactions, forming the basis of the UTXO model employed by Bitcoin and many other cryptocurrencies. ## Steps to create a simple PSBT 1. Get the tx id from UTXO ```bash= utxo_txid=$(bitcoin-cli listunspent | jq -r '.[0] | .txid') ``` 2. Get the VOUT ```bash= utxo_vout=$(bitcoin-cli listunspent | jq -r '.[0] | .vout') ``` 3. Choose a recipient. I've created a wallet on Sparrow and choosed the first address from there. 4. Use `createrawtransaction` command con bitcoin-cli ```bash= rawtxhex=$(bitcoin-cli -named createrawtransaction inputs='''[ { "txid": "'$utxo_txid'", "vout": '$utxo_vout' }]''' outputs='''{ "'$recipient'": 0.0000035 }''') ``` 5. Convert to PSBT format ```bash= psbt=$(bitcoin-cli -named converttopsbt hexstring=$rawtxhex) ``` 6. At this point you can: * see the PSBT incomplete TX format with `bitcoin-cli -named decodepsbt psbt=$psbt_f` * the current role / status with `bitcoin-cli analyzepsbt $psbt_f` 7. todo: Put steps for `utxoupdatepsbt` 8. Update and Sign all in one step: ```bash= psbt_f=$(bitcoin-cli walletprocesspsbt $psbt | jq -r '.psbt') ``` 9. Finalize and convert it back to hex format. ```bash= psbt_hex=$(bitcoin-cli finalizepsbt $psbt_f | jq -r '.hex') ``` 10. Send the raw transaction ```bash= bitcoin-cli -named sendrawtransaction hexstring=$psbt_hex ``` ## Combining two PSBTs Draft: combinepsbt takes multiple PSBTs that have different input data and merges them. The base transaction must be exactly the same, i.e. the same inputs are consumed and the same outputs are created. The information for each input is combined into the same input. Inputs and outputs cannot be added or removed. This allows for people to send the same PSBT to be signed by multiple different people and then merge the resulting the PSBTs back together. joinpsbts is very different from this. joinpsbts joins multiple PSBTs that have different underlying transactions into one transaction. It requires that the inputs of those underlying transactions be different from each other. Furthermore, joinpsbts will discard any signatures and finalized input fields from the original PSBTs (meaning the resulting PSBT will contain no signatures) as those signatures will likely be invalidated when joining. joinpsbts lets you make transactions which has other people involved in them (such as CoinJoins) more easily. Each person can specify the inputs and outputs they want in a PSBT and then all of these PSBTs with different inputs and outputs are merged together using joinpsbts. 1. Create a raw transaction. ```bash= rawtxhex = $(./bin/bitcoin-cli -named createrawtransaction inputs='''[ { "txid": "d43be33b4b1250f16bcb97902433b185eff50416f2c88b3b206e3967ddfa36ff", "vout": '0' }]''' outputs='''[ { "tb1prwarn070sawztamreln5cpeyv6s3es5mtfmvqa2n9ct3c6kr3fmsh9dscq": 0.00001}, { "tb1px7ujvsf6s86ceh6c6yh47fpxjk6pcr64rt6zzpfe3dg4xfxm3cyslswt8x": 0.00002} ]''') ``` 2. Sign the transaction with your wallet. ```bash= ./bin/bitcoin-cli signrawtransactionwithwallet $rawtxhex "[]" "SINGLE|ANYONECANPAY" ``` 3. Create the first PSBT. ```bash= psbt_1=$(./bin/bitcoin-cli -named converttopsbt hexstring=$rawtxhex permitsigdata=true iswitness=true) ``` 4. Create the second PSBT. ```bash= psbt_2=$(./bin/bitcoin-cli walletprocesspsbt $psbt_1) ``` Draft: ``` Extract a signed transaction ./bin/bitcoin-cli finalizepsbt "cHNid...AAA==" Broadcast the transaction ./bin/bitcoin-cli sendrawtransaction "02000...0000000" ``` # ORD ## Download and install ```curl --proto '=https' --tlsv1.2 -fsLS https://ordinals.com/install.sh | bash -s``` or ``` #Install rust 1.67 with your favourite method. cargo install ord source “$HOME/.cargo/env” ``` ## Create an ordinal wallet 1. `ord -t --cookie-file <path-to-bitcoin-core>/data/testnet3/.cookie --rpc-url http://127.0.0.1:18443 wallet create` ``` { "mnemonic": "object paper elephant device below process rookie bronze divert enough talk speak", "passphrase": "" } ``` 2. `ord -t --cookie-file <path-to-bitcoin-core>/data/testnet3/.cookie --rpc-url http://127.0.0.1:18443/wallet/ord wallet receive | jq -r '.address'` 3. Fund the address using faucet https://coinfaucet.eu/en/btc-testnet/ * Use a wallet created with Xverse or unisat on chrome. * Copy the legacy address. * Fund it. * Move the sats to the ord wallet. 4. Once it has been funded, check the credit. (You can check the status of the transactions using https://mempool.space/testnet) `ord -t --cookie-file <path-to-bitcoin-core>/data/testnet3/.cookie --rpc-url http://127.0.0.1:18443/wallet/ord wallet balance | jq -r '.cardinal'` 5. Inscribe some asset ``` ord -t --cookie-file <path-to-bitcoin-core>/data/testnet3/.cookie --rpc-url http://127.0.0.1:18443/wallet/ord wallet inscribe <path-to-nft-folder>/nft1.jpeg --fee-rate=100 ``` ``` { "commit": "e8161d41670a9169a61bb21b0a041fdec9d8a7392b5f1e93528cf374c491062a", "inscription": "f61c31b90f6cec6227c3c5aeb9052ea56c45100b987f62ed417f5107787bbf83i0", "reveal": "f61c31b90f6cec6227c3c5aeb9052ea56c45100b987f62ed417f5107787bbf83", "fees": 5895 } ``` 6. As the testnet.ordinals.com is out of sync run your own local server to see the NFT (you must wait a while for it). ` ord -t --cookie-file ~/blockchain/bitcoin-core/data/testnet3/.cookie --rpc-url http://127.0.0.1:18443/wallet/ord server` 6. Go to mempool.space, put the commit id on it, open http://localhost and open a beer till the tx is approved 🍻 # Stacks over Testnet ## Preparing the folder Go to the folder where you want to have the files related with stacks and run: ```bash mkdir -p ./stacks-node/persistent-data/stacks-blockchain/testnet && cd stacks-node` mkdir -p config/testnet cat > config/testnet/Config.toml << EOF [node] working_dir = "/root/stacks-node/data" rpc_bind = "0.0.0.0:20443" p2p_bind = "0.0.0.0:20444" bootstrap_node = "02da7a464ac770ae8337a343670778b93410f2f3fef6bea98dd1c3e9224459d36b@seed-0.mainnet.stacks.co:20444,02afeae522aab5f8c99a00ddf75fbcb4a641e052dd48836408d9cf437344b63516@seed-1.mainnet.stacks.co:20444,03652212ea76be0ed4cd83a25c06e57819993029a7b9999f7d63c36340b34a4e62@seed-2.mainnet.stacks.co:20444" wait_time_for_microblocks = 10000 [burnchain] chain = "bitcoin" mode = "xenon" peer_host = "host.docker.internal" rpc_port = 18443 peer_port = 18333 [connection_options] read_only_call_limit_write_length = 0 read_only_call_limit_read_length = 100000 read_only_call_limit_write_count = 0 read_only_call_limit_read_count = 30 read_only_call_limit_runtime = 1000000000 EOF ``` ## Run the docker ```bash docker run -d --rm \ --platform linux/amd64 \ --name stacks-blockchain \ -v $(pwd)/persistent-data/stacks-blockchain/testnet:/root/stacks-node/data \ -v $(pwd)/config/testnet:/src/stacks-node \ -p 20443:20443 \ -p 20444:20444 \ blockstack/stacks-blockchain \ /bin/stacks-node start --config /src/stacks-node/Config.toml ``` ## Connect the Xverse to local stacks node: 1. Go to Settings -> Network 2. Click on Mainet and change to Testnet 3. On the URL field set `http://localhost:20443` ![](https://i.imgur.com/wsT4EhI.png) ## Todo: - [ ] Find the way to avoid sync from geneses, and get only the lastest blocks.