Skip to content

Commit

Permalink
Merge pull request #114 from mintlayer/dev
Browse files Browse the repository at this point in the history
release 0.3.1
  • Loading branch information
anyxem committed Jun 18, 2024
2 parents 3d61df9 + 6de2989 commit b01f82c
Show file tree
Hide file tree
Showing 76 changed files with 13,766 additions and 25,965 deletions.
58 changes: 57 additions & 1 deletion BlueComponents.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,6 @@ export const MintLayerButton = (props) => {
{props.subtitle}
</Text>
</View>
<ComingSoon text={loc.addresses.comming_soon} />
</View>
</View>
</TouchableOpacity>
Expand Down Expand Up @@ -774,6 +773,7 @@ const stylesBlueIcon = StyleSheet.create({
width: 30,
height: 30,
borderRadius: 15,
justifyContent: 'center',
},
ballReceive: {
width: 30,
Expand Down Expand Up @@ -841,6 +841,62 @@ export const BlueTransactionIncomingIcon = (props) => {
);
};

export const BlueTransactionStakingIcon = (props) => {
const { colors } = useTheme();
const stylesBlueIconHooks = StyleSheet.create({
ballIncoming: {
backgroundColor: colors.alternativeTextColor,
},
});
return (
<View {...props}>
<View style={stylesBlueIcon.boxIncoming}>
<View style={[stylesBlueIcon.ballIncomingWithoutRotate, stylesBlueIconHooks.ballIncoming]}>
<Icon {...props} name="database" size={16} type="font-awesome" color={colors.inverseForegroundColor} />
</View>
</View>
</View>
);
};

export const BlueTransactionDelegateStakingIcon = (props) => {
const { colors } = useTheme();
const stylesBlueIconHooks = StyleSheet.create({
ballIncoming: {
backgroundColor: colors.alternativeTextColor,
},
});
return (
<View {...props}>
<View style={stylesBlueIcon.boxIncoming}>
<View style={[stylesBlueIcon.ballIncomingWithoutRotate, stylesBlueIconHooks.ballIncoming]}>
<Icon {...props} name="graph-pie" size={22} type="foundation" color={colors.inverseForegroundColor} />
</View>
</View>
</View>
);
};

export const BlueTransactionDelegateWithdrawalIcon = (props) => {
const { colors } = useTheme();
const stylesBlueIconHooks = StyleSheet.create({
ballIncoming: {
backgroundColor: colors.ballReceive,
},
row: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', paddingHorizontal: 5 },
});
return (
<View {...props}>
<View style={stylesBlueIcon.boxIncoming}>
<View style={[stylesBlueIcon.ballIncomingWithoutRotate, stylesBlueIconHooks.row, stylesBlueIconHooks.ballIncoming]}>
<Icon {...props} name="database" size={14} type="font-awesome" color={colors.incomingForegroundColor} />
<Icon {...props} name="long-arrow-down" size={16} type="font-awesome" color={colors.incomingForegroundColor} />
</View>
</View>
</View>
);
};

export const BlueTransactionPendingIcon = (props) => {
const { colors } = useTheme();

Expand Down
2 changes: 1 addition & 1 deletion Navigation.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ import RBFCancel from './screen/transactions/RBFCancel';
import ReceiveDetails from './screen/receive/details';
import AztecoRedeem from './screen/receive/aztecoRedeem';

import SendDetails from './screen/send/details';
import SendDetails from './screen/send/details/index';
import ScanQRCode from './screen/send/ScanQRCode';
import SendCreate from './screen/send/create';
import Confirm from './screen/send/confirm';
Expand Down
8 changes: 6 additions & 2 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@ def jscFlavor = 'org.webkit:android-jsc-intl:+'
def enableHermes = project.ext.react.get("enableHermes", false);

android {
aaptOptions {
noCompress "wasm"
}

ndkVersion rootProject.ext.ndkVersion

compileSdkVersion rootProject.ext.compileSdkVersion
Expand All @@ -138,8 +142,8 @@ android {
applicationId "com.mojitowallet"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 39
versionName "0.2.10"
versionCode 41
versionName "0.3.1"
multiDexEnabled true
missingDimensionStrategy 'react-native-camera', 'general'
testBuildType System.getProperty('testBuildType', 'debug') // This will later be used to control the test apk build type
Expand Down
3 changes: 2 additions & 1 deletion android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:installLocation="auto"
package="com.mojitowallet">
Expand Down Expand Up @@ -67,6 +67,7 @@
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<action android:name="android.intent.action.DOWNLOAD_COMPLETE"/>
</intent-filter>
</activity>

Expand Down
21 changes: 21 additions & 0 deletions android/link-assets-manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"migIndex": 1,
"data": [
{
"path": "assets/fonts/Montserrat-Bold.ttf",
"sha1": "bf257f6f91f6522eccea6d4f28d57bb118c98729"
},
{
"path": "assets/fonts/Montserrat-Light_0.ttf",
"sha1": "08e510137064a3c9859b71cff5b999fe8c351e67"
},
{
"path": "assets/fonts/Montserrat-SemiBold.ttf",
"sha1": "4ef29a9163b56df34a3486b98b24be3a3d0cdca6"
},
{
"path": "assets/mintlayer/wasm_wrappers_bg.wasm",
"sha1": "fec25b2cc459a2a7866029751541b43f2edf0852"
}
]
}
Binary file added assets/mintlayer/wasm_wrappers_bg.wasm
Binary file not shown.
113 changes: 113 additions & 0 deletions blue_modules/Mintlayer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
const prefix = '/api/v2';

const MINTLAYER_ENDPOINTS = {
GET_ADDRESS_DATA: '/address/:address',
GET_TRANSACTION_DATA: '/transaction/:txid',
GET_ADDRESS_UTXO: '/address/:address/spendable-utxos',
POST_TRANSACTION: '/transaction',
GET_FEES_ESTIMATES: '/feerate',
GET_ADDRESS_DELEGATIONS: '/address/:address/delegations',
GET_DELEGATION: '/delegation/:delegation',
GET_CHAIN_TIP: '/chain/tip',
};

const ML_NETWORK_TYPES = {
MAINNET: 'mainnet',
TESTNET: 'testnet',
};

const TransactionType = {
Transfer: 'Transfer',
LockThenTransfer: 'LockThenTransfer',
CreateDelegationId: 'CreateDelegationId',
DelegateStaking: 'DelegateStaking',
CreateStakePool: 'CreateStakePool',
};

const ML_ATOMS_PER_COIN = 100000000000;

const MAINNET_MINTLAYER_SERVERS = ['https://api-server.mintlayer.org'];
const TESTNET_MINTLAYER_SERVERS = ['https://api-server-lovelace.mintlayer.org'];

const requestMintlayer = async (url, body = null, request = fetch) => {
const method = body ? 'POST' : 'GET';

const result = await request(url, { method, body });
if (!result.ok) {
const error = await result.json();

if (error.error === 'Address not found') {
return Promise.resolve(JSON.stringify({ coin_balance: { atoms: '0', decimal: '0' }, transaction_history: [] }));
}

// handle RPC error
if (error.error.includes('Mempool error:')) {
const errorMessage = error.error.split('Mempool error: ')[1].split('(')[0];
throw new Error(errorMessage);
}

if (error.error) {
console.error(error.error);
}

throw new Error('Request not successful');
}
const content = await result.text();
return Promise.resolve(content);
};

const tryServers = async ({ endpoint, body = null, network }) => {
const mintlayerServers = network === ML_NETWORK_TYPES.TESTNET ? TESTNET_MINTLAYER_SERVERS : MAINNET_MINTLAYER_SERVERS;
for (let i = 0; i < mintlayerServers.length; i++) {
try {
const response = await requestMintlayer(mintlayerServers[i] + prefix + endpoint, body);
return response;
} catch (error) {
console.warn(`${mintlayerServers[i] + prefix + endpoint} request failed: `, error);
if (i === mintlayerServers.length - 1) {
throw error;
}
}
}
};

const getAddressData = (address, network) => {
const endpoint = MINTLAYER_ENDPOINTS.GET_ADDRESS_DATA.replace(':address', address);
return tryServers({ endpoint, network });
};

const getTransactionData = async (txid, network) => {
try {
const endpoint = MINTLAYER_ENDPOINTS.GET_TRANSACTION_DATA.replace(':txid', txid);
const response = await tryServers({ endpoint, network });
const data = JSON.parse(response);
return { txid, ...data };
} catch (error) {
console.warn(`Failed to get data for transaction ${txid}: `, error);
throw error;
}
};

const getAddressUtxo = (address, network) => {
const endpoint = MINTLAYER_ENDPOINTS.GET_ADDRESS_UTXO.replace(':address', address);
return tryServers({ endpoint, network });
};

const getWalletUtxos = (addresses) => {
const utxosPromises = addresses.map((address) => getAddressUtxo(address));
return Promise.all(utxosPromises);
};

const getChainTip = async () => {
return tryServers(MINTLAYER_ENDPOINTS.GET_CHAIN_TIP);
};

const getFeesEstimates = async (network) => {
return tryServers({ endpoint: MINTLAYER_ENDPOINTS.GET_FEES_ESTIMATES, network });
};

const broadcastTransaction = (transaction, network) => {
return tryServers({ endpoint: MINTLAYER_ENDPOINTS.POST_TRANSACTION, body: transaction, network });
};

export { TransactionType, getAddressData, getTransactionData, getAddressUtxo, getWalletUtxos, broadcastTransaction, getFeesEstimates, getChainTip, MINTLAYER_ENDPOINTS, ML_NETWORK_TYPES, ML_ATOMS_PER_COIN };
83 changes: 74 additions & 9 deletions blue_modules/currency.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import DefaultPreference from 'react-native-default-preference';
import * as RNLocalize from 'react-native-localize';
import BigNumber from 'bignumber.js';
import { FiatUnit, getFiatRate } from '../models/fiatUnit';
import * as ExchangeRates from '../models/exchangeRates';
import WidgetCommunication from './WidgetCommunication';
import { ML_ATOMS_PER_COIN } from './Mintlayer';

const PREFERRED_CURRENCY_STORAGE_KEY = 'preferredCurrency';
const EXCHANGE_RATES_STORAGE_KEY = 'currency';
Expand Down Expand Up @@ -53,12 +55,13 @@ async function _restoreSavedPreferredFiatCurrencyFromStorage() {
throw Error('No Preferred Fiat selected');
}
} catch (_) {
const deviceCurrencies = RNLocalize.getCurrencies();
if (Object.keys(FiatUnit).some((unit) => unit === deviceCurrencies[0])) {
preferredFiatCurrency = FiatUnit[deviceCurrencies[0]];
} else {
preferredFiatCurrency = FiatUnit.USD;
}
// todo uncomment code with device local currency when ML currency api supports it
// const deviceCurrencies = RNLocalize.getCurrencies();
// if (Object.keys(FiatUnit).some((unit) => unit === deviceCurrencies[0])) {
// preferredFiatCurrency = FiatUnit[deviceCurrencies[0]];
// } else {
preferredFiatCurrency = FiatUnit.USD;
// }
}
}

Expand All @@ -82,13 +85,17 @@ async function updateExchangeRate() {
}
console.log('updating exchange rate...');

let rate;
try {
rate = await getFiatRate(preferredFiatCurrency.endPointKey);
const btcRate = await getFiatRate(preferredFiatCurrency.endPointKey);
exchangeRates[LAST_UPDATED] = +new Date();
exchangeRates['BTC_' + preferredFiatCurrency.endPointKey] = rate;
exchangeRates['BTC_' + preferredFiatCurrency.endPointKey] = btcRate;
exchangeRates.LAST_UPDATED_ERROR = false;
await AsyncStorage.setItem(EXCHANGE_RATES_STORAGE_KEY, JSON.stringify(exchangeRates));

const mlRate = await ExchangeRates.getRate('ml', preferredFiatCurrency.endPointKey);
exchangeRates[LAST_UPDATED] = +new Date();
exchangeRates['ML_' + preferredFiatCurrency.endPointKey] = mlRate[`ml-${preferredFiatCurrency.endPointKey}`];
await AsyncStorage.setItem(EXCHANGE_RATES_STORAGE_KEY, JSON.stringify(exchangeRates));
} catch (Err) {
console.log('Error encountered when attempting to update exchange rate...');
console.warn(Err.message);
Expand Down Expand Up @@ -131,6 +138,43 @@ async function init(clearLastUpdatedTime = false) {
return updateExchangeRate();
}

function mlCoinsToLocalCurrency(ml, format = true) {
if (!exchangeRates['ML_' + preferredFiatCurrency.endPointKey]) {
updateExchangeRate();
return '...';
}

let b = new BigNumber(ml).dividedBy(ML_ATOMS_PER_COIN).multipliedBy(exchangeRates['ML_' + preferredFiatCurrency.endPointKey]);

if (b.isGreaterThanOrEqualTo(0.005) || b.isLessThanOrEqualTo(-0.005)) {
b = b.toFixed(2);
} else {
b = b.toPrecision(2);
}

if (format === false) return b;

let formatter;
try {
formatter = new Intl.NumberFormat(preferredFiatCurrency.locale, {
style: 'currency',
currency: preferredFiatCurrency.endPointKey,
minimumFractionDigits: 2,
maximumFractionDigits: 8,
});
} catch (error) {
console.warn(error);
formatter = new Intl.NumberFormat(FiatUnit.USD.locale, {
style: 'currency',
currency: preferredFiatCurrency.endPointKey,
minimumFractionDigits: 2,
maximumFractionDigits: 8,
});
}

return formatter.format(b);
}

function satoshiToLocalCurrency(satoshi, format = true) {
if (!exchangeRates['BTC_' + preferredFiatCurrency.endPointKey]) {
updateExchangeRate();
Expand Down Expand Up @@ -186,6 +230,7 @@ async function mostRecentFetchedRate() {
return {
LastUpdated: currencyInformation[LAST_UPDATED],
Rate: formatter.format(currencyInformation[`BTC_${preferredFiatCurrency.endPointKey}`]),
MlRate: formatter.format(currencyInformation[`ML_${preferredFiatCurrency.endPointKey}`]),
};
}

Expand All @@ -205,6 +250,22 @@ function fiatToBTC(fiatFloat) {
return b;
}

function coinsToML(coins) {
let b = new BigNumber(coins);
b = b.dividedBy(ML_ATOMS_PER_COIN);
return b.toString(10);
}

function mlToCoins(ml) {
return new BigNumber(ml).multipliedBy(ML_ATOMS_PER_COIN).toNumber();
}

function fiatToML(fiatFloat) {
let b = new BigNumber(fiatFloat);
b = b.dividedBy(exchangeRates['ML_' + preferredFiatCurrency.endPointKey]).toFixed(8);
return b;
}

function getCurrencySymbol() {
return preferredFiatCurrency.symbol;
}
Expand All @@ -230,8 +291,12 @@ function _setExchangeRate(pair, rate) {

module.exports.updateExchangeRate = updateExchangeRate;
module.exports.init = init;
module.exports.mlCoinsToLocalCurrency = mlCoinsToLocalCurrency;
module.exports.satoshiToLocalCurrency = satoshiToLocalCurrency;
module.exports.fiatToBTC = fiatToBTC;
module.exports.coinsToML = coinsToML;
module.exports.mlToCoins = mlToCoins;
module.exports.fiatToML = fiatToML;
module.exports.satoshiToBTC = satoshiToBTC;
module.exports.BTCToLocalCurrency = BTCToLocalCurrency;
module.exports.setPrefferedCurrency = setPrefferedCurrency;
Expand Down
Empty file.
Loading

0 comments on commit b01f82c

Please sign in to comment.