Skip to content

Commit 1ec9b77

Browse files
authored
Merge pull request #10 from Tezsure/dev
Tezster_dart version 2.0.0 release
2 parents f03d51d + 952428f commit 1ec9b77

22 files changed

+951
-3
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
# [2.0.0]
2+
3+
* Dependencies update.
4+
* Added Get Balance.
5+
* Added Transfer Balance.
6+
* Added Delegate an Account.
7+
18
# [1.0.1]
29

310
* Dependencies update.

README.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,14 @@ Tezos is a decentralized blockchain that governs itself by establishing a true d
1414
### Features
1515

1616
* Tezos wallet utilities.
17+
* Get Balance.
1718
* Generate mnemonics.
1819
* Generate keys from mnemonic.
1920
* Generate keys from mnemonics and passphrase.
2021
* Sign Operation Group.
2122
* Unlock fundraiser identity.
23+
* Transfer Balance.
24+
* Delegate an Account.
2225

2326
### Getting started
2427

@@ -32,6 +35,12 @@ import 'package:tezster_dart/tezster_dart.dart';
3235

3336
### Usage
3437

38+
* Get Balance
39+
40+
``` dart
41+
String balance = await TezsterDart.getBalance('tz1c....ozGGs', 'your rpc server');
42+
```
43+
3544
* Generate mnemonic
3645

3746
``` dart
@@ -86,6 +95,65 @@ List<String> identityFundraiser = await TezsterDart.unlockFundraiserIdentity(
8695
tz1hhkSbaocSWm3wawZUuUdX57L3maSH16Pv] */
8796
```
8897

98+
* Transfer Balance.
99+
* The most basic operation on the chain is the transfer of value between two accounts. In this example we have the account we activated above: tz1QSHaKpTFhgHLbqinyYRjxD5sLcbfbzhxy and some random testnet address to test with: tz1RVcUP9nUurgEJMDou8eW3bVDs6qmP5Lnc. Note all amounts are in µtz, as in micro-tez, hence 0.5tz is represented as 500000. The fee of 1500 was chosen arbitrarily, but some operations have minimum fee requirements.
100+
101+
``` dart
102+
var server = '';
103+
104+
var keyStore = KeyStoreModel(
105+
publicKey: 'edpkvQtuhdZQmjdjVfaY9Kf4hHfrRJYugaJErkCGvV3ER1S7XWsrrj',
106+
secretKey:
107+
'edskRgu8wHxjwayvnmpLDDijzD3VZDoAH7ZLqJWuG4zg7LbxmSWZWhtkSyM5Uby41rGfsBGk4iPKWHSDniFyCRv3j7YFCknyHH',
108+
publicKeyHash: 'tz1QSHaKpTFhgHLbqinyYRjxD5sLcbfbzhxy',
109+
);
110+
111+
var signer = await TezsterDart.createSigner(
112+
TezsterDart.writeKeyWithHint(keyStore.secretKey, 'edsk'));
113+
114+
var result = await TezsterDart.sendTransactionOperation(
115+
server,
116+
signer,
117+
keyStore,
118+
'tz1RVcUP9nUurgEJMDou8eW3bVDs6qmP5Lnc',
119+
500000,
120+
1500,
121+
);
122+
123+
print("Applied operation ===> $result['appliedOp']");
124+
print("Operation groupID ===> $result['operationGroupID']");
125+
126+
```
127+
128+
* Delegate an Account.
129+
* One of the most exciting features of Tezos is delegation. This is a means for non-"baker" (non-validator) accounts to participate in the on-chain governance process and receive staking rewards. It is possible to delegate both implicit and originated accounts. For implicit addresses, those starting with tz1, tz2 and tz3, simply call sendDelegationOperation. Originated accounts, that is smart contracts, must explicitly support delegate assignment, but can also be deployed with a delegate already set.
130+
131+
``` dart
132+
var server = '';
133+
134+
var keyStore = KeyStoreModel(
135+
publicKey: 'edpkvQtuhdZQmjdjVfaY9Kf4hHfrRJYugaJErkCGvV3ER1S7XWsrrj',
136+
secretKey:
137+
'edskRgu8wHxjwayvnmpLDDijzD3VZDoAH7ZLqJWuG4zg7LbxmSWZWhtkSyM5Uby41rGfsBGk4iPKWHSDniFyCRv3j7YFCknyHH',
138+
publicKeyHash: 'tz1QSHaKpTFhgHLbqinyYRjxD5sLcbfbzhxy',
139+
);
140+
141+
var signer = await TezsterDart.createSigner(
142+
TezsterDart.writeKeyWithHint(keyStore.secretKey, 'edsk'));
143+
144+
var result = await TezsterDart.sendDelegationOperation(
145+
server,
146+
signer,
147+
keyStore,
148+
'tz1RVcUP9nUurgEJMDou8eW3bVDs6qmP5Lnc',
149+
10000,
150+
);
151+
152+
print("Applied operation ===> $result['appliedOp']");
153+
print("Operation groupID ===> $result['operationGroupID']");
154+
155+
```
156+
89157
---
90158
**NOTE:**
91159
Use stable version of flutter to avoid package conflicts.

