diff --git a/neoutils/btckey/btckey_test.go b/neoutils/btckey/btckey_test.go index 145208b..dc95ebd 100644 --- a/neoutils/btckey/btckey_test.go +++ b/neoutils/btckey/btckey_test.go @@ -492,7 +492,7 @@ func TestGenerateKey(t *testing.T) { func TestSignData(t *testing.T) { - wif := "L5hbtj4mX16TnVnQTdda4znw1nvt3DB7DVxU6sP97RDVMtufQwbT" + wif := "" var priv PrivateKey err := priv.FromWIF(wif) diff --git a/neoutils/multisig.go b/neoutils/multisig.go index b6c8ad1..2bbe695 100644 --- a/neoutils/multisig.go +++ b/neoutils/multisig.go @@ -3,12 +3,13 @@ package neoutils import ( "fmt" + "sort" + "github.com/o3labs/neo-utils/neoutils/btckey" "github.com/o3labs/neo-utils/neoutils/smartcontract" ) type MultiSigInterface interface { - CreateMultiSignedAddress(publicKeys [][]byte) error CreateMultiSigRedeemScript(numerOfRequiredSignature int, publicKeys [][]byte) ([]byte, error) } @@ -16,12 +17,6 @@ type MultiSig struct{} var _ MultiSigInterface = (*MultiSig)(nil) -//TODO: finish this -func (m *MultiSig) CreateMultiSignedAddress(publicKeys [][]byte) error { - return nil -} - -//TODO: finish this func (m *MultiSig) CreateMultiSigRedeemScript(numerOfRequiredSignature int, publicKeys [][]byte) ([]byte, error) { numberOfPublicKeys := len(publicKeys) if numberOfPublicKeys <= 1 { @@ -31,19 +26,23 @@ func (m *MultiSig) CreateMultiSigRedeemScript(numerOfRequiredSignature int, publ return nil, fmt.Errorf("Number of required Signature is more than public keys provided.") } - sb := smartcontract.NewScriptBuilder() - sb.EmitPush(numerOfRequiredSignature) - for _, publicKey := range publicKeys { - // pub := btckey.PublicKey{} - // err := pub.FromBytes(publicKey) - // if err != nil { - // return err - // } - //this publicKey is already a compressed bytes so we can add that directly - sb.EmitPush(publicKey) + //sort public key + keys := []btckey.PublicKey{} + for _, pb := range publicKeys { + publicKey := btckey.PublicKey{} + publicKey.FromBytes(pb) + keys = append(keys, publicKey) } - sb.EmitPush(numberOfPublicKeys) - sb.EmitPush(smartcontract.CHECKMULTISIG) + //https://golang.org/pkg/math/big/#Int.Cmp + sort.SliceStable(keys, func(i, j int) bool { return keys[i].Point.X.Cmp(keys[j].Point.X) == -1 }) + + sb := smartcontract.NewScriptBuilder() + sb.Push(numerOfRequiredSignature) + for _, publicKey := range keys { + sb.Push(publicKey.ToBytes()) + } + sb.Push(numberOfPublicKeys) + sb.PushOpCode(smartcontract.CHECKMULTISIG) return sb.ToBytes(), nil } diff --git a/neoutils/multisig_test.go b/neoutils/multisig_test.go new file mode 100644 index 0000000..42c7dc0 --- /dev/null +++ b/neoutils/multisig_test.go @@ -0,0 +1,56 @@ +package neoutils_test + +import ( + "log" + "sort" + "testing" + + "github.com/o3labs/neo-utils/neoutils" + "github.com/o3labs/neo-utils/neoutils/btckey" +) + +func TestGenerateMultiSigAddress(t *testing.T) { + + pb1 := "02e77ff280db51ef3638009f11947c544ed094d4e5f2d96a9e654dc817bc3a8986" + pb2 := "024da93f9a66981e499b36ce763e57fd89a47a052e86d40b42f81708c40fe9eff0" + require := 2 + pubKeys := [][]byte{} + + pubKeys = append(pubKeys, neoutils.HexTobytes(pb1)) + pubKeys = append(pubKeys, neoutils.HexTobytes(pb2)) + + multisign := neoutils.MultiSig{} + vmCode, err := multisign.CreateMultiSigRedeemScript(require, pubKeys) + if err != nil { + log.Printf("%v", err) + } + log.Printf("vm code %x", vmCode) + + multisigAddress := neoutils.VMCodeToNEOAddress(vmCode) + log.Printf("multi sig address %v", multisigAddress) + if multisigAddress != "AKo8k27H5nCG8MwSirmnraH6uUG6fQQVC2" { + t.Fail() + } +} + +func TestSortPublicKeys(t *testing.T) { + p1Hex := "02e77ff280db51ef3638009f11947c544ed094d4e5f2d96a9e654dc817bc3a8986" + p2Hex := "024da93f9a66981e499b36ce763e57fd89a47a052e86d40b42f81708c40fe9eff0" + p3Hex := "035ca1deea29ccb25a3a4d32701a0e735f76f3b44d233e23930cd74b68a63d10c3" + p1 := btckey.PublicKey{} + p2 := btckey.PublicKey{} + p3 := btckey.PublicKey{} + p1.FromBytes(neoutils.HexTobytes(p1Hex)) + p2.FromBytes(neoutils.HexTobytes(p2Hex)) + p3.FromBytes(neoutils.HexTobytes(p3Hex)) + + keys := []btckey.PublicKey{p3, p1, p2} + + //https://golang.org/pkg/math/big/#Int.Cmp + sort.SliceStable(keys, func(i, j int) bool { return keys[i].Point.X.Cmp(keys[j].Point.X) == -1 }) + for _, k := range keys { + log.Printf("%x", k.ToBytes()) + } + //correct order is p2, p3, p1 + +} diff --git a/neoutils/native_asset.go b/neoutils/native_asset.go index 2ebf6c0..0bc4c60 100644 --- a/neoutils/native_asset.go +++ b/neoutils/native_asset.go @@ -8,6 +8,7 @@ import ( type NativeAssetInterface interface { SendNativeAssetRawTransaction(wallet Wallet, asset smartcontract.NativeAsset, amount float64, to smartcontract.NEOAddress, unspent smartcontract.Unspent, attributes map[smartcontract.TransactionAttribute][]byte) ([]byte, string, error) + GenerateRawTx(fromAddress string, asset smartcontract.NativeAsset, amount float64, to smartcontract.NEOAddress, unspent smartcontract.Unspent, attributes map[smartcontract.TransactionAttribute][]byte) ([]byte, string, error) } type NativeAsset struct { @@ -23,42 +24,14 @@ func UseNativeAsset(networkFeeAmount smartcontract.NetworkFeeAmount) NativeAsset var _ NativeAssetInterface = (*NativeAsset)(nil) func (n *NativeAsset) SendNativeAssetRawTransaction(wallet Wallet, asset smartcontract.NativeAsset, amount float64, to smartcontract.NEOAddress, unspent smartcontract.Unspent, attributes map[smartcontract.TransactionAttribute][]byte) ([]byte, string, error) { - //New invocation transaction struct and fill with all necessary data - tx := smartcontract.NewContractTransaction() - - amountToSend := amount - assetToSend := asset - - //generate transaction inputs - txInputs, err := smartcontract.NewScriptBuilder().GenerateTransactionInput(unspent, assetToSend, amountToSend, n.NetworkFeeAmount) - if err != nil { - return nil, "", err - } - //transaction inputs - tx.Inputs = txInputs - - //generate transaction outputs - txAttributes, err := smartcontract.NewScriptBuilder().GenerateTransactionAttributes(attributes) + tx, txID, err := n.GenerateRawTx(wallet.Address, asset, amount, to, unspent, attributes) if err != nil { return nil, "", err } - //transaction attributes - tx.Attributes = txAttributes - sender := smartcontract.ParseNEOAddress(wallet.Address) - receiver := to - txOutputs, err := smartcontract.NewScriptBuilder().GenerateTransactionOutput(sender, receiver, unspent, assetToSend, amountToSend, n.NetworkFeeAmount) - if err != nil { - log.Printf("%v", err) - return nil, "", err - } - - tx.Outputs = txOutputs - - //begin signing process and invocation script + //begin signing privateKeyInHex := bytesToHex(wallet.PrivateKey) - - signedData, err := Sign(tx.ToBytes(), privateKeyInHex) + signedData, err := Sign(tx, privateKeyInHex) if err != nil { log.Printf("err signing %v", err) return nil, "", err @@ -68,17 +41,49 @@ func (n *NativeAsset) SendNativeAssetRawTransaction(wallet Wallet, asset smartco SignedData: signedData, PublicKey: wallet.PublicKey, } + // try to verify it + // hash := sha256.Sum256(tx.ToBytes()) + // valid := Verify(wallet.PublicKey, signedData, hash[:]) + // log.Printf("verify tx %v", valid) scripts := []interface{}{signature} txScripts := smartcontract.NewScriptBuilder().GenerateVerificationScripts(scripts) - //assign scripts to the tx - tx.Script = txScripts - //end signing process //concat data endPayload := []byte{} - endPayload = append(endPayload, tx.ToBytes()...) + endPayload = append(endPayload, tx...) + endPayload = append(endPayload, txScripts...) - txID := tx.ToTXID() return endPayload, txID, nil } + +func (n *NativeAsset) GenerateRawTx(fromAddress string, asset smartcontract.NativeAsset, amount float64, to smartcontract.NEOAddress, unspent smartcontract.Unspent, attributes map[smartcontract.TransactionAttribute][]byte) ([]byte, string, error) { + //New invocation transaction struct and fill with all necessary data + tx := smartcontract.NewContractTransaction() + + //generate transaction inputs + txInputs, err := smartcontract.NewScriptBuilder().GenerateTransactionInput(unspent, asset, amount, n.NetworkFeeAmount) + if err != nil { + return nil, "", err + } + tx.Inputs = txInputs + + txAttributes, err := smartcontract.NewScriptBuilder().GenerateTransactionAttributes(attributes) + if err != nil { + return nil, "", err + } + + tx.Attributes = txAttributes + + sender := smartcontract.ParseNEOAddress(fromAddress) + + txOutputs, err := smartcontract.NewScriptBuilder().GenerateTransactionOutput(sender, to, unspent, asset, amount, n.NetworkFeeAmount) + if err != nil { + log.Printf("%v", err) + return nil, "", err + } + + tx.Outputs = txOutputs + + return tx.ToBytes(), tx.ToTXID(), nil +} diff --git a/neoutils/native_asset_test.go b/neoutils/native_asset_test.go index 0910361..c72689a 100644 --- a/neoutils/native_asset_test.go +++ b/neoutils/native_asset_test.go @@ -1,6 +1,7 @@ package neoutils_test import ( + "crypto/sha256" "fmt" "log" "strconv" @@ -82,19 +83,19 @@ func TestSendingGAS(t *testing.T) { t.Fail() } - unspent, err := utxoFromO3Platform("private", privateNetwallet.Address) + unspent, err := utxoFromO3Platform("test", privateNetwallet.Address) if err != nil { log.Printf("error %v", err) t.Fail() return } asset := smartcontract.GAS - amount := float64(10) - toAddress := "AaZmUKtuNEA2NTsjKGyjoAnFLxWsuQgeP3" + amount := float64(0.1) + toAddress := "AKo8k27H5nCG8MwSirmnraH6uUG6fQQVC2" //this is multi signature adddress 3/2 to := smartcontract.ParseNEOAddress(toAddress) - remark := "O3TX" + // remark := "O3TX" attributes := map[smartcontract.TransactionAttribute][]byte{} - attributes[smartcontract.Remark1] = []byte(remark) + // attributes[smartcontract.Remark1] = []byte(remark) fee := smartcontract.NetworkFeeAmount(0.0) nativeAsset := neoutils.UseNativeAsset(fee) @@ -140,3 +141,72 @@ func TestSendingNEO(t *testing.T) { } log.Printf("%v\n%x", txid, rawtx) } + +func TestSendingGASFromMultiSig(t *testing.T) { + fromAddress := "AKo8k27H5nCG8MwSirmnraH6uUG6fQQVC2" //this is multi signature adddress 3/2 + unspent, err := utxoFromO3Platform("test", fromAddress) + if err != nil { + log.Printf("error %v", err) + t.Fail() + return + } + asset := smartcontract.GAS + amount := float64(0.1) + + toAddress := "AKo8k27H5nCG8MwSirmnraH6uUG6fQQVC2" + to := smartcontract.ParseNEOAddress(toAddress) + + attributes := map[smartcontract.TransactionAttribute][]byte{} + + fee := smartcontract.NetworkFeeAmount(0.0) + nativeAsset := neoutils.UseNativeAsset(fee) + rawtx, txid, err := nativeAsset.GenerateRawTx(fromAddress, asset, amount, to, unspent, attributes) + if err != nil { + log.Printf("error sending natie %v", err) + t.Fail() + return + } + log.Printf("txid %v\n", txid) + log.Printf("raw %x\n", rawtx) + + wallet1, _ := neoutils.GenerateFromWIF("") + wallet2, _ := neoutils.GenerateFromWIF("") + + wallets := []*neoutils.Wallet{wallet1, wallet2} + + signatures := []smartcontract.TransactionSignature{} + + for _, w := range wallets { + privateKeyInHex := neoutils.BytesToHex(w.PrivateKey) + + signedData, err := neoutils.Sign(rawtx, privateKeyInHex) + if err != nil { + log.Printf("err signing %v", err) + return + } + + signature := smartcontract.TransactionSignature{ + SignedData: signedData, + PublicKey: w.PublicKey, + } + signatures = append(signatures, signature) + + log.Printf("pub key = %x\n", w.PublicKey) + log.Printf("signedData = %x\n", signedData) + hash := sha256.Sum256(rawtx) + valid := neoutils.Verify(w.PublicKey, signedData, hash[:]) + log.Printf("valid %v", valid) + } + + verificationScripts := smartcontract.NewScriptBuilder().GenerateVerificationScriptsMultiSig(signatures) + + //concat data + endPayload := []byte{} + endPayload = append(endPayload, rawtx...) + endPayload = append(endPayload, verificationScripts...) + + redeemScript := "5221024da93f9a66981e499b36ce763e57fd89a47a052e86d40b42f81708c40fe9eff02102e77ff280db51ef3638009f11947c544ed094d4e5f2d96a9e654dc817bc3a898652ae" + b := neoutils.HexTobytes(redeemScript) + length := len(b) + log.Printf("%x%x%v", endPayload, length, redeemScript) +} diff --git a/neoutils/neorpc/rpc.go b/neoutils/neorpc/rpc.go index 5b6acf3..ce4cdfb 100644 --- a/neoutils/neorpc/rpc.go +++ b/neoutils/neorpc/rpc.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/json" "fmt" - "log" "net/http" "net/url" "time" @@ -156,7 +155,6 @@ func (n *NEORPCClient) GetTokenBalance(tokenHash string, neoAddress string) Toke return TokenBalanceResponse{} } adddressScriptHash := fmt.Sprintf("%x", b) - log.Printf("adddressScriptHash %v", adddressScriptHash) input := NewInvokeFunctionStackByteArray(adddressScriptHash) args = append(args, input) diff --git a/neoutils/neorpc/rpc_test.go b/neoutils/neorpc/rpc_test.go index cac1129..a95fd30 100644 --- a/neoutils/neorpc/rpc_test.go +++ b/neoutils/neorpc/rpc_test.go @@ -87,12 +87,12 @@ func TestGetAccountState(t *testing.T) { } func TestGetTokenBalance(t *testing.T) { - client := neorpc.NewClient("http://localhost:30333") + client := neorpc.NewClient("http://seed3.aphelion-neo.com:10332") if client == nil { t.Fail() } - result := client.GetTokenBalance("0xc2b0fed82b8fa28c358f99849136f45f057bb6fe", "APLNwfJTHp1MBHYNeMAxkeqNCquLpBVjcD") + result := client.GetTokenBalance("fc732edee1efdf968c23c20a9628eaa5a6ccb934", "AcydXy1MvrzaT8qD3Qe4B8mqEoinTvRy8U") log.Printf("%+v", result.Result) } diff --git a/neoutils/ont.go b/neoutils/ont.go new file mode 100644 index 0000000..d409d03 --- /dev/null +++ b/neoutils/ont.go @@ -0,0 +1,22 @@ +package neoutils + +import ( + "log" + + "github.com/o3labs/ont-mobile/ontmobile" +) + +func OntologyTransfer(endpoint string, gasPrice uint, gasLimit uint, wif string, asset string, to string, amount float64) (string, error) { + raw, err := ontmobile.Transfer(gasPrice, gasLimit, wif, asset, to, amount) + if err != nil { + return "", err + } + log.Printf("%x", raw.Data) + return "", nil + // txid, err := ontmobile.SendRawTransaction(endpoint, fmt.Sprintf("%x", raw.Data)) + // if err != nil { + // return "", err + // } + + // return txid, nil +} diff --git a/neoutils/ont_test.go b/neoutils/ont_test.go new file mode 100644 index 0000000..c5150dc --- /dev/null +++ b/neoutils/ont_test.go @@ -0,0 +1,24 @@ +package neoutils_test + +import ( + "log" + "testing" + + "github.com/o3labs/neo-utils/neoutils" +) + +func TestONTTransfer(t *testing.T) { + endpoint := "http://dappnode2.ont.io:20336" + wif := "" + asset := "ont" + to := "AcydXy1MvrzaT8qD3Qe4B8mqEoinTvRy8U" + amount := float64(2) + gasPrice := uint(500) + gasLimit := uint(20000) + txid, err := neoutils.OntologyTransfer(endpoint, gasPrice, gasLimit, wif, asset, to, amount) + if err != nil { + log.Printf("err %v", err) + return + } + log.Printf("tx id =%v", txid) +} diff --git a/neoutils/smartcontract/scriptbuilder.go b/neoutils/smartcontract/scriptbuilder.go index 2b9831f..7ea1968 100644 --- a/neoutils/smartcontract/scriptbuilder.go +++ b/neoutils/smartcontract/scriptbuilder.go @@ -7,6 +7,7 @@ import ( "encoding/hex" "fmt" "log" + "sort" "github.com/o3labs/neo-utils/neoutils/btckey" "golang.org/x/crypto/ripemd160" @@ -51,12 +52,18 @@ type ScriptBuilderInterface interface { GenerateTransactionOutput(sender NEOAddress, receiver NEOAddress, unspent Unspent, assetToSend NativeAsset, amountToSend float64, networkFeeAmount NetworkFeeAmount) ([]byte, error) GenerateVerificationScripts(signatures []interface{}) []byte + + GenerateVerificationScriptsMultiSig(signatures []TransactionSignature) []byte + EmptyTransactionAttributes() []byte ToBytes() []byte FullHexString() string Clear() - EmitPush(data interface{}) error + //public method to wrap pushData + Push(data interface{}) error + PushOpCode(opcode OpCode) + ToScriptHash() []byte //UInt160 pushInt(value int) error @@ -95,7 +102,7 @@ func (s ScriptBuilder) FullHexString() string { return hex.EncodeToString(b) } -func (s *ScriptBuilder) pushOpCode(opcode OpCode) { +func (s *ScriptBuilder) PushOpCode(opcode OpCode) { s.RawBytes = append(s.RawBytes, byte(opcode)) } func (s *ScriptBuilder) pushInt8bytes(value int) error { @@ -107,10 +114,10 @@ func (s *ScriptBuilder) pushInt8bytes(value int) error { func (s *ScriptBuilder) pushInt(value int) error { switch { case value == -1: - s.pushOpCode(PUSHM1) + s.PushOpCode(PUSHM1) return nil case value == 0: - s.pushOpCode(PUSH0) + s.PushOpCode(PUSH0) return nil case value >= 1 && value < 16: rawValue := byte(PUSH1) + byte(value) - 1 @@ -151,22 +158,22 @@ func (s *ScriptBuilder) pushHexString(hexString string) error { s.RawBytes = append(s.RawBytes, trimmedCountByte...) s.RawBytes = append(s.RawBytes, b...) } else if count < 0x100 { - s.pushOpCode(PUSHDATA1) + s.PushOpCode(PUSHDATA1) s.RawBytes = append(s.RawBytes, trimmedCountByte...) s.RawBytes = append(s.RawBytes, b...) } else if count < 0x10000 { - s.pushOpCode(PUSHDATA2) + s.PushOpCode(PUSHDATA2) s.RawBytes = append(s.RawBytes, trimmedCountByte...) s.RawBytes = append(s.RawBytes, b...) } else { - s.pushOpCode(PUSHDATA4) + s.PushOpCode(PUSHDATA4) s.RawBytes = append(s.RawBytes, trimmedCountByte...) s.RawBytes = append(s.RawBytes, b...) } return nil } -func (s *ScriptBuilder) EmitPush(data interface{}) error { +func (s *ScriptBuilder) Push(data interface{}) error { return s.pushData(data) } @@ -239,9 +246,9 @@ func (s *ScriptBuilder) pushData(data interface{}) error { return s.pushHexString(hex.EncodeToString(e)) case bool: if e == true { - s.pushOpCode(PUSH1) + s.PushOpCode(PUSH1) } else { - s.pushOpCode(PUSH0) + s.PushOpCode(PUSH0) } return nil case []interface{}: @@ -251,7 +258,7 @@ func (s *ScriptBuilder) pushData(data interface{}) error { s.pushData(e[i]) } s.pushInt(count) - s.pushOpCode(PACK) + s.PushOpCode(PACK) return nil case int: s.pushInt(e) @@ -296,7 +303,7 @@ func (s *ScriptBuilder) GenerateContractInvocationData(scriptHash ScriptHash, op s.pushData(args) } s.pushData([]byte(operation)) //operation is in string we need to convert it to hex first - s.pushOpCode(APPCALL) //use APPCALL only + s.PushOpCode(APPCALL) //use APPCALL only s.pushData(scriptHash) //script hash of the smart contract that we want to invoke s.RawBytes = append([]byte{byte(len(s.RawBytes))}, s.RawBytes...) //the length of the entire raw bytes return s.ToBytes() @@ -308,7 +315,7 @@ func (s *ScriptBuilder) GenerateContractInvocationScript(scriptHash ScriptHash, s.pushData(args) } s.pushData([]byte(operation)) //operation is in string we need to convert it to hex first - s.pushOpCode(APPCALL) //use APPCALL only + s.PushOpCode(APPCALL) //use APPCALL only s.pushData(scriptHash) //script hash of the smart contract that we want to invoke return s.ToBytes() } @@ -547,7 +554,7 @@ func (s *ScriptBuilder) GenerateVerificationScripts(scripts []interface{}) []byt switch e := script.(type) { case TransactionSignature: s.pushData(e) - s.pushOpCode(CHECKSIG) + s.PushOpCode(CHECKSIG) continue case TransactionValidationScript: s.pushData(e) @@ -555,3 +562,46 @@ func (s *ScriptBuilder) GenerateVerificationScripts(scripts []interface{}) []byt } return s.ToBytes() } + +func (s *ScriptBuilder) GenerateVerificationScriptsMultiSig(signatures []TransactionSignature) []byte { + + s.pushLength(1) + + list := []struct { + TransactionSignature + PB btckey.PublicKey + }{} + + for _, e := range signatures { + pb := btckey.PublicKey{} + + pb.FromBytes(e.PublicKey) + list = append(list, + struct { + TransactionSignature + PB btckey.PublicKey + }{ + TransactionSignature: e, + PB: pb, + }) + } + + //we need to sort signature by public key here + sort.SliceStable(list, func(i, j int) bool { + return list[i].PB.Point.X.Cmp(list[j].PB.Point.X) == -1 + }) + + all := []byte{} + for _, e := range list { + log.Printf("sorted %x", e.PublicKey) + b := []byte{} + b = append(b, uintToBytes(uint(len(e.SignedData)))...) + b = append(b, e.SignedData...) + all = append(all, b...) + } + //push length of signed data + + s.pushLength(len(all)) + s.RawBytes = append(s.RawBytes, all...) + return s.ToBytes() +} diff --git a/neoutils/utils.go b/neoutils/utils.go index 580aff2..8ae5f8e 100644 --- a/neoutils/utils.go +++ b/neoutils/utils.go @@ -147,3 +147,22 @@ func PublicKeyToNEOAddress(publicKeyBytes []byte) string { address := btckey.B58checkencodeNEO(0x17, program_hash) return address } + +func VMCodeToNEOAddress(vmCode []byte) string { + /* SHA256 Hash */ + sha256_h := sha256.New() + sha256_h.Reset() + sha256_h.Write(vmCode) + pub_hash_1 := sha256_h.Sum(nil) + + /* RIPEMD-160 Hash */ + ripemd160_h := ripemd160.New() + ripemd160_h.Reset() + ripemd160_h.Write(pub_hash_1) + pub_hash_2 := ripemd160_h.Sum(nil) + + program_hash := pub_hash_2 + + address := btckey.B58checkencodeNEO(0x17, program_hash) + return address +} diff --git a/neoutils/utils_test.go b/neoutils/utils_test.go index d49f2ff..c1533d9 100644 --- a/neoutils/utils_test.go +++ b/neoutils/utils_test.go @@ -29,7 +29,7 @@ func TestSmartContractScripthashToAddress(t *testing.T) { } func TestNEOAddressToScriptHash(t *testing.T) { - hash := NEOAddressToScriptHashWithEndian("ARLohhmauabPoyYgy6aSnFqCArf5RVpvtn", binary.LittleEndian) + hash := NEOAddressToScriptHashWithEndian("AeNkbJdiMx49kBStQdDih7BzfDwyTNVRfb", binary.LittleEndian) b, _ := hex.DecodeString(hash) log.Printf("\nlittle endian %v \nbig endian %x", hash, ReverseBytes(b)) } @@ -49,7 +49,7 @@ func TestValidateNEOAddressInvalidAddress(t *testing.T) { } func TestConverting(t *testing.T) { - hexByteArray := "0000b2d3595bf006" //500000000000000000 + hexByteArray := "07ca92e5b37b4fff" //500000000000000000 //hex := "005c7c875e" = 405991873536 value := ConvertByteArrayToBigInt(hexByteArray) vvv := float64(value.Int64()) / float64(math.Pow10(8)) diff --git a/neoutils/version.go b/neoutils/version.go index f8ead6e..c147579 100644 --- a/neoutils/version.go +++ b/neoutils/version.go @@ -1,11 +1,14 @@ package neoutils const ( - VERSION = "1.0.8" + VERSION = "1.1.0" ) //RELEASE NOTES +// V. 1.1.0 +// - Added Ontology asset transfer + // V. 1.0.8 // - Added Generate NEP6 wallet for mobile