Skip to content

Commit

Permalink
feat: add stake integration schema
Browse files Browse the repository at this point in the history
  • Loading branch information
parodyBit committed May 17, 2024
1 parent 6453865 commit 0cd862d
Show file tree
Hide file tree
Showing 9 changed files with 571 additions and 2 deletions.
62 changes: 62 additions & 0 deletions example/stake_transaction_example.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// 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 stake transaction body
StakeBody body = StakeBody(
inputs: [
Input(outputPointer: outputPointer),
],
output: StakeOutput(
value: MINIMUM_STAKEABLE_AMOUNT_WITS,
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());
}

/// 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())),
);
}
5 changes: 4 additions & 1 deletion lib/constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;
3 changes: 3 additions & 0 deletions lib/src/constants.dart
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
9 changes: 8 additions & 1 deletion lib/src/schema/schema.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -54,6 +56,11 @@ part 'reveal_body.dart';
part 'reveal_transaction.dart';
part 'secp256k1_signature.dart';
part 'signature.dart';
part 'stake_body.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';
Expand Down
113 changes: 113 additions & 0 deletions lib/src/schema/stake_body.dart
Original file line number Diff line number Diff line change
@@ -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<Input>(1, 'inputs', PbFieldType.PM, subBuilder: Input.create)
..aOM<StakeOutput>(2, 'output', subBuilder: StakeOutput.create)
..aOM<ValueTransferOutput>(2, 'change',
subBuilder: ValueTransferOutput.create)
..hasRequiredFields = false;

static StakeBody create() => StakeBody._();
static PbList<StakeBody> createRepeated() => PbList<StakeBody>();
static StakeBody getDefault() =>
_defaultInstance ??= GeneratedMessage.$_defaultFor<StakeBody>(create);
static StakeBody? _defaultInstance;

StakeBody._() : super();

@override
StakeBody clone() => StakeBody()..mergeFromMessage(this);

@override
StakeBody createEmptyInstance() => create();

factory StakeBody({
Iterable<Input>? 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<int> i,
[ExtensionRegistry r = ExtensionRegistry.EMPTY]) =>
create()..mergeFromBuffer(i, r);

@override
factory StakeBody.fromJson(Map<String, dynamic> json) => StakeBody(
inputs: List<Input>.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<String, dynamic> jsonMap({bool asHex = false}) => {
"inputs":
List<dynamic>.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<Input> 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);
}
81 changes: 81 additions & 0 deletions lib/src/schema/stake_output.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
part of 'schema.dart';

class StakeOutput extends GeneratedMessage {
static final BuilderInfo _i = BuilderInfo('StakeOutput',
package: const PackageName('witnet'), createEmptyInstance: create)
..a<Int64>(1, 'value', PbFieldType.OU6, defaultOrMaker: Int64.ZERO)
..aOM<KeyedSignature>(2, 'authorization', subBuilder: KeyedSignature.create)
..hasRequiredFields = false;

static StakeOutput create() => StakeOutput._();
static PbList<StakeOutput> createRepeated() => PbList<StakeOutput>();
static StakeOutput getDefault() =>
_defaultInstance ??= GeneratedMessage.$_defaultFor<StakeOutput>(create);
static StakeOutput? _defaultInstance;
StakeOutput._() : super();

@override
GeneratedMessage clone() => StakeOutput()..mergeFromMessage(this);

@override
GeneratedMessage createEmptyInstance() => create();

factory StakeOutput({
int? value,
KeyedSignature? authorization,
}) {
final _result = create();
if (value != null) {
_result.value = Int64(value);
}
if (authorization != null) {
_result.authorization = authorization;
}
return _result;
}

factory StakeOutput.fromRawJson(String str) =>
StakeOutput.fromJson(json.decode(str));

@override
factory StakeOutput.fromJson(Map<String, dynamic> json) => StakeOutput(
value: json["value"],
authorization: KeyedSignature.fromJson(json["authorization"]),
);

Map<String, dynamic> jsonMap({bool asHex = false}) => {
"value": value.toInt(),
"authorization": authorization.jsonMap(asHex: asHex),
};

@override
BuilderInfo get info_ => _i;

Uint8List get pbBytes => writeToBuffer();

@TagNumber(1)
Int64 get value => $_getI64(1);
@TagNumber(1)
set value(Int64 v) {
$_setInt64(0, v);
}

@TagNumber(1)
bool hasValue() => $_has(0);
@TagNumber(1)
void clearValue() => clearField(1);

@TagNumber(2)
KeyedSignature get authorization => $_getN(2);
@TagNumber(2)
set authorization(KeyedSignature v) {
setField(2, v);
}

@TagNumber(2)
bool hasAuthorization() => $_has(1);
@TagNumber(2)
void clearAuthorization() => clearField(2);
@TagNumber(2)
PublicKeyHash ensureAuthorization() => $_ensure(1);
}
89 changes: 89 additions & 0 deletions lib/src/schema/stake_transaction.dart
Original file line number Diff line number Diff line change
@@ -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<StakeBody>(1, 'body', subBuilder: StakeBody.create)
..pc<KeyedSignature>(2, 'signatures', PbFieldType.PM,
subBuilder: KeyedSignature.create)
..hasRequiredFields = false;

static StakeTransaction create() => StakeTransaction._();
static PbList<StakeTransaction> createRepeated() =>
PbList<StakeTransaction>();
static StakeTransaction getDefault() => _defaultInstance ??=
GeneratedMessage.$_defaultFor<StakeTransaction>(create);
static StakeTransaction? _defaultInstance;

StakeTransaction._() : super();

@override
StakeTransaction clone() => StakeTransaction()..mergeFromMessage(this);

@override
StakeTransaction createEmptyInstance() => create();

factory StakeTransaction({
StakeBody? body,
Iterable<KeyedSignature>? 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<String, dynamic> json) =>
StakeTransaction(
body: StakeBody.fromJson(json["body"]),
signatures: List<KeyedSignature>.from(
json["signatures"].map((x) => KeyedSignature.fromJson(x))),
);

@override
factory StakeTransaction.fromBuffer(List<int> i,
[ExtensionRegistry r = ExtensionRegistry.EMPTY]) =>
create()..mergeFromBuffer(i, r);

String rawJson({bool asHex = false}) => json.encode(jsonMap(asHex: asHex));

Map<String, dynamic> jsonMap({bool asHex = false}) => {
"body": body.jsonMap(asHex: asHex),
"signatures":
List<dynamic>.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<KeyedSignature> get signatures => $_getList(1);
}
Loading

0 comments on commit 0cd862d

Please sign in to comment.