One address to redirect to several addresses.

As the Title says, “One address to redirect to multiple addresses.”
I’m trying to find out if this functionality is possible. I didn’t see anything in the whitepaper about it but I think it would be a great opportunity that traditional banks don’t offer :grinning:

It’s possible, but I don’t think anyone has implemented it yet. Off the top of my head, maybe it would be implemented as a singleton that contains a list of addresses and payout percentages, both of which could then be updated with a spend of the singleton. Payouts could also be done by spending the singleton.

Good question! I think we could achieve this by creating a coin that when it is spent, it will create multiple coins for multiple addresses.

The puzzle p2_addresses.clsp could look like this:

(mod (PUZZLE_HASHES total_amount amount)
    (include condition_codes.clib)

    (defun pay_to (puzzle_hashes amount)
        (if (l puzzle_hashes)
        (c 
            (list CREATE_COIN (f puzzle_hashes) amount)
            (pay_to (r puzzle_hashes) amount)
        )
        ()
        )
    )

    (c
        (list ASSERT_MY_AMOUNT total_amount)
        (pay_to PUZZLE_HASHES amount)
    )
)

Then we can curry in the list of puzzle hashes that we want to redirect. For example, if we want to send to three addresses:

(
   0x79a4034c96a1c841bde9fcaa719879b723f8e6fe21f4f8d33da3105590abe39e
   0x9911c986fa81f7db76f6b110cee66deb11690b67f204fe290b3396b0824f467a
   0xca2d649e52b48d7da1d29ac661c99385422b2bc4cfdaaad97fde98f57a9cf526
)
❯ cdv clsp curry ./p2_addresses.clsp.hex -a '(0x79a4034c96a1c841bde9fcaa719879b723f8e6fe21f4f8d33da3105590abe39e 0x9911c986fa81f7db76f6b110cee66deb11690b67f204fe290b3396b0824f467a 0xca2d649e52b48d7da1d29ac661c99385422b2bc4cfdaaad97fde98f57a9cf526)'
(a (q 2 (q 4 (c 4 (c 11 ())) (a 14 (c 2 (c 5 (c 23 ()))))) (c (q 73 51 2 (i (l 5) (q 4 (c 10 (c 9 (c 11 ()))) (a 14 (c 2 (c 13 (c 11 ()))))) ()) 1) 1)) (c (q 0x79a4034c96a1c841bde9fcaa719879b723f8e6fe21f4f8d33da3105590abe39e 0x9911c986fa81f7db76f6b110cee66deb11690b67f204fe290b3396b0824f467a 0xca2d649e52b48d7da1d29ac661c99385422b2bc4cfdaaad97fde98f57a9cf526) 1))

We can spend a coin with the puzzle above and it should send three coins to those three addresses:

❯ brun '(a (q 2 (q 4 (c 4 (c 11 ())) (a 14 (c 2 (c 5 (c 23 ()))))) (c (q 73 51 2 (i (l 5) (q 4 (c 10 (c 9 (c 11 ()))) (a 14 (c 2 (c 13 (c 11 ()))))) ()) 1) 1)) (c (q 0x79a4034c96a1c841bde9fcaa719879b723f8e6fe21f4f8d33da3105590abe39e 0x9911c986fa81f7db76f6b110cee66deb11690b67f204fe290b3396b0824f467a 0xca2d649e52b48d7da1d29ac661c99385422b2bc4cfdaaad97fde98f57a9cf526) 1))' '(30 10)'
((73 30) (51 0x79a4034c96a1c841bde9fcaa719879b723f8e6fe21f4f8d33da3105590abe39e 10) (51 0x9911c986fa81f7db76f6b110cee66deb11690b67f204fe290b3396b0824f467a 10) (51 0xca2d649e52b48d7da1d29ac661c99385422b2bc4cfdaaad97fde98f57a9cf526 10))

The solution of the coin is (30 10). 30 is the amount of the p2_addresses coin and 10 is the amount that we want to send to each new coin.

1 Like

very good the code is automatically adapted to the number of addresses?
3 addresses = / 3
4 adresses = /4
Etc…

then what happens if 1 XCH is divided into 3? who gets the latest mojo?

very good the code is automatically adapted to the number of addresses?

Yes, our code can handle any number of addresses. However, the bigger the solution and the conditions, the more CLVM cost associated. So it’s always better to only do necessary tasks on the blockchain (e.g., do most computations in the python driver code).

Here are some good references:

You can check the cost with brun as well:

