-
Notifications
You must be signed in to change notification settings - Fork 247
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
feat_: share and parse transaction deep link #5959
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -45,11 +45,21 @@ | |
PublicKey string `json:"publicKey"` | ||
} | ||
|
||
type TransactionURLData struct { | ||
TxType int `json:"txType"` | ||
Address string `json:"address"` | ||
Amount string `json:"amount"` | ||
Asset string `json:"asset"` | ||
ChainID int `json:"chainId"` | ||
ToAsset string `json:"toAsset"` | ||
} | ||
|
||
type URLDataResponse struct { | ||
Community *CommunityURLData `json:"community"` | ||
Channel *CommunityChannelURLData `json:"channel"` | ||
Contact *ContactURLData `json:"contact"` | ||
Shard *shard.Shard `json:"shard,omitempty"` | ||
Community *CommunityURLData `json:"community"` | ||
Channel *CommunityChannelURLData `json:"channel"` | ||
Contact *ContactURLData `json:"contact"` | ||
Transaction *TransactionURLData `json:"tx"` | ||
Shard *shard.Shard `json:"shard,omitempty"` | ||
} | ||
|
||
const baseShareURL = "https://status.app" | ||
|
@@ -58,12 +68,14 @@ | |
const communityPath = "c#" | ||
const communityWithDataPath = "c/" | ||
const channelPath = "cc/" | ||
const transactionPath = "tx/" | ||
|
||
const sharedURLUserPrefix = baseShareURL + "/" + userPath | ||
const sharedURLUserPrefixWithData = baseShareURL + "/" + userWithDataPath | ||
const sharedURLCommunityPrefix = baseShareURL + "/" + communityPath | ||
const sharedURLCommunityPrefixWithData = baseShareURL + "/" + communityWithDataPath | ||
const sharedURLChannelPrefixWithData = baseShareURL + "/" + channelPath | ||
const sharedURLTransaction = baseShareURL + "/" + transactionPath | ||
|
||
const channelUUIDRegExp = "^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$" | ||
|
||
|
@@ -302,6 +314,77 @@ | |
return encodedData, shortKey, nil | ||
} | ||
|
||
func (m *Messenger) ShareTransactionURL(request *requests.TransactionShareURL) (string, error) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So to build the transaction URL, I need to know all details about it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This feature creates link from the modal, not existing transaction. It is to request the payment by setting proper fields. Please note that not all the fields are required. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
wait, so there's no transaction yet? Should we call this |
||
encodedData, err := m.prepareTransactionUrl(request) | ||
if err != nil { | ||
return "", err | ||
} | ||
return fmt.Sprintf("%s%s", sharedURLTransaction, encodedData), nil | ||
} | ||
|
||
func (m *Messenger) prepareTransactionUrl(request *requests.TransactionShareURL) (string, error) { | ||
if err := request.Validate(); err != nil { | ||
return "", err | ||
} | ||
|
||
txProto := &protobuf.Transaction{ | ||
TxType: uint32(request.TxType), | ||
Address: request.Address, | ||
Amount: request.Amount, | ||
Asset: request.Asset, | ||
ChainId: uint32(request.ChainID), | ||
ToAsset: request.ToAsset, | ||
} | ||
txData, err := proto.Marshal(txProto) | ||
if err != nil { | ||
return "", err | ||
} | ||
urlDataProto := &protobuf.URLData{ | ||
Content: txData, | ||
} | ||
|
||
urlData, err := proto.Marshal(urlDataProto) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
encodedData, err := encodeDataURL(urlData) | ||
if err != nil { | ||
return "", err | ||
} | ||
return encodedData, nil | ||
} | ||
|
||
func parseTransactionURL(data string) (*URLDataResponse, error) { | ||
urlData, err := decodeDataURL(data) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
var urlDataProto protobuf.URLData | ||
err = proto.Unmarshal(urlData, &urlDataProto) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
var txProto protobuf.Transaction | ||
err = proto.Unmarshal(urlDataProto.Content, &txProto) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return &URLDataResponse{ | ||
Transaction: &TransactionURLData{ | ||
TxType: int(txProto.TxType), | ||
Address: txProto.Address, | ||
Amount: txProto.Amount, | ||
Asset: txProto.Asset, | ||
ChainID: int(txProto.ChainId), | ||
ToAsset: txProto.ToAsset, | ||
}, | ||
}, nil | ||
} | ||
|
||
func (m *Messenger) ShareCommunityChannelURLWithData(request *requests.CommunityChannelShareURL) (string, error) { | ||
if err := request.Validate(); err != nil { | ||
return "", err | ||
|
@@ -518,7 +601,8 @@ | |
strings.HasPrefix(url, sharedURLUserPrefixWithData) || | ||
strings.HasPrefix(url, sharedURLCommunityPrefix) || | ||
strings.HasPrefix(url, sharedURLCommunityPrefixWithData) || | ||
strings.HasPrefix(url, sharedURLChannelPrefixWithData) | ||
strings.HasPrefix(url, sharedURLChannelPrefixWithData) || | ||
strings.HasPrefix(url, sharedURLTransaction) | ||
} | ||
|
||
func splitSharedURLData(data string) (string, string, error) { | ||
|
@@ -576,6 +660,11 @@ | |
return parseCommunityChannelURLWithData(encodedData, chatKey) | ||
} | ||
|
||
if strings.HasPrefix(url, sharedURLTransaction) { | ||
trimmedURL := strings.TrimPrefix(url, sharedURLTransaction) | ||
return parseTransactionURL(trimmedURL) | ||
} | ||
|
||
return nil, fmt.Errorf("not a status shared url") | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package requests | ||
|
||
import ( | ||
"errors" | ||
) | ||
|
||
var ( | ||
ErrInvalidTransactionType = errors.New("transaction-share-url: invalid transaction type") | ||
) | ||
|
||
type TransactionShareURL struct { | ||
TxType int `json:"txType"` | ||
Asset string `json:"asset"` | ||
Amount string `json:"amount"` | ||
Address string `json:"address"` | ||
ChainID int `json:"chainId"` | ||
ToAsset string `json:"toAsset"` | ||
} | ||
|
||
func (r *TransactionShareURL) Validate() error { | ||
if r.TxType < 0 { | ||
return ErrInvalidTransactionType | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we also validate that the address is not empty for example? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not really. It might be changed by design team, but right now, deep link can be created without recipient. For example Swap doesn't have recipient. I don't see the reason why I couldn't share tx setup for specific token, it is much easier than copy pasting name. |
||
return nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think
tx
is redundant here, it's all about the transaction?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I 100% agree with you. The reason why I set it to txType to prevent any issues of
type
keyword that might happen on any layer.While it might be redundant, I wanted to clearly point it is about transaction not url type or something like that.