Skip to content

SubmitIntent should support any type of message #34

@louisinger

Description

@louisinger

Summary

SubmitIntent in the introspector currently only accepts and validates a register-type intent message (RegisterMessage). However, the Ark intent system uses intent proofs as an authentication mechanism for multiple arkd RPCs — not just registration. The introspector must be able to sign proofs for all intent message types so that smart contract cosigners can authenticate all arkd operations that require intent proofs.

Background

In arkd, intent proofs serve a dual purpose:

  1. Registration — authenticate the VTXO registration in a batch round (IntentMessageTypeRegister)
  2. Authentication — prove ownership for other RPCs:
    • IntentMessageTypeDelete (delete) — used to delete a registered intent
    • IntentMessageTypeGetPendingTx (get-pending-tx) — retrieve the pending commitment tx
    • IntentMessageTypeEstimateFee (estimate-intent-fee) — estimate fees for an intent

All four message types are defined in arkd/pkg/ark-lib/intent/message.go:

const (
    IntentMessageTypeRegister     IntentMessageType = "register"
    IntentMessageTypeDelete       IntentMessageType = "delete"
    IntentMessageTypeGetPendingTx IntentMessageType = "get-pending-tx"
    IntentMessageTypeEstimateFee  IntentMessageType = "estimate-intent-fee"
)

Current Limitation

Handler layer (internal/interface/grpc/handlers/introspector_handler.go)

parseIntent hard-codes deserialization to intent.RegisterMessage:

var registerMessage intent.RegisterMessage
if err := registerMessage.Decode(message); err != nil {
    return nil, fmt.Errorf("invalid message: %w", err)
}
return &application.Intent{
    Proof:   intentProof,
    Message: registerMessage,  // always RegisterMessage
}, nil

Application layer (internal/application/intent.go)

SubmitIntent calls validateRegisterMessage which only validates RegisterMessage semantics (timestamps ValidAt/ExpireAt):

func (s *service) SubmitIntent(ctx context.Context, intent Intent) (*psbt.Packet, error) {
    if err := validateRegisterMessage(intent.Message); err != nil {  // register-only
        return nil, fmt.Errorf("invalid message: %w", err)
    }
    // ...
}

Application domain struct (Intent)

application.Intent.Message is typed as intent.RegisterMessage, not a generic message interface.

Affected Components

Component File Issue
gRPC handler internal/interface/grpc/handlers/introspector_handler.go parseIntent() hard-coded to RegisterMessage
Application service internal/application/intent.go validateRegisterMessage() called unconditionally; Intent.Message typed as RegisterMessage
Proto definition api-spec/protobuf/introspector/v1/service.proto SubmitIntent comment says "register message" only — needs updating

Suggested Approach

  1. Update parseIntent to decode based on message type:

    • First decode only BaseMessage to read the type field
    • Switch on type to decode the full message (RegisterMessage, DeleteMessage, GetPendingTxMessage, EstimateIntentFeeMessage)
  2. Generalize application.Intent.Message:

    • Define an IntentMessage interface (with Encode/Decode methods) or use intent.BaseMessage + a typed union
    • Update Intent struct to hold the interface type
  3. Update validation logic:

    • validateRegisterMessage should only be called for register type
    • DeleteMessage / GetPendingTxMessage share the same timestamp fields as RegisterMessage (via ExpireAt) — validate accordingly
    • EstimateIntentFeeMessage is a type alias for RegisterMessage — reuse the same validation
  4. Update proto comment for SubmitIntent to reflect it accepts any intent message type

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions