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

Feature Request: MultiOutput Edict for Airdrops #3658

Closed
gamedevalice opened this issue Apr 22, 2024 · 6 comments
Closed

Feature Request: MultiOutput Edict for Airdrops #3658

gamedevalice opened this issue Apr 22, 2024 · 6 comments

Comments

@gamedevalice
Copy link

gamedevalice commented Apr 22, 2024

This would make it a lot simpler to do large airdrops, and would require much fewer transactions, making it more cost efficient as well.

Based on:

pub struct Edict {
pub id: RuneId,
pub amount: u128,
pub output: u32,
}

I can see that the type of output is u32, i.e can have a maximum value of: 4,294,967,295

According to: https://bitcoinops.org/en/tools/calc-size/
You could probably fit roughly 100,000 outputs in a transaction that would be large enough to hit the block size limit.

So, given that the higher values are actually far from achievable, I suggest when output has a value of u32::MAX, we treat it as meaning:

  • send amount to every output (except the output to which the remaining change is sent to)

This approach requires no changes to the runestone's data structure or size, so it is 'free' as far as the runestone size fitting in a OP_RETURN is concerned.

@cryptoni9n
Copy link
Collaborator

I would like to second this request on behalf of many in the Ordicord. This has been the number one ask since halving by those wishing to airdrop their premined runes.

@raphjaph raphjaph added this to Tracker Apr 22, 2024
@raphjaph raphjaph moved this to To Do in Tracker Apr 22, 2024
@gamedevalice
Copy link
Author

gamedevalice commented Apr 23, 2024

Note that according to this post from less than 2 hours ago this feature is already implemented in the protocol:
https://github.com/ordinals/ord/assets/124552025/e7fb05f5-ab70-4ced-8455-3c7014f747ad

To use it you set output to the total number of outputs (including OP_RETURNs). You also have the option to set amount to zero to split all of the runes in the transaction.

It seems like it may also airdrop to yourself. If that's the case, that's not ideal. You typically wouldn't want the airdrop to include the output where you are sending the remaining change,

Also note, even if this is considered sufficient, there are some remaining things to do:
1 - add it to the documentation so people can know about it
2 - adding a command to the wallet for constructing transactions with edicts and multiple outputs

For reference, the code to the current implementation is here:

if output == tx.output.len() {
// find non-OP_RETURN outputs
let destinations = tx
.output
.iter()
.enumerate()
.filter_map(|(output, tx_out)| {
(!tx_out.script_pubkey.is_op_return()).then_some(output)
})
.collect::<Vec<usize>>();
if !destinations.is_empty() {
if amount == 0 {
// if amount is zero, divide balance between eligible outputs
let amount = *balance / destinations.len() as u128;
let remainder = usize::try_from(*balance % destinations.len() as u128).unwrap();
for (i, output) in destinations.iter().enumerate() {
allocate(
balance,
if i < remainder { amount + 1 } else { amount },
*output,
);
}
} else {
// if amount is non-zero, distribute amount to eligible outputs
for output in destinations {
allocate(balance, amount.min(*balance), output);
}
}
}
} else {

@revofusion
Copy link
Contributor

revofusion commented Apr 23, 2024

@raphjaph the current split all works great already, what is needed rather is a flag for excluding an output # from the split all, so that we can reliably exclude change outputs

@gamedevalice
Copy link
Author

gamedevalice commented Apr 23, 2024

following the pattern that's already in place,
output == tx.output.len() means split to all outputs
so perhaps
output == tx.output.len() + 1 could mean split to all outputs except pointer

this allows the possibility for other kinds of special Edicts with new behaviors in the future, like:
output == tx.output.len() + 2
output == tx.output.len() + 3
etc

@raphjaph
Copy link
Collaborator

raphjaph commented Nov 15, 2024

We now have the split command #4030 and also documentation for it #4062.

  • send amount to every output (except the output to which the remaining change is sent to)

You can actually implicitly exclude the change output by prepending an edict that allocates the surplus runes to the change output. The second edict then allocates 10 UNCOMMON•GOODS to all remaining outputs (until no more input runes left) but since we already transferred the surplus to the change output it won't receive any extra runes.

Example: Airdrop 10 UNCOMMON•GOODS each to 8 people.

Inputs:

0: 100 UNCOMMON•GOODS
1: Only sats

Outputs:

Outputs:
0: OP_RETURN 
  Edict {
    rune: UNCOMMON•GOODS,
    amount: 20, 
    output: 9, 
  },
  Edict {
    rune: UNCOMMON•GOODS,
    amount: 10, 
    output: 10, 
  }
1: 330 sats + 10  UNCOMMON•GOODS
2: 330 sats + 10  UNCOMMON•GOODS
3: 330 sats + 10  UNCOMMON•GOODS
4: 330 sats + 10  UNCOMMON•GOODS
5: 330 sats + 10  UNCOMMON•GOODS
6: 330 sats + 10  UNCOMMON•GOODS
7: 330 sats + 10  UNCOMMON•GOODS
8: 330 sats + 10  UNCOMMON•GOODS
9: change sats  + 20  UNCOMMON•GOODS

I will close this since you can actually exclude the change output and airdrop efficiently. I will open a new issue to actually implement this logic in ord.

@raphjaph
Copy link
Collaborator

#4081

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Runes
Development

No branches or pull requests

4 participants