Skip to content

Commit ea1f5ca

Browse files
Merge pull request #245 from kaleido-io/transfer
Allow sending a message with a token transfer
2 parents aabcb8e + 4884273 commit ea1f5ca

25 files changed

+674
-207
lines changed

docs/swagger/swagger.yaml

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5102,14 +5102,120 @@ paths:
51025102
schema:
51035103
properties:
51045104
amount: {}
5105+
created: {}
51055106
from:
51065107
type: string
51075108
key:
51085109
type: string
5110+
localId: {}
5111+
message:
5112+
properties:
5113+
batch: {}
5114+
confirmed: {}
5115+
data:
5116+
items:
5117+
properties:
5118+
blob:
5119+
properties:
5120+
hash: {}
5121+
public:
5122+
type: string
5123+
type: object
5124+
datatype:
5125+
properties:
5126+
name:
5127+
type: string
5128+
version:
5129+
type: string
5130+
type: object
5131+
hash: {}
5132+
id: {}
5133+
validator:
5134+
type: string
5135+
value:
5136+
format: byte
5137+
type: string
5138+
type: object
5139+
type: array
5140+
group:
5141+
properties:
5142+
ledger: {}
5143+
members:
5144+
items:
5145+
properties:
5146+
identity:
5147+
type: string
5148+
node:
5149+
type: string
5150+
type: object
5151+
type: array
5152+
name:
5153+
type: string
5154+
type: object
5155+
hash: {}
5156+
header:
5157+
properties:
5158+
author:
5159+
type: string
5160+
cid: {}
5161+
created: {}
5162+
datahash: {}
5163+
group: {}
5164+
id: {}
5165+
key:
5166+
type: string
5167+
namespace:
5168+
type: string
5169+
tag:
5170+
type: string
5171+
topics:
5172+
items:
5173+
type: string
5174+
type: array
5175+
txtype:
5176+
type: string
5177+
type:
5178+
enum:
5179+
- definition
5180+
- broadcast
5181+
- private
5182+
- groupinit
5183+
- transfer_broadcast
5184+
- transfer_private
5185+
type: string
5186+
type: object
5187+
local:
5188+
type: boolean
5189+
pending:
5190+
type: boolean
5191+
pins:
5192+
items:
5193+
type: string
5194+
type: array
5195+
rejected:
5196+
type: boolean
5197+
type: object
5198+
messageHash: {}
5199+
poolProtocolId:
5200+
type: string
5201+
protocolId:
5202+
type: string
51095203
to:
51105204
type: string
51115205
tokenIndex:
51125206
type: string
5207+
tx:
5208+
properties:
5209+
id: {}
5210+
type:
5211+
type: string
5212+
type: object
5213+
type:
5214+
enum:
5215+
- mint
5216+
- burn
5217+
- transfer
5218+
type: string
51135219
type: object
51145220
responses:
51155221
"200":

internal/apiserver/route_post_token_transfer.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,13 @@ var postTokenTransfer = &oapispec.Route{
4040
},
4141
FilterFactory: nil,
4242
Description: i18n.MsgTBD,
43-
JSONInputValue: func() interface{} { return &fftypes.TokenTransfer{} },
43+
JSONInputValue: func() interface{} { return &fftypes.TokenTransferInput{} },
4444
JSONInputMask: []string{"Type", "LocalID", "PoolProtocolID", "ProtocolID", "MessageHash", "TX", "Created"},
4545
JSONOutputValue: func() interface{} { return &fftypes.TokenTransfer{} },
4646
JSONOutputCodes: []int{http.StatusAccepted, http.StatusOK},
4747
JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) {
4848
waitConfirm := strings.EqualFold(r.QP["confirm"], "true")
4949
r.SuccessStatus = syncRetcode(waitConfirm)
50-
return r.Or.Assets().TransferTokens(r.Ctx, r.PP["ns"], r.PP["type"], r.PP["name"], r.Input.(*fftypes.TokenTransfer), waitConfirm)
50+
return r.Or.Assets().TransferTokens(r.Ctx, r.PP["ns"], r.PP["type"], r.PP["name"], r.Input.(*fftypes.TokenTransferInput), waitConfirm)
5151
},
5252
}

