github.com/mavryk-network/mvgo@v1.19.9/internal/compose/alpha/task/token_transfer.go (about) 1 // Copyright (c) 2023 Blockwatch Data Inc. 2 // Author: alex@blockwatch.cc, abdul@blockwatch.cc 3 4 package task 5 6 import ( 7 "fmt" 8 9 "github.com/mavryk-network/mvgo/codec" 10 "github.com/mavryk-network/mvgo/contract" 11 "github.com/mavryk-network/mvgo/internal/compose" 12 "github.com/mavryk-network/mvgo/internal/compose/alpha" 13 "github.com/mavryk-network/mvgo/mavryk" 14 "github.com/mavryk-network/mvgo/rpc" 15 "github.com/mavryk-network/mvgo/signer" 16 17 "github.com/pkg/errors" 18 ) 19 20 var _ alpha.TaskBuilder = (*TokenTransferTask)(nil) 21 22 func init() { 23 alpha.RegisterTask("token_transfer", NewTokenTransferTask) 24 } 25 26 type TokenTransferTask struct { 27 TargetTask 28 Standard string 29 From mavryk.Address 30 Receivers []TokenReceiver 31 } 32 33 type TokenReceiver struct { 34 Address mavryk.Address 35 Amount mavryk.Z 36 TokenId mavryk.Z 37 } 38 39 func NewTokenTransferTask() alpha.TaskBuilder { 40 return &TokenTransferTask{} 41 } 42 43 func (t *TokenTransferTask) Type() string { 44 return "token_transfer" 45 } 46 47 func (t *TokenTransferTask) Build(ctx compose.Context, task alpha.Task) (*codec.Op, *rpc.CallOptions, error) { 48 if err := t.parse(ctx, task); err != nil { 49 return nil, nil, errors.Wrap(err, "parse") 50 } 51 var xfer codec.Operation 52 switch t.Standard { 53 case "fa2", "": 54 args := contract.NewFA2TransferArgs() 55 for _, r := range t.Receivers { 56 args.WithTransfer(t.From, r.Address, r.TokenId, r.Amount) 57 } 58 xfer = args. 59 Optimize(). 60 WithSource(t.Source). 61 WithDestination(t.Destination). 62 Encode() 63 case "fa1", "fa12", "fa1.2": 64 xfer = contract.NewFA1TransferArgs(). 65 WithTransfer(t.From, t.Receivers[0].Address, t.Receivers[0].Amount). 66 WithSource(t.Source). 67 WithDestination(t.Destination). 68 Encode() 69 } 70 71 opts := rpc.NewCallOptions() 72 opts.Signer = signer.NewFromKey(t.Key) 73 op := codec.NewOp().WithContents(xfer) 74 return op, opts, nil 75 } 76 77 func (t *TokenTransferTask) Validate(ctx compose.Context, task alpha.Task) error { 78 return t.parse(ctx, task) 79 } 80 81 func (t *TokenTransferTask) parse(ctx compose.Context, task alpha.Task) (err error) { 82 if err = t.TargetTask.parse(ctx, task); err != nil { 83 return err 84 } 85 if t.Standard, err = ctx.ResolveString(task.Args["standard"]); err != nil { 86 return errors.Wrap(err, "standard") 87 } 88 switch t.Standard { 89 case "fa2", "", "fa1", "fa12", "fa1.2": 90 // skip 91 default: 92 return fmt.Errorf("unsupported token standard %s", t.Standard) 93 } 94 if t.From, err = ctx.ResolveAddress(task.Args["from"]); err != nil { 95 return errors.Wrap(err, "from") 96 } 97 if val := task.Args["receivers"]; val == nil { 98 var tr TokenReceiver 99 if tr.Address, err = ctx.ResolveAddress(task.Args["to"]); err != nil { 100 return errors.Wrap(err, "to") 101 } 102 if tr.Amount, err = ctx.ResolveZ(task.Args["amount"]); err != nil { 103 return errors.Wrap(err, "amount") 104 } 105 // only required for fa2 106 switch t.Standard { 107 case "fa2", "": 108 if tr.TokenId, err = ctx.ResolveZ(task.Args["token_id"]); err != nil { 109 return errors.Wrap(err, "token_id") 110 } 111 } 112 t.Receivers = append(t.Receivers, tr) 113 } else { 114 recvs, ok := val.([]any) 115 if !ok { 116 return fmt.Errorf("invalid type %T for receivers, expected list(map)", val) 117 } 118 for i, v := range recvs { 119 var tr TokenReceiver 120 recv, ok := v.(map[string]any) 121 if !ok { 122 return fmt.Errorf("receiver[%d]: invalid type %T for receiver, expected map[string]string", i, val) 123 } 124 if tr.Address, err = ctx.ResolveAddress(recv["to"]); err != nil { 125 return fmt.Errorf("receiver[%d] to: %v", i, err) 126 } 127 if tr.Amount, err = ctx.ResolveZ(recv["amount"]); err != nil { 128 return fmt.Errorf("receiver[%d] amount: %v", i, err) 129 } 130 switch t.Standard { 131 case "fa2", "": 132 if tr.TokenId, err = ctx.ResolveZ(recv["token_id"]); err != nil { 133 return fmt.Errorf("receiver[%d] amount: %v", i, err) 134 } 135 } 136 t.Receivers = append(t.Receivers, tr) 137 } 138 } 139 return 140 }