Skip to content
This repository has been archived by the owner on Jan 25, 2021. It is now read-only.

Commit

Permalink
Merge pull request #36 from O3Labs/nep5-tx-transfer
Browse files Browse the repository at this point in the history
nep5 transfer with fee
  • Loading branch information
apisit committed Oct 17, 2018
2 parents ec881cc + bd0ef40 commit 6964a37
Show file tree
Hide file tree
Showing 25 changed files with 1,190 additions and 103 deletions.
64 changes: 64 additions & 0 deletions neoutils/deploy_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package neoutils_test

import (
"bytes"
"log"
"testing"

"github.com/o3labs/neo-utils/neoutils"
"github.com/o3labs/neo-utils/neoutils/smartcontract"
)

func TestDeploy(t *testing.T) {

contract := neoutils.SmartContractInfo{
AVMHEX: "",
Name: "Test Contract",
Version: "1.0",
Author: "Apisit",
Email: "[email protected]",
Description: "https://o3.network",
InputTypes: []smartcontract.ParameterType{smartcontract.String, smartcontract.Array},
ReturnType: smartcontract.ByteArray,
Properties: smartcontract.HasStorage + smartcontract.Payable,
}

log.Printf("sc hash %v", contract.GetScriptHash())

asset := smartcontract.GAS
amount := float64(490)

encryptedKey := ""
passphrase := ""
wif, _ := neoutils.NEP2Decrypt(encryptedKey, passphrase)

privateNetwallet, err := neoutils.GenerateFromWIF(wif)
if err != nil {
log.Printf("%v", err)
t.Fail()
return
}
log.Printf("wallet address %v", privateNetwallet.Address)

unspent, err := utxo("main", privateNetwallet.Address)
log.Printf("unspent %+v", unspent)
if err != nil {
log.Printf("error %v", err)
t.Fail()
return
}
attributes := map[smartcontract.TransactionAttribute][]byte{}
tx, err := neoutils.DeploySmartContractScript(contract, *privateNetwallet, asset, amount, unspent, attributes)
if err != nil {
log.Printf("error %v", err)
return
}
log.Printf("tx %x", tx)

}

func TestVarInt(t *testing.T) {
buff := new(bytes.Buffer)
neoutils.WriteVarUint(buff, uint64(286))
log.Printf("%x", buff.Bytes())
}
135 changes: 135 additions & 0 deletions neoutils/deployment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package neoutils

import (
"bytes"
"encoding/binary"
"io"
"log"

"github.com/o3labs/neo-utils/neoutils/smartcontract"
)

func WriteVarUint(w io.Writer, val uint64) error {
if val < 0xfd {
binary.Write(w, binary.LittleEndian, uint8(val))
return nil
}
if val < 0xFFFF {
binary.Write(w, binary.LittleEndian, byte(0xfd))
binary.Write(w, binary.LittleEndian, uint16(val))
return nil
}
if val < 0xFFFFFFFF {
binary.Write(w, binary.LittleEndian, byte(0xfe))
binary.Write(w, binary.LittleEndian, uint32(val))
return nil
}

binary.Write(w, binary.LittleEndian, byte(0xff))
binary.Write(w, binary.LittleEndian, val)

return nil
}

type SmartContractInfo struct {
AVMHEX string
Name string
Version string
Author string
Email string
Description string
Properties smartcontract.Properties
InputTypes []smartcontract.ParameterType
ReturnType smartcontract.ParameterType
}

func (s *SmartContractInfo) GetScriptHash() string {
address := VMCodeToNEOAddress(hex2bytes(s.AVMHEX))
scripthash := NEOAddressToScriptHashWithEndian(address, binary.BigEndian)
return scripthash
}

func (s *SmartContractInfo) Serialize() []byte {

params := []byte{}
for _, p := range s.InputTypes {
params = append(params, p.Byte())
}

scriptBuilder := smartcontract.NewScriptBuilder()
scriptBuilder.Push([]byte(s.Description))
scriptBuilder.Push([]byte(s.Email))
scriptBuilder.Push([]byte(s.Author))
scriptBuilder.Push([]byte(s.Version))
scriptBuilder.Push([]byte(s.Name))
scriptBuilder.Push(int(s.Properties))
scriptBuilder.Push([]byte{s.ReturnType.Byte()})
scriptBuilder.Push(params)
scriptBuilder.PushVarData(hex2bytes(s.AVMHEX))
scriptBuilder.PushSysCall("Neo.Contract.Create")

b := scriptBuilder.ToBytes()
buff := new(bytes.Buffer)
WriteVarUint(buff, uint64(len(b)))
endPayload := []byte{}
endPayload = append(endPayload, buff.Bytes()...)
endPayload = append(endPayload, b...)
return endPayload
}

