Skip to content

Commit

Permalink
feat: TON support (#149)
Browse files Browse the repository at this point in the history
* feat: ton (wip)

* fix: rebase

* fix: update nekoton_bridge (`estimateMinAttachedAmount`)

---------

Co-authored-by: Egor Komarov <[email protected]>
  • Loading branch information
Odrin and Egor Komarov authored Dec 20, 2024
1 parent 3ce77be commit a61a450
Show file tree
Hide file tree
Showing 11 changed files with 318 additions and 62 deletions.
30 changes: 30 additions & 0 deletions lib/src/models/token_wallet_related/generic_token_wallet.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import 'package:flutter_nekoton_bridge/flutter_nekoton_bridge.dart';

part 'jetton_token_wallet.dart';
part 'tip3_token_wallet.dart';

sealed class GenericTokenWallet {
RefreshingInterface get inner;
Transport get transport;
BigInt get balance;
Money get moneyBalance;
Currency get currency;
Address get rootTokenContract;
Address get tokenAddress;
Address get owner;
Symbol get symbol;
ContractState get contractState;
Stream<void> get fieldUpdatesStream;
Stream<BigInt> get onBalanceChangedStream;
Stream<Money> get onMoneyBalanceChangedStream;
Stream<
(
List<TransactionWithData<TokenWalletTransaction?>>,
TransactionsBatchInfo
)> get onTransactionsFoundStream;
Future<ContractState> getContractState();
Future<void> preloadTransactions(String? fromLt);
void onBalanceChanged(String balance);
void onTransactionsFound(String payload);
void dispose();
}
104 changes: 104 additions & 0 deletions lib/src/models/token_wallet_related/jetton_token_wallet.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
part of 'generic_token_wallet.dart';

class JettonTokenWallet extends GenericTokenWallet {
JettonTokenWallet(this._wallet, this._symbol)
: _currency = _getCurrency(_symbol);

static Future<JettonTokenWallet> subscribe({
required Transport transport,
required Address owner,
required Address rootTokenContract,
required Symbol symbol,
}) async =>
JettonTokenWallet(
await JettonWallet.subscribe(
transport: transport,
owner: owner,
rootTokenContract: rootTokenContract,
),
symbol,
);

final JettonWallet _wallet;
final Symbol _symbol;
final Currency _currency;

@override
Currency get currency => _currency;

@override
JettonWallet get inner => _wallet;

@override
Transport get transport => _wallet.transport;

@override
BigInt get balance => _wallet.balance;

@override
Money get moneyBalance => Money.fromBigIntWithCurrency(balance, currency);

@override
Address get rootTokenContract => _wallet.rootTokenContract;

@override
Address get tokenAddress => _wallet.tokenAddress;

@override
Address get owner => _wallet.owner;

@override
Symbol get symbol => _symbol;

@override
ContractState get contractState => _wallet.contractState;

@override
Stream<void> get fieldUpdatesStream => _wallet.fieldUpdatesStream;

@override
Stream<BigInt> get onBalanceChangedStream => _wallet.onBalanceChangedStream;

@override
Stream<Money> get onMoneyBalanceChangedStream => onBalanceChangedStream.map(
(balance) => Money.fromBigIntWithCurrency(balance, currency),
);

@override
Stream<
(
List<TransactionWithData<TokenWalletTransaction?>>,
TransactionsBatchInfo
)> get onTransactionsFoundStream => _wallet.onTransactionsFoundStream;

@override
Future<ContractState> getContractState() => _wallet.getContractState();

@override
Future<void> preloadTransactions([String? fromLt]) =>
_wallet.preloadTransactions(fromLt);

@override
void onBalanceChanged(String balance) => _wallet.onBalanceChanged(balance);

@override
void onTransactionsFound(String payload) =>
_wallet.onTransactionsFound(payload);

@override
void dispose() => _wallet.dispose();
}

Currency _getCurrency(Symbol symbol) {
final patternDigits =
symbol.decimals > 0 ? '0.${'#' * symbol.decimals}' : '0';
final currency = Currency.create(
symbol.name,
symbol.decimals,
symbol: symbol.name,
pattern: patternDigits,
);
Currencies().register(currency);

return currency;
}
84 changes: 84 additions & 0 deletions lib/src/models/token_wallet_related/tip3_token_wallet.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
part of 'generic_token_wallet.dart';

class Tip3TokenWallet extends GenericTokenWallet {
Tip3TokenWallet(this._wallet);

static Future<Tip3TokenWallet> subscribe({
required Transport transport,
required Address owner,
required Address rootTokenContract,
}) async =>
Tip3TokenWallet(
await TokenWallet.subscribe(
transport: transport,
owner: owner,
rootTokenContract: rootTokenContract,
),
);

final TokenWallet _wallet;

@override
TokenWallet get inner => _wallet;

@override
Transport get transport => _wallet.transport;

@override
BigInt get balance => _wallet.balance;

@override
Money get moneyBalance => _wallet.moneyBalance;

@override
Currency get currency => _wallet.currency;

@override
Address get rootTokenContract => _wallet.rootTokenContract;

@override
Address get tokenAddress => _wallet.tokenAddress;

@override
Address get owner => _wallet.owner;

@override
Symbol get symbol => _wallet.symbol;

@override
ContractState get contractState => _wallet.contractState;

@override
Stream<void> get fieldUpdatesStream => _wallet.fieldUpdatesStream;

@override
Stream<BigInt> get onBalanceChangedStream => _wallet.onBalanceChangedStream;

@override
Stream<Money> get onMoneyBalanceChangedStream =>
_wallet.onMoneyBalanceChangedStream;

@override
Stream<
(
List<TransactionWithData<TokenWalletTransaction?>>,
TransactionsBatchInfo
)> get onTransactionsFoundStream => _wallet.onTransactionsFoundStream;

@override
Future<ContractState> getContractState() => _wallet.getContractState();

@override
Future<void> preloadTransactions([String? fromLt]) =>
_wallet.preloadTransactions(fromLt);

@override
void onBalanceChanged(String balance) => _wallet.onBalanceChanged(balance);

@override
void onTransactionsFound(String payload) =>
_wallet.onTransactionsFound(payload);

@override
void dispose() => _wallet.dispose();
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export 'generic_token_wallet.dart';
export 'token_wallet_ordinary_transaction.dart';
export 'token_wallet_state.dart';
export 'token_wallet_subscription.dart';
8 changes: 4 additions & 4 deletions lib/src/models/token_wallet_related/token_wallet_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import 'package:equatable/equatable.dart';
import 'package:flutter/foundation.dart';
import 'package:nekoton_repository/nekoton_repository.dart';

/// State of [TokenWallet] that allows tracking when subscription was created
/// successfully or when it failed with some error.
/// State of [GenericTokenWallet] that allows tracking when subscription was
/// created successfully or when it failed with some error.
///
/// To detect which state is active, use [hasWallet] and [hasError].
@immutable
Expand All @@ -17,7 +17,7 @@ class TokenWalletState extends Equatable {
error = err;

/// Create state with wallet
TokenWalletState.wallet(TokenWallet w)
TokenWalletState.wallet(GenericTokenWallet w)
: error = null,
owner = w.owner,
rootTokenContract = w.rootTokenContract,
Expand All @@ -31,7 +31,7 @@ class TokenWalletState extends Equatable {
/// Wallet that could be created.
/// If wallet was created, then [hasWallet] returns true and you can use it
/// as usual.
final TokenWallet? wallet;
final GenericTokenWallet? wallet;

/// Any error that could be thrown during creating subscription.
/// Typically, this is [FfiException] or
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import 'dart:async';

import 'package:nekoton_repository/nekoton_repository.dart';

/// Callbacks that allows handle events from [TokenWallet]
/// Callbacks that allows handle events from [GenericTokenWallet]
typedef TokenWalletOnBalanceChanged = void Function(BigInt event);
typedef TokenWalletOnTransactionsFound = void Function(
(
Expand All @@ -11,17 +11,17 @@ typedef TokenWalletOnTransactionsFound = void Function(
) event,
);

/// Helper class that allows to listen for events from [TokenWallet] and
/// Helper class that allows to listen for events from [GenericTokenWallet] and
/// automatically dispose all subscriptions.
class TokenWalletSubscription {
TokenWalletSubscription({
required TokenWallet tokenWallet,
required GenericTokenWallet wallet,
required TokenWalletOnBalanceChanged onBalanceChanged,
required TokenWalletOnTransactionsFound onTransactionsFound,
}) : _onBalanceChangedSubscription =
tokenWallet.onBalanceChangedStream.listen(onBalanceChanged),
wallet.onBalanceChangedStream.listen(onBalanceChanged),
_onTransactionsFoundSubscription =
tokenWallet.onTransactionsFoundStream.listen(onTransactionsFound);
wallet.onTransactionsFoundStream.listen(onTransactionsFound);

/// Dynamic is used here to avoid importing Tuple lib, anyway we do not need
/// this type in subscription.
Expand Down
6 changes: 6 additions & 0 deletions lib/src/models/transport_strategy.dart
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,10 @@ abstract class TransportStrategy {

/// If transport has currency API, then it must return base URL for it.
String? get currencyApiBaseUrl;

/// Create token wallet subscribtion.
Future<GenericTokenWallet> subscribeToken({
required Address owner,
required Address rootTokenContract,
});
}
Loading

0 comments on commit a61a450

Please sign in to comment.