Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Transactions Memo #50

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions TODO
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# mint

[ ] allow cancellation from hop 0 by attempted propagation to last node
[ ] transaction reference and metadata
[ ] allow cancellation from hop k<n by attempted propagation to last node
[ ] transaction memo
[ ] async webhooks
[ ] asset.created
[ ] balance.updated
Expand Down
10 changes: 10 additions & 0 deletions mint/endpoint/create_transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ type CreateTransaction struct {
Amount big.Int
Destination string
Path []string
Memo *string

// State
Tx *model.Transaction
Expand Down Expand Up @@ -133,6 +134,13 @@ func (e *CreateTransaction) Validate(
return errors.Trace(err)
}
e.Path = path

// Validate memo.
memo, err := ValidateMemo(ctx, r.PostFormValue("memo"))
if err != nil {
return errors.Trace(err)
}
e.Memo = memo
}

return nil
Expand Down Expand Up @@ -172,6 +180,7 @@ func (e *CreateTransaction) ExecuteCanonical(
e.Destination,
model.OfPath(e.Path),
mint.TxStPending,
e.Memo,
)
if err != nil {
return nil, nil, errors.Trace(err) // 500
Expand Down Expand Up @@ -326,6 +335,7 @@ func (e *CreateTransaction) ExecutePropagated(
model.OfPath(e.Path),
mint.TxStPending,
transaction.Lock,
transaction.Memo,
)
if err != nil {
return nil, nil, errors.Trace(err) // 500
Expand Down
19 changes: 19 additions & 0 deletions mint/endpoint/validations.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,3 +259,22 @@ func ValidatePropagation(

return &p, nil
}

// ValidateMemo validates a memo.
func ValidateMemo(
ctx context.Context,
memo string,
) (*string, error) {
if int64(len(memo)) > mint.MemoMaxLength {
return nil, errors.Trace(errors.NewUserErrorf(nil,
400, "memo_invalid",
"The memo you provided exceeds the maximum length (%d): %s.",
mint.MemoMaxLength, memo,
))
}

if len(memo) == 0 {
return nil, nil
}
return &memo, nil
}
2 changes: 2 additions & 0 deletions mint/model/schemas/mint.5.transactions.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ CREATE TABLE IF NOT EXISTS transactions(
lock VARCHAR(256) NOT NULL, -- lock = hex(scrypt(secret, id))
secret VARCHAR(256), -- lock secret

memo VARCHAR(1024), -- memo

PRIMARY KEY(owner, token)
);
`
Expand Down
16 changes: 12 additions & 4 deletions mint/model/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ type Transaction struct {

Lock string
Secret *string

Memo *string
}

// NewTransactionResource generates a new resource.
Expand All @@ -57,6 +59,7 @@ func NewTransactionResource(
Path: []string(transaction.Path),
Status: transaction.Status,
Lock: transaction.Lock,
Memo: transaction.Memo,
Operations: []mint.OperationResource{},
Crossings: []mint.CrossingResource{},
}
Expand Down Expand Up @@ -84,6 +87,7 @@ func CreateCanonicalTransaction(
destination string,
path []string,
status mint.TxStatus,
memo *string,
) (*Transaction, error) {
tok := token.New("transaction")

Expand All @@ -109,16 +113,18 @@ func CreateCanonicalTransaction(

Lock: lock,
Secret: &secret,

Memo: memo,
}

ext := db.Ext(ctx, "mint")
if _, err := sqlx.NamedExec(ext, `
INSERT INTO transactions
(owner, token, created, propagation, base_asset, quote_asset,
amount, destination, path, status, lock, secret)
amount, destination, path, status, lock, secret, memo)
VALUES
(:owner, :token, :created, :propagation, :base_asset, :quote_asset,
:amount, :destination, :path, :status, :lock, :secret)
:amount, :destination, :path, :status, :lock, :secret, :memo)
`, transaction); err != nil {
switch err := err.(type) {
case *pq.Error:
Expand Down Expand Up @@ -150,6 +156,7 @@ func CreatePropagatedTransaction(
path []string,
status mint.TxStatus,
lock string,
memo *string,
) (*Transaction, error) {
transaction := Transaction{
Owner: owner,
Expand All @@ -165,16 +172,17 @@ func CreatePropagatedTransaction(
Status: status,
Lock: lock,
Secret: nil,
Memo: memo,
}

ext := db.Ext(ctx, "mint")
if _, err := sqlx.NamedExec(ext, `
INSERT INTO transactions
(owner, token, created, propagation, base_asset, quote_asset,
amount, destination, path, status, lock, secret)
amount, destination, path, status, lock, secret, memo)
VALUES
(:owner, :token, :created, :propagation, :base_asset, :quote_asset,
:amount, :destination, :path, :status, :lock, :secret)
:amount, :destination, :path, :status, :lock, :secret, :memo)
`, transaction); err != nil {
switch err := err.(type) {
case *pq.Error:
Expand Down
4 changes: 4 additions & 0 deletions mint/protocol.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ const (
// TransactionExpiryMs is the time it takes to attempt to cancel a
// transaction for this mint. Expressed in ms.
TransactionExpiryMs int64 = 1000 * 60 * 60
// MemoMaxLength is the maximal length of a transaction's memo string.
MemoMaxLength int64 = 1024
)

// PgType is the propagation type of an object.
Expand Down Expand Up @@ -140,6 +142,8 @@ type TransactionResource struct {
Lock string `json:"lock"`
Secret *string `json:"secret"`

Memo *string `json:"memo"`

Operations []OperationResource `json:"operations"`
Crossings []CrossingResource `json:"crossings"`
}
6 changes: 6 additions & 0 deletions mint/test/functional/create_transaction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ func TestCreateTransactionWith2Offers(
"pair": {fmt.Sprintf("%s/%s", a[0].Name, a[2].Name)},
"amount": {"10"},
"destination": {u[2].Address},
"memo": {"test-20162017"},
"path[]": {
o[1].ID,
o[2].ID,
Expand Down Expand Up @@ -111,6 +112,7 @@ func TestCreateTransactionWith2Offers(
assert.Equal(t, mint.TxStReserved, tx0.Operations[0].Status)
assert.Equal(t, tx0.ID, *tx0.Operations[0].Transaction)
assert.Equal(t, int8(0), *tx0.Operations[0].TransactionHop)
assert.Equal(t, "test-20162017", *tx0.Memo)

// Check transaction on m[1].
status, raw = m[1].Get(t, nil, fmt.Sprintf("/transactions/%s", tx0.ID))
Expand Down Expand Up @@ -162,6 +164,7 @@ func TestCreateTransactionWith2Offers(
assert.Equal(t, mint.TxStReserved, tx1.Operations[0].Status)
assert.Equal(t, tx1.ID, *tx1.Operations[0].Transaction)
assert.Equal(t, int8(1), *tx1.Operations[0].TransactionHop)
assert.Equal(t, "test-20162017", *tx1.Memo)

// Check transaction on m[2].
status, raw = m[2].Get(t, nil, fmt.Sprintf("/transactions/%s", tx0.ID))
Expand Down Expand Up @@ -213,6 +216,7 @@ func TestCreateTransactionWith2Offers(
assert.Equal(t, mint.TxStReserved, tx2.Operations[0].Status)
assert.Equal(t, tx2.ID, *tx2.Operations[0].Transaction)
assert.Equal(t, int8(2), *tx2.Operations[0].TransactionHop)
assert.Equal(t, "test-20162017", *tx2.Memo)
}

func TestCreateTransactionWithInsufficientOfferAmount(
Expand Down Expand Up @@ -351,6 +355,7 @@ func TestCreateTransactionWith1Offer(
assert.Equal(t, big.NewInt(10), tx0.Operations[0].Amount)
assert.Equal(t, u[1].Address, tx0.Operations[0].Destination)
assert.Equal(t, u[0].Address, tx0.Operations[0].Source)
assert.Nil(t, tx0.Memo)

// Check transaction on m[1].
status, raw = m[1].Get(t, nil, fmt.Sprintf("/transactions/%s", tx0.ID))
Expand All @@ -373,6 +378,7 @@ func TestCreateTransactionWith1Offer(
assert.Equal(t, mint.TxStReserved, tx1.Operations[0].Status)
assert.Equal(t, tx1.ID, *tx1.Operations[0].Transaction)
assert.Equal(t, int8(1), *tx1.Operations[0].TransactionHop)
assert.Nil(t, tx1.Memo)
}

func TestCreateTransactionWithRemoteBaseAsset(
Expand Down
4 changes: 4 additions & 0 deletions mint/test/functional/settle_transaction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ func TestSettleTransactionWithRemoteBaseAsset(
"pair": {fmt.Sprintf("%s/%s", a[1].Name, a[2].Name)},
"amount": {"10"},
"destination": {u[2].Address},
"memo": {"test-20162017"},
"path[]": {
o[2].ID,
},
Expand All @@ -291,6 +292,7 @@ func TestSettleTransactionWithRemoteBaseAsset(
assert.Equal(t, mint.TxStSettled, tx0.Status)
assert.Equal(t, 0, len(tx0.Operations))
assert.Equal(t, 0, len(tx0.Crossings))
assert.Equal(t, "test-20162017", *tx0.Memo)

// Check transaction on m[1].
status, raw = m[1].Get(t, nil, fmt.Sprintf("/transactions/%s", tx0.ID))
Expand All @@ -303,6 +305,7 @@ func TestSettleTransactionWithRemoteBaseAsset(
assert.Equal(t, mint.TxStSettled, tx1.Status)
assert.Equal(t, 0, len(tx1.Crossings))
assert.Equal(t, 1, len(tx1.Operations))
assert.Equal(t, "test-20162017", *tx1.Memo)

assert.Equal(t, mint.TxStSettled, tx1.Operations[0].Status)

Expand All @@ -317,6 +320,7 @@ func TestSettleTransactionWithRemoteBaseAsset(
assert.Equal(t, mint.TxStSettled, tx2.Status)
assert.Equal(t, 1, len(tx2.Crossings))
assert.Equal(t, 1, len(tx2.Operations))
assert.Equal(t, "test-20162017", *tx2.Memo)

assert.Equal(t, mint.TxStSettled, tx2.Crossings[0].Status)
assert.Equal(t, mint.TxStSettled, tx2.Operations[0].Status)
Expand Down