Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow inscribing with a delegate #3021

Merged
merged 9 commits into from
Jan 15, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 22 additions & 23 deletions batch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,28 @@ postage: 12345
# sat: 5000000000

# inscriptions to inscribe
#
# each inscription has the following fields:
#
# `file`: path to inscription contents
# `metadata`: inscription metadata (optional)
# `metaprotocol`: inscription metaprotocol (optional)
# `destination`: destination for that inscription (optional). Note: If no destination is specified a new wallet change address will be used
inscriptions:
- file: mango.avif
metadata:
title: Delicious Mangos
description: >
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam semper,
ligula ornare laoreet tincidunt, odio nisi euismod tortor, vel blandit
metus est et odio. Nullam venenatis, urna et molestie vestibulum, orci
mi efficitur risus, eu malesuada diam lorem sed velit. Nam fermentum
dolor et luctus euismod.
destination: bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4
# path to inscription content
- file: mango.avif
# inscription to delegate content to (optional)
delegate: 6ac5cacb768794f4fd7a78bf00f2074891fce68bd65c4ff36e77177237aacacai0
# destination (optional, if no destination is specified a new wallet change address will be used)
destination: bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4
# inscription metadata (optional)
metadata:
title: Delicious Mangos
description: >
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam semper,
ligula ornare laoreet tincidunt, odio nisi euismod tortor, vel blandit
metus est et odio. Nullam venenatis, urna et molestie vestibulum, orci
mi efficitur risus, eu malesuada diam lorem sed velit. Nam fermentum
dolor et luctus euismod.
# inscription metaprotocol (optional)
metaprotocol: DOPEPROTOCOL-42069

- file: token.json
metaprotocol: brc-20
- file: token.json

- file: tulip.png
metadata:
author: Satoshi Nakamoto
destination: bc1pdqrcrxa8vx6gy75mfdfj84puhxffh4fq46h3gkp6jxdd0vjcsdyspfxcv6
- file: tulip.png
destination: bc1pdqrcrxa8vx6gy75mfdfj84puhxffh4fq46h3gkp6jxdd0vjcsdyspfxcv6
metadata:
author: Satoshi Nakamoto
48 changes: 31 additions & 17 deletions src/inscriptions/inscription.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,13 @@ impl Inscription {

pub(crate) fn from_file(
chain: Chain,
path: impl AsRef<Path>,
compress: bool,
delegate: Option<InscriptionId>,
metadata: Option<Vec<u8>>,
metaprotocol: Option<String>,
parent: Option<InscriptionId>,
path: impl AsRef<Path>,
pointer: Option<u64>,
metaprotocol: Option<String>,
metadata: Option<Vec<u8>>,
compress: bool,
) -> Result<Self, Error> {
let path = path.as_ref();

Expand Down Expand Up @@ -99,11 +100,12 @@ impl Inscription {

Ok(Self {
body: Some(body),
content_type: Some(content_type.into()),
content_encoding,
content_type: Some(content_type.into()),
delegate: delegate.map(|delegate| delegate.value()),
metadata,
metaprotocol: metaprotocol.map(|metaprotocol| metaprotocol.into_bytes()),
parent: parent.map(|id| id.value()),
parent: parent.map(|parent| parent.value()),
pointer: pointer.map(Self::pointer_value),
..Default::default()
})
Expand Down Expand Up @@ -727,45 +729,57 @@ mod tests {

write!(file, "foo").unwrap();

let inscription =
Inscription::from_file(Chain::Mainnet, file.path(), None, None, None, None, false).unwrap();
let inscription = Inscription::from_file(
Chain::Mainnet,
false,
None,
None,
None,
None,
file.path(),
None,
)
.unwrap();

assert_eq!(inscription.pointer, None);

let inscription = Inscription::from_file(
Chain::Mainnet,
file.path(),
false,
None,
Some(0),
None,
None,
false,
None,
file.path(),
Some(0),
)
.unwrap();

assert_eq!(inscription.pointer, Some(Vec::new()));

let inscription = Inscription::from_file(
Chain::Mainnet,
file.path(),
false,
None,
Some(1),
None,
None,
false,
None,
file.path(),
Some(1),
)
.unwrap();

assert_eq!(inscription.pointer, Some(vec![1]));

let inscription = Inscription::from_file(
Chain::Mainnet,
file.path(),
false,
None,
Some(256),
None,
None,
false,
None,
file.path(),
Some(256),
)
.unwrap();

Expand Down
6 changes: 4 additions & 2 deletions src/subcommand/preview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ impl Preview {
cbor_metadata: None,
commit_fee_rate: None,
compress: false,
delegate: None,
destination: None,
dry_run: false,
fee_rate: FeeRate::try_from(1.0).unwrap(),
Expand All @@ -120,8 +121,8 @@ impl Preview {
parent: None,
postage: Some(TARGET_POSTAGE),
reinscribe: false,
satpoint: None,
sat: None,
satpoint: None,
}),
}),
}
Expand All @@ -142,6 +143,7 @@ impl Preview {
cbor_metadata: None,
commit_fee_rate: None,
compress: false,
delegate: None,
destination: None,
dry_run: false,
fee_rate: FeeRate::try_from(1.0).unwrap(),
Expand All @@ -153,8 +155,8 @@ impl Preview {
parent: None,
postage: Some(TARGET_POSTAGE),
reinscribe: false,
satpoint: None,
sat: None,
satpoint: None,
}),
}),
}
Expand Down
1 change: 1 addition & 0 deletions src/subcommand/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ pub(crate) struct Wallet {
}