❯ brun --cost '(a (q 2 (q 4 (c 4 (c 11 ())) (a 14 (c 2 (c 5 (c 23 ()))))) (c (q 73 51 2 (i (l 5) (q 4 (c 10 (c 9 (c 11 ()))) (a 14 (c 2 (c 13 (c 11 ()))))) ()) 1) 1)) (c (q 0x79a4034c96a1c841bde9fcaa719879b723f8e6fe
21f4f8d33da3105590abe39e 0x9911c986fa81f7db76f6b110cee66deb11690b67f204fe290b3396b0824f467a 0xca2d649e52b48d7da1d29ac661c99385422b2bc4cfdaaad97fde98f57a9cf526) 1))' '(30 10)'
cost = 5285...

So, let’s you curry-in 30 addresses, the cost will increase!

❯ cdv clsp curry ./p2_addresses.clsp.hex -a '(0x79a4034c96a1c841bde9fcaa719879b723f8e6fe21f4f8d33da3105590abe39e 0x9911c986fa81f7db76f6b110cee66deb11690b67f204fe290b3396b0824f467a 0xca2d649e52b48d7da1d29ac661c99385422b2bc4cfdaaad97fde98f57a9cf526 0x79a4034c96a1c841bde9fcaa719879b723f8e6fe21f4f8d33da3105590abe39e 0x9911c986fa81f7db76f6b110cee66deb11690b67f204fe290b3396b0824f467a ...)'
(a (q 2 (q 4 (c 4 (c 11 ())) (a 14 (c 2 (c 5 (c 23 ()))))) (c (q 73 51 2 (i (l 5) (q 4 (c 10 (c 9 (c 11 ()))) (a 14 (c 2 (c 13 (c 11 ()))))) ()) 1) 1)) (c (q 0x79a4034c96a1c841bde9fcaa719879b723f8e6fe21f4f8d33da3105590abe39e 0x9911c986fa81f7db76f6b110cee66deb11690b67f204fe290b3396b0824f467a 0xca2d649e52b48d7da1d29ac661c99385422b2bc4cfdaaad97fde98f57a9cf526 0x79a4034c96a1c841bde9fcaa719879b723f8e6fe21f4f8d33da3105590abe39e 0x9911c986fa81f7db76f6b110cee66deb11690b67f204fe290b3396b0824f467a...) 1))

❯ brun --cost $(cdv clsp curry ./p2_addresses.clsp.hex -a '(0x79a4034c96a1c841bde9fcaa719879b723f8e6fe21f4f8d33da3105590abe39e 0x9911c986fa81f7db76f6b110cee66deb11690b67f204fe290b3396b0824f467a 0xca2d649e52b48d7da1d29ac661c99385422b2bc4cfdaaad97fde98f57a9cf526 0x79a4034c96a1c841bde9fcaa719879b723f8e6fe21f4f8d33da3105590abe39e 0x9911c986fa81f7db76f6b110cee66deb11690b67f204fe290b3396b0824f467a...)') '(30 1)'
cost = 38360...

then what happens if 1 XCH is divided into 3? who gets the latest mojo?

In our code, mojos are specified inside the solution, so your driver code should make sure the calculation is correct otherwise the spend might not be valid. For example, you couldn’t spend one 30-mojo coin and create five 10-mojo coins).

But if there is any mojos unused, those mojos will be fees for our beloved farmers.

A fee is created when the sum of the CREATE_COIN outputs is less than the amount of the coin that is being spent.

1 Like

I like the mojo for farmer :slight_smile:

1 Like

There is no verification for total_amount = amount * #curried_puzzhashes is this puzzle or am I wrong?

2 Likes

Good catch! You are right that there’s no check in this chialisp code (as I expect that to be done in the driver code). In the production, you should add more verification depending on your use cases. Most importantly is something like AGG_SIG_ME which will make sure that the values in solution are not tampered by anyone.

The example is just to show how we can model the concept of redirecting mojos to multiple addresses. The coin itself could be an ephemeral coin that is created and spent within the same block!

1 Like

Do you have any python code?
when I to try face error:

cdv encode a8886c13970eabd43956d3ba7729348641da20dbe5d08c4c90d20e42738072fb --prefix txch
txch14zyxcyuhp64agw2k6wa8w2f5seqa5gxmuhggcnys6g8yyuuqwtasung7vh
chia wallet send -a 0.3 -t txch14zyxcyuhp64agw2k6wa8w2f5seqa5gxmuhggcnys6g8yyuuqwtasung7vh
cdv rpc coinrecords --by puzhash a8886c13970eabd43956d3ba7729348641da20dbe5d08c4c90d20e42738072fb
opc ‘(300000000000,100000000000)’

