github.com/MetalBlockchain/metalgo@v1.11.9/wallet/chain/p/wallet.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package p 5 6 import ( 7 "errors" 8 "time" 9 10 "github.com/MetalBlockchain/metalgo/ids" 11 "github.com/MetalBlockchain/metalgo/vms/components/avax" 12 "github.com/MetalBlockchain/metalgo/vms/platformvm" 13 "github.com/MetalBlockchain/metalgo/vms/platformvm/txs" 14 "github.com/MetalBlockchain/metalgo/vms/secp256k1fx" 15 "github.com/MetalBlockchain/metalgo/wallet/chain/p/builder" 16 "github.com/MetalBlockchain/metalgo/wallet/subnet/primary/common" 17 18 vmsigner "github.com/MetalBlockchain/metalgo/vms/platformvm/signer" 19 walletsigner "github.com/MetalBlockchain/metalgo/wallet/chain/p/signer" 20 ) 21 22 var ( 23 ErrNotCommitted = errors.New("not committed") 24 25 _ Wallet = (*wallet)(nil) 26 ) 27 28 type Wallet interface { 29 // Builder returns the builder that will be used to create the transactions. 30 Builder() builder.Builder 31 32 // Signer returns the signer that will be used to sign the transactions. 33 Signer() walletsigner.Signer 34 35 // IssueBaseTx creates, signs, and issues a new simple value transfer. 36 // 37 // - [outputs] specifies all the recipients and amounts that should be sent 38 // from this transaction. 39 IssueBaseTx( 40 outputs []*avax.TransferableOutput, 41 options ...common.Option, 42 ) (*txs.Tx, error) 43 44 // IssueAddValidatorTx creates, signs, and issues a new validator of the 45 // primary network. 46 // 47 // - [vdr] specifies all the details of the validation period such as the 48 // startTime, endTime, stake weight, and nodeID. 49 // - [rewardsOwner] specifies the owner of all the rewards this validator 50 // may accrue during its validation period. 51 // - [shares] specifies the fraction (out of 1,000,000) that this validator 52 // will take from delegation rewards. If 1,000,000 is provided, 100% of 53 // the delegation reward will be sent to the validator's [rewardsOwner]. 54 IssueAddValidatorTx( 55 vdr *txs.Validator, 56 rewardsOwner *secp256k1fx.OutputOwners, 57 shares uint32, 58 options ...common.Option, 59 ) (*txs.Tx, error) 60 61 // IssueAddSubnetValidatorTx creates, signs, and issues a new validator of a 62 // subnet. 63 // 64 // - [vdr] specifies all the details of the validation period such as the 65 // startTime, endTime, sampling weight, nodeID, and subnetID. 66 IssueAddSubnetValidatorTx( 67 vdr *txs.SubnetValidator, 68 options ...common.Option, 69 ) (*txs.Tx, error) 70 71 // IssueAddSubnetValidatorTx creates, signs, and issues a transaction that 72 // removes a validator of a subnet. 73 // 74 // - [nodeID] is the validator being removed from [subnetID]. 75 IssueRemoveSubnetValidatorTx( 76 nodeID ids.NodeID, 77 subnetID ids.ID, 78 options ...common.Option, 79 ) (*txs.Tx, error) 80 81 // IssueAddDelegatorTx creates, signs, and issues a new delegator to a 82 // validator on the primary network. 83 // 84 // - [vdr] specifies all the details of the delegation period such as the 85 // startTime, endTime, stake weight, and validator's nodeID. 86 // - [rewardsOwner] specifies the owner of all the rewards this delegator 87 // may accrue at the end of its delegation period. 88 IssueAddDelegatorTx( 89 vdr *txs.Validator, 90 rewardsOwner *secp256k1fx.OutputOwners, 91 options ...common.Option, 92 ) (*txs.Tx, error) 93 94 // IssueCreateChainTx creates, signs, and issues a new chain in the named 95 // subnet. 96 // 97 // - [subnetID] specifies the subnet to launch the chain in. 98 // - [genesis] specifies the initial state of the new chain. 99 // - [vmID] specifies the vm that the new chain will run. 100 // - [fxIDs] specifies all the feature extensions that the vm should be 101 // running with. 102 // - [chainName] specifies a human readable name for the chain. 103 IssueCreateChainTx( 104 subnetID ids.ID, 105 genesis []byte, 106 vmID ids.ID, 107 fxIDs []ids.ID, 108 chainName string, 109 options ...common.Option, 110 ) (*txs.Tx, error) 111 112 // IssueCreateSubnetTx creates, signs, and issues a new subnet with the 113 // specified owner. 114 // 115 // - [owner] specifies who has the ability to create new chains and add new 116 // validators to the subnet. 117 IssueCreateSubnetTx( 118 owner *secp256k1fx.OutputOwners, 119 options ...common.Option, 120 ) (*txs.Tx, error) 121 122 // IssueTransferSubnetOwnershipTx creates, signs, and issues a transaction that 123 // changes the owner of the named subnet. 124 // 125 // - [subnetID] specifies the subnet to be modified 126 // - [owner] specifies who has the ability to create new chains and add new 127 // validators to the subnet. 128 IssueTransferSubnetOwnershipTx( 129 subnetID ids.ID, 130 owner *secp256k1fx.OutputOwners, 131 options ...common.Option, 132 ) (*txs.Tx, error) 133 134 // IssueImportTx creates, signs, and issues an import transaction that 135 // attempts to consume all the available UTXOs and import the funds to [to]. 136 // 137 // - [chainID] specifies the chain to be importing funds from. 138 // - [to] specifies where to send the imported funds to. 139 IssueImportTx( 140 chainID ids.ID, 141 to *secp256k1fx.OutputOwners, 142 options ...common.Option, 143 ) (*txs.Tx, error) 144 145 // IssueExportTx creates, signs, and issues an export transaction that 146 // attempts to send all the provided [outputs] to the requested [chainID]. 147 // 148 // - [chainID] specifies the chain to be exporting the funds to. 149 // - [outputs] specifies the outputs to send to the [chainID]. 150 IssueExportTx( 151 chainID ids.ID, 152 outputs []*avax.TransferableOutput, 153 options ...common.Option, 154 ) (*txs.Tx, error) 155 156 // IssueTransformSubnetTx creates a transform subnet transaction that attempts 157 // to convert the provided [subnetID] from a permissioned subnet to a 158 // permissionless subnet. This transaction will convert 159 // [maxSupply] - [initialSupply] of [assetID] to staking rewards. 160 // 161 // - [subnetID] specifies the subnet to transform. 162 // - [assetID] specifies the asset to use to reward stakers on the subnet. 163 // - [initialSupply] is the amount of [assetID] that will be in circulation 164 // after this transaction is accepted. 165 // - [maxSupply] is the maximum total amount of [assetID] that should ever 166 // exist. 167 // - [minConsumptionRate] is the rate that a staker will receive rewards 168 // if they stake with a duration of 0. 169 // - [maxConsumptionRate] is the maximum rate that staking rewards should be 170 // consumed from the reward pool per year. 171 // - [minValidatorStake] is the minimum amount of funds required to become a 172 // validator. 173 // - [maxValidatorStake] is the maximum amount of funds a single validator 174 // can be allocated, including delegated funds. 175 // - [minStakeDuration] is the minimum number of seconds a staker can stake 176 // for. 177 // - [maxStakeDuration] is the maximum number of seconds a staker can stake 178 // for. 179 // - [minValidatorStake] is the minimum amount of funds required to become a 180 // delegator. 181 // - [maxValidatorWeightFactor] is the factor which calculates the maximum 182 // amount of delegation a validator can receive. A value of 1 effectively 183 // disables delegation. 184 // - [uptimeRequirement] is the minimum percentage a validator must be 185 // online and responsive to receive a reward. 186 IssueTransformSubnetTx( 187 subnetID ids.ID, 188 assetID ids.ID, 189 initialSupply uint64, 190 maxSupply uint64, 191 minConsumptionRate uint64, 192 maxConsumptionRate uint64, 193 minValidatorStake uint64, 194 maxValidatorStake uint64, 195 minStakeDuration time.Duration, 196 maxStakeDuration time.Duration, 197 minDelegationFee uint32, 198 minDelegatorStake uint64, 199 maxValidatorWeightFactor byte, 200 uptimeRequirement uint32, 201 options ...common.Option, 202 ) (*txs.Tx, error) 203 204 // IssueAddPermissionlessValidatorTx creates, signs, and issues a new 205 // validator of the specified subnet. 206 // 207 // - [vdr] specifies all the details of the validation period such as the 208 // subnetID, startTime, endTime, stake weight, and nodeID. 209 // - [signer] if the subnetID is the primary network, this is the BLS key 210 // for this validator. Otherwise, this value should be the empty signer. 211 // - [assetID] specifies the asset to stake. 212 // - [validationRewardsOwner] specifies the owner of all the rewards this 213 // validator earns for its validation period. 214 // - [delegationRewardsOwner] specifies the owner of all the rewards this 215 // validator earns for delegations during its validation period. 216 // - [shares] specifies the fraction (out of 1,000,000) that this validator 217 // will take from delegation rewards. If 1,000,000 is provided, 100% of 218 // the delegation reward will be sent to the validator's [rewardsOwner]. 219 IssueAddPermissionlessValidatorTx( 220 vdr *txs.SubnetValidator, 221 signer vmsigner.Signer, 222 assetID ids.ID, 223 validationRewardsOwner *secp256k1fx.OutputOwners, 224 delegationRewardsOwner *secp256k1fx.OutputOwners, 225 shares uint32, 226 options ...common.Option, 227 ) (*txs.Tx, error) 228 229 // IssueAddPermissionlessDelegatorTx creates, signs, and issues a new 230 // delegator of the specified subnet on the specified nodeID. 231 // 232 // - [vdr] specifies all the details of the delegation period such as the 233 // subnetID, startTime, endTime, stake weight, and nodeID. 234 // - [assetID] specifies the asset to stake. 235 // - [rewardsOwner] specifies the owner of all the rewards this delegator 236 // earns during its delegation period. 237 IssueAddPermissionlessDelegatorTx( 238 vdr *txs.SubnetValidator, 239 assetID ids.ID, 240 rewardsOwner *secp256k1fx.OutputOwners, 241 options ...common.Option, 242 ) (*txs.Tx, error) 243 244 // IssueUnsignedTx signs and issues the unsigned tx. 245 IssueUnsignedTx( 246 utx txs.UnsignedTx, 247 options ...common.Option, 248 ) (*txs.Tx, error) 249 250 // IssueTx issues the signed tx. 251 IssueTx( 252 tx *txs.Tx, 253 options ...common.Option, 254 ) error 255 } 256 257 func NewWallet( 258 builder builder.Builder, 259 signer walletsigner.Signer, 260 client platformvm.Client, 261 backend Backend, 262 ) Wallet { 263 return &wallet{ 264 Backend: backend, 265 builder: builder, 266 signer: signer, 267 client: client, 268 } 269 } 270 271 type wallet struct { 272 Backend 273 builder builder.Builder 274 signer walletsigner.Signer 275 client platformvm.Client 276 } 277 278 func (w *wallet) Builder() builder.Builder { 279 return w.builder 280 } 281 282 func (w *wallet) Signer() walletsigner.Signer { 283 return w.signer 284 } 285 286 func (w *wallet) IssueBaseTx( 287 outputs []*avax.TransferableOutput, 288 options ...common.Option, 289 ) (*txs.Tx, error) { 290 utx, err := w.builder.NewBaseTx(outputs, options...) 291 if err != nil { 292 return nil, err 293 } 294 return w.IssueUnsignedTx(utx, options...) 295 } 296 297 func (w *wallet) IssueAddValidatorTx( 298 vdr *txs.Validator, 299 rewardsOwner *secp256k1fx.OutputOwners, 300 shares uint32, 301 options ...common.Option, 302 ) (*txs.Tx, error) { 303 utx, err := w.builder.NewAddValidatorTx(vdr, rewardsOwner, shares, options...) 304 if err != nil { 305 return nil, err 306 } 307 return w.IssueUnsignedTx(utx, options...) 308 } 309 310 func (w *wallet) IssueAddSubnetValidatorTx( 311 vdr *txs.SubnetValidator, 312 options ...common.Option, 313 ) (*txs.Tx, error) { 314 utx, err := w.builder.NewAddSubnetValidatorTx(vdr, options...) 315 if err != nil { 316 return nil, err 317 } 318 return w.IssueUnsignedTx(utx, options...) 319 } 320 321 func (w *wallet) IssueRemoveSubnetValidatorTx( 322 nodeID ids.NodeID, 323 subnetID ids.ID, 324 options ...common.Option, 325 ) (*txs.Tx, error) { 326 utx, err := w.builder.NewRemoveSubnetValidatorTx(nodeID, subnetID, options...) 327 if err != nil { 328 return nil, err 329 } 330 return w.IssueUnsignedTx(utx, options...) 331 } 332 333 func (w *wallet) IssueAddDelegatorTx( 334 vdr *txs.Validator, 335 rewardsOwner *secp256k1fx.OutputOwners, 336 options ...common.Option, 337 ) (*txs.Tx, error) { 338 utx, err := w.builder.NewAddDelegatorTx(vdr, rewardsOwner, options...) 339 if err != nil { 340 return nil, err 341 } 342 return w.IssueUnsignedTx(utx, options...) 343 } 344 345 func (w *wallet) IssueCreateChainTx( 346 subnetID ids.ID, 347 genesis []byte, 348 vmID ids.ID, 349 fxIDs []ids.ID, 350 chainName string, 351 options ...common.Option, 352 ) (*txs.Tx, error) { 353 utx, err := w.builder.NewCreateChainTx(subnetID, genesis, vmID, fxIDs, chainName, options...) 354 if err != nil { 355 return nil, err 356 } 357 return w.IssueUnsignedTx(utx, options...) 358 } 359 360 func (w *wallet) IssueCreateSubnetTx( 361 owner *secp256k1fx.OutputOwners, 362 options ...common.Option, 363 ) (*txs.Tx, error) { 364 utx, err := w.builder.NewCreateSubnetTx(owner, options...) 365 if err != nil { 366 return nil, err 367 } 368 return w.IssueUnsignedTx(utx, options...) 369 } 370 371 func (w *wallet) IssueTransferSubnetOwnershipTx( 372 subnetID ids.ID, 373 owner *secp256k1fx.OutputOwners, 374 options ...common.Option, 375 ) (*txs.Tx, error) { 376 utx, err := w.builder.NewTransferSubnetOwnershipTx(subnetID, owner, options...) 377 if err != nil { 378 return nil, err 379 } 380 return w.IssueUnsignedTx(utx, options...) 381 } 382 383 func (w *wallet) IssueImportTx( 384 sourceChainID ids.ID, 385 to *secp256k1fx.OutputOwners, 386 options ...common.Option, 387 ) (*txs.Tx, error) { 388 utx, err := w.builder.NewImportTx(sourceChainID, to, options...) 389 if err != nil { 390 return nil, err 391 } 392 return w.IssueUnsignedTx(utx, options...) 393 } 394 395 func (w *wallet) IssueExportTx( 396 chainID ids.ID, 397 outputs []*avax.TransferableOutput, 398 options ...common.Option, 399 ) (*txs.Tx, error) { 400 utx, err := w.builder.NewExportTx(chainID, outputs, options...) 401 if err != nil { 402 return nil, err 403 } 404 return w.IssueUnsignedTx(utx, options...) 405 } 406 407 func (w *wallet) IssueTransformSubnetTx( 408 subnetID ids.ID, 409 assetID ids.ID, 410 initialSupply uint64, 411 maxSupply uint64, 412 minConsumptionRate uint64, 413 maxConsumptionRate uint64, 414 minValidatorStake uint64, 415 maxValidatorStake uint64, 416 minStakeDuration time.Duration, 417 maxStakeDuration time.Duration, 418 minDelegationFee uint32, 419 minDelegatorStake uint64, 420 maxValidatorWeightFactor byte, 421 uptimeRequirement uint32, 422 options ...common.Option, 423 ) (*txs.Tx, error) { 424 utx, err := w.builder.NewTransformSubnetTx( 425 subnetID, 426 assetID, 427 initialSupply, 428 maxSupply, 429 minConsumptionRate, 430 maxConsumptionRate, 431 minValidatorStake, 432 maxValidatorStake, 433 minStakeDuration, 434 maxStakeDuration, 435 minDelegationFee, 436 minDelegatorStake, 437 maxValidatorWeightFactor, 438 uptimeRequirement, 439 options..., 440 ) 441 if err != nil { 442 return nil, err 443 } 444 return w.IssueUnsignedTx(utx, options...) 445 } 446 447 func (w *wallet) IssueAddPermissionlessValidatorTx( 448 vdr *txs.SubnetValidator, 449 signer vmsigner.Signer, 450 assetID ids.ID, 451 validationRewardsOwner *secp256k1fx.OutputOwners, 452 delegationRewardsOwner *secp256k1fx.OutputOwners, 453 shares uint32, 454 options ...common.Option, 455 ) (*txs.Tx, error) { 456 utx, err := w.builder.NewAddPermissionlessValidatorTx( 457 vdr, 458 signer, 459 assetID, 460 validationRewardsOwner, 461 delegationRewardsOwner, 462 shares, 463 options..., 464 ) 465 if err != nil { 466 return nil, err 467 } 468 return w.IssueUnsignedTx(utx, options...) 469 } 470 471 func (w *wallet) IssueAddPermissionlessDelegatorTx( 472 vdr *txs.SubnetValidator, 473 assetID ids.ID, 474 rewardsOwner *secp256k1fx.OutputOwners, 475 options ...common.Option, 476 ) (*txs.Tx, error) { 477 utx, err := w.builder.NewAddPermissionlessDelegatorTx( 478 vdr, 479 assetID, 480 rewardsOwner, 481 options..., 482 ) 483 if err != nil { 484 return nil, err 485 } 486 return w.IssueUnsignedTx(utx, options...) 487 } 488 489 func (w *wallet) IssueUnsignedTx( 490 utx txs.UnsignedTx, 491 options ...common.Option, 492 ) (*txs.Tx, error) { 493 ops := common.NewOptions(options) 494 ctx := ops.Context() 495 tx, err := walletsigner.SignUnsigned(ctx, w.signer, utx) 496 if err != nil { 497 return nil, err 498 } 499 500 return tx, w.IssueTx(tx, options...) 501 } 502 503 func (w *wallet) IssueTx( 504 tx *txs.Tx, 505 options ...common.Option, 506 ) error { 507 ops := common.NewOptions(options) 508 ctx := ops.Context() 509 txID, err := w.client.IssueTx(ctx, tx.Bytes()) 510 if err != nil { 511 return err 512 } 513 514 if f := ops.PostIssuanceFunc(); f != nil { 515 f(txID) 516 } 517 518 if ops.AssumeDecided() { 519 return w.Backend.AcceptTx(ctx, tx) 520 } 521 522 if err := platformvm.AwaitTxAccepted(w.client, ctx, txID, ops.PollFrequency()); err != nil { 523 return err 524 } 525 526 return w.Backend.AcceptTx(ctx, tx) 527 }