func DeploySmartContractScript(contractInfo SmartContractInfo, wallet Wallet, asset smartcontract.NativeAsset, amount float64, unspent smartcontract.Unspent, attributes map[smartcontract.TransactionAttribute][]byte) ([]byte, error) {

tx := smartcontract.NewInvocationTransactionPayable()

tx.Data = contractInfo.Serialize()
tx.GAS = uint64(490)

amountToSend := amount
assetToSend := asset

networkFee := smartcontract.NetworkFeeAmount(0)

txInputs, err := smartcontract.NewScriptBuilder().GenerateTransactionInput(unspent, assetToSend, amountToSend, networkFee)
if err != nil {
return nil, err
}
tx.Inputs = txInputs

txAttributes, err := smartcontract.NewScriptBuilder().GenerateTransactionAttributes(attributes)
if err != nil {
return nil, err
}
tx.Attributes = txAttributes

//when deploy smart contract, you don't actually send asset to another address
//so the receiver is the same address
sender := smartcontract.ParseNEOAddress(wallet.Address)
receiver := smartcontract.ParseNEOAddress(wallet.Address)
txOutputs, err := smartcontract.NewScriptBuilder().GenerateTransactionOutputPayableGAS(sender, receiver, unspent, assetToSend, amount, networkFee, float64(tx.GAS))
if err != nil {
return nil, err
}

tx.Outputs = txOutputs

//begin signing process and invocation script
privateKeyInHex := bytesToHex(wallet.PrivateKey)
signedData, err := Sign(tx.ToBytes(), privateKeyInHex)
if err != nil {
return nil, err
}

signature := smartcontract.TransactionSignature{
SignedData: signedData,
PublicKey: wallet.PublicKey,
}

scripts := []interface{}{signature}
txScripts := smartcontract.NewScriptBuilder().GenerateVerificationScripts(scripts)
tx.Script = txScripts
//end signing process

log.Printf("txid = %v", tx.ToTXID())

return tx.ToBytes(), nil
}
22 changes: 22 additions & 0 deletions neoutils/mobile.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package neoutils

import (
"bytes"
"encoding/binary"
"encoding/json"
"fmt"
"log"
"strconv"
"strings"

Expand Down Expand Up @@ -122,3 +125,22 @@ func GenerateNEP6FromEncryptedKey(walletName, addressLabel, address, encryptedKe
}
return string(b)
}

func SerializeTX(jsonString string) []byte {
tx := NeonJSTransaction{}
json.Unmarshal([]byte(jsonString), &tx)
log.Printf("%+v", tx)
final := NeonJSTXSerializer(tx)
return final
}

func NEOAddresstoScriptHashBigEndian(neoAddress string) string {
return NEOAddressToScriptHashWithEndian(neoAddress, binary.BigEndian)
}

func GetVarUInt(value int64) []byte {
buff := new(bytes.Buffer)
WriteVarUint(buff, uint64(value))

return buff.Bytes()
}
66 changes: 57 additions & 9 deletions neoutils/mobile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,27 @@ import (
)

