Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions binary-codec/types/issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,7 @@ func (i *Issue) FromJSON(json any) ([]byte, error) {
return nil, err
}

issuer, ok := mapObj["issuer"]
if issuerString, okstring := issuer.(string); ok && okstring {
if issuerString, okstring := mapObj["issuer"].(string); ok && okstring {
_, issuerBytes, err := addresscodec.DecodeClassicAddressToAccountID(issuerString)
if err != nil {
return nil, err
Expand All @@ -92,7 +91,9 @@ func (i *Issue) FromJSON(json any) ([]byte, error) {
return append(currencyBytes, issuerBytes...), nil
}

return currencyBytes, nil
// For XRP or currency-only issues, append 20 bytes of zeros for the issuer
// to ensure the full 40-byte Issue structure is maintained.
return append(currencyBytes, XRPBytes...), nil
}

// ToJSON converts a binary Issue representation back to a JSON object.
Expand All @@ -110,6 +111,10 @@ func (i *Issue) ToJSON(p interfaces.BinaryParser, _ ...int) (any, error) {

// Step 2: Check if it's XRP (all zeros)
if bytes.Equal(currencyOrAccount, XRPBytes) {
// Consume the next 20 bytes (issuer) which should also be all zeros for XRP
if _, err := p.ReadBytes(20); err != nil {
return nil, err
}
return map[string]any{
"currency": "XRP",
}, nil
Expand Down
7 changes: 6 additions & 1 deletion binary-codec/types/issue_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ func TestIssue_FromJson(t *testing.T) {
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
// issuer zeros (20 bytes)
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
},
expectedErr: nil,
},
Expand Down Expand Up @@ -140,12 +144,13 @@ func TestIssue_ToJson(t *testing.T) {
expected: map[string]any{
"currency": "XRP",
},
opts: []int{20},
opts: []int{40}, // 40 bytes for XRP (currency + issuer zeros)
err: nil,
setup: func(t *testing.T) (*Issue, *testutil.MockBinaryParser) {
ctrl := gomock.NewController(t)
mock := testutil.NewMockBinaryParser(ctrl)
mock.EXPECT().ReadBytes(20).Return(XRPBytes, nil)
mock.EXPECT().ReadBytes(20).Return(XRPBytes, nil) // issuer zeros
return &Issue{}, mock
},
},
Expand Down
6 changes: 6 additions & 0 deletions xrpl/rpc/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,9 @@ func (c *Client) SubmitTxBlobAndWait(txBlob string, failHard bool) (*requests.Tx
// via a submission request. It applies the provided submit options to decide whether
// to autofill missing fields and enforce failHard mode during submission.
func (c *Client) SubmitTx(tx transaction.FlatTransaction, opts *rpctypes.SubmitOptions) (*requests.SubmitResponse, error) {
if opts == nil {
opts = &rpctypes.SubmitOptions{}
}
txBlob, err := c.getSignedTx(tx, opts.Autofill, opts.Wallet)
if err != nil {
return nil, err
Expand All @@ -185,6 +188,9 @@ func (c *Client) SubmitTx(tx transaction.FlatTransaction, opts *rpctypes.SubmitO
// It validates that the transaction's EngineResult is successful before returning
// the transaction response.
func (c *Client) SubmitTxAndWait(tx transaction.FlatTransaction, opts *rpctypes.SubmitOptions) (*requests.TxResponse, error) {
if opts == nil {
opts = &rpctypes.SubmitOptions{}
}
// Get the signed transaction blob.
txBlob, err := c.getSignedTx(tx, opts.Autofill, opts.Wallet)
if err != nil {
Expand Down
6 changes: 6 additions & 0 deletions xrpl/wallet/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,12 @@ func (w *Wallet) computeSignature(encodedTx string) (string, error) {
return txHash, nil
}

// ComputeSignature is the public wrapper for computeSignature, exposed for
// external dual-signing use cases (e.g., XLS-66 LoanSet transactions).
func (w *Wallet) ComputeSignature(encodedTx string) (string, error) {
return w.computeSignature(encodedTx)
}

// Ensures that the address is a classic address.
// If the address is an x-address with a tag of 0 (no tag), it will be converted to a classic address.
// If the address is not a classic address, it will be returned as is.
Expand Down