Skip to content

Commit

Permalink
Nep17 (neo-project#412)
Browse files Browse the repository at this point in the history
* [RpcServer] Querying contracts by ID/name (neo-project#378)

* fixed-bug-1021

* Update src/RpcServer/RpcServer.SmartContract.cs

* 😂

* draft

* draft

* update

* fixed bug with decimal of GAS consumed in invokefunction/invokescript

* remove modify of invokescript

* Querying contracts by ID/name, server side

* update

* Enable using native.name for search

Enable using native.name for search

* Using keyword instead of addressOrScriptHash

* revert

* _initialize

* split

* update

* Update exception message in ApplicationLog

* Update src/ApplicationLogs/LogReader.cs

Co-authored-by: Luchuan <[email protected]>

* update

* a

* More fix

* fix

* Fixed UT

* Simplify Code

* Simplify Code 2

* Update RpcServer

* update

Co-authored-by: Shargon <[email protected]>
Co-authored-by: Owen Zhang <[email protected]>
Co-authored-by: superboyiii <[email protected]>
Co-authored-by: Vitor Nazário Coelho <[email protected]>
Co-authored-by: Luchuan <[email protected]>

* String Substitution

* Modify filename and name methods

* update

* update

* Update src/RpcClient/Models/RpcNep5TokenInfo.cs

Co-authored-by: Vitor Nazário Coelho <[email protected]>

* Update src/RpcClient/Nep17API.cs

Co-authored-by: Vitor Nazário Coelho <[email protected]>

* MPT in StateService from core (neo-project#410)

* Unify GetUnclaimedGas and GetWalletUnclaimedGas with decimal (neo-project#413)

* Unify GetUnclaimedGas and GetWalletUnclaimedGas with decimal

* fix

* Fixed UT (Neo CI01089)

* Update Nep17API.cs

* Update README.md

Co-authored-by: Owen Zhang <[email protected]>

* update filename

* Fix UT

* Format

* fix

* update

* update UT

* Add Unit Tests

* update

Co-authored-by: Shargon <[email protected]>
Co-authored-by: Owen Zhang <[email protected]>
Co-authored-by: superboyiii <[email protected]>
Co-authored-by: Vitor Nazário Coelho <[email protected]>
Co-authored-by: Luchuan <[email protected]>
Co-authored-by: ZhangTao <[email protected]>
  • Loading branch information
7 people committed Dec 10, 2020
1 parent b522dce commit bd80d9e
Show file tree
Hide file tree
Showing 24 changed files with 208 additions and 197 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,12 @@ You can also use `RocksDBStore` in the NEO system by modifying the default stora
### RpcServer
Plugin for hosting a RpcServer on the neo-node, being able to disable specific calls.

### RpcNep5Tracker
Plugin that enables NEP5 tracking using LevelDB.
### RpcNep17Tracker
Plugin that enables NEP17 tracking using LevelDB.
This module works in conjunction with RpcServer, otherwise, just local storage (on leveldb) would be created.

## C# SDK

### RpcClient
The RpcClient Project is an individual SDK that is used to interact with NEO blockchain through NEO RPC methods for development using. The main functions include RPC calling, Transaction making, Contract deployment & calling, and Asset transfering.
It needs a NEO node with the `RpcServer` plugin as a provider. And the provider needs more plugins like `RpcNep5Tracker` and `ApplicationLogs` if you want to call RPC methods supplied by the plugins.
It needs a NEO node with the `RpcServer` plugin as a provider. And the provider needs more plugins like `RpcNep17Tracker` and `ApplicationLogs` if you want to call RPC methods supplied by the plugins.
2 changes: 1 addition & 1 deletion neo-modules.sln
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApplicationLogs", "src\Appl
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StatesDumper", "src\StatesDumper\StatesDumper.csproj", "{86531DB1-A231-46C4-823F-BE60972F7523}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcNep5Tracker", "src\RpcNep5Tracker\RpcNep5Tracker.csproj", "{BBE8AC15-12DF-4AF0-ABC1-F1557EB5DC8E}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcNep17Tracker", "src\RpcNep17Tracker\RpcNep17Tracker.csproj", "{BBE8AC15-12DF-4AF0-ABC1-F1557EB5DC8E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LevelDBStore", "src\LevelDBStore\LevelDBStore.csproj", "{C66214CD-0B97-4EA5-B7A2-164F54346F19}"
EndProject
Expand Down
2 changes: 1 addition & 1 deletion src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Neo" Version="3.0.0-CI01089" />
<PackageReference Include="Neo" Version="3.0.0-CI01091" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@

namespace Neo.Network.RPC.Models
{
public class RpcNep5Balances
public class RpcNep17Balances
{
public UInt160 UserScriptHash { get; set; }

public List<RpcNep5Balance> Balances { get; set; }
public List<RpcNep17Balance> Balances { get; set; }

public JObject ToJson()
{
Expand All @@ -20,18 +20,18 @@ public JObject ToJson()
return json;
}

public static RpcNep5Balances FromJson(JObject json)
public static RpcNep17Balances FromJson(JObject json)
{
RpcNep5Balances nep5Balance = new RpcNep5Balances
RpcNep17Balances nep17Balance = new RpcNep17Balances
{
Balances = ((JArray)json["balance"]).Select(p => RpcNep5Balance.FromJson(p)).ToList(),
Balances = ((JArray)json["balance"]).Select(p => RpcNep17Balance.FromJson(p)).ToList(),
UserScriptHash = json["address"].ToScriptHash()
};
return nep5Balance;
return nep17Balance;
}
}

public class RpcNep5Balance
public class RpcNep17Balance
{
public UInt160 AssetHash { get; set; }

Expand All @@ -48,9 +48,9 @@ public JObject ToJson()
return json;
}

public static RpcNep5Balance FromJson(JObject json)
public static RpcNep17Balance FromJson(JObject json)
{
RpcNep5Balance balance = new RpcNep5Balance
RpcNep17Balance balance = new RpcNep17Balance
{
AssetHash = json["assethash"].ToScriptHash(),
Amount = BigInteger.Parse(json["amount"].AsString()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Neo.Network.RPC.Models
{
public class RpcNep5TokenInfo
public class RpcNep17TokenInfo
{
public string Name { get; set; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@

namespace Neo.Network.RPC.Models
{
public class RpcNep5Transfers
public class RpcNep17Transfers
{
public UInt160 UserScriptHash { get; set; }

public List<RpcNep5Transfer> Sent { get; set; }
public List<RpcNep17Transfer> Sent { get; set; }

public List<RpcNep5Transfer> Received { get; set; }
public List<RpcNep17Transfer> Received { get; set; }

public JObject ToJson()
{
Expand All @@ -24,19 +24,19 @@ public JObject ToJson()
return json;
}

public static RpcNep5Transfers FromJson(JObject json)
public static RpcNep17Transfers FromJson(JObject json)
{
RpcNep5Transfers transfers = new RpcNep5Transfers
RpcNep17Transfers transfers = new RpcNep17Transfers
{
Sent = ((JArray)json["sent"]).Select(p => RpcNep5Transfer.FromJson(p)).ToList(),
Received = ((JArray)json["received"]).Select(p => RpcNep5Transfer.FromJson(p)).ToList(),
Sent = ((JArray)json["sent"]).Select(p => RpcNep17Transfer.FromJson(p)).ToList(),
Received = ((JArray)json["received"]).Select(p => RpcNep17Transfer.FromJson(p)).ToList(),
UserScriptHash = json["address"].ToScriptHash()
};
return transfers;
}
}

public class RpcNep5Transfer
public class RpcNep17Transfer
{
public ulong TimestampMS { get; set; }

Expand Down Expand Up @@ -65,9 +65,9 @@ public JObject ToJson()
return json;
}

public static RpcNep5Transfer FromJson(JObject json)
public static RpcNep17Transfer FromJson(JObject json)
{
return new RpcNep5Transfer
return new RpcNep17Transfer
{
TimestampMS = (ulong)json["timestamp"].AsNumber(),
AssetHash = json["assethash"].ToScriptHash(),
Expand Down
57 changes: 25 additions & 32 deletions src/RpcClient/Nep5API.cs → src/RpcClient/Nep17API.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,18 @@
namespace Neo.Network.RPC
{
/// <summary>
/// Call NEP5 methods with RPC API
/// Call NEP17 methods with RPC API
/// </summary>
public class Nep5API : ContractClient
public class Nep17API : ContractClient
{
/// <summary>
/// Nep5API Constructor
/// Nep17API Constructor
/// </summary>
/// <param name="rpcClient">the RPC client to call NEO RPC methods</param>
public Nep5API(RpcClient rpcClient) : base(rpcClient) { }
public Nep17API(RpcClient rpcClient) : base(rpcClient) { }

/// <summary>
/// Get balance of NEP5 token
/// Get balance of NEP17 token
/// </summary>
/// <param name="scriptHash">contract script hash</param>
/// <param name="account">account script hash</param>
Expand All @@ -37,18 +37,7 @@ public async Task<BigInteger> BalanceOfAsync(UInt160 scriptHash, UInt160 account
}

/// <summary>
/// Get name of NEP5 token
/// </summary>
/// <param name="scriptHash">contract script hash</param>
/// <returns></returns>
public async Task<string> NameAsync(UInt160 scriptHash)
{
var result = await TestInvokeAsync(scriptHash, "name").ConfigureAwait(false);
return result.Stack.Single().GetString();
}

/// <summary>
/// Get symbol of NEP5 token
/// Get symbol of NEP17 token
/// </summary>
/// <param name="scriptHash">contract script hash</param>
/// <returns></returns>
Expand All @@ -59,7 +48,7 @@ public async Task<string> SymbolAsync(UInt160 scriptHash)
}

/// <summary>
/// Get decimals of NEP5 token
/// Get decimals of NEP17 token
/// </summary>
/// <param name="scriptHash">contract script hash</param>
/// <returns></returns>
Expand All @@ -70,7 +59,7 @@ public async Task<byte> DecimalsAsync(UInt160 scriptHash)
}

/// <summary>
/// Get total supply of NEP5 token
/// Get total supply of NEP17 token
/// </summary>
/// <param name="scriptHash">contract script hash</param>
/// <returns></returns>
Expand All @@ -85,40 +74,43 @@ public async Task<BigInteger> TotalSupplyAsync(UInt160 scriptHash)
/// </summary>
/// <param name="scriptHash">contract script hash</param>
/// <returns></returns>
public async Task<RpcNep5TokenInfo> GetTokenInfoAsync(UInt160 scriptHash)
public async Task<RpcNep17TokenInfo> GetTokenInfoAsync(UInt160 scriptHash)
{
byte[] script = Concat(
scriptHash.MakeScript("name"),
scriptHash.MakeScript("symbol"),
scriptHash.MakeScript("decimals"),
scriptHash.MakeScript("totalSupply"));

var contractState = await rpcClient.GetContractStateAsync(scriptHash.ToString()).ConfigureAwait(false);
var name = contractState.Manifest.Name;

var result = await rpcClient.InvokeScriptAsync(script).ConfigureAwait(false);
var stack = result.Stack;

return new RpcNep5TokenInfo
return new RpcNep17TokenInfo
{
Name = stack[0].GetString(),
Symbol = stack[1].GetString(),
Decimals = (byte)stack[2].GetInteger(),
TotalSupply = stack[3].GetInteger()
Name = name,
Symbol = stack[0].GetString(),
Decimals = (byte)stack[1].GetInteger(),
TotalSupply = stack[2].GetInteger()
};
}

/// <summary>
/// Create NEP5 token transfer transaction
/// Create NEP17 token transfer transaction
/// </summary>
/// <param name="scriptHash">contract script hash</param>
/// <param name="fromKey">from KeyPair</param>
/// <param name="to">to account script hash</param>
/// <param name="amount">transfer amount</param>
/// <param name="data">onPayment data</param>
/// <returns></returns>
public async Task<Transaction> CreateTransferTxAsync(UInt160 scriptHash, KeyPair fromKey, UInt160 to, BigInteger amount)
public async Task<Transaction> CreateTransferTxAsync(UInt160 scriptHash, KeyPair fromKey, UInt160 to, BigInteger amount, object data = null)
{
var sender = Contract.CreateSignatureRedeemScript(fromKey.PublicKey).ToScriptHash();
Signer[] signers = new[] { new Signer { Scopes = WitnessScope.CalledByEntry, Account = sender } };

byte[] script = scriptHash.MakeScript("transfer", sender, to, amount);
byte[] script = data is null ? scriptHash.MakeScript("transfer", sender, to, amount) : scriptHash.MakeScript("transfer", sender, to, amount, data);

TransactionManagerFactory factory = new TransactionManagerFactory(rpcClient, magic);
TransactionManager manager = await factory.MakeTransactionAsync(script, signers).ConfigureAwait(false);
Expand All @@ -128,23 +120,24 @@ public async Task<Transaction> CreateTransferTxAsync(UInt160 scriptHash, KeyPair
}

/// <summary>
/// Create NEP5 token transfer transaction from multi-sig account
/// Create NEP17 token transfer transaction from multi-sig account
/// </summary>
/// <param name="scriptHash">contract script hash</param>
/// <param name="m">multi-sig min signature count</param>
/// <param name="pubKeys">multi-sig pubKeys</param>
/// <param name="fromKeys">sign keys</param>
/// <param name="to">to account</param>
/// <param name="amount">transfer amount</param>
/// <param name="data">onPayment data</param>
/// <returns></returns>
public async Task<Transaction> CreateTransferTxAsync(UInt160 scriptHash, int m, ECPoint[] pubKeys, KeyPair[] fromKeys, UInt160 to, BigInteger amount)
public async Task<Transaction> CreateTransferTxAsync(UInt160 scriptHash, int m, ECPoint[] pubKeys, KeyPair[] fromKeys, UInt160 to, BigInteger amount, object data = null)
{
if (m > fromKeys.Length)
throw new ArgumentException($"Need at least {m} KeyPairs for signing!");
var sender = Contract.CreateMultiSigContract(m, pubKeys).ScriptHash;
Signer[] signers = new[] { new Signer { Scopes = WitnessScope.CalledByEntry, Account = sender } };

byte[] script = scriptHash.MakeScript("transfer", sender, to, amount);
byte[] script = data is null ? scriptHash.MakeScript("transfer", sender, to, amount) : scriptHash.MakeScript("transfer", sender, to, amount, data);

TransactionManagerFactory factory = new TransactionManagerFactory(rpcClient, magic);
TransactionManager manager = await factory.MakeTransactionAsync(script, signers).ConfigureAwait(false);
Expand Down
20 changes: 10 additions & 10 deletions src/RpcClient/RpcClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -447,14 +447,14 @@ public async Task<string> GetNewAddressAsync()

/// <summary>
/// Returns the balance of the corresponding asset in the wallet, based on the specified asset Id.
/// This method applies to assets that conform to NEP-5 standards.
/// This method applies to assets that conform to NEP-17 standards.
/// </summary>
/// <returns>new address as string</returns>
public async Task<BigDecimal> GetWalletBalanceAsync(string assetId)
{
var result = await RpcSendAsync(GetRpcName(), assetId).ConfigureAwait(false);
BigInteger balance = BigInteger.Parse(result["balance"].AsString());
byte decimals = await new Nep5API(this).DecimalsAsync(UInt160.Parse(assetId.AsScriptHash())).ConfigureAwait(false);
byte decimals = await new Nep17API(this).DecimalsAsync(UInt160.Parse(assetId.AsScriptHash())).ConfigureAwait(false);
return new BigDecimal(balance, decimals);
}

Expand Down Expand Up @@ -556,30 +556,30 @@ public async Task<RpcApplicationLog> GetApplicationLogAsync(string txHash, Trigg
}

/// <summary>
/// Returns all the NEP-5 transaction information occurred in the specified address.
/// This method is provided by the plugin RpcNep5Tracker.
/// Returns all the NEP-17 transaction information occurred in the specified address.
/// This method is provided by the plugin RpcNep17Tracker.
/// </summary>
/// <param name="address">The address to query the transaction information.</param>
/// <param name="startTimestamp">The start block Timestamp, default to seven days before UtcNow</param>
/// <param name="endTimestamp">The end block Timestamp, default to UtcNow</param>
public async Task<RpcNep5Transfers> GetNep5TransfersAsync(string address, ulong? startTimestamp = default, ulong? endTimestamp = default)
public async Task<RpcNep17Transfers> GetNep17TransfersAsync(string address, ulong? startTimestamp = default, ulong? endTimestamp = default)
{
startTimestamp ??= 0;
endTimestamp ??= DateTime.UtcNow.ToTimestampMS();
var result = await RpcSendAsync(GetRpcName(), address.AsScriptHash(), startTimestamp, endTimestamp)
.ConfigureAwait(false);
return RpcNep5Transfers.FromJson(result);
return RpcNep17Transfers.FromJson(result);
}

/// <summary>
/// Returns the balance of all NEP-5 assets in the specified address.
/// This method is provided by the plugin RpcNep5Tracker.
/// Returns the balance of all NEP-17 assets in the specified address.
/// This method is provided by the plugin RpcNep17Tracker.
/// </summary>
public async Task<RpcNep5Balances> GetNep5BalancesAsync(string address)
public async Task<RpcNep17Balances> GetNep17BalancesAsync(string address)
{
var result = await RpcSendAsync(GetRpcName(), address.AsScriptHash())
.ConfigureAwait(false);
return RpcNep5Balances.FromJson(result);
return RpcNep17Balances.FromJson(result);
}

#endregion Plugins
Expand Down
2 changes: 1 addition & 1 deletion src/RpcClient/TransactionManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ public async Task<Transaction> SignAsync()
Tx.NetworkFee = await rpcClient.CalculateNetworkFeeAsync(Tx).ConfigureAwait(false);
Tx.Witnesses = null;

var gasBalance = await new Nep5API(rpcClient).BalanceOfAsync(NativeContract.GAS.Hash, Tx.Sender).ConfigureAwait(false);
var gasBalance = await new Nep17API(rpcClient).BalanceOfAsync(NativeContract.GAS.Hash, Tx.Sender).ConfigureAwait(false);
if (gasBalance < Tx.SystemFee + Tx.NetworkFee)
throw new InvalidOperationException($"Insufficient GAS in address: {Tx.Sender.ToAddress()}");

Expand Down
Loading

0 comments on commit bd80d9e

Please sign in to comment.