|
| 1 | +package transaction |
| 2 | + |
| 3 | +import ( |
| 4 | +"encoding/hex" |
| 5 | +"errors" |
| 6 | + |
| 7 | +"github.com/CodeChain-io/codechain-sdk-go/core" |
| 8 | +"github.com/CodeChain-io/codechain-sdk-go/crypto" |
| 9 | +"github.com/CodeChain-io/codechain-sdk-go/key" |
| 10 | +"github.com/CodeChain-io/codechain-sdk-go/primitives" |
| 11 | +"github.com/ethereum/go-ethereum/rlp" |
| 12 | +) |
| 13 | + |
| 14 | +type AssetTransferTransactionJSON struct { |
| 15 | +NetworkID string `json:"networkId"` |
| 16 | +Burns []core.AssetTransferInputJSON `json:"burns"` |
| 17 | +Inputs []core.AssetTransferInputJSON `json:"inputs"` |
| 18 | +Outputs []core.AssetTransferOutputJSON `json:"outputs"` |
| 19 | +} |
| 20 | + |
| 21 | +type TransferAssetActionJSON struct { |
| 22 | +AssetTransferTransactionJSON |
| 23 | +Metadata string `json:"metadata"` |
| 24 | +Approvals []string `json:"aprovals"` |
| 25 | +Expiration int `json:"expiration:omitempty"` |
| 26 | +} |
| 27 | + |
| 28 | +type TransferAsset struct { |
| 29 | +core.Transaction |
| 30 | +Burns []core.AssetTransferInput |
| 31 | +Inputs []core.AssetTransferInput |
| 32 | +Outputs []core.AssetTransferOutput |
| 33 | +Approvals []string |
| 34 | +Metadata string |
| 35 | +Expiration *int |
| 36 | +} |
| 37 | + |
| 38 | +func NewTransferAsset( |
| 39 | +burns []core.AssetTransferInput, |
| 40 | +inputs []core.AssetTransferInput, |
| 41 | +outputs []core.AssetTransferOutput, |
| 42 | +networkID string, |
| 43 | +metadata string, |
| 44 | +approvals []string, |
| 45 | +expiration *int) TransferAsset { |
| 46 | + |
| 47 | +tx := core.NewTransaction(networkID) |
| 48 | +return TransferAsset{tx, burns, inputs, outputs, approvals, metadata, expiration} |
| 49 | +} |
| 50 | + |
| 51 | +func (t TransferAsset) Tracker() primitives.H256 { |
| 52 | +hash, _ := crypto.Blake256(t.ActionRlpBytes()) |
| 53 | +return primitives.NewH256(hash) |
| 54 | +} |
| 55 | + |
| 56 | +func (t *TransferAsset) AddApproval(approval string) { |
| 57 | +t.Approvals = append(t.Approvals, approval) |
| 58 | +} |
| 59 | + |
| 60 | +func (t *TransferAsset) AddBurn(burn core.AssetTransferInput) { |
| 61 | +t.Burns = append(t.Burns, burn) |
| 62 | +} |
| 63 | + |
| 64 | +func (t *TransferAsset) AddBurns(burns []core.AssetTransferInput) { |
| 65 | +t.Burns = append(t.Burns, burns...) |
| 66 | +} |
| 67 | + |
| 68 | +func (t *TransferAsset) AddBurnWithAsset(asset core.Asset) { |
| 69 | +t.Burns = append(t.Burns, asset.CreateTransferInput()) |
| 70 | +} |
| 71 | + |
| 72 | +func (t *TransferAsset) AddBurnsWithAsset(assets []core.Asset) { |
| 73 | + |
| 74 | +burns := make([]core.AssetTransferInput, len(assets)) |
| 75 | +for i, d := range assets { |
| 76 | +burns[i] = d.CreateTransferInput() |
| 77 | +} |
| 78 | +t.Burns = append(t.Burns, burns...) |
| 79 | +} |
| 80 | + |
| 81 | +func (t *TransferAsset) AddInput(input core.AssetTransferInput) { |
| 82 | +t.Inputs = append(t.Inputs, input) |
| 83 | +} |
| 84 | + |
| 85 | +func (t *TransferAsset) AddInputs(inputs []core.AssetTransferInput) { |
| 86 | +t.Inputs = append(t.Inputs, inputs...) |
| 87 | +} |
| 88 | + |
| 89 | +func (t *TransferAsset) AddInputWithAsset(asset core.Asset) { |
| 90 | +t.Inputs = append(t.Inputs, asset.CreateTransferInput()) |
| 91 | +} |
| 92 | + |
| 93 | +func (t *TransferAsset) AddInputsWithAsset(assets []core.Asset) { |
| 94 | + |
| 95 | +inputs := make([]core.AssetTransferInput, len(assets)) |
| 96 | +for i, d := range assets { |
| 97 | +inputs[i] = d.CreateTransferInput() |
| 98 | +} |
| 99 | +t.Inputs = append(t.Inputs, inputs...) |
| 100 | +} |
| 101 | + |
| 102 | +func (t *TransferAsset) AddOutputs(outputs []core.AssetTransferOutput) TransferAsset { |
| 103 | +t.Outputs = append(t.Outputs, outputs...) |
| 104 | +return *t |
| 105 | +} |
| 106 | + |
| 107 | +func (t TransferAsset) ToEncodeObject() []interface{} { |
| 108 | +actionEncode := t.ActionToEncodeObject() |
| 109 | + |
| 110 | +actionEncode = append(actionEncode, t.Metadata) |
| 111 | +actionEncode = append(actionEncode, t.Approvals) |
| 112 | +if t.Expiration != nil { |
| 113 | +actionEncode = append(actionEncode, []interface{}{t.Expiration}) |
| 114 | +} else { |
| 115 | +actionEncode = append(actionEncode, []interface{}{}) |
| 116 | +} |
| 117 | + |
| 118 | +return []interface{}{t.Seq(), t.Fee().ToEncodeObject(), t.NetworkID(), actionEncode} |
| 119 | + |
| 120 | +} |
| 121 | + |
| 122 | +func (t TransferAsset) ActionToEncodeObject() []interface{} { |
| 123 | +burns := make([][]interface{}, len(t.Burns)) |
| 124 | +for i, d := range t.Burns { |
| 125 | +res := d.ToEncodeObject() |
| 126 | +burns[i] = res |
| 127 | +} |
| 128 | + |
| 129 | +inputs := make([][]interface{}, len(t.Inputs)) |
| 130 | +for i, d := range t.Inputs { |
| 131 | +res := d.ToEncodeObject() |
| 132 | +inputs[i] = res |
| 133 | +} |
| 134 | + |
| 135 | +outputs := make([][]interface{}, len(t.Outputs)) |
| 136 | +for i, d := range t.Outputs { |
| 137 | +res := d.ToEncodeObject() |
| 138 | +outputs[i] = res |
| 139 | +} |
| 140 | + |
| 141 | +return []interface{}{ |
| 142 | +uint(0x14), |
| 143 | +t.Transaction.NetworkID(), |
| 144 | +burns, |
| 145 | +inputs, |
| 146 | +outputs, |
| 147 | +[]interface{}{}} |
| 148 | +} |
| 149 | + |
| 150 | +func (t TransferAsset) GetTransferredAsset(index int) core.Asset { |
| 151 | +output := t.Outputs[index] |
| 152 | + |
| 153 | +parameters := make([]string, len(output.Parameters)) |
| 154 | +for i, d := range output.Parameters { |
| 155 | +res := hex.EncodeToString(d) |
| 156 | +parameters[i] = res |
| 157 | +} |
| 158 | + |
| 159 | +return core.NewAsset(output.AssetType, |
| 160 | +output.ShardID, |
| 161 | +output.LockScriptHash, |
| 162 | +parameters, |
| 163 | +output.Quantity, |
| 164 | +t.Tracker(), |
| 165 | +uint(index)) |
| 166 | +} |
| 167 | + |
| 168 | +func (t TransferAsset) GetTransferredAssets() []core.Asset { |
| 169 | +assets := make([]core.Asset, len(t.Outputs)) |
| 170 | +for i := range t.Outputs { |
| 171 | +assets[i] = t.GetTransferredAsset(i) |
| 172 | +} |
| 173 | +return assets |
| 174 | +} |
| 175 | + |
| 176 | +func (t TransferAsset) HashWithoutScript() primitives.H256 { |
| 177 | +inputs := make([]core.AssetTransferInput, len(t.Inputs)) |
| 178 | +for i, d := range t.Inputs { |
| 179 | +inputs[i] = d.WithOutScript() |
| 180 | +} |
| 181 | + |
| 182 | +burns := make([]core.AssetTransferInput, len(t.Burns)) |
| 183 | +for i, d := range t.Burns { |
| 184 | +burns[i] = d.WithOutScript() |
| 185 | +} |
| 186 | + |
| 187 | +outputs := t.Outputs |
| 188 | + |
| 189 | +t = NewTransferAsset(burns, inputs, outputs, t.NetworkID(), "", []string{}, nil) |
| 190 | +hashKey, _ := crypto.Blake128([]byte{3}) |
| 191 | + |
| 192 | +blake, _ := crypto.Blake256WithKey(t.ActionRlpBytes(), hashKey) |
| 193 | + |
| 194 | +return primitives.NewH256(blake) |
| 195 | +} |
| 196 | + |
| 197 | +func (t TransferAsset) ActionRlpBytes() []byte { |
| 198 | +res, _ := rlp.EncodeToBytes(t.ActionToEncodeObject()) |
| 199 | +return res |
| 200 | +} |
| 201 | + |
| 202 | +func (t TransferAsset) ActionToJSON() interface{} { |
| 203 | +burns := make([]core.AssetTransferInputJSON, len(t.Burns)) |
| 204 | +for i, d := range t.Burns { |
| 205 | +res := d.ToJSON() |
| 206 | +burns[i] = res |
| 207 | +} |
| 208 | + |
| 209 | +inputs := make([]core.AssetTransferInputJSON, len(t.Inputs)) |
| 210 | +for i, d := range t.Inputs { |
| 211 | +res := d.ToJSON() |
| 212 | +inputs[i] = res |
| 213 | +} |
| 214 | + |
| 215 | +outputs := make([]core.AssetTransferOutputJSON, len(t.Outputs)) |
| 216 | +for i, d := range t.Outputs { |
| 217 | +res := d.ToJSON() |
| 218 | +outputs[i] = res |
| 219 | +} |
| 220 | + |
| 221 | +return AssetTransferTransactionJSON{t.NetworkID(), burns, inputs, outputs} |
| 222 | +} |
| 223 | + |
| 224 | +func (t TransferAsset) UnsignedHash() primitives.H256 { |
| 225 | +hash, _ := crypto.Blake256(t.RlpBytes()) |
| 226 | + |
| 227 | +var value [32]byte |
| 228 | +copy(value[:], hash[:32]) |
| 229 | +return primitives.H256(value) |
| 230 | +} |
| 231 | + |
| 232 | +func (t TransferAsset) RlpBytes() []byte { |
| 233 | +x, _ := rlp.EncodeToBytes(t.ToEncodeObject()) |
| 234 | +return x |
| 235 | +} |
| 236 | + |
| 237 | +func (t *TransferAsset) Sign(secret primitives.H256, seq uint, fee primitives.U64) core.SignedTransaction { |
| 238 | +t.SetSeq(seq) |
| 239 | +t.SetFee(fee) |
| 240 | +sig := crypto.SignEcdsa(t.UnsignedHash().Bytes(), secret.Bytes()) |
| 241 | + |
| 242 | +return core.NewSignedTransaction(t, sig, nil, nil, nil) |
| 243 | +} |
| 244 | + |
| 245 | +func (t TransferAsset) GetType() string { |
| 246 | +return "transferAsset" |
| 247 | +} |
| 248 | + |
| 249 | +func (t *TransferAsset) SignTransactionInput(index int, pubkey []byte, privkey []byte) error { |
| 250 | + |
| 251 | +parameters := t.Inputs[index].PrevOut.Parameters |
| 252 | +parameter := hex.EncodeToString(parameters[0]) |
| 253 | +pubkeyhsh, _ := crypto.Blake160(pubkey) |
| 254 | +if parameter != hex.EncodeToString(pubkeyhsh) { |
| 255 | +return errors.New("Wrong Publick Key") |
| 256 | +} |
| 257 | + |
| 258 | +scriptOpcode := key.GetP2PKHLockScript() |
| 259 | +opcode := make([]byte, len(scriptOpcode)) |
| 260 | +for i, d := range scriptOpcode { |
| 261 | +opcode[i] = byte(d) |
| 262 | +} |
| 263 | + |
| 264 | +t.Inputs[index].SetLockScript(opcode) |
| 265 | + |
| 266 | +message := t.HashWithoutScript() |
| 267 | + |
| 268 | +script := key.CreateP2PKHUnlockScript(pubkey, privkey, message) |
| 269 | + |
| 270 | +bytescript := make([]byte, len(script)) |
| 271 | +for i, d := range script { |
| 272 | +bytescript[i] = byte(d) |
| 273 | +} |
| 274 | +t.Inputs[index].SetUnlockScript(bytescript) |
| 275 | + |
| 276 | +return nil |
| 277 | +} |
0 commit comments