CashScript / cashscript

⚖️ Easily write and interact with Bitcoin Cash smart contracts
https://cashscript.org
MIT License
112 stars 79 forks source link

Is there a way to get the total of output of smart contract in CashScript? #131

Open smacz42 opened 1 year ago

smacz42 commented 1 year ago

I found in CashScript that there are no loops:

limitations in the underlying Bitcoin Script which prevent loops, recursion, and return statements

And it appears that in the introspection, there is only the ability to access a specified index of the output array:

You need to access an output with a specific index and specify the properties you want to access.

So for example, if I wanted to get the amount of funds that were NOT getting sent back to the contract itself, I don't know what I would do. (P.S. I'm assuming that with an if-statement, I can exclude any outputs whose lockingBytecode is the script hash itself.)

With those two restrictions, is there any way to get the total output (to addresses other than the smart contract itself) of a smart contract using CashScript?

smacz42 commented 1 year ago

I think the following lines from flipstarter do this, but in the opposite manner:

// require the campaign contract to be at index0
// allows for more than 2 inputs
require(this.activeInputIndex == 0);

// pledge can have change output so pledge amount is difference in contract value before and after
int amountPledge = tx.outputs[0].value - tx.inputs[0].value;

// pledge should be atleast 1200sats for fee+dust ouput chose 10k sats as DOS measure
// implicity requires tx.outputs[0].value > tx.inputs[0].value
require(amountPledge > 10000);

// require this contract to be replicated on output index zero
require(tx.outputs[0].lockingBytecode == tx.inputs[0].lockingBytecode);

https://github.com/mr-zwets/p2shAssuranceContract/blob/main/v2/assuranceContract.cash#L26-L38

To use this in a way that I'm talking about, it may be that it needs to be used like so:

// require the campaign contract to be at index0
// allows for more than 2 inputs
require(this.activeInputIndex == 0);
// require this contract to be replicated on output index zero
require(tx.outputs[0].lockingBytecode == tx.inputs[0].lockingBytecode);

// now that we know which output goes back to the contract, and which input is from the
// contract, we just find the difference in the input value and the output value in order to
// determine how much was NOT sent back to the contract, e.g. how much was send to
// other addresses (public keys, other smart contracts, etc.)
int amountSpent = tx.inputs[0].value - tx.outputs[0].value;

Feel free to close this issue if the above is correct.

rkalis commented 1 year ago

Wow, sorry. I completely missed this issue. I think the method you suggested makes sense. One thing to keep in mind here though is that it could be possible for additional inputs to exist to this transaction (separate from the contract) that could contribute to the total funds sent in this transaction. But I think for most use case, that doesn't matter too much.