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

PaymentRequestInfoData to be slice instead of a union and remove Currency field #68

Merged
merged 4 commits into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions .github/workflows/ci-lint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Install Go
uses: actions/setup-go@v4
with:
go-version: 1.21.0
- name: Checkout code
uses: actions/checkout@v3
go-version-file: go.mod
cache: true
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
version: v1.54.2
version: v1.60.3
2 changes: 1 addition & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
service:
golangci-lint-version: 1.45.x
golangci-lint-version: 1.60.3

run:
timeout: 2m
Expand Down
214 changes: 78 additions & 136 deletions protocol/payment.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"encoding/json"
"fmt"

"github.com/iden3/driver-did-iden3/pkg/document"
"github.com/iden3/go-schema-processor/v2/verifiable"
"github.com/pkg/errors"

Expand Down Expand Up @@ -34,9 +35,6 @@ const (

// Iden3PaymentRailsERC20V1Type is a Iden3PaymentRailsERC20V1 payment type
Iden3PaymentRailsERC20V1Type PaymentType = "Iden3PaymentRailsERC20V1"

// Eip712SignatureProofType is a EthereumEip712Signature2021 proof type
Eip712SignatureProofType ProofType = "EthereumEip712Signature2021"
)

// PaymentType is type for Payment
Expand All @@ -45,9 +43,6 @@ type PaymentType string
// PaymentRequestType is type for Payment request
type PaymentRequestType string

// ProofType is type for Proof
type ProofType string

