Hello,
I have forked Rosetta-Bitcoin and doing the changes what we need for our Blockchain.
Our blockchain doesn’t support Witness/Segwit.
Now mine Construction-service.go looks like:
// ConstructionDerive implements the /construction/derive endpoint.
func (s *ConstructionAPIService) ConstructionDerive(
ctx context.Context,
request *types.ConstructionDeriveRequest,
) (*types.ConstructionDeriveResponse, *types.Error) {
addr, err := btcutil.NewAddressPubKey(
request.PublicKey.Bytes,
s.config.Params,
)
if err != nil {
return nil, wrapErr(ErrUnableToDerive, err)
}
return &types.ConstructionDeriveResponse{
AccountIdentifier: &types.AccountIdentifier{
Address: addr.EncodeAddress(),
},
}, nil
}
// estimateSize returns the estimated size of a transaction in vBytes.
func (s *ConstructionAPIService) estimateSize(operations []*types.Operation) float64 {
size := bitcoin.TransactionOverhead
for _, operation := range operations {
switch operation.Type {
case bitcoin.InputOpType:
size += bitcoin.InputSize
case bitcoin.OutputOpType:
size += bitcoin.OutputOverhead
addr, err := btcutil.DecodeAddress(operation.Account.Address, s.config.Params)
if err != nil {
size += bitcoin.P2PKHScriptPubkeySize
continue
}
script, err := txscript.PayToAddrScript(addr)
if err != nil {
size += bitcoin.P2PKHScriptPubkeySize
continue
}
size += len(script)
}
}
return float64(size)
}
// ConstructionPreprocess implements the /construction/preprocess
// endpoint.
func (s *ConstructionAPIService) ConstructionPreprocess(
ctx context.Context,
request *types.ConstructionPreprocessRequest,
) (*types.ConstructionPreprocessResponse, *types.Error) {
descriptions := &parser.Descriptions{
OperationDescriptions: []*parser.OperationDescription{
{
Type: bitcoin.InputOpType,
Account: &parser.AccountDescription{
Exists: true,
},
Amount: &parser.AmountDescription{
Exists: true,
Sign: parser.NegativeAmountSign,
Currency: s.config.Currency,
},
CoinAction: types.CoinSpent,
AllowRepeats: true,
},
},
}
matches, err := parser.MatchOperations(descriptions, request.Operations)
if err != nil {
return nil, wrapErr(ErrUnclearIntent, err)
}
coins := make([]*types.Coin, len(matches[0].Operations))
for i, input := range matches[0].Operations {
if input.CoinChange == nil {
return nil, wrapErr(ErrUnclearIntent, errors.New("CoinChange cannot be nil"))
}
coins[i] = &types.Coin{
CoinIdentifier: input.CoinChange.CoinIdentifier,
Amount: input.Amount,
}
}
options, err := types.MarshalMap(&preprocessOptions{
Coins: coins,
EstimatedSize: s.estimateSize(request.Operations),
FeeMultiplier: request.SuggestedFeeMultiplier,
})
if err != nil {
return nil, wrapErr(ErrUnableToParseIntermediateResult, err)
}
return &types.ConstructionPreprocessResponse{
Options: options,
}, nil
}
// ConstructionMetadata implements the /construction/metadata endpoint.
func (s *ConstructionAPIService) ConstructionMetadata(
ctx context.Context,
request *types.ConstructionMetadataRequest,
) (*types.ConstructionMetadataResponse, *types.Error) {
if s.config.Mode != configuration.Online {
return nil, wrapErr(ErrUnavailableOffline, nil)
}
var options preprocessOptions
if err := types.UnmarshalMap(request.Options, &options); err != nil {
return nil, wrapErr(ErrUnableToParseIntermediateResult, err)
}
// Determine feePerKB and ensure it is not below the minimum fee
// relay rate.
feePerKB := float64(0.001)
// Calculated the estimated fee in Satoshis
satoshisPerB := (feePerKB * float64(bitcoin.SatoshisInBitcoin)) / bytesInKb
estimatedFee := satoshisPerB * options.EstimatedSize
suggestedFee := &types.Amount{
Value: fmt.Sprintf("%d", int64(estimatedFee)),
Currency: s.config.Currency,
}
scripts, err := s.i.GetScriptPubKeys(ctx, options.Coins)
if err != nil {
return nil, wrapErr(ErrScriptPubKeysMissing, err)
}
metadata, err := types.MarshalMap(&constructionMetadata{ScriptPubKeys: scripts})
if err != nil {
return nil, wrapErr(ErrUnableToParseIntermediateResult, err)
}
return &types.ConstructionMetadataResponse{
Metadata: metadata,
SuggestedFee: []*types.Amount{suggestedFee},
}, nil
}
// ConstructionPayloads implements the /construction/payloads endpoint.
func (s *ConstructionAPIService) ConstructionPayloads(
ctx context.Context,
request *types.ConstructionPayloadsRequest,
) (*types.ConstructionPayloadsResponse, *types.Error) {
descriptions := &parser.Descriptions{
OperationDescriptions: []*parser.OperationDescription{
{
Type: bitcoin.InputOpType,
Account: &parser.AccountDescription{
Exists: true,
},
Amount: &parser.AmountDescription{
Exists: true,
Sign: parser.NegativeAmountSign,
Currency: s.config.Currency,
},
AllowRepeats: true,
CoinAction: types.CoinSpent,
},
{
Type: bitcoin.OutputOpType,
Account: &parser.AccountDescription{
Exists: true,
},
Amount: &parser.AmountDescription{
Exists: true,
Sign: parser.PositiveAmountSign,
Currency: s.config.Currency,
},
AllowRepeats: true,
},
},
ErrUnmatched: true,
}
matches, err := parser.MatchOperations(descriptions, request.Operations)
if err != nil {
return nil, wrapErr(ErrUnclearIntent, err)
}
tx := wire.NewMsgTx(wire.TxVersion)
for _, input := range matches[0].Operations {
if input.CoinChange == nil {
return nil, wrapErr(ErrUnclearIntent, errors.New("CoinChange cannot be nil"))
}
transactionHash, index, err := bitcoin.ParseCoinIdentifier(input.CoinChange.CoinIdentifier)
if err != nil {
return nil, wrapErr(ErrInvalidCoin, err)
}
tx.AddTxIn(&wire.TxIn{
PreviousOutPoint: wire.OutPoint{
Hash: *transactionHash,
Index: index,
},
SignatureScript: nil,
Sequence: wire.MaxTxInSequenceNum,
})
}
for i, output := range matches[1].Operations {
addr, err := btcutil.DecodeAddress(output.Account.Address, s.config.Params)
if err != nil {
return nil, wrapErr(ErrUnableToDecodeAddress, fmt.Errorf(
"%w unable to decode address %s",
err,
output.Account.Address,
),
)
}
pkScript, err := txscript.PayToAddrScript(addr)
if err != nil {
return nil, wrapErr(
ErrUnableToDecodeAddress,
fmt.Errorf("%w unable to construct payToAddrScript", err),
)
}
tx.AddTxOut(&wire.TxOut{
Value: matches[1].Amounts[i].Int64(),
PkScript: pkScript,
})
}
// Create Signing Payloads (must be done after entire tx is constructed
// or hash will not be correct).
inputAmounts := make([]string, len(tx.TxIn))
inputAddresses := make([]string, len(tx.TxIn))
payloads := make([]*types.SigningPayload, len(tx.TxIn))
var metadata constructionMetadata
if err := types.UnmarshalMap(request.Metadata, &metadata); err != nil {
return nil, wrapErr(ErrUnableToParseIntermediateResult, err)
}
for i := range tx.TxIn {
address := matches[0].Operations[i].Account.Address
script, err := hex.DecodeString(metadata.ScriptPubKeys[i].Hex)
if err != nil {
return nil, wrapErr(ErrUnableToDecodeScriptPubKey, err)
}
class, _, err := bitcoin.ParseSingleAddress(s.config.Params, script)
if err != nil {
return nil, wrapErr(
ErrUnableToDecodeAddress,
fmt.Errorf("%w unable to parse address for utxo %d", err, i),
)
}
inputAddresses[i] = address
inputAmounts[i] = matches[0].Amounts[i].String()
absAmount := new(big.Int).Abs(matches[0].Amounts[i]).Int64()
switch class {
case txscript.WitnessV0PubKeyHashTy:
hash, err := txscript.CalcWitnessSigHash(
script,
txscript.NewTxSigHashes(tx),
txscript.SigHashAll,
tx,
i,
absAmount,
)
if err != nil {
return nil, wrapErr(ErrUnableToCalculateSignatureHash, err)
}
payloads[i] = &types.SigningPayload{
AccountIdentifier: &types.AccountIdentifier{
Address: address,
},
Bytes: hash,
SignatureType: types.Ecdsa,
}
case txscript.PubKeyHashTy:
hash, err := txscript.CalcSignatureHash(
script,
txscript.SigHashAll,
tx,
i,
)
if err != nil {
return nil, wrapErr(ErrUnableToCalculateSignatureHash, err)
}
payloads[i] = &types.SigningPayload{
AccountIdentifier: &types.AccountIdentifier{
Address: address,
},
Bytes: hash,
SignatureType: types.Ecdsa,
}
default:
return nil, wrapErr(
ErrUnsupportedScriptType,
fmt.Errorf("unupported script type: %s", class),
)
}
}
buf := bytes.NewBuffer(make([]byte, 0, tx.SerializeSize()))
if err := tx.Serialize(buf); err != nil {
return nil, wrapErr(ErrUnableToParseIntermediateResult, err)
}
rawTx, err := json.Marshal(&unsignedTransaction{
Transaction: hex.EncodeToString(buf.Bytes()),
ScriptPubKeys: metadata.ScriptPubKeys,
InputAmounts: inputAmounts,
InputAddresses: inputAddresses,
})
if err != nil {
return nil, wrapErr(ErrUnableToParseIntermediateResult, err)
}
return &types.ConstructionPayloadsResponse{
UnsignedTransaction: hex.EncodeToString(rawTx),
Payloads: payloads,
}, nil
}
func normalizeSignature(signature []byte) []byte {
sig := btcec.Signature{ // signature is in form of R || S
R: new(big.Int).SetBytes(signature[:32]),
S: new(big.Int).SetBytes(signature[32:64]),
}
return append(sig.Serialize(), byte(txscript.SigHashAll))
}
// ConstructionCombine implements the /construction/combine
// endpoint.
func (s *ConstructionAPIService) ConstructionCombine(
ctx context.Context,
request *types.ConstructionCombineRequest,
) (*types.ConstructionCombineResponse, *types.Error) {
decodedTx, err := hex.DecodeString(request.UnsignedTransaction)
if err != nil {
return nil, wrapErr(
ErrUnableToParseIntermediateResult,
fmt.Errorf("%w transaction cannot be decoded", err),
)
}
var unsigned unsignedTransaction
if err := json.Unmarshal(decodedTx, &unsigned); err != nil {
return nil, wrapErr(
ErrUnableToParseIntermediateResult,
fmt.Errorf("%w unable to unmarshal bitcoin transaction", err),
)
}
decodedCoreTx, err := hex.DecodeString(unsigned.Transaction)
if err != nil {
return nil, wrapErr(
ErrUnableToParseIntermediateResult,
fmt.Errorf("%w transaction cannot be decoded", err),
)
}
var tx wire.MsgTx
if err := tx.Deserialize(bytes.NewReader(decodedCoreTx)); err != nil {
return nil, wrapErr(
ErrUnableToParseIntermediateResult,
fmt.Errorf("%w unable to deserialize tx", err),
)
}
for i := range tx.TxIn {
decodedScript, err := hex.DecodeString(unsigned.ScriptPubKeys[i].Hex)
if err != nil {
return nil, wrapErr(ErrUnableToDecodeScriptPubKey, err)
}
class, _, err := bitcoin.ParseSingleAddress(s.config.Params, decodedScript)
if err != nil {
return nil, wrapErr(
ErrUnableToDecodeAddress,
fmt.Errorf("%w unable to parse address for script", err),
)
}
pkData := request.Signatures[i].PublicKey.Bytes
fullsig := normalizeSignature(request.Signatures[i].Bytes)
switch class {
case txscript.WitnessV0PubKeyHashTy:
tx.TxIn[i].Witness = wire.TxWitness{fullsig, pkData}
case txscript.PubKeyHashTy:
tx.TxIn[i].Witness = wire.TxWitness{fullsig, pkData}
default:
return nil, wrapErr(
ErrUnsupportedScriptType,
fmt.Errorf("unupported script type: %s", class),
)
}
}
buf := bytes.NewBuffer(make([]byte, 0, tx.SerializeSize()))
if err := tx.Serialize(buf); err != nil {
return nil, wrapErr(ErrUnableToParseIntermediateResult, fmt.Errorf("%w serialize tx", err))
}
rawTx, err := json.Marshal(&signedTransaction{
Transaction: hex.EncodeToString(buf.Bytes()),
InputAmounts: unsigned.InputAmounts,
})
if err != nil {
return nil, wrapErr(
ErrUnableToParseIntermediateResult,
fmt.Errorf("%w unable to serialize signed tx", err),
)
}
return &types.ConstructionCombineResponse{
SignedTransaction: hex.EncodeToString(rawTx),
}, nil
}
// ConstructionHash implements the /construction/hash endpoint.
func (s *ConstructionAPIService) ConstructionHash(
ctx context.Context,
request *types.ConstructionHashRequest,
) (*types.TransactionIdentifierResponse, *types.Error) {
decodedTx, err := hex.DecodeString(request.SignedTransaction)
if err != nil {
return nil, wrapErr(
ErrUnableToParseIntermediateResult,
fmt.Errorf("%w signed transaction cannot be decoded", err),
)
}
var signed signedTransaction
if err := json.Unmarshal(decodedTx, &signed); err != nil {
return nil, wrapErr(
ErrUnableToParseIntermediateResult,
fmt.Errorf("%w unable to unmarshal signed bitcoin transaction", err),
)
}
bytesTx, err := hex.DecodeString(signed.Transaction)
if err != nil {
return nil, wrapErr(
ErrUnableToParseIntermediateResult,
fmt.Errorf("%w unable to decode hex transaction", err),
)
}
tx, err := btcutil.NewTxFromBytes(bytesTx)
if err != nil {
return nil, wrapErr(
ErrUnableToParseIntermediateResult,
fmt.Errorf("%w unable to parse transaction", err),
)
}
return &types.TransactionIdentifierResponse{
TransactionIdentifier: &types.TransactionIdentifier{
Hash: tx.Hash().String(),
},
}, nil
}
func (s *ConstructionAPIService) parseUnsignedTransaction(
request *types.ConstructionParseRequest,
) (*types.ConstructionParseResponse, *types.Error) {
decodedTx, err := hex.DecodeString(request.Transaction)
if err != nil {
return nil, wrapErr(
ErrUnableToParseIntermediateResult,
fmt.Errorf("%w transaction cannot be decoded", err),
)
}
var unsigned unsignedTransaction
if err := json.Unmarshal(decodedTx, &unsigned); err != nil {
return nil, wrapErr(
ErrUnableToParseIntermediateResult,
fmt.Errorf("%w unable to unmarshal bitcoin transaction", err),
)
}
decodedCoreTx, err := hex.DecodeString(unsigned.Transaction)
if err != nil {
return nil, wrapErr(
ErrUnableToParseIntermediateResult,
fmt.Errorf("%w transaction cannot be decoded", err),
)
}
var tx wire.MsgTx
if err := tx.Deserialize(bytes.NewReader(decodedCoreTx)); err != nil {
return nil, wrapErr(
ErrUnableToParseIntermediateResult,
fmt.Errorf("%w unable to deserialize tx", err),
)
}
ops := []*types.Operation{}
for i, input := range tx.TxIn {
networkIndex := int64(i)
ops = append(ops, &types.Operation{
OperationIdentifier: &types.OperationIdentifier{
Index: int64(len(ops)),
NetworkIndex: &networkIndex,
},
Type: bitcoin.InputOpType,
Account: &types.AccountIdentifier{
Address: unsigned.InputAddresses[i],
},
Amount: &types.Amount{
Value: unsigned.InputAmounts[i],
Currency: s.config.Currency,
},
CoinChange: &types.CoinChange{
CoinAction: types.CoinSpent,
CoinIdentifier: &types.CoinIdentifier{
Identifier: fmt.Sprintf(
"%s:%d",
input.PreviousOutPoint.Hash.String(),
input.PreviousOutPoint.Index,
),
},
},
})
}
for i, output := range tx.TxOut {
networkIndex := int64(i)
_, addr, err := bitcoin.ParseSingleAddress(s.config.Params, output.PkScript)
if err != nil {
return nil, wrapErr(
ErrUnableToDecodeAddress,
fmt.Errorf("%w unable to parse output address", err),
)
}
ops = append(ops, &types.Operation{
OperationIdentifier: &types.OperationIdentifier{
Index: int64(len(ops)),
NetworkIndex: &networkIndex,
},
Type: bitcoin.OutputOpType,
Account: &types.AccountIdentifier{
Address: addr.String(),
},
Amount: &types.Amount{
Value: strconv.FormatInt(output.Value, 10),
Currency: s.config.Currency,
},
})
}
return &types.ConstructionParseResponse{
Operations: ops,
AccountIdentifierSigners: []*types.AccountIdentifier{},
}, nil
}
func (s *ConstructionAPIService) parseSignedTransaction(
request *types.ConstructionParseRequest,
) (*types.ConstructionParseResponse, *types.Error) {
decodedTx, err := hex.DecodeString(request.Transaction)
if err != nil {
return nil, wrapErr(
ErrUnableToParseIntermediateResult,
fmt.Errorf("%w signed transaction cannot be decoded", err),
)
}
var signed signedTransaction
if err := json.Unmarshal(decodedTx, &signed); err != nil {
return nil, wrapErr(
ErrUnableToParseIntermediateResult,
fmt.Errorf("%w unable to unmarshal signed bitcoin transaction", err),
)
}
serializedTx, err := hex.DecodeString(signed.Transaction)
if err != nil {
return nil, wrapErr(
ErrUnableToParseIntermediateResult,
fmt.Errorf("%w unable to decode hex transaction", err),
)
}
var tx wire.MsgTx
if err := tx.Deserialize(bytes.NewReader(serializedTx)); err != nil {
return nil, wrapErr(
ErrUnableToParseIntermediateResult,
fmt.Errorf("%w unable to decode msgTx", err),
)
}
ops := []*types.Operation{}
signers := []*types.AccountIdentifier{}
for i, input := range tx.TxIn {
pkScript, err := txscript.ComputePkScript(input.SignatureScript, input.Witness)
if err != nil {
return nil, wrapErr(
ErrUnableToComputePkScript,
fmt.Errorf("%w: unable to compute pk script", err),
)
}
_, addr, err := bitcoin.ParseSingleAddress(s.config.Params, pkScript.Script())
if err != nil {
return nil, wrapErr(
ErrUnableToDecodeAddress,
fmt.Errorf("%w unable to decode address", err),
)
}
networkIndex := int64(i)
signers = append(signers, &types.AccountIdentifier{
Address: addr.EncodeAddress(),
})
ops = append(ops, &types.Operation{
OperationIdentifier: &types.OperationIdentifier{
Index: int64(len(ops)),
NetworkIndex: &networkIndex,
},
Type: bitcoin.InputOpType,
Account: &types.AccountIdentifier{
Address: addr.EncodeAddress(),
},
Amount: &types.Amount{
Value: signed.InputAmounts[i],
Currency: s.config.Currency,
},
CoinChange: &types.CoinChange{
CoinAction: types.CoinSpent,
CoinIdentifier: &types.CoinIdentifier{
Identifier: fmt.Sprintf(
"%s:%d",
input.PreviousOutPoint.Hash.String(),
input.PreviousOutPoint.Index,
),
},
},
})
}
for i, output := range tx.TxOut {
networkIndex := int64(i)
_, addr, err := bitcoin.ParseSingleAddress(s.config.Params, output.PkScript)
if err != nil {
return nil, wrapErr(
ErrUnableToDecodeAddress,
fmt.Errorf("%w unable to parse output address", err),
)
}
ops = append(ops, &types.Operation{
OperationIdentifier: &types.OperationIdentifier{
Index: int64(len(ops)),
NetworkIndex: &networkIndex,
},
Type: bitcoin.OutputOpType,
Account: &types.AccountIdentifier{
Address: addr.String(),
},
Amount: &types.Amount{
Value: strconv.FormatInt(output.Value, 10),
Currency: s.config.Currency,
},
})
}
return &types.ConstructionParseResponse{
Operations: ops,
AccountIdentifierSigners: signers,
}, nil
}
// ConstructionParse implements the /construction/parse endpoint.
func (s *ConstructionAPIService) ConstructionParse(
ctx context.Context,
request *types.ConstructionParseRequest,
) (*types.ConstructionParseResponse, *types.Error) {
if request.Signed {
return s.parseSignedTransaction(request)
}
return s.parseUnsignedTransaction(request)
}
// ConstructionSubmit implements the /construction/submit endpoint.
func (s *ConstructionAPIService) ConstructionSubmit(
ctx context.Context,
request *types.ConstructionSubmitRequest,
) (*types.TransactionIdentifierResponse, *types.Error) {
if s.config.Mode != configuration.Online {
return nil, wrapErr(ErrUnavailableOffline, nil)
}
decodedTx, err := hex.DecodeString(request.SignedTransaction)
if err != nil {
return nil, wrapErr(
ErrUnableToParseIntermediateResult,
fmt.Errorf("%w signed transaction cannot be decoded", err),
)
}
var signed signedTransaction
if err := json.Unmarshal(decodedTx, &signed); err != nil {
return nil, wrapErr(
ErrUnableToParseIntermediateResult,
fmt.Errorf("%w unable to unmarshal signed bitcoin transaction", err),
)
}
txHash, err := s.client.SendRawTransaction(ctx, signed.Transaction)
if err != nil {
return nil, wrapErr(ErrBitcoind, fmt.Errorf("%w unable to submit transaction", err))
}
return &types.TransactionIdentifierResponse{
TransactionIdentifier: &types.TransactionIdentifier{
Hash: txHash,
},
}, nil
}
When i’m running the rosetta-cli test i’m getting:
Command Failed: Account.Address is missing: account identifier is invalid in operation 0 unable to parse operations: /construction/parse: unable to parse signed transaction: unable to create transaction
Workflow of rosetta-cli
2022/05/13 23:46:20 REQUEST /construction/preprocess network_identifier:{"blockchain":"EUNO","network":"Testnet"} intent:[{"operation_identifier":{"index":0},"type":"INPUT","account":{"address":"yHcAXpDBgBdkc5GZ1rcA3sC3GKYbaa2jD9"},"amount":{"value":"-240000000000","currency":{"symbol":"tEUNO","decimals":8}},"coin_change":{"coin_identifier":{"identifier":"6b26480336d18a8d2f2e9c66662fe17ecd5a4d87a0482b27f3e6e68d5a67fff5:0"},"coin_action":"coin_spent"}},{"operation_identifier":{"index":1},"type":"OUTPUT","account":{"address":"yFZa81DZ5ZoPACQCSQjfgAWz9WeibGyUHJ"},"amount":{"value":"150784319081","currency":{"symbol":"tEUNO","decimals":8}}},{"operation_identifier":{"index":2},"type":"OUTPUT","account":{"address":"yHcAXpDBgBdkc5GZ1rcA3sC3GKYbaa2jD9"},"amount":{"value":"89215666219","currency":{"symbol":"tEUNO","decimals":8}}}] metadata:null
2022/05/13 23:46:20 Syncing 490148-490154
2022/05/13 23:46:20 RESPONSE /construction/preprocess options:{"coins":[{"amount":{"currency":{"decimals":8,"symbol":"tEUNO"},"value":"-240000000000"},"coin_identifier":{"identifier":"6b26480336d18a8d2f2e9c66662fe17ecd5a4d87a0482b27f3e6e68d5a67fff5:0"}}],"estimated_size":147} required_public_keys:null
2022/05/13 23:46:20 REQUEST /construction/metadata network_identifier:{"blockchain":"EUNO","network":"Testnet"} metadata:{"coins":[{"amount":{"currency":{"decimals":8,"symbol":"tEUNO"},"value":"-240000000000"},"coin_identifier":{"identifier":"6b26480336d18a8d2f2e9c66662fe17ecd5a4d87a0482b27f3e6e68d5a67fff5:0"}}],"estimated_size":147} public_keys:[]
2022/05/13 23:46:20 RESPONSE /construction/metadata metadata:{"script_pub_keys":[{"addresses":["yHcAXpDBgBdkc5GZ1rcA3sC3GKYbaa2jD9"],"asm":"OP_DUP OP_HASH160 e24112be979bd0fbad7a0db9a06525abe88f440b OP_EQUALVERIFY OP_CHECKSIG","hex":"76a914e24112be979bd0fbad7a0db9a06525abe88f440b88ac","reqSigs":1,"type":"pubkeyhash"}]} suggested_fee:[{"value":"14700","currency":{"symbol":"tEUNO","decimals":8}}]
2022/05/13 23:46:20 REQUEST /construction/payloads network_identifier:{"blockchain":"EUNO","network":"Testnet"} intent:[{"operation_identifier":{"index":0},"type":"INPUT","account":{"address":"yHcAXpDBgBdkc5GZ1rcA3sC3GKYbaa2jD9"},"amount":{"value":"-240000000000","currency":{"symbol":"tEUNO","decimals":8}},"coin_change":{"coin_identifier":{"identifier":"6b26480336d18a8d2f2e9c66662fe17ecd5a4d87a0482b27f3e6e68d5a67fff5:0"},"coin_action":"coin_spent"}},{"operation_identifier":{"index":1},"type":"OUTPUT","account":{"address":"yFZa81DZ5ZoPACQCSQjfgAWz9WeibGyUHJ"},"amount":{"value":"150784319081","currency":{"symbol":"tEUNO","decimals":8}}},{"operation_identifier":{"index":2},"type":"OUTPUT","account":{"address":"yHcAXpDBgBdkc5GZ1rcA3sC3GKYbaa2jD9"},"amount":{"value":"89215666219","currency":{"symbol":"tEUNO","decimals":8}}}] public_keys:[]
2022/05/13 23:46:20 RESPONSE /construction/payloads unsigned_transaction:"7b227472616e73616374696f6e223a2230313030303030303031663566663637356138646536653666333237326234386130383734643561636437656531326636363636396332653266386438616431333630333438323636623030303030303030303066666666666666663032363931653732316232333030303030303139373661393134636264333433653865643866636565663237616561336362343762653430303037666361616665333838616332623038616263353134303030303030313937366139313465323431313262653937396264306662616437613064623961303635323561626538386634343062383861633030303030303030222c227363726970745075624b657973223a5b7b2261736d223a224f505f445550204f505f484153483136302065323431313262653937396264306662616437613064623961303635323561626538386634343062204f505f455155414c564552494659204f505f434845434b534947222c22686578223a223736613931346532343131326265393739626430666261643761306462396130363532356162653838663434306238386163222c2272657153696773223a312c2274797065223a227075626b657968617368222c22616464726573736573223a5b2279486341587044426742646b6335475a3172634133734333474b59626161326a4439225d7d5d2c22696e7075745f616d6f756e7473223a5b222d323430303030303030303030225d2c22696e7075745f616464726573736573223a5b2279486341587044426742646b6335475a3172634133734333474b59626161326a4439225d7d" payloads:[{"address":"yHcAXpDBgBdkc5GZ1rcA3sC3GKYbaa2jD9","hex_bytes":"35d991f5895814e519540995ac3129312cb592bc426fcbdd446d1b572e503353","account_identifier":{"address":"yHcAXpDBgBdkc5GZ1rcA3sC3GKYbaa2jD9"},"signature_type":"ecdsa"}]
2022/05/13 23:46:20 REQUEST /construction/parse network_identifier:{"blockchain":"EUNO","network":"Testnet"} signed:false transaction:"7b227472616e73616374696f6e223a2230313030303030303031663566663637356138646536653666333237326234386130383734643561636437656531326636363636396332653266386438616431333630333438323636623030303030303030303066666666666666663032363931653732316232333030303030303139373661393134636264333433653865643866636565663237616561336362343762653430303037666361616665333838616332623038616263353134303030303030313937366139313465323431313262653937396264306662616437613064623961303635323561626538386634343062383861633030303030303030222c227363726970745075624b657973223a5b7b2261736d223a224f505f445550204f505f484153483136302065323431313262653937396264306662616437613064623961303635323561626538386634343062204f505f455155414c564552494659204f505f434845434b534947222c22686578223a223736613931346532343131326265393739626430666261643761306462396130363532356162653838663434306238386163222c2272657153696773223a312c2274797065223a227075626b657968617368222c22616464726573736573223a5b2279486341587044426742646b6335475a3172634133734333474b59626161326a4439225d7d5d2c22696e7075745f616d6f756e7473223a5b222d323430303030303030303030225d2c22696e7075745f616464726573736573223a5b2279486341587044426742646b6335475a3172634133734333474b59626161326a4439225d7d"
2022/05/13 23:46:20 RESPONSE /construction/parse operations:[{"operation_identifier":{"index":0,"network_index":0},"type":"INPUT","account":{"address":"yHcAXpDBgBdkc5GZ1rcA3sC3GKYbaa2jD9"},"amount":{"value":"-240000000000","currency":{"symbol":"tEUNO","decimals":8}},"coin_change":{"coin_identifier":{"identifier":"6b26480336d18a8d2f2e9c66662fe17ecd5a4d87a0482b27f3e6e68d5a67fff5:0"},"coin_action":"coin_spent"}},{"operation_identifier":{"index":1,"network_index":0},"type":"OUTPUT","account":{"address":"yFZa81DZ5ZoPACQCSQjfgAWz9WeibGyUHJ"},"amount":{"value":"150784319081","currency":{"symbol":"tEUNO","decimals":8}}},{"operation_identifier":{"index":2,"network_index":1},"type":"OUTPUT","account":{"address":"yHcAXpDBgBdkc5GZ1rcA3sC3GKYbaa2jD9"},"amount":{"value":"89215666219","currency":{"symbol":"tEUNO","decimals":8}}}] signers:null metadata:null
2022/05/13 23:46:20 REQUEST /construction/combine network_identifier:{"blockchain":"EUNO","network":"Testnet"} unsigned_transaction:"7b227472616e73616374696f6e223a2230313030303030303031663566663637356138646536653666333237326234386130383734643561636437656531326636363636396332653266386438616431333630333438323636623030303030303030303066666666666666663032363931653732316232333030303030303139373661393134636264333433653865643866636565663237616561336362343762653430303037666361616665333838616332623038616263353134303030303030313937366139313465323431313262653937396264306662616437613064623961303635323561626538386634343062383861633030303030303030222c227363726970745075624b657973223a5b7b2261736d223a224f505f445550204f505f484153483136302065323431313262653937396264306662616437613064623961303635323561626538386634343062204f505f455155414c564552494659204f505f434845434b534947222c22686578223a223736613931346532343131326265393739626430666261643761306462396130363532356162653838663434306238386163222c2272657153696773223a312c2274797065223a227075626b657968617368222c22616464726573736573223a5b2279486341587044426742646b6335475a3172634133734333474b59626161326a4439225d7d5d2c22696e7075745f616d6f756e7473223a5b222d323430303030303030303030225d2c22696e7075745f616464726573736573223a5b2279486341587044426742646b6335475a3172634133734333474b59626161326a4439225d7d" signatures:[{"hex_bytes":"924cca81054ee08330e7701cb3f1fbe71f96fe37629967b353eda990d712b4ec05596ec46e2d2331d1e4e24f7ce8968303bef279a693099be75c5afbe826755e","signing_payload":{"address":"yHcAXpDBgBdkc5GZ1rcA3sC3GKYbaa2jD9","hex_bytes":"35d991f5895814e519540995ac3129312cb592bc426fcbdd446d1b572e503353","account_identifier":{"address":"yHcAXpDBgBdkc5GZ1rcA3sC3GKYbaa2jD9"},"signature_type":"ecdsa"},"public_key":{"hex_bytes":"02b21d299d9c981e15e381c2d2293d1d78a2e3a1894c47fd388dc2d921a951214d","curve_type":"secp256k1"},"signature_type":"ecdsa"}]
2022/05/13 23:46:20 RESPONSE /construction/combine network_transaction:"7b227472616e73616374696f6e223a223031303030303030303030313031663566663637356138646536653666333237326234386130383734643561636437656531326636363636396332653266386438616431333630333438323636623030303030303030303066666666666666663032363931653732316232333030303030303139373661393134636264333433653865643866636565663237616561336362343762653430303037666361616665333838616332623038616263353134303030303030313937366139313465323431313262653937396264306662616437613064623961303635323561626538386634343062383861633032343833303435303232313030393234636361383130353465653038333330653737303163623366316662653731663936666533373632393936376233353365646139393064373132623465633032323030353539366563343665326432333331643165346532346637636538393638333033626566323739613639333039396265373563356166626538323637353565303132313032623231643239396439633938316531356533383163326432323933643164373861326533613138393463343766643338386463326439323161393531323134643030303030303030222c22696e7075745f616d6f756e7473223a5b222d323430303030303030303030225d7d"
2022/05/13 23:46:20 REQUEST /construction/parse network_identifier:{"blockchain":"EUNO","network":"Testnet"} signed:true transaction:"7b227472616e73616374696f6e223a223031303030303030303030313031663566663637356138646536653666333237326234386130383734643561636437656531326636363636396332653266386438616431333630333438323636623030303030303030303066666666666666663032363931653732316232333030303030303139373661393134636264333433653865643866636565663237616561336362343762653430303037666361616665333838616332623038616263353134303030303030313937366139313465323431313262653937396264306662616437613064623961303635323561626538386634343062383861633032343833303435303232313030393234636361383130353465653038333330653737303163623366316662653731663936666533373632393936376233353365646139393064373132623465633032323030353539366563343665326432333331643165346532346637636538393638333033626566323739613639333039396265373563356166626538323637353565303132313032623231643239396439633938316531356533383163326432323933643164373861326533613138393463343766643338386463326439323161393531323134643030303030303030222c22696e7075745f616d6f756e7473223a5b222d323430303030303030303030225d7d"
2022/05/13 23:46:20 ERROR /construction/parse error:{"err":{},"client_err":null,"retry":false}
2022/05/13 23:46:20 check:construction status server shutting down
Any idea where its going wrong with the convertition?
ENV for rosetta-cli has also been added. (export RECIPIENT=“xxMwLcK2tsC37rGZyDosYAHUeDUQpcff2g”)