Skip to content

Chary/multisig sign update #1464

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

Merged
merged 13 commits into from
Nov 12, 2024
64 changes: 56 additions & 8 deletions server/handler/transactions.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,11 +145,11 @@ func (h *Handler) GetTransactions(c echo.Context) error {
status := utils.GetStatus(c.QueryParam("status"))
var rows *sql.Rows
if status == model.Pending {
rows, err = h.DB.Query(`SELECT t.id,t.multisig_address,t.status,t.created_at,t.last_updated,t.memo,t.signatures,t.messages,t.hash,t.err_msg,t.fee, m.threshold,
rows, err = h.DB.Query(`SELECT t.id,COALESCE(t.signed_at, '0001-01-01 00:00:00'::timestamp) AS signed_at,t.multisig_address,t.status,t.created_at,t.last_updated,t.memo,t.signatures,t.messages,t.hash,t.err_msg,t.fee, m.threshold,
json_agg(jsonb_build_object('pubkey', p.pubkey, 'address', p.address, 'multisig_address',p.multisig_address)) AS pubkeys FROM transactions t JOIN multisig_accounts m ON t.multisig_address = m.address JOIN pubkeys p ON t.multisig_address = p.multisig_address WHERE t.multisig_address=$1 and t.status='PENDING' GROUP BY t.id, t.multisig_address, m.threshold, t.messages LIMIT $2 OFFSET $3`,
address, limit, (page-1)*limit)
} else {
rows, err = h.DB.Query(`SELECT t.id,t.multisig_address,t.status,t.created_at,t.last_updated,t.memo,t.signatures,t.messages,t.hash,t.err_msg,t.fee, m.threshold,
rows, err = h.DB.Query(`SELECT t.id,COALESCE(t.signed_at, '0001-01-01 00:00:00'::timestamp) AS signed_at,t.multisig_address,t.status,t.created_at,t.last_updated,t.memo,t.signatures,t.messages,t.hash,t.err_msg,t.fee, m.threshold,
json_agg(jsonb_build_object('pubkey', p.pubkey, 'address', p.address, 'multisig_address',p.multisig_address)) AS pubkeys FROM transactions t JOIN multisig_accounts m ON t.multisig_address = m.address JOIN pubkeys p ON t.multisig_address = p.multisig_address WHERE t.multisig_address=$1 and t.status <> 'PENDING' GROUP BY t.id, t.multisig_address, m.threshold, t.messages LIMIT $2 OFFSET $3`,
address, limit, (page-1)*limit)
}
Expand All @@ -173,8 +173,11 @@ func (h *Handler) GetTransactions(c echo.Context) error {
transactions := make([]schema.AllTransactionResult, 0)
for rows.Next() {
var transaction schema.AllTransactionResult
var signedAt time.Time

if err := rows.Scan(
&transaction.ID,
&signedAt,
&transaction.MultisigAddress,
&transaction.Status,
&transaction.CreatedAt,
Expand All @@ -194,6 +197,13 @@ func (h *Handler) GetTransactions(c echo.Context) error {
Log: err.Error(),
})
}

if signedAt.IsZero() {
transaction.SignedAt = time.Time{} // Set it to zero time if not set
} else {
transaction.SignedAt = signedAt // Otherwise, set the actual signed time
}

transactions = append(transactions, transaction)
}

Expand Down Expand Up @@ -236,11 +246,11 @@ func (h *Handler) GetAllMultisigTxns(c echo.Context) error {

var rows *sql.Rows
if status == "PENDING" {
rows, err = h.DB.Query(`SELECT t.id,t.multisig_address,t.status,t.created_at,t.last_updated,t.memo,t.signatures,t.messages,t.hash,t.err_msg,t.fee, m.threshold,
rows, err = h.DB.Query(`SELECT t.id, COALESCE(t.signed_at, '0001-01-01 00:00:00'::timestamp) AS signed_at, t.multisig_address,t.status,t.created_at,t.last_updated,t.memo,t.signatures,t.messages,t.hash,t.err_msg,t.fee, m.threshold,
json_agg(jsonb_build_object('pubkey', p.pubkey, 'address', p.address, 'multisig_address',p.multisig_address)) AS pubkeys FROM transactions t JOIN multisig_accounts m ON t.multisig_address = m.address JOIN pubkeys p ON t.multisig_address = p.multisig_address WHERE t.multisig_address=$1 and t.status='PENDING' GROUP BY t.id, t.multisig_address, m.threshold, t.messages LIMIT $2 OFFSET $3`,
multisigAddress, limit, (page-1)*limit)
} else {
rows, err = h.DB.Query(`SELECT t.id,t.multisig_address,t.status,t.created_at,t.last_updated,t.memo,t.signatures,t.messages,t.hash,t.err_msg,t.fee, m.threshold,
rows, err = h.DB.Query(`SELECT t.id, COALESCE(t.signed_at, '0001-01-01 00:00:00'::timestamp) AS signed_at, t.multisig_address,t.status,t.created_at,t.last_updated,t.memo,t.signatures,t.messages,t.hash,t.err_msg,t.fee, m.threshold,
json_agg(jsonb_build_object('pubkey', p.pubkey, 'address', p.address, 'multisig_address',p.multisig_address)) AS pubkeys FROM transactions t JOIN multisig_accounts m ON t.multisig_address = m.address JOIN pubkeys p ON t.multisig_address = p.multisig_address WHERE t.multisig_address=$1 and t.status <> 'PENDING' GROUP BY t.id, t.multisig_address, m.threshold, t.messages LIMIT $2 OFFSET $3`,
multisigAddress, limit, (page-1)*limit)
}
Expand All @@ -262,8 +272,11 @@ func (h *Handler) GetAllMultisigTxns(c echo.Context) error {

for rows.Next() {
var transaction schema.AllTransactionResult
var signedAt time.Time

if err := rows.Scan(
&transaction.ID,
&signedAt,
&transaction.MultisigAddress,
&transaction.Status,
&transaction.CreatedAt,
Expand All @@ -283,6 +296,11 @@ func (h *Handler) GetAllMultisigTxns(c echo.Context) error {
Log: err.Error(),
})
}
if signedAt.IsZero() {
transaction.SignedAt = time.Time{}
} else {
transaction.SignedAt = signedAt
}
transactions = append(transactions, transaction)
}
rows.Close()
Expand Down Expand Up @@ -436,7 +454,7 @@ func (h *Handler) SignTransaction(c echo.Context) error {
})
}

_, err = h.DB.Exec("UPDATE transactions SET signatures=$1 WHERE id=$2", bz, id)
_, err = h.DB.Exec("UPDATE transactions SET signatures=$1, signed_at=$2 WHERE id=$3", bz, time.Now().UTC(), id)
if err != nil {
return c.JSON(http.StatusBadRequest, model.ErrorResponse{
Status: "error",
Expand Down Expand Up @@ -499,20 +517,50 @@ func (h *Handler) DeleteTransaction(c echo.Context) error {
if err != nil {
return c.JSON(http.StatusBadRequest, model.ErrorResponse{
Status: "error",
Message: "invalid transaction id ",
Message: "invalid transaction id",
})
}

_, err = h.DB.Exec(`DELETE from transactions WHERE id=$1 AND multisig_address=$2`, txId, address)
// Fetch signed_at before attempting to delete, to avoid issues if the transaction does not exist
var signedAt time.Time
row := h.DB.QueryRow(`SELECT signed_at FROM transactions WHERE id=$1 AND multisig_address=$2`, txId, address)
err = row.Scan(&signedAt)
if err != nil {
if err == sql.ErrNoRows {
return c.JSON(http.StatusNotFound, model.ErrorResponse{
Status: "error",
Message: "transaction not found",
})
}
return c.JSON(http.StatusInternalServerError, model.ErrorResponse{
Status: "error",
Message: "failed to fetch transaction details",
Log: err.Error(),
})
}

// Delete the transaction
_, err = h.DB.Exec(`DELETE FROM transactions WHERE id=$1 AND multisig_address=$2`, txId, address)
if err != nil {
return c.JSON(http.StatusBadRequest, model.ErrorResponse{
return c.JSON(http.StatusInternalServerError, model.ErrorResponse{
Status: "error",
Message: "failed to delete transaction",
Log: err.Error(),
})
}

// Clear signatures for transactions with signed_at > txSignedAt
if !signedAt.IsZero() {
_, err = h.DB.Exec(`UPDATE transactions SET signatures='[]'::jsonb WHERE multisig_address=$1 AND signed_at > $2`, address, signedAt)
if err != nil {
return c.JSON(http.StatusInternalServerError, model.ErrorResponse{
Status: "error",
Message: "failed to update transaction signatures",
Log: err.Error(),
})
}
}

return c.JSON(http.StatusOK, model.SuccessResponse{
Status: "transaction deleted",
})
Expand Down
2 changes: 2 additions & 0 deletions server/schema/transactions.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type Transaction struct {
Signatures json.RawMessage `pg:"signatures" json:"signatures"`
LastUpdated time.Time `pg:"last_updated,use_zero" json:"last_updated"`
CreatedAt time.Time `pg:"created_at,use_zero" json:"created_at"`
SignedAt time.Time `pg:"signed_at,use_zero" sql:"-" json:"signed_at,omitempty"`
}

type TransactionCount struct {
Expand All @@ -39,4 +40,5 @@ type AllTransactionResult struct {
CreatedAt time.Time `pg:"created_at" sql:"-" json:"created_at,omitempty"`
Threshold int `pg:"threshold" json:"threshold"`
Pubkeys json.RawMessage `pg:"pubkeys" json:"pubkeys"`
SignedAt time.Time `pg:"signed_at,use_zero" sql:"-" json:"signed_at,omitempty"`
}
13 changes: 13 additions & 0 deletions server/schema/update_schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,16 @@ BEGIN
ADD COLUMN title VARCHAR(255) DEFAULT '';
END IF;
END $$;

DO $$
BEGIN
-- Check and add new_column_name if it doesn't exist
IF NOT EXISTS (
SELECT 1
FROM information_schema.columns
WHERE table_name = 'transactions' AND column_name = 'signed_at'
) THEN
ALTER TABLE transactions
ADD COLUMN signed_at TIMESTAMP DEFAULT NULL;
END IF;
END $$;
Loading