// PaymentRequestMessage represents Iden3message for payment request.
type PaymentRequestMessage struct {
ID string `json:"id"`
Expand All @@ -72,147 +67,86 @@ type PaymentRequestMessageBody struct {

// PaymentRequestInfo represents the payments request information.
type PaymentRequestInfo struct {
Type string `json:"type,omitempty"`
Credentials []PaymentRequestInfoCredentials `json:"credentials"`
Description string `json:"description"`
Data PaymentRequestInfoData `json:"data"`
}

// PaymentRequestInfoData is a union type for field Data in PaymentRequestInfo.
// Only one of the fields can be set at a time.
type PaymentRequestInfoData struct {
dataType PaymentRequestType
crypto []Iden3PaymentRequestCryptoV1
rails []Iden3PaymentRailsRequestV1
railsERC20 []Iden3PaymentRailsERC20RequestV1
}

// NewPaymentRequestInfoDataCrypto creates a new PaymentRequestInfoData with Iden3PaymentRequestCryptoV1 data.
func NewPaymentRequestInfoDataCrypto(data Iden3PaymentRequestCryptoV1) PaymentRequestInfoData {
return PaymentRequestInfoData{
dataType: Iden3PaymentRequestCryptoV1Type,
crypto: []Iden3PaymentRequestCryptoV1{data},
}
}
type PaymentRequestInfoData []PaymentRequestInfoDataItem

// NewPaymentRequestInfoDataRails creates a new PaymentRequestInfoData with Iden3PaymentRailsRequestV1 data.
func NewPaymentRequestInfoDataRails(data Iden3PaymentRailsRequestV1) PaymentRequestInfoData {
return PaymentRequestInfoData{
dataType: Iden3PaymentRailsRequestV1Type,
rails: []Iden3PaymentRailsRequestV1{data},
}
}

// NewPaymentRequestInfoDataRailsERC20 creates a new PaymentRequestInfoData with Iden3PaymentRailsERC20RequestV1 data.
func NewPaymentRequestInfoDataRailsERC20(data Iden3PaymentRailsERC20RequestV1) PaymentRequestInfoData {
return PaymentRequestInfoData{
dataType: Iden3PaymentRailsERC20RequestV1Type,
railsERC20: []Iden3PaymentRailsERC20RequestV1{data},
}
}

// Type returns the type of the data in the union. You can use Data() to get the data.
func (p *PaymentRequestInfoData) Type() PaymentRequestType {
return p.dataType
}

// Data returns the data in the union. You can use Type() to determine the type of the data.
func (p *PaymentRequestInfoData) Data() interface{} {
switch p.dataType {
case Iden3PaymentRequestCryptoV1Type:
return p.crypto
case Iden3PaymentRailsRequestV1Type:
return p.rails
case Iden3PaymentRailsERC20RequestV1Type:
return p.railsERC20
}
return nil
// PaymentRequestInfoDataItem is the interface that any PaymentRequestInfoData.Data item must implement.
type PaymentRequestInfoDataItem interface {
PaymentRequestType() PaymentRequestType
}

// MarshalJSON marshals the PaymentRequestInfoData into JSON.
func (p PaymentRequestInfoData) MarshalJSON() ([]byte, error) {
switch p.dataType {
case Iden3PaymentRequestCryptoV1Type:
return json.Marshal(p.crypto[0])
case Iden3PaymentRailsRequestV1Type:
return json.Marshal(p.rails)
case Iden3PaymentRailsERC20RequestV1Type:
return json.Marshal(p.railsERC20)
if len(p) == 1 && p[0].PaymentRequestType() == Iden3PaymentRequestCryptoV1Type {
return json.Marshal(p[0])
}
return nil, errors.New("failed to marshal not initialized PaymentRequestInfoData")
return json.Marshal([]PaymentRequestInfoDataItem(p))
}

// UnmarshalJSON unmarshal the PaymentRequestInfoData from JSON.
func (p *PaymentRequestInfoData) UnmarshalJSON(data []byte) error {
var item struct {
Type PaymentRequestType `json:"type"`
}
var collection []struct {
type rawItem struct {
Type PaymentRequestType `json:"type"`
}

p.crypto, p.rails, p.railsERC20 = nil, nil, nil
var item rawItem
var collection []json.RawMessage

if err := json.Unmarshal(data, &item); err == nil {
p.dataType = item.Type
return p.unmarshalFromItem(item.Type, data)
err := json.Unmarshal(data, &item)
if err == nil {
o, errItem := p.unmarshalFromItem(item.Type, data)
if errItem != nil {
return errItem
}
*p = append(*p, o)
return nil
}

if err := json.Unmarshal(data, &collection); err == nil {
if len(collection) == 0 {
return nil
err = json.Unmarshal(data, &collection)
if err != nil {
return fmt.Errorf("PaymentRequestInfoData must be a PaymentRequestInfoDataItem or a collection: %w", err)
}
for n, rawItem := range collection {
if err := json.Unmarshal(rawItem, &item); err != nil {
return fmt.Errorf("field PaymentRequestInfoData[%d].Type not found: %w", n, err)
}

p.dataType = collection[0].Type
return p.unmarshalFromCollection(p.dataType, data)
o, err := p.unmarshalFromItem(item.Type, rawItem)
if err != nil {
return err
}
*p = append(*p, o)
}
return errors.New("failed to unmarshal PaymentRequestInfoData. not a single item nor a collection")
return nil
}

func (p *PaymentRequestInfoData) unmarshalFromItem(typ PaymentRequestType, data []byte) error {
func (p *PaymentRequestInfoData) unmarshalFromItem(typ PaymentRequestType, data []byte) (PaymentRequestInfoDataItem, error) {
switch typ {
case Iden3PaymentRequestCryptoV1Type:
var o Iden3PaymentRequestCryptoV1
if err := json.Unmarshal(data, &o); err != nil {
return fmt.Errorf("unmarshalling PaymentRequestInfoData: %w", err)
return nil, fmt.Errorf("unmarshalling PaymentRequestInfoData: %w", err)
}
p.crypto = []Iden3PaymentRequestCryptoV1{o}
return o, nil
case Iden3PaymentRailsRequestV1Type:
var o Iden3PaymentRailsRequestV1
if err := json.Unmarshal(data, &o); err != nil {
return fmt.Errorf("unmarshalling PaymentRequestInfoData: %w", err)
return nil, fmt.Errorf("unmarshalling PaymentRequestInfoData: %w", err)
}
p.rails = []Iden3PaymentRailsRequestV1{o}
return o, nil
case Iden3PaymentRailsERC20RequestV1Type:
var o Iden3PaymentRailsERC20RequestV1
if err := json.Unmarshal(data, &o); err != nil {
return fmt.Errorf("unmarshalling PaymentRequestInfoData: %w", err)
}
p.railsERC20 = []Iden3PaymentRailsERC20RequestV1{o}
default:
return errors.Errorf("unmarshalling PaymentRequestInfoData. unknown type: %s", typ)
}
return nil
}

func (p *PaymentRequestInfoData) unmarshalFromCollection(typ PaymentRequestType, data []byte) error {
switch typ {
case Iden3PaymentRequestCryptoV1Type:
if err := json.Unmarshal(data, &p.crypto); err != nil {
return fmt.Errorf("unmarshalling PaymentRequestInfoData: %w", err)
}
case Iden3PaymentRailsRequestV1Type:
if err := json.Unmarshal(data, &p.rails); err != nil {
return fmt.Errorf("unmarshalling PaymentRequestInfoData: %w", err)
}
case Iden3PaymentRailsERC20RequestV1Type:
if err := json.Unmarshal(data, &p.railsERC20); err != nil {
return fmt.Errorf("unmarshalling PaymentRequestInfoData: %w", err)
return nil, fmt.Errorf("unmarshalling PaymentRequestInfoData: %w", err)
}
return o, nil
default:
return errors.Errorf("unmarshalling PaymentRequestInfoData. unknown type: %s", typ)
return nil, errors.Errorf("unmarshalling PaymentRequestInfoData. unknown type: %s", typ)
}
return nil
}

// Iden3PaymentRequestCryptoV1 represents the Iden3PaymentRequestCryptoV1 payment request data.
Expand All @@ -227,6 +161,11 @@ type Iden3PaymentRequestCryptoV1 struct {
Expiration string `json:"expiration,omitempty"`
}

// PaymentRequestType implements the PaymentRequestInfoDataItem interface.
func (i Iden3PaymentRequestCryptoV1) PaymentRequestType() PaymentRequestType {
return Iden3PaymentRequestCryptoV1Type
}

// Iden3PaymentRailsRequestV1 represents the Iden3PaymentRailsRequestV1 payment request data.
type Iden3PaymentRailsRequestV1 struct {
Nonce string `json:"nonce"`
Expand All @@ -237,7 +176,11 @@ type Iden3PaymentRailsRequestV1 struct {
ExpirationDate string `json:"expirationDate"`
Proof PaymentProof `json:"proof"`
Metadata string `json:"metadata"`
Currency string `json:"currency"`
}

// PaymentRequestType implements the PaymentRequestInfoDataItem interface.
func (i Iden3PaymentRailsRequestV1) PaymentRequestType() PaymentRequestType {
return Iden3PaymentRailsRequestV1Type
}

// Iden3PaymentRailsERC20RequestV1 represents the Iden3PaymentRailsERC20RequestV1 payment request data.
Expand All @@ -250,49 +193,45 @@ type Iden3PaymentRailsERC20RequestV1 struct {
ExpirationDate string `json:"expirationDate"`
Proof PaymentProof `json:"proof"`
Metadata string `json:"metadata"`
Currency string `json:"currency"`
TokenAddress string `json:"tokenAddress"`
Features []PaymentFeatures `json:"features,omitempty"`
}

// PaymentRequestType implements the PaymentRequestInfoDataItem interface.
func (i Iden3PaymentRailsERC20RequestV1) PaymentRequestType() PaymentRequestType {
return Iden3PaymentRailsERC20RequestV1Type
}

// PaymentFeatures represents type Features used in ERC20 payment request.
type PaymentFeatures string

// PaymentProof represents a payment proof.
type PaymentProof struct {
dataType ProofType
eip712Signature []EthereumEip712Signature2021
}
type PaymentProof []PaymentProofItem

// NewPaymentProofEip712Signature creates a new PaymentProof with EthereumEip712Signature2021 data.
func NewPaymentProofEip712Signature(data []EthereumEip712Signature2021) PaymentProof {
return PaymentProof{
dataType: Eip712SignatureProofType,
eip712Signature: data,
}
// PaymentProofItem is the interface that any PaymentProof item must implement.
type PaymentProofItem interface {
PaymentProofItem() verifiable.ProofType
}

// UnmarshalJSON unmarshal the PaymentRequestInfoData from JSON.
func (p *PaymentProof) UnmarshalJSON(data []byte) error {
p.dataType = Eip712SignatureProofType
var col []EthereumEip712Signature2021
var col []*EthereumEip712Signature2021
if err := json.Unmarshal(data, &col); err != nil {
var single EthereumEip712Signature2021
if err := json.Unmarshal(data, &single); err != nil {
return fmt.Errorf("failed to unmarshal EthereumEip712Signature2021Col: %w", err)
}
col = append(col, single)
col = append(col, &single)
}
for _, item := range col {
*p = append(*p, *item)
}
p.eip712Signature = col
return nil
}

// MarshalJSON marshals the PaymentProof into JSON.
func (p PaymentProof) MarshalJSON() ([]byte, error) {
if p.dataType == Eip712SignatureProofType {
return json.Marshal(p.eip712Signature)
}
return nil, errors.New("failed to marshal not initialized PaymentProof")
return json.Marshal([]PaymentProofItem(p))
}

// EthereumEip712Signature2021 represents the Ethereum EIP712 signature.
Expand All @@ -305,6 +244,11 @@ type EthereumEip712Signature2021 struct {
Eip712 Eip712Data `json:"eip712"`
}

// PaymentProofItem implements the PaymentProofItem interface.
func (e EthereumEip712Signature2021) PaymentProofItem() verifiable.ProofType {
return document.EthereumEip712SignatureProof2021Type
}

// Eip712Data represents the EIP712 data.
type Eip712Data struct {
Types string `json:"types"`
Expand Down Expand Up @@ -372,8 +316,8 @@ func NewPaymentRails(data Iden3PaymentRailsV1) Payment {
}
}

// NEwPaymentRailsERC20 creates a new Payment with Iden3PaymentRailsERC20V1 data.
func NEwPaymentRailsERC20(data Iden3PaymentRailsERC20V1) Payment {
// NewPaymentRailsERC20 creates a new Payment with Iden3PaymentRailsERC20V1 data.
func NewPaymentRailsERC20(data Iden3PaymentRailsERC20V1) Payment {
return Payment{
dataType: Iden3PaymentRailsERC20V1Type,
railsERC: &data,
Expand Down Expand Up @@ -473,17 +417,15 @@ type PaymentContext struct {
}

// NewPaymentContextString creates a new PaymentContext with a string.
func NewPaymentContextString(str string) PaymentContext {
return PaymentContext{str: &str}
}

// NewPaymentContextStringCol creates a new PaymentContext with a string collection.
func NewPaymentContextStringCol(strCol []string) PaymentContext {
return PaymentContext{strCol: strCol}
func NewPaymentContextString(str ...string) PaymentContext {
if len(str) == 1 {
return PaymentContext{str: &str[0]}
}
return PaymentContext{strCol: str}
}

// NewPaymentContextItemCol creates a new PaymentContext with an interface{} collection.
func NewPaymentContextItemCol(itemCol []interface{}) PaymentContext {
func NewPaymentContextItemCol(itemCol ...interface{}) PaymentContext {
return PaymentContext{itemCol: itemCol}
}

Expand Down
Loading
Loading