Skip to content

Commit

Permalink
v3.1.0
Browse files Browse the repository at this point in the history
update dependencies.
Constructors for Tron Native Contracts for Deserialization from Protobuf
  • Loading branch information
mrtnetwork committed Apr 20, 2024
1 parent 89d6bb8 commit 4f5debe
Show file tree
Hide file tree
Showing 99 changed files with 1,456 additions and 198 deletions.
1 change: 0 additions & 1 deletion example/lib/example/cardano/mint_with_metadata.dart
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ void main() async {
mint: mint,
auxiliaryDataHash: auxiliary.toHash(),
);

final transaction = ADATransaction(
body: body,
data: auxiliary,
Expand Down
17 changes: 9 additions & 8 deletions example/lib/example/cardano/provider_example/provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,15 @@ class BlockforestHTTPProvider implements BlockfrostServiceProvider {
@override
Future<dynamic> post(BlockforestRequestDetails params,
[Duration? timeout]) async {
final response = await client.post(
Uri.parse(params.url(url, version)),
headers: {
"Accept": "application/json",
if (projectId != null) ...{"project_id": projectId!},
...params.header
},
).timeout(timeout ?? defaultRequestTimeout);
final response = await client
.post(Uri.parse(params.url(url, version)),
headers: {
"Accept": "application/json",
if (projectId != null) ...{"project_id": projectId!},
...params.header
},
body: params.body)
.timeout(timeout ?? defaultRequestTimeout);
final data = json.decode(response.body);
return data;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class QuickWalletForTest {
QuickWalletForTest._(this.privateKey);
final SolanaPrivateKey privateKey;
late final SolAddress address = privateKey.publicKey().toAddress();
static final rpc = solanaRPC("https://api.devnet.solana.com");
static final rpc = solanaRPC("https://api.testnet.solana.com");

Future<String> faucent([SolAddress? addr]) async {
final f = await rpc.request(SolanaRPCRequestAirdrop(
Expand Down
2 changes: 1 addition & 1 deletion example/macos/Runner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0920;
LastUpgradeCheck = 1430;
LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "";
TargetAttributes = {
331C80D4294CF70F00263BE5 = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1430"
LastUpgradeVersion = "1510"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
3 changes: 2 additions & 1 deletion example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ dependencies:
path: ../
web_socket_channel: ^2.4.0
http: ^1.1.0
blockchain_utils: ^2.1.1
blockchain_utils:
path: ../../blockchain_utils
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2
Expand Down
131 changes: 1 addition & 130 deletions example/test/widget_test.dart
Original file line number Diff line number Diff line change
@@ -1,130 +1 @@
void main() async {
// final seed = BytesUtils.fromHexString(
// "6fed8bf347b201c4ff0379c9173a042163dbd5f1110bcb983ac8615dcbb98c853f7c1b524dcebdf47e2d19778d0b30e25065d5a5012d83b874ab7034e95a713f");
// final bip44 = Bip44.fromSeed(seed, Bip44Coins.tron);
// final prv = TronPrivateKey.fromBytes(bip44.privateKey.raw);
// final publicKey = prv.publicKey();
// final address = publicKey.toAddress();
// final receiverAddress = TronAddress("TF3cDajEAaJ8jFXFB2KF3XSUbTpZWzuSrp");
// final rpc =
// TronProvider(TronHTTPProvider(url: "https://api.shasta.trongrid.io"));
// final block = await rpc.request(TronRequestGetNowBlock());

// /// create contract (i use TransferContract)
// final contract = TransferContract(
// amount: TronHelper.toSun("1"),
// ownerAddress: address,
// toAddress: receiverAddress);
// final parameter = Any(typeUrl: contract.typeURL, value: contract);
// final transactionContract =
// TransactionContract(type: contract.contractType, parameter: parameter);

// /// maximum 24H
// final expireTime = DateTime.now().toUtc().add(const Duration(hours: 12));
// TransactionRaw rawTr = TransactionRaw(
// refBlockBytes: block.blockHeader.rawData.refBlockBytes,
// refBlockHash: block.blockHeader.rawData.refBlockHash,
// expiration: BigInt.from(expireTime.millisecondsSinceEpoch),
// // 10 TRX
// feeLimit: TronHelper.toSun("10"),

// /// memo
// data: utf8.encode("https://github.com/mrtnetwork"),
// contract: [transactionContract],
// timestamp: block.blockHeader.rawData.timestamp);

// /// ok now we want to calculate fee limit before signing
// /// i create fake transaction to get size of tr
// /// in this case transaction is not multi-sig address and we just need one signature
// /// i add 65byte empty bytes to transaction beacuse each signature has fixed 65 bytes
// /// signer * 65 bytes (1 * 65)
// final fakeTr = Transaction(rawData: rawTr, signature: [Uint8List(65)]);

// /// transaction Size
// /// ok we now how much bandwidth need
// final trSize = fakeTr.length + 64;
// int needBandiwdth = trSize;

// /// we does not need energy (energy its only for smart contract and u can see in smart contract calculate fee example)
// // ignore: unused_local_variable
// final int? energyNeed;

// /// sometimes when we want to send transaction to not active account, netwokr has required bandwidth for burn and
// /// this cannot reduce with account bandwidth
// int needBandWidthToBurn = 0;

// /// ok now we got network parameters
// final chainParams = await rpc.request(TronRequestGetChainParameters());

// /// ok we got chain param and now we need accounts resource
// final ownerAccountResource =
// await rpc.request(TronRequestGetAccountResource(address: address));

// /// ok we have owner account resource and now we got receiver account details for its active or not
// /// in this case if accountIsActive is null, its mean account does not active
// final accountIsActive =
// await rpc.request(TronRequestGetAccount(address: receiverAddress));

// /// total burn (transaction fee)
// int totalBurnInSun = 0;

// /// ok in this case we calculate how much need for new account
// if (accountIsActive == null) {
// needBandWidthToBurn += chainParams.getCreateNewAccountFeeInSystemContract!;
// totalBurnInSun += chainParams.getCreateAccountFee!;
// }

// /// if we have note (memo) we calculate memo foo
// /// in this case we have note ("https://github.com/mrtnetwork")
// if (rawTr.data != null) {
// totalBurnInSun += chainParams.getMemoFee!;
// }

// /// for transfer trx we dont need anything but some special transaction has special values for
// /// 1. Issue a TRC10 token: 1,024 TRX
// /// 2. Apply to be an SR candidate: 9,999 TRX
// /// 3. Create a Bancor transaction: 1,024 TRX
// /// 4. Update the account permission: 100 TRX
// /// 5. Activate the account: 1 TRX (used in this transaction)
// /// 6. Multi-sig transaction: 1 TRX
// /// 7. Transaction note: 1 TRX (used in this transaction)

// /// ok now we need to reduce bandwidth with account bandwidth
// /// how much account have bandwidth
// final BigInt accountBandWidth = ownerAccountResource.howManyBandwIth;

// /// Only when we have the total bandwidth in our account, we will set the total amount of bandwidth to zero
// if (accountBandWidth >= BigInt.from(needBandiwdth)) {
// needBandiwdth = 0;
// }

// /// ok now we must add to total burn
// if (needBandiwdth > 0) {
// totalBurnInSun += needBandiwdth * chainParams.getTransactionFee!;
// }
// if (needBandWidthToBurn > 0) {
// totalBurnInSun += needBandWidthToBurn * chainParams.getTransactionFee!;
// }

// /// now we replace transaction fee limit with total burn
// rawTr = rawTr.copyWith(feeLimit: BigInt.from(totalBurnInSun));

// // txID
// final _ = rawTr.txID;

// /// get transaaction digest and sign with private key
// final sign = prv.sign(rawTr.toBuffer());
// print("sig ${sign.length}");
// return;

// /// create transaction object and add raw data and signature to this
// final transaction = Transaction(rawData: rawTr, signature: [sign]);

// /// get raw data buffer
// final raw = BytesUtils.toHexString(transaction.toBuffer());

// /// send transaction to network
// await rpc.request(TronRequestBroadcastHex(transaction: raw));

// /// https://shasta.tronscan.org/#/transaction/a7f39b66145aa2dd14f03557000e069230c91f60e46cc7b516ab00f87a854c31
}
void main() async {}
1 change: 1 addition & 0 deletions lib/ada/src/ada.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export 'models/ada_models.dart';
export 'provider/provider.dart';
export 'serialization/cbor_serialization.dart';
export 'utils/ada_helper.dart';
export 'builder/builder.dart';
2 changes: 2 additions & 0 deletions lib/ada/src/builder/builder.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export 'builder/tranasction_builder_utils.dart';
export 'builder/transaction_builder.dart';
27 changes: 27 additions & 0 deletions lib/ada/src/builder/builder/tranasction_builder_utils.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import 'package:on_chain/ada/src/address/address.dart';
import 'package:on_chain/ada/src/models/constant.dart';
import 'package:on_chain/ada/src/models/fixed_bytes/models/models.dart';

import '../../models/transaction/witnesses/witnesses.dart';

class ADATransactionBuilderUtils {
static BootstrapWitness fakeBootStrapWitness(String byronAddr) {
final address = ADAByronAddress(byronAddr);
return BootstrapWitness(
vkey: Vkey(
List<int>.filled(AdaTransactionConstant.blake2b256DigestSize, 0)),
signature: Ed25519Signature(
List<int>.filled(AdaTransactionConstant.signatureLength, 0)),
chainCode:
List<int>.filled(AdaTransactionConstant.blake2b256DigestSize, 0),
attributes: address.attributeSerialize());
}

static Vkeywitness fakeVkeyWitnessWitness() {
return Vkeywitness(
vKey: Vkey(
List<int>.filled(AdaTransactionConstant.blake2b256DigestSize, 0)),
signature: Ed25519Signature(
List<int>.filled(AdaTransactionConstant.signatureLength, 0)));
}
}
162 changes: 162 additions & 0 deletions lib/ada/src/builder/builder/transaction_builder.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
import 'dart:developer';

import 'package:blockchain_utils/blockchain_utils.dart';
import 'package:on_chain/ada/src/address/address.dart';
import 'package:on_chain/ada/src/builder/builder/tranasction_builder_utils.dart';
import 'package:on_chain/ada/src/models/ada_models.dart';
import 'package:on_chain/ada/src/provider/provider.dart';

typedef ONSignADA = ADABaseTransactionWitness Function(
{required List<int> digest, required ADAAddress address});

class ADATransactionBuilder {
ADATransactionBuilder({
required this.utxos,
required List<TransactionOutput> outputs,
this.metadata,
}) : _outputs = List<TransactionOutput>.unmodifiable(outputs);
final List<ADAAccountUTXOResponse> utxos;
final GeneralTransactionMetadata? metadata;
List<TransactionOutput> _outputs;
List<TransactionOutput> get outputs => List<TransactionOutput>.from(_outputs);
BigInt? _fee;
BigInt? get fee => _fee;

void setFee(BigInt fee) => _fee = fee;

BigInt get sumOflovelace {
return utxos.sumOflovelace;
}

MultiAsset get multiAsset {
return utxos.multiAsset;
}

List<ADAAddress> get signers {
final Set<String> addresses = utxos.map((e) => e.address).toSet();
return addresses.map((e) => ADAAddress.fromAddress(e)).toList();
}

TransactionOutput? _changeOutput(ADAAddress addr) {
final lovelence =
(utxos.sumOflovelace - (_outputs.sumOflovelace + (fee ?? BigInt.zero)));
final multiAsset = utxos.multiAsset;
final asset = multiAsset - _outputs.multiAsset;
if (lovelence.isNegative) {
throw MessageException("Insufficient input in transaction.", details: {
"utxo lovelence": utxos.sumOflovelace,
"output lovelence": _outputs.sumOflovelace
});
}

if (lovelence > BigInt.zero || asset.hasAsset) {
return TransactionOutput(
address: addr,
amount: Value(
coin: lovelence, multiAsset: asset.hasAsset ? asset : null));
}
return null;
}

int estimateSize({ADAAddress? onChangeAddress}) {
if (utxos.isEmpty || _outputs.isEmpty) {
throw MessageException("Utxos and outputs must not be not empty.");
}
// final change = _changeOutput(onChangeAddress ?? utxos.first.toAdddress);
final outs = _outputs.map((e) {
if (e.amount.coin == BigInt.zero) {
return e.copyWith(amount: e.amount.copyWith(coin: maxU64));
}
return e;
}).toList();
log("outs: $outs");
final transactionSigners = signers;
final aux = auxiliaryData;
final ADATransaction transaction = ADATransaction(
data: aux,
body: TransactionBody(
inputs: utxos.map((e) => e.toInput).toList(),
outputs: outs,
fee: BigInt.from(mask32),
auxiliaryDataHash: aux?.toHash()),
witnessSet: TransactionWitnessSet(
bootstraps: transactionSigners
.where((element) => element.addressType == ADAAddressType.byron)
.map((e) =>
ADATransactionBuilderUtils.fakeBootStrapWitness(e.address))
.toList(),
vKeys: transactionSigners
.where((element) => element.addressType != ADAAddressType.byron)
.map((e) => ADATransactionBuilderUtils.fakeVkeyWitnessWitness())
.toList(),
),
);
return transaction.size;
}

Future<void> calculateFees(BlockforestProvider provider) async {
final protocol = await provider
.request(BlockfrostRequestLatestEpochProtocolParameters());
_fee = BigInt.from(protocol.minFeeA * estimateSize() + protocol.minFeeB);
}

TransactionOutput? onChangeAddress(ADAAddress onChangeAddress) {
if (_fee == null) {
throw MessageException(
"please calculation the transaction fees befor using change address.");
}
final change = _changeOutput(onChangeAddress);
if (change != null) {
_outputs = [..._outputs, change];
}
return change;
}

AuxiliaryData? get auxiliaryData {
if (metadata == null) return null;
return AuxiliaryData(metadata: metadata);
}

TransactionBody buildTxBody({AuxiliaryDataHash? auxHash}) {
if (fee == null) {
throw MessageException(
"cannot build transaction body before calculation fee.");
}
return TransactionBody(
fee: fee!,
inputs: utxos.map((e) => e.toInput).toList(),
outputs: outputs,
auxiliaryDataHash: auxHash);
}

ADATransaction signAndBuildTransaction(ONSignADA onSignADA) {
_validateAmounts();
final aux = auxiliaryData;
final trBody = buildTxBody(auxHash: aux?.toHash());
final bodyHash = List<int>.unmodifiable(trBody.toHash().data);
final List<ADABaseTransactionWitness> witnesses = [];
final transactionSigners = signers;

for (final i in transactionSigners) {
final wit = onSignADA(address: i, digest: bodyHash);
witnesses.add(wit);
}
return ADATransaction(
body: trBody,
data: aux,
witnessSet: TransactionWitnessSet(
vKeys: witnesses.whereType<Vkeywitness>().toList(),
bootstraps: witnesses.whereType<BootstrapWitness>().toList()));
}

void _validateAmounts() {
final lovelence =
utxos.sumOflovelace - (outputs.sumOflovelace + (fee ?? BigInt.zero));
final asset = utxos.multiAsset - outputs.multiAsset;
if (lovelence != BigInt.zero || asset != MultiAsset.empty) {
throw MessageException(
"The amount of inputs and outputs is not calculated correctly",
details: {"lovelence": lovelence, "asset": asset});
}
}
}
Loading

0 comments on commit 4f5debe

Please sign in to comment.