github.com/hashgraph/hedera-sdk-go/v2@v2.48.0/contract_update_transaction.go (about) 1 package hedera 2 3 /*- 4 * 5 * Hedera Go SDK 6 * 7 * Copyright (C) 2020 - 2024 Hedera Hashgraph, LLC 8 * 9 * Licensed under the Apache License, Version 2.0 (the "License"); 10 * you may not use this file except in compliance with the License. 11 * You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 * 21 */ 22 23 import ( 24 "time" 25 26 "google.golang.org/protobuf/types/known/wrapperspb" 27 28 "github.com/hashgraph/hedera-protobufs-go/services" 29 ) 30 31 // ContractUpdateTransaction is used to modify a smart contract instance to have the given parameter values. Any nil 32 // field is ignored (left unchanged). If only the contractInstanceExpirationTime is being modified, then no signature is 33 // needed on this transaction other than for the account paying for the transaction itself. But if any of the other 34 // fields are being modified, then it must be signed by the adminKey. The use of adminKey is not currently supported in 35 // this API, but in the future will be implemented to allow these fields to be modified, and also to make modifications 36 // to the state of the instance. If the contract is created with no admin key, then none of the fields can be changed 37 // that need an admin signature, and therefore no admin key can ever be added. So if there is no admin key, then things 38 // like the bytecode are immutable. But if there is an admin key, then they can be changed. 39 // 40 // For example, the admin key might be a threshold key, which requires 3 of 5 binding arbitration judges to agree before 41 // the bytecode can be changed. This can be used to add flexibility to the management of smart contract behavior. But 42 // this is optional. If the smart contract is created without an admin key, then such a key can never be added, and its 43 // bytecode will be immutable. 44 type ContractUpdateTransaction struct { 45 Transaction 46 contractID *ContractID 47 proxyAccountID *AccountID 48 bytecodeFileID *FileID 49 adminKey Key 50 autoRenewPeriod *time.Duration 51 expirationTime *time.Time 52 memo string 53 autoRenewAccountID *AccountID 54 maxAutomaticTokenAssociations int32 55 stakedAccountID *AccountID 56 stakedNodeID *int64 57 declineReward bool 58 } 59 60 // NewContractUpdateTransaction creates a ContractUpdateTransaction transaction which can be 61 // used to construct and execute a Contract Update Transaction. 62 // ContractUpdateTransaction is used to modify a smart contract instance to have the given parameter values. Any nil 63 // field is ignored (left unchanged). If only the contractInstanceExpirationTime is being modified, then no signature is 64 // needed on this transaction other than for the account paying for the transaction itself. But if any of the other 65 // fields are being modified, then it must be signed by the adminKey. The use of adminKey is not currently supported in 66 // this API, but in the future will be implemented to allow these fields to be modified, and also to make modifications 67 // to the state of the instance. If the contract is created with no admin key, then none of the fields can be changed 68 // that need an admin signature, and therefore no admin key can ever be added. So if there is no admin key, then things 69 // like the bytecode are immutable. But if there is an admin key, then they can be changed. 70 // 71 // For example, the admin key might be a threshold key, which requires 3 of 5 binding arbitration judges to agree before 72 // the bytecode can be changed. This can be used to add flexibility to the management of smart contract behavior. But 73 // this is optional. If the smart contract is created without an admin key, then such a key can never be added, and its 74 // bytecode will be immutable. 75 func NewContractUpdateTransaction() *ContractUpdateTransaction { 76 tx := ContractUpdateTransaction{ 77 Transaction: _NewTransaction(), 78 } 79 tx._SetDefaultMaxTransactionFee(NewHbar(2)) 80 81 return &tx 82 } 83 84 func _ContractUpdateTransactionFromProtobuf(tx Transaction, pb *services.TransactionBody) *ContractUpdateTransaction { 85 key, _ := _KeyFromProtobuf(pb.GetContractUpdateInstance().AdminKey) 86 autoRenew := _DurationFromProtobuf(pb.GetContractUpdateInstance().GetAutoRenewPeriod()) 87 expiration := _TimeFromProtobuf(pb.GetContractUpdateInstance().GetExpirationTime()) 88 var memo string 89 90 switch m := pb.GetContractUpdateInstance().GetMemoField().(type) { 91 case *services.ContractUpdateTransactionBody_Memo: 92 memo = m.Memo // nolint 93 case *services.ContractUpdateTransactionBody_MemoWrapper: 94 memo = m.MemoWrapper.Value 95 } 96 97 stakedNodeID := pb.GetContractUpdateInstance().GetStakedNodeId() 98 99 var stakeNodeAccountID *AccountID 100 if pb.GetContractUpdateInstance().GetStakedAccountId() != nil { 101 stakeNodeAccountID = _AccountIDFromProtobuf(pb.GetContractUpdateInstance().GetStakedAccountId()) 102 } 103 104 var autoRenewAccountID *AccountID 105 if pb.GetContractUpdateInstance().AutoRenewAccountId != nil { 106 autoRenewAccountID = _AccountIDFromProtobuf(pb.GetContractUpdateInstance().GetAutoRenewAccountId()) 107 } 108 109 return &ContractUpdateTransaction{ 110 Transaction: tx, 111 contractID: _ContractIDFromProtobuf(pb.GetContractUpdateInstance().GetContractID()), 112 adminKey: key, 113 autoRenewPeriod: &autoRenew, 114 expirationTime: &expiration, 115 memo: memo, 116 autoRenewAccountID: autoRenewAccountID, 117 maxAutomaticTokenAssociations: pb.GetContractUpdateInstance().MaxAutomaticTokenAssociations.GetValue(), 118 stakedAccountID: stakeNodeAccountID, 119 stakedNodeID: &stakedNodeID, 120 declineReward: pb.GetContractUpdateInstance().GetDeclineReward().GetValue(), 121 } 122 } 123 124 // SetContractID sets The Contract ID instance to update (this can't be changed on the contract) 125 func (tx *ContractUpdateTransaction) SetContractID(contractID ContractID) *ContractUpdateTransaction { 126 tx.contractID = &contractID 127 return tx 128 } 129 130 func (tx *ContractUpdateTransaction) GetContractID() ContractID { 131 if tx.contractID == nil { 132 return ContractID{} 133 } 134 135 return *tx.contractID 136 } 137 138 // Deprecated 139 func (tx *ContractUpdateTransaction) SetBytecodeFileID(bytecodeFileID FileID) *ContractUpdateTransaction { 140 tx._RequireNotFrozen() 141 tx.bytecodeFileID = &bytecodeFileID 142 return tx 143 } 144 145 // Deprecated 146 func (tx *ContractUpdateTransaction) GetBytecodeFileID() FileID { 147 if tx.bytecodeFileID == nil { 148 return FileID{} 149 } 150 151 return *tx.bytecodeFileID 152 } 153 154 // SetAdminKey sets the key which can be used to arbitrarily modify the state of the instance by signing a 155 // ContractUpdateTransaction to modify it. If the admin key was never set then such modifications are not possible, 156 // and there is no administrator that can overrIDe the normal operation of the smart contract instance. 157 func (tx *ContractUpdateTransaction) SetAdminKey(publicKey PublicKey) *ContractUpdateTransaction { 158 tx._RequireNotFrozen() 159 tx.adminKey = publicKey 160 return tx 161 } 162 163 func (tx *ContractUpdateTransaction) GetAdminKey() (Key, error) { 164 return tx.adminKey, nil 165 } 166 167 // Deprecated 168 // SetProxyAccountID sets the ID of the account to which this contract is proxy staked. If proxyAccountID is left unset, 169 // is an invalID account, or is an account that isn't a _Node, then this contract is automatically proxy staked to a _Node 170 // chosen by the _Network, but without earning payments. If the proxyAccountID account refuses to accept proxy staking, 171 // or if it is not currently running a _Node, then it will behave as if proxyAccountID was never set. 172 func (tx *ContractUpdateTransaction) SetProxyAccountID(proxyAccountID AccountID) *ContractUpdateTransaction { 173 tx._RequireNotFrozen() 174 tx.proxyAccountID = &proxyAccountID 175 return tx 176 } 177 178 // Deprecated 179 func (tx *ContractUpdateTransaction) GetProxyAccountID() AccountID { 180 if tx.proxyAccountID == nil { 181 return AccountID{} 182 } 183 184 return *tx.proxyAccountID 185 } 186 187 // SetAutoRenewPeriod sets the duration for which the contract instance will automatically charge its account to 188 // renew for. 189 func (tx *ContractUpdateTransaction) SetAutoRenewPeriod(autoRenewPeriod time.Duration) *ContractUpdateTransaction { 190 tx._RequireNotFrozen() 191 tx.autoRenewPeriod = &autoRenewPeriod 192 return tx 193 } 194 195 func (tx *ContractUpdateTransaction) GetAutoRenewPeriod() time.Duration { 196 if tx.autoRenewPeriod != nil { 197 return *tx.autoRenewPeriod 198 } 199 200 return time.Duration(0) 201 } 202 203 // SetExpirationTime extends the expiration of the instance and its account to the provIDed time. If the time provIDed 204 // is the current or past time, then there will be no effect. 205 func (tx *ContractUpdateTransaction) SetExpirationTime(expiration time.Time) *ContractUpdateTransaction { 206 tx._RequireNotFrozen() 207 tx.expirationTime = &expiration 208 return tx 209 } 210 211 func (tx *ContractUpdateTransaction) GetExpirationTime() time.Time { 212 if tx.expirationTime != nil { 213 return *tx.expirationTime 214 } 215 216 return time.Time{} 217 } 218 219 // SetContractMemo sets the memo associated with the contract (max 100 bytes) 220 func (tx *ContractUpdateTransaction) SetContractMemo(memo string) *ContractUpdateTransaction { 221 tx._RequireNotFrozen() 222 tx.memo = memo 223 // if transaction.pb.GetMemoWrapper() != nil { 224 // transaction.pb.GetMemoWrapper().Value = memo 225 // } else { 226 // transaction.pb.MemoField = &services.ContractUpdateTransactionBody_MemoWrapper{ 227 // MemoWrapper: &wrapperspb.StringValue{Value: memo}, 228 // } 229 // } 230 231 return tx 232 } 233 234 // SetAutoRenewAccountID 235 // An account to charge for auto-renewal of this contract. If not set, or set to an 236 // account with zero hbar balance, the contract's own hbar balance will be used to 237 // cover auto-renewal fees. 238 func (tx *ContractUpdateTransaction) SetAutoRenewAccountID(id AccountID) *ContractUpdateTransaction { 239 tx._RequireNotFrozen() 240 tx.autoRenewAccountID = &id 241 return tx 242 } 243 244 func (tx *ContractUpdateTransaction) GetAutoRenewAccountID() AccountID { 245 if tx.autoRenewAccountID == nil { 246 return AccountID{} 247 } 248 249 return *tx.autoRenewAccountID 250 } 251 252 // SetMaxAutomaticTokenAssociations 253 // The maximum number of tokens that this contract can be automatically associated 254 // with (i.e., receive air-drops from). 255 func (tx *ContractUpdateTransaction) SetMaxAutomaticTokenAssociations(max int32) *ContractUpdateTransaction { 256 tx._RequireNotFrozen() 257 tx.maxAutomaticTokenAssociations = max 258 return tx 259 } 260 261 func (tx *ContractUpdateTransaction) GetMaxAutomaticTokenAssociations() int32 { 262 return tx.maxAutomaticTokenAssociations 263 } 264 265 func (tx *ContractUpdateTransaction) GetContractMemo() string { 266 return tx.memo 267 } 268 269 func (tx *ContractUpdateTransaction) SetStakedAccountID(id AccountID) *ContractUpdateTransaction { 270 tx._RequireNotFrozen() 271 tx.stakedAccountID = &id 272 return tx 273 } 274 275 func (tx *ContractUpdateTransaction) GetStakedAccountID() AccountID { 276 if tx.stakedAccountID != nil { 277 return *tx.stakedAccountID 278 } 279 280 return AccountID{} 281 } 282 283 func (tx *ContractUpdateTransaction) SetStakedNodeID(id int64) *ContractUpdateTransaction { 284 tx._RequireNotFrozen() 285 tx.stakedNodeID = &id 286 return tx 287 } 288 289 func (tx *ContractUpdateTransaction) GetStakedNodeID() int64 { 290 if tx.stakedNodeID != nil { 291 return *tx.stakedNodeID 292 } 293 294 return 0 295 } 296 297 func (tx *ContractUpdateTransaction) SetDeclineStakingReward(decline bool) *ContractUpdateTransaction { 298 tx._RequireNotFrozen() 299 tx.declineReward = decline 300 return tx 301 } 302 303 func (tx *ContractUpdateTransaction) GetDeclineStakingReward() bool { 304 return tx.declineReward 305 } 306 307 func (tx *ContractUpdateTransaction) ClearStakedAccountID() *ContractUpdateTransaction { 308 tx._RequireNotFrozen() 309 tx.stakedAccountID = &AccountID{Account: 0} 310 return tx 311 } 312 313 func (tx *ContractUpdateTransaction) ClearStakedNodeID() *ContractUpdateTransaction { 314 tx._RequireNotFrozen() 315 *tx.stakedNodeID = -1 316 return tx 317 } 318 319 // ---- Required Interfaces ---- // 320 321 // Sign uses the provided privateKey to sign the transaction. 322 func (tx *ContractUpdateTransaction) Sign( 323 privateKey PrivateKey, 324 ) *ContractUpdateTransaction { 325 tx.Transaction.Sign(privateKey) 326 return tx 327 } 328 329 // SignWithOperator signs the transaction with client's operator privateKey. 330 func (tx *ContractUpdateTransaction) SignWithOperator( 331 client *Client, 332 ) (*ContractUpdateTransaction, error) { 333 // If the transaction is not signed by the _Operator, we need 334 // to sign the transaction with the _Operator 335 _, err := tx.Transaction.signWithOperator(client, tx) 336 if err != nil { 337 return nil, err 338 } 339 return tx, nil 340 } 341 342 // SignWith executes the TransactionSigner and adds the resulting signature data to the Transaction's signature map 343 // with the publicKey as the map key. 344 func (tx *ContractUpdateTransaction) SignWith( 345 publicKey PublicKey, 346 signer TransactionSigner, 347 ) *ContractUpdateTransaction { 348 tx.Transaction.SignWith(publicKey, signer) 349 return tx 350 } 351 352 // AddSignature adds a signature to the transaction. 353 func (tx *ContractUpdateTransaction) AddSignature(publicKey PublicKey, signature []byte) *ContractUpdateTransaction { 354 tx.Transaction.AddSignature(publicKey, signature) 355 return tx 356 } 357 358 // When execution is attempted, a single attempt will timeout when tx deadline is reached. (The SDK may subsequently retry the execution.) 359 func (tx *ContractUpdateTransaction) SetGrpcDeadline(deadline *time.Duration) *ContractUpdateTransaction { 360 tx.Transaction.SetGrpcDeadline(deadline) 361 return tx 362 } 363 364 func (tx *ContractUpdateTransaction) Freeze() (*ContractUpdateTransaction, error) { 365 return tx.FreezeWith(nil) 366 } 367 368 func (tx *ContractUpdateTransaction) FreezeWith(client *Client) (*ContractUpdateTransaction, error) { 369 _, err := tx.Transaction.freezeWith(client, tx) 370 return tx, err 371 } 372 373 // SetMaxTransactionFee sets the maximum transaction fee the operator (paying account) is willing to pay. 374 func (tx *ContractUpdateTransaction) SetMaxTransactionFee(fee Hbar) *ContractUpdateTransaction { 375 tx._RequireNotFrozen() 376 tx.Transaction.SetMaxTransactionFee(fee) 377 return tx 378 } 379 380 // SetRegenerateTransactionID sets if transaction IDs should be regenerated when `TRANSACTION_EXPIRED` is received 381 func (tx *ContractUpdateTransaction) SetRegenerateTransactionID(regenerateTransactionID bool) *ContractUpdateTransaction { 382 tx._RequireNotFrozen() 383 tx.Transaction.SetRegenerateTransactionID(regenerateTransactionID) 384 return tx 385 } 386 387 // SetTransactionMemo sets the memo for this ContractUpdateTransaction. 388 func (tx *ContractUpdateTransaction) SetTransactionMemo(memo string) *ContractUpdateTransaction { 389 tx._RequireNotFrozen() 390 tx.Transaction.SetTransactionMemo(memo) 391 return tx 392 } 393 394 // SetTransactionValidDuration sets the valid duration for this ContractUpdateTransaction. 395 func (tx *ContractUpdateTransaction) SetTransactionValidDuration(duration time.Duration) *ContractUpdateTransaction { 396 tx._RequireNotFrozen() 397 tx.Transaction.SetTransactionValidDuration(duration) 398 return tx 399 } 400 401 // ToBytes serialise the tx to bytes, no matter if it is signed (locked), or not 402 func (tx *ContractUpdateTransaction) ToBytes() ([]byte, error) { 403 bytes, err := tx.Transaction.toBytes(tx) 404 if err != nil { 405 return nil, err 406 } 407 return bytes, nil 408 } 409 410 // SetTransactionID sets the TransactionID for this ContractUpdateTransaction. 411 func (tx *ContractUpdateTransaction) SetTransactionID(transactionID TransactionID) *ContractUpdateTransaction { 412 tx._RequireNotFrozen() 413 414 tx.Transaction.SetTransactionID(transactionID) 415 return tx 416 } 417 418 // SetNodeAccountID sets the _Node AccountID for this ContractUpdateTransaction. 419 func (tx *ContractUpdateTransaction) SetNodeAccountIDs(nodeID []AccountID) *ContractUpdateTransaction { 420 tx._RequireNotFrozen() 421 tx.Transaction.SetNodeAccountIDs(nodeID) 422 return tx 423 } 424 425 // SetMaxRetry sets the max number of errors before execution will fail. 426 func (tx *ContractUpdateTransaction) SetMaxRetry(count int) *ContractUpdateTransaction { 427 tx.Transaction.SetMaxRetry(count) 428 return tx 429 } 430 431 // SetMaxBackoff The maximum amount of time to wait between retries. 432 // Every retry attempt will increase the wait time exponentially until it reaches this time. 433 func (tx *ContractUpdateTransaction) SetMaxBackoff(max time.Duration) *ContractUpdateTransaction { 434 tx.Transaction.SetMaxBackoff(max) 435 return tx 436 } 437 438 // SetMinBackoff sets the minimum amount of time to wait between retries. 439 func (tx *ContractUpdateTransaction) SetMinBackoff(min time.Duration) *ContractUpdateTransaction { 440 tx.Transaction.SetMinBackoff(min) 441 return tx 442 } 443 444 func (tx *ContractUpdateTransaction) SetLogLevel(level LogLevel) *ContractUpdateTransaction { 445 tx.Transaction.SetLogLevel(level) 446 return tx 447 } 448 449 func (tx *ContractUpdateTransaction) Execute(client *Client) (TransactionResponse, error) { 450 return tx.Transaction.execute(client, tx) 451 } 452 453 func (tx *ContractUpdateTransaction) Schedule() (*ScheduleCreateTransaction, error) { 454 return tx.Transaction.schedule(tx) 455 } 456 457 // ----------- Overridden functions ---------------- 458 459 func (tx *ContractUpdateTransaction) getName() string { 460 return "ContractUpdateTransaction" 461 } 462 463 func (tx *ContractUpdateTransaction) validateNetworkOnIDs(client *Client) error { 464 if client == nil || !client.autoValidateChecksums { 465 return nil 466 } 467 468 if tx.contractID != nil { 469 if err := tx.contractID.ValidateChecksum(client); err != nil { 470 return err 471 } 472 } 473 474 if tx.proxyAccountID != nil { 475 if err := tx.proxyAccountID.ValidateChecksum(client); err != nil { 476 return err 477 } 478 } 479 480 return nil 481 } 482 483 func (tx *ContractUpdateTransaction) build() *services.TransactionBody { 484 return &services.TransactionBody{ 485 TransactionFee: tx.transactionFee, 486 Memo: tx.Transaction.memo, 487 TransactionValidDuration: _DurationToProtobuf(tx.GetTransactionValidDuration()), 488 TransactionID: tx.transactionID._ToProtobuf(), 489 Data: &services.TransactionBody_ContractUpdateInstance{ 490 ContractUpdateInstance: tx.buildProtoBody(), 491 }, 492 } 493 } 494 495 func (tx *ContractUpdateTransaction) buildScheduled() (*services.SchedulableTransactionBody, error) { 496 return &services.SchedulableTransactionBody{ 497 TransactionFee: tx.transactionFee, 498 Memo: tx.Transaction.memo, 499 Data: &services.SchedulableTransactionBody_ContractUpdateInstance{ 500 ContractUpdateInstance: tx.buildProtoBody(), 501 }, 502 }, nil 503 } 504 505 func (tx *ContractUpdateTransaction) buildProtoBody() *services.ContractUpdateTransactionBody { 506 body := &services.ContractUpdateTransactionBody{ 507 DeclineReward: &wrapperspb.BoolValue{Value: tx.declineReward}, 508 } 509 510 if tx.maxAutomaticTokenAssociations != 0 { 511 body.MaxAutomaticTokenAssociations = &wrapperspb.Int32Value{Value: tx.maxAutomaticTokenAssociations} 512 } 513 514 if tx.expirationTime != nil { 515 body.ExpirationTime = _TimeToProtobuf(*tx.expirationTime) 516 } 517 518 if tx.autoRenewPeriod != nil { 519 body.AutoRenewPeriod = _DurationToProtobuf(*tx.autoRenewPeriod) 520 } 521 522 if tx.adminKey != nil { 523 body.AdminKey = tx.adminKey._ToProtoKey() 524 } 525 526 if tx.contractID != nil { 527 body.ContractID = tx.contractID._ToProtobuf() 528 } 529 530 if tx.autoRenewAccountID != nil { 531 body.AutoRenewAccountId = tx.autoRenewAccountID._ToProtobuf() 532 } 533 534 if body.GetMemoWrapper() != nil { 535 body.GetMemoWrapper().Value = tx.memo 536 } else { 537 body.MemoField = &services.ContractUpdateTransactionBody_MemoWrapper{ 538 MemoWrapper: &wrapperspb.StringValue{Value: tx.memo}, 539 } 540 } 541 542 if tx.adminKey != nil { 543 body.AdminKey = tx.adminKey._ToProtoKey() 544 } 545 546 if tx.contractID != nil { 547 body.ContractID = tx.contractID._ToProtobuf() 548 } 549 550 if tx.stakedAccountID != nil { 551 body.StakedId = &services.ContractUpdateTransactionBody_StakedAccountId{StakedAccountId: tx.stakedAccountID._ToProtobuf()} 552 } else if tx.stakedNodeID != nil { 553 body.StakedId = &services.ContractUpdateTransactionBody_StakedNodeId{StakedNodeId: *tx.stakedNodeID} 554 } 555 556 return body 557 } 558 559 func (tx *ContractUpdateTransaction) getMethod(channel *_Channel) _Method { 560 return _Method{ 561 transaction: channel._GetContract().UpdateContract, 562 } 563 } 564 func (tx *ContractUpdateTransaction) _ConstructScheduleProtobuf() (*services.SchedulableTransactionBody, error) { 565 return tx.buildScheduled() 566 }