github.com/deroproject/derosuite@v2.1.6-1.0.20200307070847-0f2e589c7a2b+incompatible/walletapi/rpc_transfer.go (about)

     1  // Copyright 2017-2018 DERO Project. All rights reserved.
     2  // Use of this source code in any form is governed by RESEARCH license.
     3  // license can be found in the LICENSE file.
     4  // GPG: 0F39 E425 8C65 3947 702A  8234 08B2 0360 A03A 9DE8
     5  //
     6  //
     7  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
     8  // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     9  // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
    10  // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    11  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    12  // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    13  // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    14  // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
    15  // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    16  
    17  package walletapi
    18  
    19  import "fmt"
    20  import "context"
    21  import "encoding/hex"
    22  import "encoding/json"
    23  
    24  //import	"log"
    25  //import 	"net/http"
    26  
    27  import "github.com/romana/rlog"
    28  import "github.com/intel-go/fastjson"
    29  import "github.com/osamingo/jsonrpc"
    30  
    31  import "github.com/deroproject/derosuite/globals"
    32  import "github.com/deroproject/derosuite/address"
    33  import "github.com/deroproject/derosuite/structures"
    34  
    35  type Transfer_Handler struct { // this has access to the wallet
    36  	r *RPCServer
    37  }
    38  
    39  func (h Transfer_Handler) ServeJSONRPC(c context.Context, params *fastjson.RawMessage) (interface{}, *jsonrpc.Error) {
    40  
    41  	h.r.Lock()
    42  	defer h.r.Unlock()
    43  	var p structures.Transfer_Params
    44  	var result structures.Transfer_Result
    45  	var err error
    46  
    47  	rlog.Debugf("transfer  handler")
    48  	defer rlog.Debugf("transfer  handler finished")
    49  
    50  	if errp := jsonrpc.Unmarshal(params, &p); err != nil {
    51  		rlog.Errorf("Could not parse incoming json, err %s\n", errp)
    52  		return nil, errp
    53  	}
    54  
    55  	//if len(p.Destinations) < 1 || p.Mixin < 4 {
    56  	//    return nil, jsonrpc.ErrInvalidParams()
    57  	//}
    58  
    59  	rlog.Debugf("Len destinations %d %+v", len(p.Destinations), p)
    60  
    61  	payment_id := p.Payment_ID
    62  	if len(payment_id) > 0 && (len(payment_id) == 64 || len(payment_id) == 16) != true  {
    63  		return nil, jsonrpc.ErrInvalidParams() // we should give invalid payment ID
    64  	}
    65  	if _, err := hex.DecodeString(p.Payment_ID); err != nil {
    66  		return nil, jsonrpc.ErrInvalidParams() // we should give invalid payment ID
    67  	}
    68  	rlog.Debugf("Payment ID %s", payment_id)
    69          
    70          unlock_time := p.Unlock_time
    71  
    72  	b, err := json.Marshal(p)
    73  	if err == nil {
    74  		rlog.Debugf("Request can be repeated using below command")
    75  		rlog.Debugf(`curl -X POST http://127.0.0.1:18092/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"transfer_split","params":%s}' -H 'Content-Type: application/json'`, string(b))
    76  
    77  	}
    78  
    79  	var address_list []address.Address
    80  	var amount_list []uint64
    81  	for i := range p.Destinations {
    82  		a, err := globals.ParseValidateAddress(p.Destinations[i].Address)
    83  		if err != nil {
    84  			rlog.Warnf("Parsing address failed %s err %s\n", p.Destinations[i].Address, err)
    85  			return nil, jsonrpc.ErrInvalidParams()
    86  		}
    87  		address_list = append(address_list, *a)
    88  		amount_list = append(amount_list, p.Destinations[i].Amount)
    89  
    90  	}
    91  
    92  	fees_per_kb := uint64(0) // fees  must be calculated by walletapi
    93  	if !h.r.w.GetMode() {    // if wallet is in online mode, use the fees, provided by the daemon, else we need to use what is provided by the user
    94  
    95  		// TODO
    96  	}
    97  	tx, inputs, input_sum, change, err := h.r.w.Transfer(address_list, amount_list, unlock_time, payment_id, fees_per_kb, p.Mixin)
    98  	_ = inputs
    99  	if err != nil {
   100  		rlog.Warnf("Error while building Transaction err %s\n", err)
   101  		return nil, &jsonrpc.Error{Code: -2, Message: fmt.Sprintf("Error while building Transaction err %s", err)}
   102  
   103  	}
   104  
   105  	rlog.Infof("Inputs Selected for %s \n", globals.FormatMoney(input_sum))
   106  	amount := uint64(0)
   107  	for i := range amount_list {
   108  		amount += amount_list[i]
   109  	}
   110  	rlog.Infof("Transfering total amount %s \n", globals.FormatMoney(amount))
   111  	rlog.Infof("change amount ( will come back ) %s \n", globals.FormatMoney(change))
   112  	rlog.Infof("fees %s \n", globals.FormatMoney(tx.RctSignature.Get_TX_Fee()))
   113  
   114  	if input_sum != (amount + change + tx.RctSignature.Get_TX_Fee()) {
   115  		panic(fmt.Sprintf("Inputs %d != outputs ( %d + %d + %d )", input_sum, amount, change, tx.RctSignature.Get_TX_Fee()))
   116  	}
   117  
   118  	//return nil, jsonrpc.ErrInvalidParams()
   119  
   120  	if p.Do_not_relay == false { // we do not relay the tx, the user must submit it manually
   121  		// TODO
   122  		err = h.r.w.SendTransaction(tx)
   123  
   124  		if err == nil {
   125  			rlog.Infof("Transaction sent successfully. txid = %s", tx.GetHash())
   126  		} else {
   127  			rlog.Warnf("Transaction sending failed txid = %s, err %s", tx.GetHash(), err)
   128  			return nil, &jsonrpc.Error{Code: -2, Message: fmt.Sprintf("Transaction sending failed txid = %s, err %s", tx.GetHash(), err)}
   129  		}
   130  
   131  	}
   132  
   133  	result.Fee = tx.RctSignature.Get_TX_Fee()
   134  	result.Tx_hash = tx.GetHash().String()
   135  	if p.Get_tx_hex { // request need TX blobs, give them
   136  		result.Tx_blob = hex.EncodeToString(tx.SerializeHeader())
   137  	}
   138  	//extract secret key and feed it in here
   139  	if p.Get_tx_key {
   140  		result.Tx_key = h.r.w.GetTXKey(tx.GetHash())
   141  	}
   142  	return result, nil
   143  }