("{‘error’: 'Failed to include transaction "
‘7ad2e63272ca05780744b8b4486b3ee617dfc19842128f8545a526fc041170a9, error ’
"GENERATOR_RUNTIME_ERROR’, ‘success’: False}")

{
“coin_spends”: [
{
“coin”: {
“parent_coin_info”: “36dc65c2d183ed5cb3696d8c9bdfc4d4da2a76d0d6771d82821ba6168113d1c5”,
“puzzle_hash”: “a8886c13970eabd43956d3ba7729348641da20dbe5d08c4c90d20e42738072fb”,
“amount”: 300000000000
},
“puzzle_reveal”: “ff02ffff01ff02ffff01ff04ffff04ff04ffff04ff0bff808080ffff02ff0effff04ff02ffff04ff05ffff04ff17ff808080808080ffff04ffff01ff49ff33ff02ffff03ffff07ff0580ffff01ff04ffff04ff0affff04ff09ffff04ff0bff80808080ffff02ff0effff04ff02ffff04ff0dffff04ff0bff808080808080ff8080ff0180ff018080ffff04ffff01ffa079a4034c96a1c841bde9fcaa719879b723f8e6fe21f4f8d33da3105590abe39effa09911c986fa81f7db76f6b110cee66deb11690b67f204fe290b3396b0824f467affa0ca2d649e52b48d7da1d29ac661c99385422b2bc4cfdaaad97fde98f57a9cf52680ff018080”,
“solution”: “ff993330303030303030303030302c31303030303030303030303080”
}
],
“aggregated_signature”: “c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000”
}

Besides brun, another easy way to debug your spend bundle is to use cdv inspect spendbundles <json file> -db

# bad spend bundle
❯ cdv inspect spendbundles ./bad-spend.json -db 
[{"aggregated_signature": ...]

Debugging Information
---------------------
...

brun -y main.sym '(a ...)' '("300000000000,100000000000")'
Traceback (most recent call last):
  ...
ValueError: ('path into atom', '80')

So you will notice the that the solution looks wrong.

You should do opc '(300000000000 100000000000)' without ,.

❯ opc '(300000000000 100000000000)'
ff8545d964b800ff85174876e80080

Update the solution in your spend bundle and it should work.

❯ cdv inspect spendbundles ./good-spend.json -db
[{"aggregated_signature": ...]

Debugging Information
---------------------
...

brun -y main.sym '(a (q 2 (q 4 (c 4 (c 11 ())) (a 14 (c 2 (c 5 (c 23 ()))))) (c (q 73 51 2 (i (l 5) (q 4 (c 10 (c 9 (c 11 ()))) (a 14 (c 2 (c 13 (c 11 ()))))) ()) 1) 1)) (c (q 0x79a4034c96a1c841bde9fcaa719879b723f8e6fe21f4f8d33da3105590abe39e 0x9911c986fa81f7db76f6b110cee66deb11690b67f204fe290b3396b0824f467a 0xca2d649e52b48d7da1d29ac661c99385422b2bc4cfdaaad97fde98f57a9cf526) 1))' '(0x45d964b800 0x174876e800)'

((ASSERT_MY_AMOUNT 0x45d964b800) (CREATE_COIN 0x79a4034c96a1c841bde9fcaa719879b723f8e6fe21f4f8d33da3105590abe39e 0x174876e800) (CREATE_COIN 0x9911c986fa81f7db76f6b110cee66deb11690b67f204fe290b3396b0824f467a 0x174876e800) (CREATE_COIN 0xca2d649e52b48d7da1d29ac661c99385422b2bc4cfdaaad97fde98f57a9cf526 0x174876e800))

grouped conditions:

  (ASSERT_MY_AMOUNT 0x45d964b800)

  (CREATE_COIN 0x79a4034c96a1c841bde9fcaa719879b723f8e6fe21f4f8d33da3105590abe39e 0x174876e800)
  (CREATE_COIN 0x9911c986fa81f7db76f6b110cee66deb11690b67f204fe290b3396b0824f467a 0x174876e800)
  (CREATE_COIN 0xca2d649e52b48d7da1d29ac661c99385422b2bc4cfdaaad97fde98f57a9cf526 0x174876e800)

-------
...

================================================================================

aggregated signature check pass: True
pks: []
msgs: []
  msg_data: []
  coin_ids: []
  add_data: []
signature: c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
None

Have fix.
Very Thanks