internal/apiserver/route_post_token_transfer_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,14 @@ func TestPostTokenTransfer(t *testing.T) {
3232
o, r := newTestAPIServer()
3333
mam := &assetmocks.Manager{}
3434
o.On("Assets").Return(mam)
35-
input := fftypes.TokenTransfer{}
35+
input := fftypes.TokenTransferInput{}
3636
var buf bytes.Buffer
3737
json.NewEncoder(&buf).Encode(&input)
3838
req := httptest.NewRequest("POST", "/api/v1/namespaces/ns1/tokens/tok1/pools/pool1/transfers", &buf)
3939
req.Header.Set("Content-Type", "application/json; charset=utf-8")
4040
res := httptest.NewRecorder()
4141

42-
mam.On("TransferTokens", mock.Anything, "ns1", "tok1", "pool1", mock.AnythingOfType("*fftypes.TokenTransfer"), false).
42+
mam.On("TransferTokens", mock.Anything, "ns1", "tok1", "pool1", mock.AnythingOfType("*fftypes.TokenTransferInput"), false).
4343
Return(&fftypes.TokenTransfer{}, nil)
4444
r.ServeHTTP(res, req)
4545

internal/assets/manager.go

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"github.com/hyperledger/firefly/internal/data"
2626
"github.com/hyperledger/firefly/internal/i18n"
2727
"github.com/hyperledger/firefly/internal/identity"
28+
"github.com/hyperledger/firefly/internal/privatemessaging"
2829
"github.com/hyperledger/firefly/internal/retry"
2930
"github.com/hyperledger/firefly/internal/syncasync"
3031
"github.com/hyperledger/firefly/internal/txcommon"
@@ -42,11 +43,10 @@ type Manager interface {
4243
GetTokenTransfers(ctx context.Context, ns, typeName, poolName string, filter database.AndFilter) ([]*fftypes.TokenTransfer, *database.FilterResult, error)
4344
MintTokens(ctx context.Context, ns, typeName, poolName string, transfer *fftypes.TokenTransfer, waitConfirm bool) (*fftypes.TokenTransfer, error)
4445
BurnTokens(ctx context.Context, ns, typeName, poolName string, transfer *fftypes.TokenTransfer, waitConfirm bool) (*fftypes.TokenTransfer, error)
45-
TransferTokens(ctx context.Context, ns, typeName, poolName string, transfer *fftypes.TokenTransfer, waitConfirm bool) (*fftypes.TokenTransfer, error)
46+
TransferTokens(ctx context.Context, ns, typeName, poolName string, transfer *fftypes.TokenTransferInput, waitConfirm bool) (*fftypes.TokenTransfer, error)
4647

4748
// Bound token callbacks
4849
TokenPoolCreated(tk tokens.Plugin, pool *fftypes.TokenPool, protocolTxID string, additionalInfo fftypes.JSONObject) error
49-
TokensTransferred(tk tokens.Plugin, transfer *fftypes.TokenTransfer, protocolTxID string, additionalInfo fftypes.JSONObject) error
5050

5151
Start() error
5252
WaitStop()
@@ -59,13 +59,14 @@ type assetManager struct {
5959
data data.Manager
6060
syncasync syncasync.Bridge
6161
broadcast broadcast.Manager
62+
messaging privatemessaging.Manager
6263
tokens map[string]tokens.Plugin
6364
retry retry.Retry
6465
txhelper txcommon.Helper
6566
}
6667

67-
func NewAssetManager(ctx context.Context, di database.Plugin, im identity.Manager, dm data.Manager, sa syncasync.Bridge, bm broadcast.Manager, ti map[string]tokens.Plugin) (Manager, error) {
68-
if di == nil || im == nil || sa == nil || bm == nil || ti == nil {
68+
func NewAssetManager(ctx context.Context, di database.Plugin, im identity.Manager, dm data.Manager, sa syncasync.Bridge, bm broadcast.Manager, pm privatemessaging.Manager, ti map[string]tokens.Plugin) (Manager, error) {
69+
if di == nil || im == nil || sa == nil || bm == nil || pm == nil || ti == nil {
6970
return nil, i18n.NewError(ctx, i18n.MsgInitializationNilDepError)
7071
}
7172
am := &assetManager{
@@ -75,6 +76,7 @@ func NewAssetManager(ctx context.Context, di database.Plugin, im identity.Manage
7576
data: dm,
7677
syncasync: sa,
7778
broadcast: bm,
79+
messaging: pm,
7880
tokens: ti,
7981
retry: retry.Retry{
8082
InitialDelay: config.GetDuration(config.AssetManagerRetryInitialDelay),
@@ -119,21 +121,13 @@ func retrieveTokenPoolCreateInputs(ctx context.Context, op *fftypes.Operation, p
119121
return nil
120122
}
121123

124+
// Note: the counterpart to below (retrieveTokenTransferInputs) lives in the events package
122125
func addTokenTransferInputs(op *fftypes.Operation, transfer *fftypes.TokenTransfer) {
123126
op.Input = fftypes.JSONObject{
124127
"id": transfer.LocalID.String(),
125128
}
126129
}
127130

128-
func retrieveTokenTransferInputs(ctx context.Context, op *fftypes.Operation, transfer *fftypes.TokenTransfer) (err error) {
129-
input := &op.Input
130-
transfer.LocalID, err = fftypes.ParseUUID(ctx, input.GetString("id"))
131-
if err != nil {
132-
return err
133-
}
134-
return nil
135-
}
136-
137131
func (am *assetManager) CreateTokenPool(ctx context.Context, ns string, typeName string, pool *fftypes.TokenPool, waitConfirm bool) (*fftypes.TokenPool, error) {
138132
return am.createTokenPoolWithID(ctx, fftypes.NewUUID(), ns, typeName, pool, waitConfirm)
139133
}
@@ -291,7 +285,25 @@ func (am *assetManager) BurnTokens(ctx context.Context, ns, typeName, poolName s
291285
return am.transferTokensWithID(ctx, fftypes.NewUUID(), ns, typeName, poolName, transfer, waitConfirm)
292286
}
293287

294-
func (am *assetManager) TransferTokens(ctx context.Context, ns, typeName, poolName string, transfer *fftypes.TokenTransfer, waitConfirm bool) (*fftypes.TokenTransfer, error) {
288+
func (am *assetManager) sendTransferMessage(ctx context.Context, ns string, in *fftypes.MessageInOut) (*fftypes.Message, error) {
289+
allowedTypes := []fftypes.FFEnum{
290+
fftypes.MessageTypeTransferBroadcast,
291+
fftypes.MessageTypeTransferPrivate,
292+
}
293+
if in.Header.Type == "" {
294+
in.Header.Type = fftypes.MessageTypeTransferBroadcast
295+
}
296+
switch in.Header.Type {
297+
case fftypes.MessageTypeTransferBroadcast:
298+
return am.broadcast.BroadcastMessage(ctx, ns, in, false)
299+
case fftypes.MessageTypeTransferPrivate:
300+
return am.messaging.SendMessage(ctx, ns, in, false)
301+
default:
302+
return nil, i18n.NewError(ctx, i18n.MsgInvalidMessageType, allowedTypes)
303+
}
304+
}
305+
306+
func (am *assetManager) TransferTokens(ctx context.Context, ns, typeName, poolName string, transfer *fftypes.TokenTransferInput, waitConfirm bool) (*fftypes.TokenTransfer, error) {
295307
transfer.Type = fftypes.TokenTransferTypeTransfer
296308
if transfer.Key == "" {
297309
org, err := am.identity.GetLocalOrganization(ctx)
@@ -309,7 +321,17 @@ func (am *assetManager) TransferTokens(ctx context.Context, ns, typeName, poolNa
309321
if transfer.From == transfer.To {
310322
return nil, i18n.NewError(ctx, i18n.MsgCannotTransferToSelf)
311323
}
312-
return am.transferTokensWithID(ctx, fftypes.NewUUID(), ns, typeName, poolName, transfer, waitConfirm)
324+
325+
if transfer.Message != nil {
326+
msg, err := am.sendTransferMessage(ctx, ns, transfer.Message)
327+
if err != nil {
328+
return nil, err
329+
}
330+
transfer.MessageHash = msg.Hash
331+
}
332+
333+
result, err := am.transferTokensWithID(ctx, fftypes.NewUUID(), ns, typeName, poolName, &transfer.TokenTransfer, waitConfirm)
334+
return result, err
313335
}
314336

315337
func (am *assetManager) transferTokensWithID(ctx context.Context, id *fftypes.UUID, ns, typeName, poolName string, transfer *fftypes.TokenTransfer, waitConfirm bool) (*fftypes.TokenTransfer, error) {

0 commit comments

Comments
 (0)