example/android/app/src/main/AndroidManifest.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
In most cases you can leave this as-is, but you if you want to provide
66
additional functionality it is fine to subclass or reimplement
77
FlutterApplication and put your custom class here. -->
8+
<uses-permission android:name="android.permission.INTERNET" />
89
<application
910
android:name="io.flutter.app.FlutterApplication"
1011
android:label="example"

example/lib/main.dart

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,47 @@ class _MyAppState extends State<MyApp> {
6565
print("identityFundraiser ===> $identityFundraiser");
6666
//identityFundraiser ===> [privateKey, publicKey, publicKeyHash]
6767
//Accessing: private key ===> identityFundraiser[0] | public key ===> identityFundraiser[1] | public Key Hash ===> identityFundraiser[2] all of type string.
68+
69+
// Get Balance
70+
String balance =
71+
await TezsterDart.getBalance('tz1c....ozGGs', 'your rpc server');
72+
print("Accoutn Balance ===> $balance");
73+
74+
var server = '';
75+
76+
var keyStore = KeyStoreModel(
77+
publicKey: 'edpkvQtuhdZQmjdjVfaY9Kf4hHfrRJYugaJErkCGvV3ER1S7XWsrrj',
78+
secretKey:
79+
'edskRgu8wHxjwayvnmpLDDijzD3VZDoAH7ZLqJWuG4zg7LbxmSWZWhtkSyM5Uby41rGfsBGk4iPKWHSDniFyCRv3j7YFCknyHH',
80+
publicKeyHash: 'tz1QSHaKpTFhgHLbqinyYRjxD5sLcbfbzhxy',
81+
);
82+
83+
//Send transaction
84+
var transactionSigner = await TezsterDart.createSigner(
85+
TezsterDart.writeKeyWithHint(keyStore.secretKey, 'edsk'));
86+
var transactionResult = await TezsterDart.sendTransactionOperation(
87+
server,
88+
transactionSigner,
89+
keyStore,
90+
'tz1RVcUP9nUurgEJMDou8eW3bVDs6qmP5Lnc',
91+
500000,
92+
1500,
93+
);
94+
print("Applied operation ===> $transactionResult['appliedOp']");
95+
print("Operation groupID ===> $transactionResult['operationGroupID']");
96+
97+
//Send delegation
98+
var delegationSigner = await TezsterDart.createSigner(
99+
TezsterDart.writeKeyWithHint(keyStore.secretKey, 'edsk'));
100+
var delegationResult = await TezsterDart.sendDelegationOperation(
101+
server,
102+
delegationSigner,
103+
keyStore,
104+
'tz1RVcUP9nUurgEJMDou8eW3bVDs6qmP5Lnc',
105+
10000,
106+
);
107+
print("Applied operation ===> $delegationResult['appliedOp']");
108+
print("Operation groupID ===> $delegationResult['operationGroupID']");
68109
}
69110

70111
@override

