Skip to content

Commit

Permalink
Merge pull request qtumproject#63 from Ferret-san/qtum_getVouts
Browse files Browse the repository at this point in the history
Vout function
  • Loading branch information
VoR0220 authored May 20, 2021
2 parents e75e76f + ecc2482 commit 8d71d25
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 28 deletions.
19 changes: 13 additions & 6 deletions pkg/eth/rpc_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -710,12 +710,19 @@ type ChainIdResponse string

// ======= qtum_getUTXOs ============= //

// NOTE: there is no response struct definition inside of this package, 'cause
// it's the same as original Qtum response, which is declared at qtum package
type GetUTXOsRequest struct {
Address string
MinSumAmount decimal.Decimal
}
type (
GetUTXOsRequest struct {
Address string
MinSumAmount decimal.Decimal
}

QtumUTXO struct {
TXID string `json:"txid"`
Vout uint `json:"vout"`
}

GetUTXOsResponse []QtumUTXO
)

func (req *GetUTXOsRequest) UnmarshalJSON(params []byte) error {
paramsBytesNum := len(params)
Expand Down
1 change: 1 addition & 0 deletions pkg/qtum/jsonrpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ const (
MethodSendRawTx = "sendrawtransaction"
MethodGetStakingInfo = "getstakinginfo"
MethodGetAddressBalance = "getaddressbalance"
MethodGetAddressUTXOs = "getaddressutxos"
)

type JSONRPCRequest struct {
Expand Down
14 changes: 14 additions & 0 deletions pkg/qtum/method.go
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,20 @@ func (m *Method) GetAccountInfo(req *GetAccountInfoRequest) (resp *GetAccountInf
return
}

func (m *Method) GetAddressUTXOs(req *GetAddressUTXOsRequest) (*GetAddressUTXOsResponse, error) {
resp := new(GetAddressUTXOsResponse)
if err := m.Request(MethodGetAddressUTXOs, req, resp); err != nil {
if m.IsDebugEnabled() {
m.GetDebugLogger().Log("function", "GetAddressUTXOs", "error", err)
}
return nil, err
}
if m.IsDebugEnabled() {
m.GetDebugLogger().Log("function", "GetAddressUTXOs", "request", marshalToString(req), "msg", "Successfully got address UTXOs")
}
return resp, nil
}

func (m *Method) ListUnspent(req *ListUnspentRequest) (resp *ListUnspentResponse, err error) {
if err := m.Request(MethodListUnspent, req, &resp); err != nil {
if m.IsDebugEnabled() {
Expand Down
63 changes: 63 additions & 0 deletions pkg/qtum/rpc_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -1284,6 +1284,69 @@ func (r *SendRawTransactionResponse) UnmarshalJSON(data []byte) error {
return nil
}

// ========== GetAddressUTXOs ============= //

type (
/*
Arguments:
1. Input params (json object, required) Json object
{
"addresses": [ (json array, required) The qtum addresses
"address", (string) The qtum address
...
],
"chainInfo": bool, (boolean, optional) Include chain info with results
}
Result:
{ (json object)
"address" : "str", (string) The address base58check encoded
"txid" : "hex", (string) The output txid
"height" : n, (numeric) The block height
"outputIndex" : n, (numeric) The output index
"script" : "hex", (string) The script hex encoded
"satoshis" : n (numeric) The number of satoshis of the output
}
*/

GetAddressUTXOsRequest struct {
Addresses []string `json:"addresses"`
}

UTXO struct {
Address string `json:"address"`
TXID string `json:"txid"`
OutputIndex uint `json:"outputIndex"`
Script string `json:"string"`
Satoshis decimal.Decimal `json:"satoshis"`
Height *big.Int `json:"height"`
IsStake bool `json:"isStake"`
}

GetAddressUTXOsResponse []UTXO
)

func (resp *GetAddressUTXOsResponse) UnmarshalJSON(data []byte) error {
// NOTE: do not use `GetTransactionReceiptResponse`, 'cause
// it may violate to infinite loop, while calling
// UnmarshalJSON interface
var utxos []UTXO
if err := json.Unmarshal(data, &utxos); err != nil {
return err
}
*resp = GetAddressUTXOsResponse(utxos)
return nil
}

func (r *GetAddressUTXOsRequest) MarshalJSON() ([]byte, error) {
params := []map[string]interface{}{}
addresses := map[string]interface{}{
"addresses": r.Addresses,
}
params = append(params, addresses)
return json.Marshal(params)
}

// ========== ListUnspent ============= //
type (

Expand Down
26 changes: 11 additions & 15 deletions pkg/transformer/eth_signTransaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,28 +50,24 @@ func (p *ProxyETHSignTransaction) getRequiredUtxos(from string, neededAmount dec
return nil, decimal.Decimal{}, err
}
// need to get utxos with txid and vouts. In order to do this we get a list of unspent transactions and begin summing them up
var unspentListReq *qtum.ListUnspentRequest = &qtum.ListUnspentRequest{MinConf: 6, MaxConf: 999, Addresses: []string{base58Addr}}
qtumresp, err := p.ListUnspent(unspentListReq)
var getaddressutxos *qtum.GetAddressUTXOsRequest = &qtum.GetAddressUTXOsRequest{Addresses: []string{base58Addr}}
qtumresp, err := p.GetAddressUTXOs(getaddressutxos)
if err != nil {
return nil, decimal.Decimal{}, err
}

balance := decimal.New(0, 0)
var inputs []qtum.RawTxInputs
var balanceReqMet bool
//Convert minSumAmount to Satoshis
minimumSum := neededAmount.Mul(decimal.NewFromFloat(float64(1e8)))
var utxos []qtum.RawTxInputs
var minUTXOsSum decimal.Decimal
for _, utxo := range *qtumresp {
balance = balance.Add(utxo.Amount)
inputs = append(inputs, qtum.RawTxInputs{TxID: utxo.Txid, Vout: utxo.Vout})
if balance.GreaterThanOrEqual(neededAmount) {
balanceReqMet = true
break
minUTXOsSum = minUTXOsSum.Add(utxo.Satoshis)
utxos = append(utxos, qtum.RawTxInputs{TxID: utxo.TXID, Vout: utxo.OutputIndex})
if minUTXOsSum.GreaterThanOrEqual(minimumSum) {
return utxos, minUTXOsSum, nil
}
}
if balanceReqMet {
// this is useful for figuring out which utxo was signed as list_unspent seems to be non deterministic
//fmt.Printf("utxos: %v\n", inputs)
return inputs, balance, nil
}

return nil, decimal.Decimal{}, fmt.Errorf("Insufficient UTXO value attempted to be sent")
}

Expand Down
21 changes: 14 additions & 7 deletions pkg/transformer/qtum_getUTXOs.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,24 +32,31 @@ func (p *ProxyQTUMGetUTXOs) Request(req *eth.JSONRPCRequest) (interface{}, error
return p.request(params)
}

func (p *ProxyQTUMGetUTXOs) request(params eth.GetUTXOsRequest) (*qtum.ListUnspentResponse, error) {
func (p *ProxyQTUMGetUTXOs) request(params eth.GetUTXOsRequest) (*eth.GetUTXOsResponse, error) {
address, err := convertETHAddress(utils.RemoveHexPrefix(params.Address), p.Chain())
if err != nil {
return nil, errors.WithMessage(err, "couldn't convert Ethereum address to Qtum address")
}

req := qtum.NewListUnspentRequest(qtum.ListUnspentQueryOptions{}, address)
resp, err := p.Qtum.ListUnspent(req)
req := qtum.GetAddressUTXOsRequest{
Addresses: []string{address},
}

resp, err := p.Qtum.GetAddressUTXOs(&req)
if err != nil {
return nil, err
}

//Convert minSumAmount to Satoshis
minimumSum := params.MinSumAmount.Mul(decimal.NewFromFloat(float64(1e8)))

var utxos []eth.QtumUTXO
var minUTXOsSum decimal.Decimal
for _, utxo := range *resp {
minUTXOsSum = minUTXOsSum.Add(utxo.Amount)

if minUTXOsSum.GreaterThanOrEqual(params.MinSumAmount) {
return resp, nil
minUTXOsSum = minUTXOsSum.Add(utxo.Satoshis)
utxos = append(utxos, eth.QtumUTXO{TXID: utxo.TXID, Vout: utxo.OutputIndex})
if minUTXOsSum.GreaterThanOrEqual(minimumSum) {
return (*eth.GetUTXOsResponse)(&utxos), nil
}
}

Expand Down

0 comments on commit 8d71d25

Please sign in to comment.