#[derive(Debug, Parser)]
#[allow(clippy::large_enum_variant)]
pub(crate) enum Subcommand {
#[command(about = "Get wallet balance")]
Balance,
Expand Down
26 changes: 21 additions & 5 deletions src/subcommand/wallet/inscribe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ pub(crate) struct Inscribe {
long,
help = "Inscribe multiple inscriptions defined in a yaml <BATCH_FILE>.",
conflicts_with_all = &[
"cbor_metadata", "destination", "file", "json_metadata", "metaprotocol", "parent", "postage", "reinscribe", "satpoint"
"cbor_metadata", "delegate", "destination", "file", "json_metadata", "metaprotocol",
"parent", "postage", "reinscribe", "satpoint"
]
)]
pub(crate) batch: Option<PathBuf>,
Expand All @@ -69,6 +70,8 @@ pub(crate) struct Inscribe {
pub(crate) commit_fee_rate: Option<FeeRate>,
#[arg(long, help = "Compress inscription content with brotli.")]
pub(crate) compress: bool,
#[arg(long, help = "Delegate inscription content to <DELEGATE>.")]
pub(crate) delegate: Option<InscriptionId>,
#[arg(long, help = "Send inscription to <DESTINATION>.")]
pub(crate) destination: Option<Address<NetworkUnchecked>>,
#[arg(long, help = "Don't sign or broadcast transactions.")]
Expand Down Expand Up @@ -138,14 +141,22 @@ impl Inscribe {

postage = self.postage.unwrap_or(TARGET_POSTAGE);

if let Some(delegate) = self.delegate {
ensure! {
index.inscription_exists(delegate)?,
"delegate {delegate} does not exist"
}
}

inscriptions = vec![Inscription::from_file(
chain,
file,
self.compress,
self.delegate,
metadata,
self.metaprotocol,
self.parent,
file,
None,
self.metaprotocol,
metadata,
self.compress,
)?];

mode = Mode::SeparateOutputs;
Expand All @@ -168,6 +179,7 @@ impl Inscribe {
.unwrap_or(TARGET_POSTAGE);

(inscriptions, destinations) = batchfile.inscriptions(
&index,
&client,
chain,
parent_info.as_ref().map(|info| info.tx_out.value),
Expand Down Expand Up @@ -1327,6 +1339,10 @@ inscriptions:
fn flags_conflict_with_batch() {
for (flag, value) in [
("--file", Some("foo")),
(
"--delegate",
Some("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33bi0"),
),
(
"--destination",
Some("tb1qsgx55dp6gn53tsmyjjv4c2ye403hgxynxs0dnm"),
Expand Down
24 changes: 17 additions & 7 deletions src/subcommand/wallet/inscribe/batch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ pub(super) struct Batch {
}

impl Default for Batch {
fn default() -> Batch {
Batch {
fn default() -> Self {
Self {
commit_fee_rate: 1.0.try_into().unwrap(),
destinations: Vec::new(),
dry_run: false,
Expand Down Expand Up @@ -543,6 +543,7 @@ pub(crate) enum Mode {
#[derive(Deserialize, Default, PartialEq, Debug, Clone)]
#[serde(deny_unknown_fields)]
pub(crate) struct BatchEntry {
pub(crate) delegate: Option<InscriptionId>,
pub(crate) destination: Option<Address<NetworkUnchecked>>,
pub(crate) file: PathBuf,
pub(crate) metadata: Option<serde_yaml::Value>,
Expand Down Expand Up @@ -585,6 +586,7 @@ impl Batchfile {

pub(crate) fn inscriptions(
&self,
index: &Index,
client: &Client,
chain: Chain,
parent_value: Option<u64>,
Expand Down Expand Up @@ -616,17 +618,25 @@ impl Batchfile {

let mut inscriptions = Vec::new();
for (i, entry) in self.inscriptions.iter().enumerate() {
if let Some(delegate) = entry.delegate {
ensure! {
index.inscription_exists(delegate)?,
"delegate {delegate} does not exist"
}
}

inscriptions.push(Inscription::from_file(
chain,
&entry.file,
self.parent,
if i == 0 { None } else { Some(pointer) },
entry.metaprotocol.clone(),
compress,
entry.delegate,
match &metadata {
Some(metadata) => Some(metadata.clone()),
None => entry.metadata()?,
},
compress,
entry.metaprotocol.clone(),
self.parent,
&entry.file,
if i == 0 { None } else { Some(pointer) },
)?);

pointer += postage.to_sat();
Expand Down
10 changes: 4 additions & 6 deletions tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,13 @@ use {
};

macro_rules! assert_regex_match {
($string:expr, $pattern:expr $(,)?) => {
($value:expr, $pattern:expr $(,)?) => {
let regex = Regex::new(&format!("^(?s){}$", $pattern)).unwrap();
let string = $string;
let string = $value.to_string();

if !regex.is_match(string.as_ref()) {
panic!(
"Regex:\n\n{}\n\n…did not match string:\n\n{}",
regex, string
);
eprintln!("Regex did not match:");
pretty_assert_eq!(regex.as_str(), string);
}
};
}
Expand Down
12 changes: 12 additions & 0 deletions tests/test_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,18 @@ impl TestServer {
assert_regex_match!(response.text().unwrap(), regex.as_ref());
}

pub(crate) fn assert_response(&self, path: impl AsRef<str>, expected_response: &str) {
self.sync_server();
let response = reqwest::blocking::get(self.url().join(path.as_ref()).unwrap()).unwrap();
assert_eq!(
response.status(),
StatusCode::OK,
"{}",
response.text().unwrap()
);
pretty_assert_eq!(response.text().unwrap(), expected_response);
}

pub(crate) fn request(&self, path: impl AsRef<str>) -> Response {
self.sync_server();

Expand Down
Loading
Loading