Comments (10)
ScriptHash (big endian): 0x746d6cc63dacd7b275bb3a3a06d54859661591a6
Entry Point:Main
Functions:
String Name();
String Symbol();
Integer Decimals();
ByteArray Main(String operation, Array args);
Boolean Deploy();
Boolean MintTokens();
Integer TotalSupply();
Boolean Transfer(ByteArray from, ByteArray to, Integer value);
Integer BalanceOf(ByteArray address);
Events:
Void transfer(ByteArray arg1, ByteArray arg2, Integer arg3);
Void refund(ByteArray arg1, Integer arg2);
Here is an example of ABI output from NEO C# compiler for an ICO template
@ixje CityOfZion/neo-python#908
from neo-boa.
I think its a good idea! Probably related to this new functionality here: #31
from neo-boa.
It would be nice to have some advances here... although I don't think it's easy to do :)
from neo-boa.
I'm guessing the biggest hurdle is going to be supporting type hints. @saltyskip can you also link the C# template that matches this ABI output?
from neo-boa.
using Neo.SmartContract.Framework;
using Neo.SmartContract.Framework.Services.Neo;
using Neo.SmartContract.Framework.Services.System;
using System;
using System.ComponentModel;
using System.Numerics;
namespace Neo.SmartContract
{
public class ICO_Template : Framework.SmartContract
{
//Token Settings
public static string Name() => "name of the token";
public static string Symbol() => "SymbolOfTheToken";
public static readonly byte[] Owner = "AK2nJJpJr6o664CWJKi1QRXjqeic2zRp8y".ToScriptHash();
public static byte Decimals() => 8;
private const ulong factor = 100000000; //decided by Decimals()
private const ulong neo_decimals = 100000000;
//ICO Settings
private static readonly byte[] neo_asset_id = { 155, 124, 255, 218, 166, 116, 190, 174, 15, 147, 14, 190, 96, 133, 175, 144, 147, 229, 254, 86, 179, 74, 92, 34, 12, 205, 207, 110, 252, 51, 111, 197 };
private const ulong total_amount = 100000000 * factor; // total token amount
private const ulong pre_ico_cap = 30000000 * factor; // pre ico token amount
private const ulong basic_rate = 1000 * factor;
private const int ico_start_time = 1506787200;
private const int ico_end_time = 1538323200;
[DisplayName("transfer")]
public static event Action<byte[], byte[], BigInteger> Transferred;
[DisplayName("refund")]
public static event Action<byte[], BigInteger> Refund;
public static Object Main(string operation, params object[] args)
{
if (Runtime.Trigger == TriggerType.Verification)
{
if (Owner.Length == 20)
{
// if param Owner is script hash
return Runtime.CheckWitness(Owner);
}
else if (Owner.Length == 33)
{
// if param Owner is public key
byte[] signature = operation.AsByteArray();
return VerifySignature(signature, Owner);
}
}
else if (Runtime.Trigger == TriggerType.Application)
{
if (operation == "deploy") return Deploy();
if (operation == "mintTokens") return MintTokens();
if (operation == "totalSupply") return TotalSupply();
if (operation == "name") return Name();
if (operation == "symbol") return Symbol();
if (operation == "transfer")
{
if (args.Length != 3) return false;
byte[] from = (byte[])args[0];
byte[] to = (byte[])args[1];
BigInteger value = (BigInteger)args[2];
return Transfer(from, to, value);
}
if (operation == "balanceOf")
{
if (args.Length != 1) return 0;
byte[] account = (byte[])args[0];
return BalanceOf(account);
}
if (operation == "decimals") return Decimals();
}
//you can choice refund or not refund
byte[] sender = GetSender();
ulong contribute_value = GetContributeValue();
if (contribute_value > 0 && sender.Length != 0)
{
Refund(sender, contribute_value);
}
return false;
}
// initialization parameters, only once
// 初始化参数
public static bool Deploy()
{
byte[] total_supply = Storage.Get(Storage.CurrentContext, "totalSupply");
if (total_supply.Length != 0) return false;
Storage.Put(Storage.CurrentContext, Owner, pre_ico_cap);
Storage.Put(Storage.CurrentContext, "totalSupply", pre_ico_cap);
Transferred(null, Owner, pre_ico_cap);
return true;
}
// The function MintTokens is only usable by the chosen wallet
// contract to mint a number of tokens proportional to the
// amount of neo sent to the wallet contract. The function
// can only be called during the tokenswap period
// 将众筹的neo转化为等价的ico代币
public static bool MintTokens()
{
byte[] sender = GetSender();
// contribute asset is not neo
if (sender.Length == 0)
{
return false;
}
ulong contribute_value = GetContributeValue();
// the current exchange rate between ico tokens and neo during the token swap period
// 获取众筹期间ico token和neo间的转化率
ulong swap_rate = CurrentSwapRate();
// crowdfunding failure
// 众筹失败
if (swap_rate == 0)
{
Refund(sender, contribute_value);
return false;
}
// you can get current swap token amount
ulong token = CurrentSwapToken(sender, contribute_value, swap_rate);
if (token == 0)
{
return false;
}
// crowdfunding success
// 众筹成功
BigInteger balance = Storage.Get(Storage.CurrentContext, sender).AsBigInteger();
Storage.Put(Storage.CurrentContext, sender, token + balance);
BigInteger totalSupply = Storage.Get(Storage.CurrentContext, "totalSupply").AsBigInteger();
Storage.Put(Storage.CurrentContext, "totalSupply", token + totalSupply);
Transferred(null, sender, token);
return true;
}
// get the total token supply
// 获取已发行token总量
public static BigInteger TotalSupply()
{
return Storage.Get(Storage.CurrentContext, "totalSupply").AsBigInteger();
}
// function that is always called when someone wants to transfer tokens.
// 流转token调用
public static bool Transfer(byte[] from, byte[] to, BigInteger value)
{
if (value <= 0) return false;
if (!Runtime.CheckWitness(from)) return false;
if (to.Length != 20) return false;
BigInteger from_value = Storage.Get(Storage.CurrentContext, from).AsBigInteger();
if (from_value < value) return false;
if (from == to) return true;
if (from_value == value)
Storage.Delete(Storage.CurrentContext, from);
else
Storage.Put(Storage.CurrentContext, from, from_value - value);
BigInteger to_value = Storage.Get(Storage.CurrentContext, to).AsBigInteger();
Storage.Put(Storage.CurrentContext, to, to_value + value);
Transferred(from, to, value);
return true;
}
// get the account balance of another account with address
// 根据地址获取token的余额
public static BigInteger BalanceOf(byte[] address)
{
return Storage.Get(Storage.CurrentContext, address).AsBigInteger();
}
// The function CurrentSwapRate() returns the current exchange rate
// between ico tokens and neo during the token swap period
private static ulong CurrentSwapRate()
{
const int ico_duration = ico_end_time - ico_start_time;
uint now = Runtime.Time;
int time = (int)now - ico_start_time;
if (time < 0)
{
return 0;
}
else if (time < ico_duration)
{
return basic_rate;
}
else
{
return 0;
}
}
//whether over contribute capacity, you can get the token amount
private static ulong CurrentSwapToken(byte[] sender, ulong value, ulong swap_rate)
{
ulong token = value / neo_decimals * swap_rate;
BigInteger total_supply = Storage.Get(Storage.CurrentContext, "totalSupply").AsBigInteger();
BigInteger balance_token = total_amount - total_supply;
if (balance_token <= 0)
{
Refund(sender, value);
return 0;
}
else if (balance_token < token)
{
Refund(sender, (token - balance_token) / swap_rate * neo_decimals);
token = (ulong)balance_token;
}
return token;
}
// check whether asset is neo and get sender script hash
private static byte[] GetSender()
{
Transaction tx = (Transaction)ExecutionEngine.ScriptContainer;
TransactionOutput[] reference = tx.GetReferences();
// you can choice refund or not refund
foreach (TransactionOutput output in reference)
{
if (output.AssetId == neo_asset_id) return output.ScriptHash;
}
return new byte[]{};
}
// get smart contract script hash
private static byte[] GetReceiver()
{
return ExecutionEngine.ExecutingScriptHash;
}
// get all you contribute neo amount
private static ulong GetContributeValue()
{
Transaction tx = (Transaction)ExecutionEngine.ScriptContainer;
TransactionOutput[] outputs = tx.GetOutputs();
ulong value = 0;
// get the total amount of Neo
// 获取转入智能合约地址的Neo总量
foreach (TransactionOutput output in outputs)
{
if (output.ScriptHash == GetReceiver() && output.AssetId == neo_asset_id)
{
value += (ulong)output.Value;
}
}
return value;
}
}
}
from neo-boa.
Apologies for the direct code post, It is the template on neocompilereco, and I could not find where it is actually hosted
from neo-boa.
Is it me or is the ABI output missing an entry for
public static readonly byte[] Owner = "AK2nJJpJr6o664CWJKi1QRXjqeic2zRp8y".ToScriptHash();
as it looks to output all public accessors.
Perhaps I'm a bit skeptical, but is this ABI output not kind of useless without knowing a mapping of "operation name => function"? e.g. the operation "deploy" maps to Boolean Deploy();
.
It also seems to force you into using a fixed Main signature and implementation structure of
public static Object Main(string operation, params object[] args)
if (operation == 'name') return Name()
which is severely limited due to the 16 objects max array length of args. Any thoughts?
Or are there perhaps plans to move to an "Ethereum model" where you can call the public functions directly? Then the ABI actually makes sense.
from neo-boa.
I just noticed that the sample ABI doesn't follow NEP3
sample ABI:
Events:
Void transfer(ByteArray arg1, ByteArray arg2, Integer arg3);
NEP3 suggestion
{
"hash": "0x746d6cc63dacd7b275bb3a3a06d54859661591a6",
"entrypoint": "main",
"functions": [],
"events": [
{
"name": "refund",
"parameters": [
{
"name": "arg1"
"type": "ByteArray"
},
{
"name": "arg2"
"type": "ByteArray"
},
{
"name": "arg3"
"type": "Integer"
},
]
}
]
}
I believe we need more alignment before this can be considered.
from neo-boa.
I think that is correct because it only outputs functions not publicly accessible static variables. Although that would be a nice addition.
@igormcoelho do you do any custom formatting on neocompiler eco?
from neo-boa.
@igormcoelho do you do any custom formatting on neocompiler eco?
From my testing it looks like NeoCompiler Eco takes the ABI output from the neon compiler with all the function names, then assumes that the operation name will be the same name (only in camelCase) when it comes time to choose one to invoke.
Of course, there's no guideline for function vs operation naming in NEP-3 so a lot of contract authors are going to name their operations one thing and their corresponding functions another, and their generated ABI will be fairly useless to NeoCompiler Eco or other tools that parse the ABI.
For neo-boa, I like the idea of using Pythonic type hints and building the ABI based on any function or event definition that contains hints, using the name of the function verbatim as the operation name.
Then, we need to amend NEP-3 with guidance to require any operation that is meant to be included in the ABI have a function name with its exact match.
Given the top-down-from-Main invocation pattern built in to the Neo VM I don't see a perfect way to solve the problem without requiring some diligence on the part of contract authors, but at least this way it will at least be easy enough for contract authors to implement after some light reading.
Edit: I see Erik had replied in the NEP-3 PR to the issue of function names and case with the following:
C# methods starts with upper case.
While you can certainly write a valid C# function name that starts with lower-case, it is technically part of the C# convention to use PascalCase for everything except parameter names. So I doubt he'll want to amend NEP-3 to suggest making a C# contract use bool transferFrom(
instead of bool TransferFrom
However the C# compiler could be modified to automatically switch the ABI function names to camelCase instead of relying on the parser to do so, at least this way the different compilers could be made to be consistent in their ABI output if nothing else.
from neo-boa.
Related Issues (20)
- Crowdsale Demo directory shouldn't be labeled "nex" HOT 1
- Crowdsale demo and nep5 demo should be the same style HOT 1
- The method to_s(), which generates the output of the executable in readable format, is outdated
- [Feature] Use Python assert in smart contract HOT 4
- Smart Contract Migration results in different return value HOT 1
- Add support for multi-line invocation
- Neo 3x support HOT 2
- Built-in command line interface for neo-boa HOT 1
- support for avmdbgnfo format HOT 4
- replace coz-bytecode dependency with official bytecode project HOT 1
- .abi.json support HOT 3
- Python typehinting support
- About NEP-5 Smart Contract
- Generating incorrect hash for ABI file HOT 1
- Visual DevTracker deploy function not detecting contracts compiled with neo-boa
- negative shift count error when running unit test HOT 1
- Convert byte array to number ? HOT 1
- Invoking Neo.Contract.IsPayable fails HOT 1
- Crowdsale Demo totalSupply returns circulation
- Crowdsale Demo Contract missing OnTransfer event in deploy
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from neo-boa.