Skip to content

Commit

Permalink
dapps: Update WalletConnect libs. Improvements to the staking dapp.
Browse files Browse the repository at this point in the history
  • Loading branch information
patniemeyer committed Sep 20, 2024
1 parent 644a27c commit 65a77f8
Show file tree
Hide file tree
Showing 22 changed files with 2,223 additions and 1,693 deletions.
6 changes: 6 additions & 0 deletions gui-orchid/lib/api/orchid_crypto.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:orchid/api/orchid_eth/abi_encode.dart';
import 'package:orchid/api/orchid_log.dart';
import 'dart:math';
import 'dart:typed_data';
Expand Down Expand Up @@ -166,6 +167,11 @@ class EthereumAddress {

final BigInt value;

// Convert to Uint8List
Uint8List get bytes {
return value.toBytesUint160();
}

EthereumAddress(BigInt value)
:
// Allow the string parser to validate.
Expand Down
24 changes: 24 additions & 0 deletions gui-orchid/lib/api/orchid_eth/abi_encode.dart
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,28 @@ extension BigIntExtension on BigInt {
}
return result;
}

Uint8List toBytesUint160() {
final number = this;
// Assert the number is non-negative and fits within 160 bits
assert(number >= BigInt.zero && number < (BigInt.one << 160),
'Number must be non-negative and less than 2^160');
var byteData = number.toRadixString(16).padLeft(40, '0'); // Ensure 20 bytes
var result = Uint8List(20);
for (int i = 0; i < byteData.length; i += 2) {
var byteString = byteData.substring(i, i + 2);
var byteValue = int.parse(byteString, radix: 16);
result[i ~/ 2] = byteValue;
}
return result;
}

// For a BigInt representing an Ethereum Address (20 bytes)
Uint8List toAddress() {
return toBytesUint160();
}
}

