diff --git a/pkg/cheques/cheques.go b/pkg/cheques/cheques.go index 57033e0d..7701a131 100644 --- a/pkg/cheques/cheques.go +++ b/pkg/cheques/cheques.go @@ -3,6 +3,7 @@ package cheques import ( "encoding/hex" "encoding/json" + "errors" "fmt" "math/big" @@ -10,6 +11,13 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" ) +var ( + ErrChequeAlreadyExpired = errors.New("cheque already expired") + ErrChequeExpiresTooSoon = errors.New("cheque expires too soon") + ErrChequeAmountLessThanPrevious = errors.New("new cheque amount less than previous cheque amount") + ErrChequeCounterNotGreaterThanPrevious = errors.New("new cheque counter not greater than previous cheque counter") +) + type SignedCheque struct { Cheque `json:"cheque"` Signature []byte `json:"signature"` @@ -87,3 +95,22 @@ func (sc *SignedCheque) UnmarshalJSON(data []byte) error { return nil } + +func VerifyCheque(previousCheque, newCheque *SignedCheque, timestamp, minDurationUntilExpiration *big.Int) error { + if newCheque.ExpiresAt.Cmp(timestamp) < 1 { // cheque.ExpiresAt <= timestamp + return fmt.Errorf("cheque expired at %s; %w", newCheque.ExpiresAt, ErrChequeAlreadyExpired) + } + durationUntilExpiration := big.NewInt(0).Sub(newCheque.ExpiresAt, timestamp) + if durationUntilExpiration.Cmp(minDurationUntilExpiration) < 0 { // durationUntilExpiration < minDurationUntilExpiration + return fmt.Errorf("duration until expiration less than min (%s < %s): %w", durationUntilExpiration, minDurationUntilExpiration, ErrChequeExpiresTooSoon) + } + switch { + case previousCheque == nil: + return nil + case previousCheque.Amount.Cmp(newCheque.Amount) > 0: // previous.Amount > new.Amount + return fmt.Errorf("new cheque amount (%s) < (%s) previous cheque amount: %w", newCheque.Amount, previousCheque.Amount, ErrChequeAmountLessThanPrevious) + case previousCheque.Counter.Cmp(newCheque.Counter) > -1: // previous.Counter >= new.Counter + return fmt.Errorf("new cheque counter (%s) <= (%s) previous cheque counter: %w", newCheque.Counter, previousCheque.Counter, ErrChequeCounterNotGreaterThanPrevious) + } + return nil +} diff --git a/pkg/matrix/types.go b/pkg/matrix/types.go index 2cdc1f82..0752aacb 100644 --- a/pkg/matrix/types.go +++ b/pkg/matrix/types.go @@ -14,6 +14,8 @@ import ( transportv1 "buf.build/gen/go/chain4travel/camino-messenger-protocol/protocolbuffers/go/cmp/services/transport/v1" "github.com/chain4travel/camino-messenger-bot/internal/messaging" "github.com/chain4travel/camino-messenger-bot/internal/metadata" + "github.com/chain4travel/camino-messenger-bot/pkg/cheques" + "github.com/ethereum/go-ethereum/common" "google.golang.org/protobuf/proto" "maunium.net/go/mautrix/event" ) @@ -136,3 +138,12 @@ func (m *CaminoMatrixMessage) UnmarshalContent(src []byte) error { return messaging.ErrUnknownMessageType } } + +func (m *CaminoMatrixMessage) GetChequeFor(addr common.Address) *cheques.SignedCheque { + for _, cheque := range m.Metadata.Cheques { + if cheque.Cheque.ToCMAccount == addr { + return &cheque + } + } + return nil +}