func TestMintTokensFromMobile(t *testing.T) {
scriptHash := "0x3e390ae61acb6713389c8fbbd47d1d69c32655a3"
scriptHash := "9121e89e8a0849857262d67c8408601b5e8e0524"

// encryptedKey := ""
// passphrase := ""
// wif, _ := neoutils.NEP2Decrypt(encryptedKey, passphrase)
wif := ""
wallet, _ := neoutils.GenerateFromWIF(wif)
log.Printf("address = %v\n address hash = %x", wallet.Address, wallet.HashedSignature)
wallet, err := neoutils.GenerateFromWIF(wif)
if err != nil {
log.Printf("%v", err)
t.Fail()
return
}

neo := string(smartcontract.NEO)
// gas := string(smartcontract.GAS)
amount := float64(2)
remark := "O3XMOONLIGHT2"
network := "test"
log.Printf("address = %v\n address hash = %x", wallet.Address, wallet.HashedSignature)
// neo := string(smartcontract.NEO)
gas := string(smartcontract.GAS)
amount := float64(1)
remark := "FIRST! APISIT FROM O3 :D"
network := "main"
networkFeeAmountInGAS := float64(0)
tx, err := neoutils.MintTokensRawTransactionMobile(network, scriptHash, wif, neo, amount, remark, networkFeeAmountInGAS)
tx, err := neoutils.MintTokensRawTransactionMobile(network, scriptHash, wif, gas, amount, remark, networkFeeAmountInGAS)
if err != nil {
log.Printf("%v", err)
t.Fail()
Expand All @@ -48,3 +56,43 @@ func TestNEP6MobileMethod(t *testing.T) {
log.Printf("%+v", nep6Wallet)

}

func TestSerializeTX(t *testing.T) {
data := `
{
"sha256": "ab1ad3efa1bf2fca51219b73c676dadaf9f446b81acd72f2557fecb7a8e7d243",
"type": 209,
"attributes": [{
"usage": 32,
"data": "4d17abe11020df91ce627af28c03c9c0cfb2a6c4"
}],
"scripts": [],
"gas": 0,
"version": 1,
"hash": "a67d3f9314383c4f7234cc9c8b7cf50602f91bf908bf6496a0c81bdc37fac7da",
"inputs": [{
"prevIndex": 0,
"prevHash": "d21043bb53d70a4762ebad4fcd55fb00528f4898d97cbe4182aef5b91139ec60"
}, {
"prevIndex": 6,
"prevHash": "6005967b1f6697d03cf241995fd4b2e71e56945ce0e4f815033700b993150c15"
}],
"outputs": [{
"assetId": "602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7",
"scriptHash": "e707714512577b42f9a011f8b870625429f93573",
"value": 1e-08
}],
"script": "0800e1f505000000001432e125258b7db0a0dffde5bd03b2b859253538ab144d17abe11020df91ce627af28c03c9c0cfb2a6c453c1076465706f73697467823b63e7c70a795a7615a38d1ba67d9e54c195a1"
}
`
final := neoutils.SerializeTX(data)
log.Printf("%x", final)
}

func TestNEOAddresstoScriptHashBigEndian(t *testing.T) {
log.Printf("%v", neoutils.NEOAddresstoScriptHashBigEndian("AQV8FNNi2o7EtMNn4etWBYx1cqBREAifgE"))
}

func TestGetVarUInt(t *testing.T) {
log.Printf("%x", neoutils.GetVarUInt(286))
}
18 changes: 11 additions & 7 deletions neoutils/multisig.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,29 @@ import (
)

type MultiSigInterface interface {
CreateMultiSigRedeemScript(numerOfRequiredSignature int, publicKeys [][]byte) ([]byte, error)
CreateMultiSigRedeemScript() ([]byte, error)
}

type MultiSig struct{}
type MultiSig struct {
NumberOfRequiredSignatures int
PublicKeys [][]byte
}

var _ MultiSigInterface = (*MultiSig)(nil)

func (m *MultiSig) CreateMultiSigRedeemScript(numerOfRequiredSignature int, publicKeys [][]byte) ([]byte, error) {
numberOfPublicKeys := len(publicKeys)
func (m *MultiSig) CreateMultiSigRedeemScript() ([]byte, error) {

numberOfPublicKeys := len(m.PublicKeys)
if numberOfPublicKeys <= 1 {
return nil, fmt.Errorf("Number of required Signature must be more than one")
}
if numerOfRequiredSignature > numberOfPublicKeys {
if m.NumberOfRequiredSignatures > numberOfPublicKeys {
return nil, fmt.Errorf("Number of required Signature is more than public keys provided.")
}

//sort public key
keys := []btckey.PublicKey{}
for _, pb := range publicKeys {
for _, pb := range m.PublicKeys {
publicKey := btckey.PublicKey{}
publicKey.FromBytes(pb)
keys = append(keys, publicKey)
Expand All @@ -38,7 +42,7 @@ func (m *MultiSig) CreateMultiSigRedeemScript(numerOfRequiredSignature int, publ
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)
sb.Push(m.NumberOfRequiredSignatures)
for _, publicKey := range keys {
sb.Push(publicKey.ToBytes())
}
Expand Down
15 changes: 9 additions & 6 deletions neoutils/multisig_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,20 @@ import (
)

func TestGenerateMultiSigAddress(t *testing.T) {

pb1 := "02e77ff280db51ef3638009f11947c544ed094d4e5f2d96a9e654dc817bc3a8986"
pb2 := "024da93f9a66981e499b36ce763e57fd89a47a052e86d40b42f81708c40fe9eff0"
require := 2
// 1/2
pb1 := "024e543aee592c4dd2361f8e02b4275e18eb665bcfb1c4b6c09bc6aed125b2f13c"
pb2 := "030adab68b3eeb02734f65b8ced64f023e70c15bcdfae94c3e74b9d647ddf9c976"
require := 1
pubKeys := [][]byte{}

pubKeys = append(pubKeys, neoutils.HexTobytes(pb1))
pubKeys = append(pubKeys, neoutils.HexTobytes(pb2))

multisign := neoutils.MultiSig{}
vmCode, err := multisign.CreateMultiSigRedeemScript(require, pubKeys)
multisign := neoutils.MultiSig{
NumberOfRequiredSignatures: require,
PublicKeys: pubKeys,
}
vmCode, err := multisign.CreateMultiSigRedeemScript()
if err != nil {
log.Printf("%v", err)
}
Expand Down
4 changes: 0 additions & 4 deletions neoutils/native_asset.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,6 @@ 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)
Expand Down
Loading

0 comments on commit 6964a37

Please sign in to comment.