example/pubspec.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ packages:
218218
path: ".."
219219
relative: true
220220
source: path
221-
version: "1.0.1"
221+
version: "2.0.0"
222222
typed_data:
223223
dependency: transitive
224224
description:
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import 'package:tezster_dart/chain/tezos/tezos_message_utils.dart';
2+
import 'package:tezster_dart/models/operation_model.dart';
3+
4+
class TezosMessageCodec {
5+
static String encodeOperation(OperationModel message) {
6+
if (message.kind == 'transaction') return encodeTransaction(message);
7+
if (message.kind == 'reveal') return encodeReveal(message);
8+
if (message.kind == 'delegation') return encodeDelegation(message);
9+
}
10+
11+
static String encodeTransaction(OperationModel message) {
12+
String hex = TezosMessageUtils.writeInt(108);
13+
hex += TezosMessageUtils.writeAddress(message.source).substring(2);
14+
hex += TezosMessageUtils.writeInt(int.parse(message.fee));
15+
hex += TezosMessageUtils.writeInt(message.counter);
16+
hex += TezosMessageUtils.writeInt(message.gasLimit);
17+
hex += TezosMessageUtils.writeInt(message.storageLimit);
18+
hex += TezosMessageUtils.writeInt(int.parse(message.amount));
19+
hex += TezosMessageUtils.writeAddress(message.destination);
20+
hex += '00';
21+
return hex;
22+
}
23+
24+
static String encodeReveal(OperationModel message) {
25+
var hex = TezosMessageUtils.writeInt(107); //sepyTnoitarepo['reveal']);
26+
hex += TezosMessageUtils.writeAddress(message.source).substring(2);
27+
hex += TezosMessageUtils.writeInt(int.parse(message.fee));
28+
hex += TezosMessageUtils.writeInt(message.counter);
29+
hex += TezosMessageUtils.writeInt(message.gasLimit);
30+
hex += TezosMessageUtils.writeInt(message.storageLimit);
31+
hex += TezosMessageUtils.writePublicKey(message.publicKey);
32+
return hex;
33+
}
34+
35+
static String encodeDelegation(OperationModel delegation) {
36+
var hex = TezosMessageUtils.writeInt(110);
37+
hex += TezosMessageUtils.writeAddress(delegation.source).substring(2);
38+
hex += TezosMessageUtils.writeInt(int.parse(delegation.fee));
39+
hex += TezosMessageUtils.writeInt(delegation.counter);
40+
hex += TezosMessageUtils.writeInt(delegation.gasLimit);
41+
hex += TezosMessageUtils.writeInt(delegation.storageLimit);
42+
if (delegation.delegate != null && delegation.delegate.isNotEmpty) {
43+
hex += TezosMessageUtils.writeBoolean(true);
44+
hex += TezosMessageUtils.writeAddress(delegation.delegate).substring(2);
45+
} else {
46+
hex += TezosMessageUtils.writeBoolean(false);
47+
}
48+
return hex;
49+
}
50+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import 'dart:typed_data';
2+
3+
import 'package:blake2b/blake2b_hash.dart';
4+
import 'package:bs58check/bs58check.dart';
5+
import 'package:convert/convert.dart';
6+
import 'package:tezster_dart/helper/generateKeys.dart';
7+
import 'package:tezster_dart/src/soft-signer/soft_signer.dart';
8+
9+
class TezosMessageUtils {
10+
static String writeBranch(String branch) {
11+
return hex.encode(base58
12+
.decode(branch)
13+
.sublist(2, base58.decode(branch).length - 4)
14+
.toList());
15+
// return hex.encode(base58.decode(branch).sublist(2).toList());
16+
}
17+
18+
static String writeInt(int value) {
19+
if (value < 0) {
20+
throw new Exception('Use writeSignedInt to encode negative numbers');
21+
}
22+
var byteHexList = Uint8List.fromList(hex.decode(twoByteHex(value)));
23+
for (var i = 0; i < byteHexList.length; i++) {
24+
if (i != 0) byteHexList[i] ^= 0x80;
25+
}
26+
var result = hex.encode(byteHexList.reversed.toList());
27+
return result;
28+
}
29+
30+
static String twoByteHex(int n) {
31+
if (n < 128) {
32+
var s = ('0' + n.toRadixString(16));
33+
return s.substring(s.length - 2);
34+
}
35+
String h = '';
36+
if (n > 2147483648) {
37+
var r = BigInt.from(n);
38+
while (r.compareTo(BigInt.zero) != -1) {
39+
var _h = ('0' + (r & BigInt.from(127)).toRadixString(16));
40+
h = _h.substring(_h.length - 2) + h;
41+
r = r >> 7;
42+
}
43+
} else {
44+
var r = n;
45+
while (r > 0) {
46+
var _h = ('0' + (r & 127).toRadixString(16));
47+
h = _h.substring(_h.length - 2) + h;
48+
r = r >> 7;
49+
}
50+
}
51+
return h;
52+
}
53+
54+
static String writeAddress(String address) {
55+
var base58data = base58.decode(address).sublist(3);
56+
base58data = base58data.sublist(0, base58data.length - 4);
57+
var _hex = hex.encode(base58data);
58+
if (address.startsWith("tz1")) {
59+
return "0000" + _hex;
60+
} else if (address.startsWith("tz2")) {
61+
return "0001" + _hex;
62+
} else if (address.startsWith("tz3")) {
63+
return "0002" + _hex;
64+
} else if (address.startsWith("KT1")) {
65+
return "01" + _hex + "00";
66+
} else {
67+
throw new Exception(
68+
'Unrecognized address prefix: ${address.substring(0, 3)}');
69+
}
70+
}
71+
72+
static String writePublicKey(String publicKey) {
73+
if (publicKey.startsWith("edpk")) {
74+
return "00" + hex.encode(base58.decode(publicKey).sublist(4));
75+
} else if (publicKey.startsWith("sppk")) {
76+
return "01" + hex.encode(base58.decode(publicKey).sublist(4));
77+
} else if (publicKey.startsWith("p2pk")) {
78+
return "02" + hex.encode(base58.decode(publicKey).sublist(4));
79+
} else {
80+
throw new Exception('Unrecognized key type');
81+
}
82+
}
83+
84+
static Uint8List simpleHash(Uint8List message, int size) {
85+
return Uint8List.fromList(Blake2bHash.hashWithDigestSize(256, message));
86+
}
87+
88+
static String readSignatureWithHint(Uint8List opSignature, SignerCurve hint) {
89+
opSignature = Uint8List.fromList(opSignature);
90+
if (hint == SignerCurve.ED25519) {
91+
return GenerateKeys.readKeysWithHint(opSignature, '09f5cd8612');
92+
} else if (hint == SignerCurve.SECP256K1) {
93+
return GenerateKeys.readKeysWithHint(opSignature, '0d7365133f');
94+
} else if (hint == SignerCurve.SECP256R1) {
95+
return GenerateKeys.readKeysWithHint(opSignature, '36f02c34');
96+
} else {
97+
throw Exception('Unrecognized signature hint, "$hint"');
98+
}
99+
}
100+
101+
static String writeBoolean(bool b) {
102+
return b ? "ff" : "00";
103+
}
104+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
2+
import 'package:tezster_dart/helper/http_helper.dart';
3+
4+
class TezosNodeReader {
5+
static Future<int> getCounterForAccount(String server, String publicKeyHash,
6+
{String chainid = 'main'}) async {
7+
var response = await HttpHelper.performGetRequest(server,
8+
'chains/$chainid/blocks/head/context/contracts/$publicKeyHash/counter');
9+
return int.parse(response.toString().replaceAll('"', ''), radix: 10);
10+
}
11+
12+
static Future<bool> isManagerKeyRevealedForAccount(
13+
String server, String publicKeyHash) async {
14+
var managerKey =
15+
await getAccountManagerForBlock(server, 'head', publicKeyHash);
16+
return managerKey.length > 0;
17+
}
18+
19+
static Future<String> getAccountManagerForBlock(
20+
String server, String block, String publicKeyHash,
21+
{String chainid = 'main'}) async {
22+
var response = await HttpHelper.performGetRequest(server,
23+
'chains/$chainid/blocks/$block/context/contracts/$publicKeyHash/manager_key');
24+
return response.toString().isNotEmpty ? response.toString() : '';
25+
}
26+
27+
static Future<Map<dynamic, dynamic>> getBlockAtOffset(
28+
String server, int offset,
29+
{String chainid = 'main'}) async {
30+
if (offset <= 0) {
31+
return await getBlock(server);
32+
}
33+
var head = await getBlock(server);
34+
var response = await HttpHelper.performGetRequest(
35+
server, 'chains/$chainid/blocks/${head['header']['level'] - offset}');
36+
return response;
37+
}
38+
39+
static Future<Map<dynamic, dynamic>> getBlock(String server,
40+
{String hash = 'head', String chainid = 'main'}) async {
41+
var response = await HttpHelper.performGetRequest(
42+
server, 'chains/$chainid/blocks/$hash');
43+
return response;
44+
}
45+
}

0 commit comments

Comments
 (0)