Uint8List tie(Uint8List a, Uint8List b) {
return Uint8List.fromList(a + b);
}
2 changes: 1 addition & 1 deletion gui-orchid/lib/api/orchid_eth/token_type.dart
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ class Token {
int? minPrecision,
bool showPrecisionIndicator = false,
}) {
print("XXX: format decimal value: $decimalValue");
// print("XXX: format decimal value: $decimalValue");
return units.formatDecimal(decimalValue,
locale: locale,
precision: precision,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class OrchidLabeledTokenValueField extends StatelessWidget {
final Widget? trailing;
final Widget? bottom;
final Widget? bottomBanner;
final Color? backgroundColor;

// TODO: enhance this to include a message
final bool error;
Expand All @@ -43,6 +44,7 @@ class OrchidLabeledTokenValueField extends StatelessWidget {
this.bottom,
this.bottomBanner,
this.error = false,
this.backgroundColor,
}) : super(key: key);

@override
Expand All @@ -55,7 +57,7 @@ class OrchidLabeledTokenValueField extends StatelessWidget {
child: Column(
children: [
Container(
color: OrchidColors.dark_background_2,
color: backgroundColor ?? OrchidColors.dark_background_2,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expand Down
2 changes: 2 additions & 0 deletions web-ethereum/account_dapp/flutter_web3.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
cd $(dirname "$0")

# Create our patched version of the flutter_web3 package.
# See the following issue for an explanation of the patch:
# "Support for Wallet Connect 2.x." @patniemeyer
# https://github.com/y-pakorn/flutter_web3/issues/56
#
if [ -d flutter_web3 ]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import 'dart:math';
import 'package:orchid/api/orchid_eth/chains.dart';
import 'package:orchid/dapp/preferences/dapp_transaction.dart';
import 'package:orchid/orchid/orchid.dart';
import 'package:orchid/dapp/orchid_web3/orchid_web3_context.dart';
import 'package:orchid/dapp/preferences/user_preferences_dapp.dart';
import 'package:orchid/dapp/orchid/transaction_status_panel.dart';

// Show pending and recent transactions in the dapp.
// The side scrolling page view of transaction status panels.
class DappTransactionList extends StatefulWidget {
final OrchidWeb3Context? web3Context;
final VoidCallback refreshUserData;
Expand Down Expand Up @@ -35,13 +39,34 @@ class _DappTransactionListState extends State<DappTransactionList> {
txs = (txs ?? [])
.where((tx) => tx.chainId == widget.web3Context?.chain.chainId)
.toList();
if (txs.isEmpty) {
return Container();
}

// REMOVE: TESTING
// txs = txs + txs + txs + txs;

// REMOVE: TESTING
// txs += [
// DappTransaction(
// transactionHash: "0x10942af0a19066e4c27b1eb6c8a7edd2e7f76a68ac147384786ee6b5fd02e78f",
// chainId: Chains.GNOSIS_CHAINID,
// type: DappTransactionType.addFunds,
// subtype: "approve",
// series_index: 1,
// series_total: 2,
// ),
// DappTransaction(
// transactionHash: "0x10942af0a19066e4c27b1eb6c8a7edd2e7f76a68ac147384786ee6b5fd02e78f",
// chainId: Chains.GNOSIS_CHAINID,
// type: DappTransactionType.addFunds,
// subtype: "push",
// series_index: 2,
// series_total: 2,
// ),
// ];

if (txs.isEmpty) {
return Container();
}

var txWidgets = txs
.map((tx) => TransactionStatusPanel(
context: widget.web3Context,
Expand All @@ -63,17 +88,39 @@ class _DappTransactionListState extends State<DappTransactionList> {
duration: millis(400),
child: SizedBox(
height: 180,
child: PageView.builder(
itemCount: txWidgets.length,
controller: PageController(viewportFraction: viewportFraction),
onPageChanged: (int index) =>
setState(() => _txStatusIndex = index),
itemBuilder: (_, i) {
return AnimatedScale(
child: ShaderMask(
shaderCallback: (Rect bounds) {
return LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
colors: [
Colors.transparent, // Start fully transparent (left side)
Colors.black, // Fully visible in the middle
Colors.black, // Fully visible in the middle
Colors.transparent, // End fully transparent (right side)
],
stops: [
0.0,
0.2,
0.8,
1.0
], // Adjust stops to control fade amount
).createShader(bounds);
},
blendMode: BlendMode.dstIn, // Use blend mode for transparency
child: PageView.builder(
itemCount: txWidgets.length,
controller: PageController(viewportFraction: viewportFraction),
onPageChanged: (int index) =>
setState(() => _txStatusIndex = index),
itemBuilder: (_, i) {
return AnimatedScale(
duration: millis(300),
scale: i == _txStatusIndex ? 1 : 0.9,
child: Center(child: txWidgets[i]));
},
child: Center(child: txWidgets[i]),
);
},
),
),
),
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,18 @@ class DappWalletInfoPanel extends StatelessWidget {
}

Widget _buildContent(BuildContext context) {
final isWalletConnect = web3Context?.walletConnectProvider != null;
final link = web3Context?.chain.explorerUrl;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(context.s.connectedWithMetamask, style: _textStyle),
Text(
isWalletConnect
? "Connected with WalletConnect" // TODO: Localize
: context.s.connectedWithMetamask,
style: _textStyle),
],
).height(26),
_buildWalletAddressRow().top(16),
Expand Down
13 changes: 12 additions & 1 deletion web-ethereum/account_dapp/lib/dapp/orchid_web3/orchid_erc20.dart
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class OrchidERC20 {
// This mitigates the potential for rounding errors in calculated amounts.
amount = Token.min(amount, walletBalance);

log('XXX: do approve: ${[spender.toString(), amount.intValue.toString()]}');
log('approveERC20: do approve: ${[spender.toString(), amount.intValue.toString()]}');

// approve(address spender, uint256 amount) external returns (bool)
var contract = _contract.connect(context.web3.getSigner());
Expand All @@ -71,3 +71,14 @@ class OrchidERC20 {
'function transferFrom(address sender, address recipient, uint256 amount) external returns (bool)',
];
}

// For a transaction that uses an ERC20 token, the transaction may require an approval
class ERC20PayableTransactionCallbacks {
final Future<void> Function(String approvalHash) onApproval;
final Future<void> Function(String txHash) onTransaction;

ERC20PayableTransactionCallbacks({
required this.onApproval,
required this.onTransaction,
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -245,10 +245,17 @@ class OrchidWeb3Context {

void removeAllListeners() {
//log("XXX: context ($id) removing listeners");
ethereumProvider?.removeAllListeners();
walletConnectProvider?.removeAllListeners();
try {
ethereumProvider?.removeAllListeners();
} catch (err) {
log("XXX: exception in removing ethereum listeners: $err");
}
try {
walletConnectProvider?.removeAllListeners();
} catch (err) {
log("XXX: exception in removing wallet connect listeners: $err");
}
_walletUpdateListener = null;
//log("XXX: after removing listeners: ${ethereumProvider.listenerCount()}");
}

void disconnect() async {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class OrchidWeb3V0 {
// Don't attempt to add more than the wallet balance.
// This mitigates the potential for rounding errors in calculated amounts.
var totalOXT = Token.min(addBalance.add(addEscrow), walletBalance);
log("Add funds signer: $signer, amount: ${totalOXT.subtract(addEscrow)}, escrow: $addEscrow");
log("Add funds: signer: $signer, amount: ${totalOXT.subtract(addEscrow)}, escrow: $addEscrow");

List<String> txHashes = [];

Expand All @@ -64,18 +64,19 @@ class OrchidWeb3V0 {
spender: OrchidContractV0.lotteryContractAddressV0,
);
if (oxtAllowance < totalOXT) {
log("XXX: oxtAllowance increase required: $oxtAllowance < $totalOXT");
log("Add funds: oxtAllowance increase required: $oxtAllowance < $totalOXT");
var approveTxHash = await _oxt.approveERC20(
owner: wallet.address!,
spender: OrchidContractV0.lotteryContractAddressV0,
amount: totalOXT);
txHashes.add(approveTxHash);
} else {
log("XXX: oxtAllowance sufficient: $oxtAllowance");
log("Add funds: oxtAllowance already sufficient: $oxtAllowance");
}

// Do the add call
var contract = _lotteryContract.connect(context.web3.getSigner());
log("Add funds: do push, totalOXT: $totalOXT, addEscrow: $addEscrow");
TransactionResponse tx = await contract.send(
'push',
[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,39 @@ class DappTransaction {
final int chainId;
final DappTransactionType? type;

// An optional subtype for components of a composite transaction.
// e.g. ERC20 transfer requiring an approval and a push.
final String? subtype;

// If this is part of a series of transactions, the index and total count.
final int? series_index;
final int? series_total;

DappTransaction({
this.transactionHash,
required this.chainId,
this.type,
this.subtype,
this.series_index = null,
this.series_total = null,
});

DappTransaction.fromJson(Map<String, dynamic> json)
: this.transactionHash = json['tx'],
this.chainId = json['chainId'],
this.type = toTransactionType(json['type']); // handles null
// toTransactionType() handles nulls
this.type = toTransactionType(json['type']),
this.subtype = json['subtype'],
this.series_index = json['series_index'],
this.series_total = json['series_total'];

Map<String, dynamic> toJson() => {
'tx': transactionHash,
'chainId': chainId,
'type': (type ?? DappTransactionType.unknown).name,
'subtype': subtype,
'series_index': series_index,
'series_total': series_total,
};

static List<DappTransaction> fromList(List<dynamic> list) {
Expand All @@ -56,7 +74,15 @@ class DappTransaction {
}

String description(BuildContext context) {
return descriptionForType(context, type);
String text = descriptionForType(context, type);
if (subtype != null) {
if (series_index != null && series_total != null) {
text += " ($subtype, $series_index/$series_total)";
} else {
text += " ($subtype)";
}
}
return text;
}

static String descriptionForType(
Expand All @@ -82,7 +108,7 @@ class DappTransaction {
case DappTransactionType.accountChanges:
return s.accountChanges;
case DappTransactionType.pullFunds:
return context.s.withdrawFunds2;
return "Pull Funds";
case DappTransactionType.moveLocation:
return "Move Location";
case DappTransactionType.pokeLocation:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,18 @@ class UserPreferencesDapp {
return _setTransactions(txs);
});

void addTransaction(DappTransaction tx) {
transactions.set(transactions.get()! + [tx]);
Future<void> addTransaction(DappTransaction tx) async {
await transactions.set(transactions.get()! + [tx]);
}

void addTransactions(Iterable<DappTransaction> txs) {
transactions.set(transactions.get()! + txs.toList());
Future<void> addTransactions(Iterable<DappTransaction> txs) async {
await transactions.set(transactions.get()! + txs.toList());
}

void removeTransaction(String txHash) {
Future<void> removeTransaction(String txHash) async {
var list = transactions.get()!;
list.removeWhere((tx) => tx.transactionHash == txHash);
transactions.set(list);
await transactions.set(list);
}

static List<DappTransaction> _getTransactions() {
Expand Down
Loading

0 comments on commit 65a77f8

Please sign in to comment.