InvokeScriptTransaction out of control

Hello, invocation activated in testnet, and there is the first call:

  "type": 16,
  "id": "AEqxpGXRw7W1br3oLN9CtbVTKKZ3gPnN8vu7VZrBe3WP",
  "sender": "3MrDis17gyNSusZDg8Eo1PuFnm5SQMda3gu",
  "senderPublicKey": "2AqMAWBPbTxYdHoE9vsELWTrCFjhEJdKAACt5UEjFGLu",
  "fee": 500000,
  "feeAssetId": null,
  "timestamp": 1553695487582,
  "proofs": [
  "version": 1,
  "dappAddress": "3MqznbvHM2CqEVG6HKpWQmmXrWWHgBmFcAJ",
  "call": {
    "function": "foo",
    "args": [
        "type": "integer",
        "value": 42
  "payment": [],
  "height": 554877

Let’s look at the app script:

  "script": "{-#STDLIB_VERSION 3#-}\n{-#SCRIPT_TYPE ACCOUNT#-}\n{-#CONTENT_TYPE DAPP#-}\n\n\n@Callable(inv)\nfunc foo (a) = WriteSet(cons(DataEntry(\"a\", a), cons(DataEntry(\"sender\", inv.caller.bytes), nil)))\n\n"

As you can see, foo() changes data state of the app at 3MrDis17gyNSusZDg8Eo1PuFnm5SQMda3gu, we can see result:

    "key": "a",
    "type": "string",
    "value": "OOO"
    "key": "sender",
    "type": "binary",
    "value": "base64:AVQZRkg4QetOTEjZiZV1VJP1JbG360zlf3o="


For now there is no way you can track invocation actions, at all, you only see ordinar transactions:


  • no independent audit is possible without a fully implemented InvokeScriptTransaction mechanic
  • services like independent explorers (eg. will be shutdown, because InvokeScriptTransaction mechanic is too hard to implement independently
  • no one can debug what is happeninig if something goes wrong
  • you even can not see who calls your app
  • and it is even more frustrating than: Smart Assets Proposal


  • make it possible to track data changes and payments without implementing InvokeScriptTransaction mechanic (all information should be available by (/transactions/info/)
  • make incoming transactions visible at the application address

Totally agree with @deemru. Good proposal, should be done before mainnet release.

Couldn’t agree more.
BTW, @ismagin, do you have any plans to introduce transparency with InvokeScriptTransaction, as @deemru proposed?

  1. make it possible to track data changes and payments without implementing InvokeScriptTransaction mechanic (all information should be available by (/transactions/info/)
  2. make incoming transactions visible at the application address

Sounds reasonable. Actually, sounds like a must-have.

We also made a test for ContractInvocation, see
Looks like RESTs and Explorer doesn’t support this feature now. It will be sad if there are no plans for their updates.

Thank you for your feedback, guys!
We’re considering different possible solutions for developers, but make a decision we need more details about use cases.

Explorer use case is one of them, are there any other applications?

  • Fundraising with invisible rats
  • Smart account backdooring
  • Additional smart account logic instead of current transaction driven logic
  • Additional smart account code instead of current statistic out of the box
  • State checking (of all variables?) instead of transaction checking
1 Like

Hi guys,

interesting discussion, but i must admit i’m a bit twofold here. On the one hand, it would clearly be a feature that would be nice to have. On the other hand, is it really necessary? How do other blockchains, e.g., Ethereum, handle this?

I think we have all necessary information available, it is just that it might be too hard to implement the script mechanics, i agree on this. But where (in the mentioned usecases) do we really need this? From a transparency point of view, everything is there that someone needs to know in order to get a complete picture about what is happening: the script is available, all state changing transactions are available and states are available.

Just two examples that make me wonder:

  1. With type 4 tx, we are also not reporting back the result of the state change, but just the state change. I guess, no one ever came up with the question in this context since the mechanics of the transfer tx is quite obvious.
  2. I don’t really see a need for a block explorer to report state changes. A block explorer (to me) is basically a tool that allows to (flexibly) search for blocks and things inside the blocks, mainly transactions. I do rarely search for states in a block explorer, and even more rarely, for a history of state changes.

So i think to further discuss this, we need a deeper understanding of the use cases. Therefore, @deemru, could you please elaborate a bit on the use cases instead of just mention them?


@ikardanov, @hawky_WavesBI

I didn’t hear why the issue did not resolved in first place.

If the only reason is to take up less space, just give us an option to:

  • = yes

Well, i don’t really think that this is the point.

New proposals:

  • add /utils/simulateInvoke call to return scriptResult for the InvokeScriptTransaction for debugging and controlling business processes
  • add scriptResult to a generating block explicitly, so there wil be no room for forks later

obviously it’s needed to control dApps

Please consider the following use case.

There are 3 accounts:

  1. dApp - it is an account, similar to wallet.ride but with several changes. Investor can deposit Waves and during withdraw he can donate 50% of amount to some organization. For such donation special attribute should be pass into @Withdraw as true
  2. Investor Acc - arbitrary user who will use our dApp
  3. Donation Acc - account for donation which is hardcoded in dApp

Let’s image that investor made a mistake during @Withdraw call and turned on donation attribute. After 3 days investor found out that debit and credit in his ledger were not equals.
The main question here: how to restore operations and find an error which was made by investor?

Also look at the Donation Acc. How to find who donated 1W ?

Modified wallet.ride:


func deposit() = {
    let pmt = extract(i.payment)
    if (isDefined(pmt.assetId))
        then throw("can hodl waves only at the moment")
    else {
        let currentKey = toBase58String(i.caller.bytes)
        let currentAmount = match getInteger(this, currentKey) {
            case a:Int => a
            case _ => 0
        let newAmount = currentAmount + pmt.amount
        WriteSet([DataEntry(currentKey, newAmount)])

func withdraw(amount: Int, donate: Boolean, name: String, vec: ByteVector) = {
    let expectedVec = toBytes("Hello, Ride4DApp!")
    let donationAddress = extract(addressFromString("$donationAddressInjection"));

    let withdrawTotal =  if (donate) then 2 * amount else amount
    let currentKey = toBase58String(i.caller.bytes)
    let currentAmount = match getInteger(this, currentKey) {
        case a:Int => a
        case _ => 0
    let newAmount = currentAmount - withdrawTotal
    if (withdrawTotal < 0)
        then throw("Can't withdraw negative amount")
    else if (newAmount < 0)
        then throw("Not enough balance")
    else if (expectedVec != vec)
        then throw("vec parameter doesn't match expected value")
        ScriptResult(WriteSet([DataEntry(currentKey, newAmount),
                              DataEntry(name + " Total", withdrawTotal),
                              DataEntry(name + " Donation", amount)

                    TransferSet([ScriptTransfer(i.caller, amount, unit),
                                 ScriptTransfer(donationAddress, amount, unit)

func verify() = {
1 Like