An exchange reported this issue to me, and I tried to repeat this issue. I created a testnet using the latest code of neo-cli 2.x on solo mode. Then I deployed a modified NEP-5 contract, and for testing purpose I modified "balanceOf" as following:
```C#
if (operation == "balanceOf")
{
if (args.Length != 1) return 0;
byte[] account = (byte[])args[0];
return account;
//return BalanceOf(account);
}
And here are the requests sent using RPC:
using "invoke":
```json
{
"jsonrpc": "2.0",
"method": "invoke",
"params": [
"08a91ebb95656fca3e9eb3fdfe4286dabdcd0da5",
[
{
"type":"String",
"value":"balanceOf"
},
{
"type":"String",
"value":"651897dcd926ab80a2026eaf7f1aa451361d60d2"
}
]
],
"id": 3
}
using "invokefunction":
{
"jsonrpc": "2.0",
"method": "invokefunction",
"params": [
"08a91ebb95656fca3e9eb3fdfe4286dabdcd0da5",
"balanceOf",
[
{
"type":"String",
"value":"651897dcd926ab80a2026eaf7f1aa451361d60d2"
}
]
],
"id": 3
}
"invoke" returned an empty byte[]:
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"script": "28363531383937646364393236616238306132303236656166376631616134353133363164363064320962616c616e63654f6667a50dcdbdda8642fefdb39e3eca6f6595bb1ea908",
"state": "HALT",
"gas_consumed": "0.121",
"stack": [
{
"type": "ByteArray",
"value": ""
}
],
"tx": "d1014828363531383937646364393236616238306132303236656166376631616134353133363164363064320962616c616e63654f6667a50dcdbdda8642fefdb39e3eca6f6595bb1ea908000000000000000000000000"
}
}
"invokefunction" returned correct result:
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"script": "283635313839376463643932366162383061323032366561663766316161343531333631643630643251c10962616c616e63654f6667a50dcdbdda8642fefdb39e3eca6f6595bb1ea908",
"state": "HALT",
"gas_consumed": "0.13",
"stack": [
{
"type": "ByteArray",
"value": "36353138393764636439323661623830613230323665616637663161613435313336316436306432"
}
],
"tx": "d1014a283635313839376463643932366162383061323032366561663766316161343531333631643630643251c10962616c616e63654f6667a50dcdbdda8642fefdb39e3eca6f6595bb1ea908000000000000000000000000"
}
}
PS: in neo3, "invoke" is removed.
I think I have figured out the reason caused this issue:
"invoke" calls the following code:
```C#
public static ScriptBuilder EmitAppCall(this ScriptBuilder sb, UInt160 scriptHash, params ContractParameter[] parameters)
{
for (int i = parameters.Length - 1; i >= 0; i--)
sb.EmitPush(parameters[i]);
return sb.EmitAppCall(scriptHash);
}
and "invokefunction" calls the following code:
```C#
public static ScriptBuilder EmitAppCall(this ScriptBuilder sb, UInt160 scriptHash, string operation, params ContractParameter[] args)
{
for (int i = args.Length - 1; i >= 0; i--)
sb.EmitPush(args[i]);
sb.EmitPush(args.Length);
sb.Emit(OpCode.PACK);
sb.EmitPush(operation);
sb.EmitAppCall(scriptHash);
return sb;
}
After I changed the "invoke" code as following:
```C#
public static ScriptBuilder EmitAppCall(this ScriptBuilder sb, UInt160 scriptHash, params ContractParameter[] parameters)
{
for (int i = parameters.Length - 1; i >= 1; i--)
sb.EmitPush(parameters[i]);
sb.EmitPush(parameters.Length - 1);
sb.Emit(OpCode.PACK);
sb.EmitPush(parameters[0].Value.ToString());
return sb.EmitAppCall(scriptHash);
}
and resent the request using "invoke", I got the correct response:
```json
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"script": "283635313839376463643932366162383061323032366561663766316161343531333631643630643251c10962616c616e63654f6667a50dcdbdda8642fefdb39e3eca6f6595bb1ea908",
"state": "HALT",
"gas_consumed": "0.13",
"stack": [
{
"type": "ByteArray",
"value": "36353138393764636439323661623830613230323665616637663161613435313336316436306432"
}
],
"tx": "d1014a283635313839376463643932366162383061323032366561663766316161343531333631643630643251c10962616c616e63654f6667a50dcdbdda8642fefdb39e3eca6f6595bb1ea908000000000000000000000000"
}
}
Hi @joeqian10, is this a new problem?
I think that these endpoints have different purposes.
The first expects 2 parameters: operation and args, while the second is more generic. You can have a smart contract that does not obey the "operation + args" signature, maybe that is the reason they are different.
Nice investigation anyway, @joeiqan10.
But I think Rick is right, maybe this invoke template needs an extra param as default. Lets double check.
@lock9 Yes, this is a new problem reported by an exchange. I agree that these two endpoints have different purposes. But the more generic one ("invoke") doesn't return correct response under this specific request, which makes it not so "generic". @vncoelho More investigation is needed.
@joeqian10 I checked git history, and it has been a really long time since this was last changed.
I think that they need to use invokefunction instead of invoke
This is from May 2018:

@lock9 I have informed the exchange to use only invokefunction for now. And in NEO3, invoke is totally removed.
If the problem is solved, could you please close this issue?
Thanks.
Sent from my iPhone
On 9 Jul 2019, at 01:52, joeqian notifications@github.com wrote:
@lock9 I have informed the exchange to use only invokefunction for now. And in NEO3, invoke is totally removed.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.
Most helpful comment
Hi @joeqian10, is this a new problem?
I think that these endpoints have different purposes.
The first expects 2 parameters: operation and args, while the second is more generic. You can have a smart contract that does not obey the "operation + args" signature, maybe that is the reason they are different.