Skip to content

Commit

Permalink
Update Counterparties to Store Compliance Contacts
Browse files Browse the repository at this point in the history
  • Loading branch information
bbengfort committed Nov 27, 2024
1 parent 7287f5c commit d7651f0
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 1 deletion.
65 changes: 64 additions & 1 deletion pkg/store/models/counterparty.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"fmt"

"github.com/oklog/ulid/v2"
"github.com/trisacrypto/envoy/pkg/store/errors"
"github.com/trisacrypto/trisa/pkg/ivms101"
)

Expand All @@ -19,7 +20,6 @@ const (
)

// TODO: how to incorporate the TRIXO form into this model?
// TODO: make sure that we add contacts associated with this model.
type Counterparty struct {
Model
Source string // either directory or locally created
Expand All @@ -35,6 +35,7 @@ type Counterparty struct {
VASPCategories VASPCategories // the categories of how the VASP handles crypto assets
VerifiedOn sql.NullTime // the datetime the VASP was verified in the directory (directory only)
IVMSRecord *ivms101.LegalPerson // IVMS101 record for the counterparty
contacts []*Contact // Associated contacts if any
}

// Scan a complete SELECT into the counterparty model
Expand Down Expand Up @@ -95,6 +96,68 @@ func (c *Counterparty) Params() []any {
}
}

// Returns the associated contacts if they are cached on the counterparty, otherwise
// returns an ErrMissingAssociation error if not.
func (c *Counterparty) Contacts() ([]*Contact, error) {
if c.contacts == nil {
return nil, errors.ErrMissingAssociation
}
return c.contacts, nil
}

// Used by store implementation to cache associated contacts on the counterparty.
func (c *Counterparty) SetContacts(contacts []*Contact) {
c.contacts = contacts
}

type Contact struct {
Model
Name string // The full name of the contact
Email string // A unique address for the contact (professional email) must be lowercase
Role string // A description of what the contact does at the counterparty
CounterpartyID ulid.ULID // Reference to the counterparty the contact is associated with
counterparty *Counterparty // Associated counterparty if fetched from the database
}

// Scan a complete SELECT into the counterparty model
func (c *Contact) Scan(scanner Scanner) error {
return scanner.Scan(
&c.ID,
&c.Name,
&c.Email,
&c.Role,
&c.CounterpartyID,
&c.Created,
&c.Modified,
)
}

// Get complete named params of the counterparty from the model.
func (c *Contact) Params() []any {
return []any{
sql.Named("id", c.ID),
sql.Named("name", c.Name),
sql.Named("email", c.Email),
sql.Named("role", c.Role),
sql.Named("counterpartyID", c.CounterpartyID),
sql.Named("created", c.Created),
sql.Named("modified", c.Modified),
}
}

// Returns the associated counterparty if it is cached on the model, otherwise returns
// an ErrMissingAssociation error.
func (c *Contact) Counterparty() (*Counterparty, error) {
if c.counterparty == nil {
return nil, errors.ErrMissingAssociation
}
return c.counterparty, nil
}

func (c *Contact) SetCounterparty(counterparty *Counterparty) {
c.counterparty = counterparty
}

type CounterpartySourceInfo struct {
ID ulid.ULID
Source string // either directory or locally created
Expand Down
19 changes: 19 additions & 0 deletions pkg/store/sqlite/migrations/0005_sunrise_tokens.sql
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,26 @@
-- linkage to a specific transaction or envelope set.
BEGIN;

-- The contacts table stores email address information for compliance officers and
-- other travel rule contacts that the Envoy system may want to email either for
-- troubleshooting a compliance transfer or for sunrise purposes.
-- NOTE: a contact is uniquely associated with a Counterparty.
-- NOTE: ensure email address is not case-sensitive when stored.
CREATE TABLE IF NOT EXISTS contacts (
id TEXT PRIMARY KEY,
name TEXT NOT NULL DEFAULT '',
email TEXT NOT NULL UNIQUE,
role TEXT NOT NULL DEFAULT '',
counterparty_id TEXT NOT NULL,
created DATETIME NOT NULL,
modified DATETIME NOT NULL,
FOREIGN KEY (counterparty_id) REFERENCES counterparties(id) ON DELETE CASCADE
)

-- The sunrise table stores verification tokens and enough information to manage
-- sunrise accounts and resend tokens without loading the transaction from the db.
-- NOTE: the verification tokens are only associated with the contacts via email (not ID).
-- NOTE: ensure email address is not case-sensitive when stored.
CREATE TABLE IF NOT EXISTS sunrise (
id TEXT PRIMARY KEY,
envelope_id TEXT NOT NULL,
Expand All @@ -18,6 +36,7 @@ CREATE TABLE IF NOT EXISTS sunrise (
modified DATETIME NOT NULL,
UNIQUE(envelope_id, email),
FOREIGN KEY (envelope_id) REFERENCES transactions(id) ON DELETE CASCADE
FOREIGN KEY (email) REFERENCES contacts(email) ON DELETE CASCADE
);

COMMIT;

0 comments on commit d7651f0

Please sign in to comment.