diff --git a/example/stake_transaction_example.dart b/example/stake_transaction_example.dart new file mode 100644 index 0000000..1d04ddd --- /dev/null +++ b/example/stake_transaction_example.dart @@ -0,0 +1,84 @@ +// import 'package:witnet/node.dart'; +import 'package:witnet/schema.dart'; +import 'package:witnet/src/constants.dart'; +import 'package:witnet/src/utils/transformations/transformations.dart'; +import 'package:witnet/witnet.dart'; + +var outputPointer = OutputPointer.fromString( + '0000000000000000000000000000000000000000000000000000000000000000:0'); + +void main() async { + /// connect to local node rpc + // NodeClient nodeClient = NodeClient(address: "127.0.0.1", port: 21338); + + // String mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"; + /// load node xprv for the default mnemonic + Xprv masterNode = Xprv.fromXprv( + "xprv1qpujxsyd4hfu0dtwa524vac84e09mjsgnh5h9crl8wrqg58z5wmsuqqcxlqmar3fjhkprndzkpnp2xlze76g4hu7g7c4r4r2m2e6y8xlvu566tn6"); + + Xprv withdrawer = masterNode / + KEYPATH_PURPOSE / + KEYPATH_COIN_TYPE / + KEYPATH_ACCOUNT / + EXTERNAL_KEYCHAIN / + 0; + + /// The 20 byte Public Key Hash of the withdrawer + String pkh = bytesToHex(withdrawer.privateKey.publicKey.publicKeyHash); + + /// The authorization by the node + KeyedSignature authorization = signHash(pkh, masterNode.privateKey); + + /// Build the Stake Key + StakeKey stakeKey = StakeKey( + validator: authorization.publicKey.pkh, + withdrawer: PublicKeyHash.fromAddress(withdrawer.address.address), + ); + + /// build stake transaction body + StakeBody body = StakeBody( + inputs: [ + Input(outputPointer: outputPointer), + ], + output: StakeOutput( + value: MINIMUM_STAKEABLE_AMOUNT_WITS, + key: stakeKey, + authorization: authorization, + ), + ); + + /// build and sign stake transaction + StakeTransaction stake = StakeTransaction( + body: body, + signatures: [signHash(body.transactionId, masterNode.privateKey)]); + + /// The Stake Transaction ID + print(stake.transactionID); + + /// send stake transaction + /// var response = await nodeClient.inventory(stake.jsonMap()); + /// + UnstakeBody unstakeBody = UnstakeBody( + operator: PublicKeyHash.fromAddress(withdrawer.address.address), + withdrawal: ValueTransferOutput.fromJson({ + "pkh": withdrawer.address.address, + "time_lock": 0, + "value": 1, + })); + + KeyedSignature unstakeSignature = + signHash(bytesToHex(unstakeBody.hash), masterNode.privateKey); + UnstakeTransaction unstake = + UnstakeTransaction(body: unstakeBody, signature: unstakeSignature); + + print(unstake.transactionID); +} + +/// Sign Hash +KeyedSignature signHash(String hash, WitPrivateKey privateKey) { + final sig = privateKey.signature(hash); + return KeyedSignature( + publicKey: PublicKey(bytes: privateKey.publicKey.encode()), + signature: Signature(secp256k1: Secp256k1Signature(der: sig.encode())), + ); +} diff --git a/lib/constants.dart b/lib/constants.dart index a8cfdc0..8bdd107 100644 --- a/lib/constants.dart +++ b/lib/constants.dart @@ -12,4 +12,7 @@ export 'src/constants.dart' KEYPATH_PURPOSE, KEYPATH_COIN_TYPE, EXTERNAL_KEYCHAIN, - INTERNAL_KEYCHAIN; + INTERNAL_KEYCHAIN, + STAKE_OUTPUT_WEIGHT, + UNSTAKE_OUTPUT_WEIGHT, + MINIMUM_STAKEABLE_AMOUNT_WITS; diff --git a/lib/src/constants.dart b/lib/src/constants.dart index d0b8be0..1a10d62 100644 --- a/lib/src/constants.dart +++ b/lib/src/constants.dart @@ -1,5 +1,8 @@ const INPUT_SIZE = 133; const OUTPUT_SIZE = 36; +const STAKE_OUTPUT_WEIGHT = 105; +const UNSTAKE_OUTPUT_WEIGHT = 153; +const MINIMUM_STAKEABLE_AMOUNT_WITS = 10000; const COMMIT_WEIGHT = 400; const REVEAL_WEIGHT = 200; const TALLY_WEIGHT = 100; diff --git a/lib/src/crypto/hd_wallet/extended_private_key.dart b/lib/src/crypto/hd_wallet/extended_private_key.dart index c875eb4..f1e16f0 100644 --- a/lib/src/crypto/hd_wallet/extended_private_key.dart +++ b/lib/src/crypto/hd_wallet/extended_private_key.dart @@ -146,6 +146,7 @@ class Xprv extends ExtendedKey { } factory Xprv.fromEncryptedXprv(String xprv, String password) { + // throw 'Error from encrypted xprv'; try { Bech32 bech = bech32.decode(xprv); List checksum = createChecksum(bech.hrp, bech.data); diff --git a/lib/src/data_structures/utxo_pool.dart b/lib/src/data_structures/utxo_pool.dart index caed66c..c5dc955 100644 --- a/lib/src/data_structures/utxo_pool.dart +++ b/lib/src/data_structures/utxo_pool.dart @@ -41,6 +41,8 @@ class UtxoPool { } List sortUtxos(UtxoSelectionStrategy utxoSelectionStrategy) { + print(utxoSelectionStrategy); + print('...sortUtxos.. 0. ${map.values.toList().length}'); List sortedUtxos; switch (utxoSelectionStrategy) { case UtxoSelectionStrategy.Random: @@ -68,6 +70,7 @@ class UtxoPool { }); } } + print('...sortUtxos.. 1. ${sortedUtxos.length}'); return sortedUtxos; } @@ -75,6 +78,8 @@ class UtxoPool { required int amountNanoWit, required UtxoSelectionStrategy utxoStrategy, }) { + print('-------cover UTXOS-------'); + print('amount nanowit: $amountNanoWit'); List utxos = sortUtxos(utxoStrategy); if (utxos.isEmpty) { throw 'No UTXOS to select'; @@ -86,7 +91,8 @@ class UtxoPool { }); List selectedUtxos = []; - + print('utxos value: $utxoValue'); + print('Insufficient funds?? ${amountNanoWit > utxoValue}'); if (amountNanoWit > utxoValue) { throw 'Insufficient funds'; } diff --git a/lib/src/schema/public_key.dart b/lib/src/schema/public_key.dart index f157650..0bd44b7 100644 --- a/lib/src/schema/public_key.dart +++ b/lib/src/schema/public_key.dart @@ -64,6 +64,10 @@ class PublicKey extends GeneratedMessage { Uint8List get pbBytes => writeToBuffer(); + PublicKeyHash get pkh => PublicKeyHash( + hash: sha256(data: Uint8List.fromList(publicKey)).sublist(0, 20), + ); + @TagNumber(1) List get publicKey => $_getN(0); @TagNumber(1) diff --git a/lib/src/schema/schema.dart b/lib/src/schema/schema.dart index a904830..c3486bd 100644 --- a/lib/src/schema/schema.dart +++ b/lib/src/schema/schema.dart @@ -16,7 +16,9 @@ import 'package:witnet/constants.dart' REVEAL_WEIGHT, TALLY_WEIGHT, INPUT_SIZE, - OUTPUT_SIZE; + OUTPUT_SIZE, + STAKE_OUTPUT_WEIGHT, + UNSTAKE_OUTPUT_WEIGHT; import '../../radon.dart' show radToCbor, cborToRad; @@ -54,6 +56,12 @@ part 'reveal_body.dart'; part 'reveal_transaction.dart'; part 'secp256k1_signature.dart'; part 'signature.dart'; +part 'stake_body.dart'; +part 'stake_key.dart'; +part 'stake_output.dart'; +part 'stake_transaction.dart'; +part 'unstake_body.dart'; +part 'unstake_transaction.dart'; part 'string_pair.dart'; part 'super_block.dart'; part 'super_block_vote.dart'; diff --git a/lib/src/schema/stake_body.dart b/lib/src/schema/stake_body.dart new file mode 100644 index 0000000..eac5f7f --- /dev/null +++ b/lib/src/schema/stake_body.dart @@ -0,0 +1,113 @@ +part of 'schema.dart'; + +class StakeBody extends GeneratedMessage { + static final BuilderInfo _i = BuilderInfo('StakeBody', + package: const PackageName('witnet'), createEmptyInstance: create) + ..pc(1, 'inputs', PbFieldType.PM, subBuilder: Input.create) + ..aOM(2, 'output', subBuilder: StakeOutput.create) + ..aOM(3, 'change', + subBuilder: ValueTransferOutput.create) + ..hasRequiredFields = false; + + static StakeBody create() => StakeBody._(); + static PbList createRepeated() => PbList(); + static StakeBody getDefault() => + _defaultInstance ??= GeneratedMessage.$_defaultFor(create); + static StakeBody? _defaultInstance; + + StakeBody._() : super(); + + @override + StakeBody clone() => StakeBody()..mergeFromMessage(this); + + @override + StakeBody createEmptyInstance() => create(); + + factory StakeBody({ + Iterable? inputs, + StakeOutput? output, + ValueTransferOutput? change, + }) { + final _result = create(); + if (inputs != null) { + _result.inputs.addAll(inputs); + } + if (output != null) { + _result.output = output; + } + if (change != null) { + _result.change = change; + } + return _result; + } + + factory StakeBody.fromRawJson(String str) => + StakeBody.fromJson(json.decode(str)); + + @override + factory StakeBody.fromBuffer(List i, + [ExtensionRegistry r = ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(i, r); + + @override + factory StakeBody.fromJson(Map json) => StakeBody( + inputs: List.from(json["inputs"].map((x) => Input.fromJson(x))), + output: StakeOutput.fromJson(json["output"]), + change: ValueTransferOutput.fromJson(json["change"]), + ); + + factory StakeBody.fromPbBytes(Uint8List buffer) => + create()..mergeFromBuffer(buffer, ExtensionRegistry.EMPTY); + + String toRawJson({bool asHex = false}) => json.encode(jsonMap(asHex: asHex)); + + Map jsonMap({bool asHex = false}) => { + "inputs": + List.from(inputs.map((x) => x.jsonMap(asHex: asHex))), + "output": output.jsonMap(asHex: asHex), + "change": change.jsonMap(asHex: asHex), + }; + + Uint8List get pbBytes => writeToBuffer(); + + Uint8List get hash => sha256(data: pbBytes); + + String get transactionId => bytesToHex(hash); + // VT_weight = N * INPUT_SIZE + M * OUTPUT_SIZE + STAKE_OUTPUT_WEIGHT + int get weight => + (inputs.length * INPUT_SIZE) + OUTPUT_SIZE + STAKE_OUTPUT_WEIGHT; + + @override + BuilderInfo get info_ => _i; + + @TagNumber(1) + List get inputs => $_getList(0); + + @TagNumber(2) + StakeOutput get output => $_getN(1); + @TagNumber(2) + set output(StakeOutput v) { + setField(2, v); + } + + @TagNumber(2) + bool hasOutput() => $_has(1); + @TagNumber(2) + void clearOutput() => clearField(2); + @TagNumber(2) + StakeOutput ensureOutput() => $_ensure(1); + + @TagNumber(3) + ValueTransferOutput get change => $_getN(2); + @TagNumber(3) + set change(ValueTransferOutput v) { + setField(3, v); + } + + @TagNumber(3) + bool hasChange() => $_has(2); + @TagNumber(3) + void clearChange() => clearField(3); + @TagNumber(3) + VTTransactionBody ensureChange() => $_ensure(2); +} diff --git a/lib/src/schema/stake_key.dart b/lib/src/schema/stake_key.dart new file mode 100644 index 0000000..b8406e8 --- /dev/null +++ b/lib/src/schema/stake_key.dart @@ -0,0 +1,83 @@ +part of 'schema.dart'; + +class StakeKey extends GeneratedMessage { + static final BuilderInfo _i = BuilderInfo('StakeOutput', + package: const PackageName('witnet'), createEmptyInstance: create) + ..aOM(1, 'validator', subBuilder: PublicKeyHash.create) + ..aOM(2, 'withdrawer', subBuilder: PublicKeyHash.create) + ..hasRequiredFields = false; + + static StakeKey create() => StakeKey._(); + static PbList createRepeated() => PbList(); + static StakeKey getDefault() => + _defaultInstance ??= GeneratedMessage.$_defaultFor(create); + static StakeKey? _defaultInstance; + StakeKey._() : super(); + + @override + GeneratedMessage clone() => StakeKey()..mergeFromMessage(this); + + @override + GeneratedMessage createEmptyInstance() => create(); + + factory StakeKey({ + PublicKeyHash? validator, + PublicKeyHash? withdrawer, + }) { + final _result = create(); + if (validator != null) { + _result.validator = validator; + } + if (withdrawer != null) { + _result.withdrawer = withdrawer; + } + return _result; + } + + factory StakeKey.fromRawJson(String str) => + StakeKey.fromJson(json.decode(str)); + + @override + factory StakeKey.fromJson(Map json) => StakeKey( + validator: PublicKeyHash.fromAddress(json["validator"]), + withdrawer: PublicKeyHash.fromAddress(json["withdrawer"]), + ); + + Map jsonMap({bool asHex = false}) => { + "validator": validator.address, + "withdrawer": withdrawer.address, + }; + + @override + BuilderInfo get info_ => _i; + + Uint8List get pbBytes => writeToBuffer(); + + @TagNumber(1) + PublicKeyHash get validator => $_getN(0); + @TagNumber(1) + set validator(PublicKeyHash v) { + setField(1, v); + } + + @TagNumber(1) + bool hasValidator() => $_has(0); + @TagNumber(1) + void clearValidator() => clearField(1); + @TagNumber(1) + PublicKeyHash ensureValidator() => $_ensure(0); + + @TagNumber(2) + PublicKeyHash get withdrawer => $_getN(1); + @TagNumber(2) + set withdrawer(PublicKeyHash v) { + setField(1, v); + } + + @TagNumber(2) + bool hasWithdrawer() => $_has(1); + @TagNumber(2) + void clearWithdrawer() => clearField(2); + @TagNumber(2) + PublicKeyHash ensureWithdrawer() => $_ensure(1); +} diff --git a/lib/src/schema/stake_output.dart b/lib/src/schema/stake_output.dart new file mode 100644 index 0000000..1036524 --- /dev/null +++ b/lib/src/schema/stake_output.dart @@ -0,0 +1,113 @@ +part of 'schema.dart'; + +class StakeOutput extends GeneratedMessage { + static final BuilderInfo _i = BuilderInfo('StakeOutput', + package: const PackageName('witnet'), createEmptyInstance: create) + ..a(1, 'value', PbFieldType.OU6, defaultOrMaker: Int64.ZERO) + ..aOM(2, 'key', subBuilder: StakeKey.create) + ..aOM(3, 'authorization', subBuilder: KeyedSignature.create) + ..hasRequiredFields = false; + + static StakeOutput create() => StakeOutput._(); + static PbList createRepeated() => PbList(); + static StakeOutput getDefault() => + _defaultInstance ??= GeneratedMessage.$_defaultFor(create); + static StakeOutput? _defaultInstance; + StakeOutput._() : super(); + + @override + GeneratedMessage clone() => StakeOutput()..mergeFromMessage(this); + + @override + GeneratedMessage createEmptyInstance() => create(); + + factory StakeOutput({ + int? value, + StakeKey? key, + KeyedSignature? authorization, + }) { + final _result = create(); + print('result >>>>***** $value'); + print('result >>>>***** $key'); + print('result >>>>***** $authorization'); + if (value != null) { + _result.value = Int64(value); + } + + if (key != null) { + _result.key = key; + } + + if (authorization != null) { + _result.authorization = authorization; + } + print('result >>>>***** $_result'); + return _result; + } + + factory StakeOutput.fromRawJson(String str) => + StakeOutput.fromJson(json.decode(str)); + + @override + factory StakeOutput.fromJson(Map json) => StakeOutput( + value: json["value"], + key: StakeKey.fromJson(json["key"]), + authorization: json["authorization"] != null + ? KeyedSignature.fromJson(json["authorization"]) + : null, + ); + + Map jsonMap({bool asHex = false}) => { + "value": value.toInt(), + "key": key.jsonMap(asHex: asHex), + "authorization": + authorization != null ? authorization!.jsonMap(asHex: asHex) : null, + }; + + @override + BuilderInfo get info_ => _i; + + Uint8List get pbBytes => writeToBuffer(); + + @TagNumber(1) + Int64 get value => $_getI64(0); + @TagNumber(1) + set value(Int64 v) { + setField(1, v); + } + + @TagNumber(1) + bool hasValue() => $_has(0); + @TagNumber(1) + void clearValue() => clearField(1); + + @TagNumber(2) + StakeKey get key => $_getN(1); + @TagNumber(2) + set key(StakeKey v) { + setField(2, v); + } + + @TagNumber(2) + bool hasKey() => $_has(1); + @TagNumber(2) + void clearKey() => clearField(2); + @TagNumber(2) + StakeKey ensureKey() => $_ensure(1); + + @TagNumber(3) + KeyedSignature? get authorization => $_getN(2); + @TagNumber(3) + set authorization(KeyedSignature? v) { + if (v != null) { + setField(3, v); + } + } + + @TagNumber(3) + bool hasAuthorization() => $_has(2); + @TagNumber(3) + void clearAuthorization() => clearField(3); + @TagNumber(3) + KeyedSignature? ensureAuthorization() => $_ensure(2); +} diff --git a/lib/src/schema/stake_transaction.dart b/lib/src/schema/stake_transaction.dart new file mode 100644 index 0000000..6b80ff8 --- /dev/null +++ b/lib/src/schema/stake_transaction.dart @@ -0,0 +1,89 @@ +part of 'schema.dart'; + +class StakeTransaction extends GeneratedMessage { + static final BuilderInfo _i = BuilderInfo('StakeTransaction', + package: const PackageName('witnet'), createEmptyInstance: create) + ..aOM(1, 'body', subBuilder: StakeBody.create) + ..pc(2, 'signatures', PbFieldType.PM, + subBuilder: KeyedSignature.create) + ..hasRequiredFields = false; + + static StakeTransaction create() => StakeTransaction._(); + static PbList createRepeated() => + PbList(); + static StakeTransaction getDefault() => _defaultInstance ??= + GeneratedMessage.$_defaultFor(create); + static StakeTransaction? _defaultInstance; + + StakeTransaction._() : super(); + + @override + StakeTransaction clone() => StakeTransaction()..mergeFromMessage(this); + + @override + StakeTransaction createEmptyInstance() => create(); + + factory StakeTransaction({ + StakeBody? body, + Iterable? signatures, + }) { + final _result = create(); + if (body != null) { + _result.body = body; + } + if (signatures != null) { + _result.signatures.addAll(signatures); + } + return _result; + } + + factory StakeTransaction.fromRawJson(String str) => + StakeTransaction.fromJson(json.decode(str)); + + @override + factory StakeTransaction.fromJson(Map json) => + StakeTransaction( + body: StakeBody.fromJson(json["body"]), + signatures: List.from( + json["signatures"].map((x) => KeyedSignature.fromJson(x))), + ); + + @override + factory StakeTransaction.fromBuffer(List i, + [ExtensionRegistry r = ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(i, r); + + String rawJson({bool asHex = false}) => json.encode(jsonMap(asHex: asHex)); + + Map jsonMap({bool asHex = false}) => { + "body": body.jsonMap(asHex: asHex), + "signatures": + List.from(signatures.map((x) => x.jsonMap(asHex: asHex))), + }; + + String get transactionID => bytesToHex(body.hash); + + int get weight => body.weight; + + @override + BuilderInfo get info_ => _i; + + Uint8List get pbBytes => writeToBuffer(); + + @TagNumber(1) + StakeBody get body => $_getN(0); + @TagNumber(1) + set body(StakeBody v) { + setField(1, v); + } + + @TagNumber(1) + bool hasBody() => $_has(0); + @TagNumber(1) + void clearBody() => clearField(1); + @TagNumber(1) + StakeBody ensureBody() => $_ensure(0); + + @TagNumber(2) + List get signatures => $_getList(1); +} diff --git a/lib/src/schema/transaction.dart b/lib/src/schema/transaction.dart index 4a64ac9..4248b37 100644 --- a/lib/src/schema/transaction.dart +++ b/lib/src/schema/transaction.dart @@ -7,6 +7,8 @@ enum TransactionKind { reveal, tally, mint, + stake, + unstake, notSet } @@ -17,13 +19,15 @@ const Map _Transaction_KindByTag = { 4: TransactionKind.reveal, 5: TransactionKind.tally, 6: TransactionKind.mint, + 7: TransactionKind.stake, + 8: TransactionKind.unstake, 0: TransactionKind.notSet }; class Transaction extends GeneratedMessage { static final BuilderInfo _i = BuilderInfo('Transaction', package: const PackageName('witnet'), createEmptyInstance: create) - ..oo(0, [1, 2, 3, 4, 5, 6]) + ..oo(0, [1, 2, 3, 4, 5, 6, 7, 8]) ..aOM(1, 'ValueTransfer', protoName: 'ValueTransfer', subBuilder: VTTransaction.create) ..aOM(2, 'DataRequest', @@ -36,6 +40,10 @@ class Transaction extends GeneratedMessage { protoName: 'Tally', subBuilder: TallyTransaction.create) ..aOM(6, 'Mint', protoName: 'Mint', subBuilder: MintTransaction.create) + ..aOM(7, 'Stake', + protoName: 'Stake', subBuilder: StakeTransaction.create) + ..aOM(8, 'Unstake', + protoName: 'Unstake', subBuilder: UnstakeTransaction.create) ..hasRequiredFields = false; static Transaction create() => Transaction._(); @@ -59,6 +67,8 @@ class Transaction extends GeneratedMessage { RevealTransaction? reveal, TallyTransaction? tally, MintTransaction? mint, + StakeTransaction? stake, + UnstakeTransaction? unstake, }) { final _result = create(); if (valueTransfer != null) { @@ -79,6 +89,12 @@ class Transaction extends GeneratedMessage { if (mint != null) { _result.mint = mint; } + if (stake != null) { + _result.stake = stake; + } + if (unstake != null) { + _result.unstake = unstake; + } return _result; } @@ -110,9 +126,13 @@ class Transaction extends GeneratedMessage { case 'Reveal': return Transaction( reveal: RevealTransaction.fromJson(_txn['Reveal'])); - case 'Tally': return Transaction(tally: TallyTransaction.fromJson(_txn['Tally'])); + case 'Stake': + return Transaction(stake: StakeTransaction.fromJson(_txn['Stake'])); + case 'Unstake': + return Transaction( + unstake: UnstakeTransaction.fromJson(_txn['Unstake'])); } } else { throw ArgumentError('Invalid json'); @@ -123,16 +143,55 @@ class Transaction extends GeneratedMessage { String toRawJson({bool asHex = false}) => json.encode(jsonMap(asHex: asHex)); Map jsonMap({bool asHex = false}) { - final txType = hasDataRequest() ? 'DataRequest' : 'ValueTransfer'; - return { - "transaction": { - txType: { - "body": transaction.body.jsonMap(asHex: asHex), - "signatures": List.from( - transaction.signatures.map((x) => x.jsonMap(asHex: asHex))), + if (hasValueTransfer()) + return { + "transaction": { + 'ValueTransfer': { + "body": transaction.body.jsonMap(asHex: asHex), + "signatures": List.from( + transaction.signatures.map((x) => x.jsonMap(asHex: asHex))), + } } - } - }; + }; + if (hasDataRequest()) + return { + "transaction": { + 'DataRequest': { + "body": transaction.body.jsonMap(asHex: asHex), + "signatures": List.from( + transaction.signatures.map((x) => x.jsonMap(asHex: asHex))), + } + } + }; + if (hasStake()) + return { + "transaction": { + 'Stake': { + "body": transaction.body.jsonMap(asHex: asHex), + "signatures": List.from( + transaction.signatures.map((x) => x.jsonMap(asHex: asHex))), + }, + } + }; + if (hasUnstake()) + return { + "transaction": { + 'Unstake': { + "body": transaction.body.jsonMap(asHex: asHex), + "signature": transaction.signature.jsonMap(asHex: asHex), + } + } + }; + else + return { + "transaction": { + 'ValueTransfer': { + "body": transaction.body.jsonMap(asHex: asHex), + "signatures": List.from( + transaction.signatures.map((x) => x.jsonMap(asHex: asHex))), + } + } + }; } @override @@ -161,6 +220,8 @@ class Transaction extends GeneratedMessage { if (hasReveal()) return reveal; if (hasTally()) return tally; if (hasMint()) return mint; + if (hasStake()) return stake; + if (hasUnstake()) return unstake; } TransactionKind whichKind() => _Transaction_KindByTag[$_whichOneof(0)]!; @@ -250,4 +311,32 @@ class Transaction extends GeneratedMessage { void clearMint() => clearField(6); @TagNumber(6) MintTransaction ensureMint() => $_ensure(5); + + @TagNumber(7) + StakeTransaction get stake => $_getN(6); + @TagNumber(7) + set stake(StakeTransaction v) { + setField(7, v); + } + + @TagNumber(7) + bool hasStake() => $_has(6); + @TagNumber(7) + void clearStake() => clearField(7); + @TagNumber(7) + StakeTransaction ensureStake() => $_ensure(6); + + @TagNumber(8) + UnstakeTransaction get unstake => $_getN(7); + @TagNumber(8) + set unstake(UnstakeTransaction v) { + setField(8, v); + } + + @TagNumber(8) + bool hasUnstake() => $_has(7); + @TagNumber(8) + void clearUnstake() => clearField(8); + @TagNumber(8) + UnstakeTransaction ensureUnstake() => $_ensure(7); } diff --git a/lib/src/schema/unstake_body.dart b/lib/src/schema/unstake_body.dart new file mode 100644 index 0000000..3ea59c0 --- /dev/null +++ b/lib/src/schema/unstake_body.dart @@ -0,0 +1,101 @@ +part of 'schema.dart'; + +class UnstakeBody extends GeneratedMessage { + static final BuilderInfo _i = BuilderInfo('UnstakeBody', + package: const PackageName('witnet'), createEmptyInstance: create) + ..aOM(1, 'operator', subBuilder: PublicKeyHash.create) + ..aOM(2, 'withdrawal', + subBuilder: ValueTransferOutput.create) + ..hasRequiredFields = false; + + static UnstakeBody create() => UnstakeBody._(); + static PbList createRepeated() => PbList(); + static UnstakeBody getDefault() => + _defaultInstance ??= GeneratedMessage.$_defaultFor(create); + static UnstakeBody? _defaultInstance; + + UnstakeBody._() : super(); + + @override + UnstakeBody clone() => UnstakeBody()..mergeFromMessage(this); + + @override + UnstakeBody createEmptyInstance() => create(); + + factory UnstakeBody({ + PublicKeyHash? operator, + ValueTransferOutput? withdrawal, + }) { + final _result = create(); + if (operator != null) { + _result.operator = operator; + } + if (withdrawal != null) { + _result.withdrawal = withdrawal; + } + + return _result; + } + + factory UnstakeBody.fromRawJson(String str) => + UnstakeBody.fromJson(json.decode(str)); + + @override + factory UnstakeBody.fromBuffer(List i, + [ExtensionRegistry r = ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(i, r); + + @override + factory UnstakeBody.fromJson(Map json) => UnstakeBody( + operator: PublicKeyHash.fromAddress(json["operator"]), + withdrawal: ValueTransferOutput.fromJson(json["withdrawal"]), + ); + + factory UnstakeBody.fromPbBytes(Uint8List buffer) => + create()..mergeFromBuffer(buffer, ExtensionRegistry.EMPTY); + + String toRawJson({bool asHex = false}) => json.encode(jsonMap(asHex: asHex)); + + Map jsonMap({bool asHex = false}) => { + "operator": operator.address, + "withdrawal": withdrawal.jsonMap(asHex: asHex), + }; + + Uint8List get pbBytes => writeToBuffer(); + + Uint8List get hash => sha256(data: pbBytes); + + // VT_weight = 153 + int get weight => UNSTAKE_OUTPUT_WEIGHT; + + @override + BuilderInfo get info_ => _i; + + @TagNumber(1) + PublicKeyHash get operator => $_getN(0); + @TagNumber(1) + set operator(PublicKeyHash v) { + setField(1, v); + } + + @TagNumber(1) + bool hasOperator() => $_has(0); + @TagNumber(1) + void clearOperator() => clearField(1); + @TagNumber(1) + PublicKeyHash ensureOperator() => $_ensure(0); + + @TagNumber(2) + ValueTransferOutput get withdrawal => $_getN(1); + @TagNumber(2) + set withdrawal(ValueTransferOutput v) { + setField(2, v); + } + + @TagNumber(2) + bool hasWithdrawal() => $_has(1); + @TagNumber(2) + void clearWithdrawal() => clearField(2); + @TagNumber(2) + ValueTransferOutput ensureWithdrawal() => $_ensure(1); +} diff --git a/lib/src/schema/unstake_transaction.dart b/lib/src/schema/unstake_transaction.dart new file mode 100644 index 0000000..1848dbc --- /dev/null +++ b/lib/src/schema/unstake_transaction.dart @@ -0,0 +1,97 @@ +part of 'schema.dart'; + +class UnstakeTransaction extends GeneratedMessage { + static final BuilderInfo _i = BuilderInfo('UnstakeTransaction', + package: const PackageName('witnet'), createEmptyInstance: create) + ..aOM(1, 'body', subBuilder: UnstakeBody.create) + ..aOM(2, 'signature', subBuilder: KeyedSignature.create) + ..hasRequiredFields = false; + + static UnstakeTransaction create() => UnstakeTransaction._(); + static PbList createRepeated() => + PbList(); + static UnstakeTransaction getDefault() => _defaultInstance ??= + GeneratedMessage.$_defaultFor(create); + static UnstakeTransaction? _defaultInstance; + + UnstakeTransaction._() : super(); + + @override + UnstakeTransaction clone() => UnstakeTransaction()..mergeFromMessage(this); + + @override + UnstakeTransaction createEmptyInstance() => create(); + + factory UnstakeTransaction({ + UnstakeBody? body, + KeyedSignature? signature, + }) { + final _result = create(); + if (body != null) { + _result.body = body; + } + if (signature != null) { + _result.signature = signature; + } + return _result; + } + + factory UnstakeTransaction.fromRawJson(String str) => + UnstakeTransaction.fromJson(json.decode(str)); + + @override + factory UnstakeTransaction.fromJson(Map json) => + UnstakeTransaction( + body: UnstakeBody.fromJson(json["body"]), + signature: KeyedSignature.fromJson(json["signature"]), + ); + + @override + factory UnstakeTransaction.fromBuffer(List i, + [ExtensionRegistry r = ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(i, r); + + String rawJson({bool asHex = false}) => json.encode(jsonMap(asHex: asHex)); + + Map jsonMap({bool asHex = false}) => { + "body": body.jsonMap(asHex: asHex), + "signature": signature.jsonMap(asHex: asHex) + }; + + String get transactionID => bytesToHex(body.hash); + + int get weight => body.weight; + + @override + BuilderInfo get info_ => _i; + + Uint8List get pbBytes => writeToBuffer(); + + @TagNumber(1) + UnstakeBody get body => $_getN(0); + @TagNumber(1) + set body(UnstakeBody v) { + setField(1, v); + } + + @TagNumber(1) + bool hasBody() => $_has(0); + @TagNumber(1) + void clearBody() => clearField(1); + @TagNumber(1) + UnstakeBody ensureBody() => $_ensure(0); + + @TagNumber(2) + KeyedSignature get signature => $_getN(1); + + @TagNumber(2) + bool hasSignature() => $_has(1); + @TagNumber(2) + void clearSignature() => clearField(2); + @TagNumber(2) + UnstakeBody ensureSignature() => $_ensure(1); + @TagNumber(2) + set signature(KeyedSignature v) { + setField(2, v); + } +}