Initial commit: Pezkuwi Wallet Android

Complete rebrand of Nova Wallet for Pezkuwichain ecosystem.

## Features
- Full Pezkuwichain support (HEZ & PEZ tokens)
- Polkadot ecosystem compatibility
- Staking, Governance, DeFi, NFTs
- XCM cross-chain transfers
- Hardware wallet support (Ledger, Polkadot Vault)
- WalletConnect v2
- Push notifications

## Languages
- English, Turkish, Kurmanci (Kurdish), Spanish, French, German, Russian, Japanese, Chinese, Korean, Portuguese, Vietnamese

Based on Nova Wallet by Novasama Technologies GmbH
© Dijital Kurdistan Tech Institute 2026
This commit is contained in:
2026-01-23 01:31:12 +03:00
commit 31c8c5995f
7621 changed files with 425838 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
/build
+39
View File
@@ -0,0 +1,39 @@
apply plugin: 'org.mozilla.rust-android-gradle.rust-android'
android {
ndkVersion "26.1.10909125"
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
namespace 'io.novafoundation.nova.hydra_dx_math'
}
dependencies {
implementation kotlinDep
implementation project(':common')
testImplementation jUnitDep
androidTestImplementation androidTestRunnerDep
androidTestImplementation androidTestRulesDep
androidTestImplementation androidJunitDep
}
cargo {
module = "rust/"
libname = "hydra_dx_math_java"
targets = ["arm", "arm64", "x86", "x86_64"]
profile = "release"
pythonCommand = "python3"
}
tasks.matching { it.name.matches(/merge.*JniLibFolders/) }.configureEach {
it.inputs.dir(new File(buildDir, "rustJniLibs/android"))
it.dependsOn("cargoBuild")
}
+2
View File
@@ -0,0 +1,2 @@
.idea
target
File diff suppressed because it is too large Load Diff
+29
View File
@@ -0,0 +1,29 @@
[package]
authors = ['Novasama Technologies']
edition = '2021'
license = 'Apache 2.0'
name = "hydra-dx-math-java"
repository = 'https://github.com/nova-wallet/nova-wallet-android'
version = "0.1.0"
[dependencies]
serde = { version = "1.0.169", features = ["derive"] }
serde_json = "1.0.100"
serde-aux = "4.2.0"
sp-arithmetic = { git = "https://github.com/galacticcouncil/polkadot-sdk", branch = "stable2409-patch6", default-features = false }
hydra-dx-math = { git = "https://github.com/galacticcouncil/HydraDX-node", version="10.3.0"}
jni = { version = "0.17.0", default-features = false }
[profile.release]
strip = true
lto = true
opt-level = "s"
[lib]
name = "hydra_dx_math_java"
crate_type = ["cdylib"]
[features]
default = ["std"]
std = ["sp-arithmetic/std"]
stableswap = []
+732
View File
@@ -0,0 +1,732 @@
#![allow(non_snake_case)]
extern crate core;
extern crate hydra_dx_math;
extern crate jni;
extern crate serde;
extern crate sp_arithmetic;
use std::collections::HashMap;
use hydra_dx_math::stableswap::types::AssetReserve;
use jni::objects::{JClass, JString};
use jni::sys::jint;
use jni::JNIEnv;
use serde::Deserialize;
use sp_arithmetic::per_things::Permill;
use serde_aux::prelude::*;
fn error() -> String {
"-1".to_string()
}
macro_rules! parse_into {
($x:ty, $y:expr) => {{
let r = if let Some(x) = $y.parse::<$x>().ok() {
x
} else {
println!("Parse failed");
return error();
};
r
}};
}
const D_ITERATIONS: u8 = 128;
const Y_ITERATIONS: u8 = 64;
#[derive(Deserialize, Copy, Clone, Debug)]
pub struct AssetBalance {
asset_id: u32,
#[serde(deserialize_with = "deserialize_number_from_string")]
amount: u128,
decimals: u8,
}
impl From<&AssetBalance> for AssetReserve {
fn from(value: &AssetBalance) -> Self {
Self {
amount: value.amount,
decimals: value.decimals,
}
}
}
#[derive(Deserialize, Copy, Clone, Debug)]
pub struct AssetAmount {
asset_id: u32,
#[serde(deserialize_with = "deserialize_number_from_string")]
amount: u128,
}
// Tuple struct to apply per-field deserializers on u128s
#[derive(Deserialize, Copy, Clone, Debug)]
struct U128Pair(
#[serde(deserialize_with = "deserialize_number_from_string")] u128,
#[serde(deserialize_with = "deserialize_number_from_string")] u128,
);
// Parse JSON like: [["0","0"],["1000000000000","500000000000"],["42","1337"]]
fn parse_pairs(json: &str) -> Option<Vec<(u128, u128)>> {
let v: serde_json::Result<Vec<U128Pair>> = serde_json::from_str(json);
match v {
Ok(vecp) => Some(vecp.into_iter().map(|p| (p.0, p.1)).collect()),
Err(_) => None,
}
}
fn get_str<'a>(jni: &'a JNIEnv<'a>, string: JString<'a>) -> String {
jni.get_string(string).unwrap().to_str().unwrap().to_string()
}
/* ---------------- STABLESWAP ---------------- */
#[no_mangle]
pub fn Java_io_novafoundation_nova_hydra_1dx_1math_stableswap_StableSwapMathBridge_calculate_1out_1given_1in<'a>(
jni_env: JNIEnv<'a>,
_: JClass,
reserves: JString,
asset_in: jint,
asset_out: jint,
amount_in: JString,
amplification: JString,
fee: JString,
pegs: JString,
) -> JString<'a> {
let reserves = get_str(&jni_env, reserves);
let asset_in = asset_in as u32;
let asset_out = asset_out as u32;
let amount_in = get_str(&jni_env, amount_in);
let amplification = get_str(&jni_env, amplification);
let fee = get_str(&jni_env, fee);
let pegs = get_str(&jni_env, pegs);
let out = calculate_out_given_in(
reserves,
asset_in,
asset_out,
amount_in,
amplification,
fee,
pegs,
);
jni_env.new_string(out).unwrap()
}
fn calculate_out_given_in(
reserves: String,
asset_in: u32,
asset_out: u32,
amount_in: String,
amplification: String,
fee: String,
pegs: String,
) -> String {
let reserves: serde_json::Result<Vec<AssetBalance>> = serde_json::from_str(&reserves);
if reserves.is_err() {
return error();
}
let mut reserves = reserves.unwrap();
reserves.sort_by_key(|v| v.asset_id);
let idx_in = reserves.iter().position(|v| v.asset_id == asset_in);
let idx_out = reserves.iter().position(|v| v.asset_id == asset_out);
if idx_in.is_none() || idx_out.is_none() {
return error();
}
let amount_in = parse_into!(u128, amount_in);
let amplification = parse_into!(u128, amplification);
let fee = Permill::from_float(parse_into!(f64, fee));
let balances: Vec<AssetReserve> = reserves.iter().map(|v| v.into()).collect();
// Parse 7th param
let pairs = match parse_pairs(&pegs) {
Some(p) => p,
None => return error(),
};
let result = hydra_dx_math::stableswap::calculate_out_given_in_with_fee::<D_ITERATIONS, Y_ITERATIONS>(
&balances,
idx_in.unwrap(),
idx_out.unwrap(),
amount_in,
amplification,
fee,
&pairs,
);
if let Some(r) = result {
r.0.to_string()
} else {
error()
}
}
#[no_mangle]
pub fn Java_io_novafoundation_nova_hydra_1dx_1math_stableswap_StableSwapMathBridge_calculate_1in_1given_1out<'a>(
jni_env: JNIEnv<'a>,
_: JClass,
reserves: JString,
asset_in: jint,
asset_out: jint,
amount_in: JString,
amplification: JString,
fee: JString,
pegs: JString,
) -> JString<'a> {
let reserves = get_str(&jni_env, reserves);
let asset_in = asset_in as u32;
let asset_out = asset_out as u32;
let amount_in = get_str(&jni_env, amount_in);
let amplification = get_str(&jni_env, amplification);
let fee = get_str(&jni_env, fee);
let pegs = get_str(&jni_env, pegs);
let result = calculate_in_given_out(
reserves,
asset_in,
asset_out,
amount_in,
amplification,
fee,
pegs,
);
jni_env.new_string(result).unwrap()
}
fn calculate_in_given_out(
reserves: String,
asset_in: u32,
asset_out: u32,
amount_out: String,
amplification: String,
fee: String,
pegs: String,
) -> String {
let reserves: serde_json::Result<Vec<AssetBalance>> = serde_json::from_str(&reserves);
if reserves.is_err() {
return error();
}
let mut reserves = reserves.unwrap();
reserves.sort_by_key(|v| v.asset_id);
let idx_in = reserves.iter().position(|v| v.asset_id == asset_in);
let idx_out = reserves.iter().position(|v| v.asset_id == asset_out);
if idx_in.is_none() || idx_out.is_none() {
return error();
}
let amount_out = parse_into!(u128, amount_out);
let amplification = parse_into!(u128, amplification);
let fee = Permill::from_float(parse_into!(f64, fee));
let balances: Vec<AssetReserve> = reserves.iter().map(|v| v.into()).collect();
// Parse 7th param
let pairs = match parse_pairs(&pegs) {
Some(p) => p,
None => return error(),
};
let result =
hydra_dx_math::stableswap::calculate_in_given_out_with_fee::<D_ITERATIONS, Y_ITERATIONS>(
&balances,
idx_in.unwrap(),
idx_out.unwrap(),
amount_out,
amplification,
fee,
&pairs,
);
if let Some(r) = result {
r.0.to_string()
} else {
error()
}
}
#[no_mangle]
pub fn Java_io_novafoundation_nova_hydra_1dx_1math_stableswap_StableSwapMathBridge_calculate_1amplification<'a>(
jni_env: JNIEnv<'a>,
_: JClass,
initial_amplification: JString,
final_amplification: JString,
initial_block: JString,
final_block: JString,
current_block: JString,
) -> JString<'a> {
let initial_amplification = get_str(&jni_env, initial_amplification);
let final_amplification = get_str(&jni_env, final_amplification);
let initial_block = get_str(&jni_env, initial_block);
let final_block = get_str(&jni_env, final_block);
let current_block = get_str(&jni_env, current_block);
let result = calculate_amplification(
initial_amplification,
final_amplification,
initial_block,
final_block,
current_block,
);
jni_env.new_string(result).unwrap()
}
fn calculate_amplification(
initial_amplification: String,
final_amplification: String,
initial_block: String,
final_block: String,
current_block: String,
) -> String {
let initial_amplification = parse_into!(u128, initial_amplification);
let final_amplification = parse_into!(u128, final_amplification);
let initial_block = parse_into!(u128, initial_block);
let final_block = parse_into!(u128, final_block);
let current_block = parse_into!(u128, current_block);
hydra_dx_math::stableswap::calculate_amplification(
initial_amplification,
final_amplification,
initial_block,
final_block,
current_block,
)
.to_string()
}
#[no_mangle]
pub fn Java_io_novafoundation_nova_hydra_1dx_1math_stableswap_StableSwapMathBridge_calculate_1shares<'a>(
jni_env: JNIEnv<'a>,
_: JClass,
reserves: JString,
assets: JString,
amplification: JString,
share_issuance: JString,
fee: JString,
pegs: JString,
) -> JString<'a> {
let reserves = get_str(&jni_env, reserves);
let assets = get_str(&jni_env, assets);
let amplification = get_str(&jni_env, amplification);
let share_issuance = get_str(&jni_env, share_issuance);
let fee = get_str(&jni_env, fee);
let pegs = get_str(&jni_env, pegs);
let result = calculate_shares(reserves, assets, amplification, share_issuance, fee, pegs);
jni_env.new_string(result).unwrap()
}
fn calculate_shares(
reserves: String,
assets: String,
amplification: String,
share_issuance: String,
fee: String,
pegs: String,
) -> String {
let reserves: serde_json::Result<Vec<AssetBalance>> = serde_json::from_str(&reserves);
if reserves.is_err() {
return error();
}
let mut reserves = reserves.unwrap();
reserves.sort_by_key(|v| v.asset_id);
let assets: serde_json::Result<Vec<AssetAmount>> = serde_json::from_str(&assets);
if assets.is_err() {
return error();
}
let assets = assets.unwrap();
if assets.len() > reserves.len() {
return error();
}
let mut updated_reserves = reserves.clone();
let mut liquidity: HashMap<u32, u128> = HashMap::new();
for a in assets.iter() {
let r = liquidity.insert(a.asset_id, a.amount);
if r.is_some() {
return error();
}
}
for reserve in updated_reserves.iter_mut() {
if let Some(v) = liquidity.get(&reserve.asset_id) {
reserve.amount += v;
}
}
let balances: Vec<AssetReserve> = reserves.iter().map(|v| v.into()).collect();
let updated_balances: Vec<AssetReserve> = updated_reserves.iter().map(|v| v.into()).collect();
let amplification = parse_into!(u128, amplification);
let issuance = parse_into!(u128, share_issuance);
let fee = Permill::from_float(parse_into!(f64, fee));
let pairs = match parse_pairs(&pegs) {
Some(p) => p,
None => return error(),
};
let result = hydra_dx_math::stableswap::calculate_shares::<D_ITERATIONS>(
&balances,
&updated_balances,
amplification,
issuance,
fee,
&pairs,
);
if let Some(r) = result {
r.0.to_string()
} else {
error()
}
}
#[no_mangle]
pub fn Java_io_novafoundation_nova_hydra_1dx_1math_stableswap_StableSwapMathBridge_calculate_1shares_1for_1amount<'a>(
jni_env: JNIEnv<'a>,
_: JClass,
reserves: JString,
asset_in: jint,
amount: JString,
amplification: JString,
share_issuance: JString,
fee: JString,
pegs: JString,
) -> JString<'a> {
let reserves = get_str(&jni_env, reserves);
let asset_in = asset_in as u32;
let amount = get_str(&jni_env, amount);
let amplification = get_str(&jni_env, amplification);
let share_issuance = get_str(&jni_env, share_issuance);
let fee = get_str(&jni_env, fee);
let pegs = get_str(&jni_env, pegs);
let result = calculate_shares_for_amount(
reserves,
asset_in,
amount,
amplification,
share_issuance,
fee,
pegs,
);
jni_env.new_string(result).unwrap()
}
fn calculate_shares_for_amount(
reserves: String,
asset_in: u32,
amount: String,
amplification: String,
share_issuance: String,
fee: String,
pegs: String,
) -> String {
let reserves: serde_json::Result<Vec<AssetBalance>> = serde_json::from_str(&reserves);
if reserves.is_err() {
return error();
}
let mut reserves = reserves.unwrap();
reserves.sort_by_key(|v| v.asset_id);
let idx_in = reserves.iter().position(|v| v.asset_id == asset_in);
if idx_in.is_none() {
return error();
}
let amount_in = parse_into!(u128, amount);
let balances: Vec<AssetReserve> = reserves.iter().map(|v| v.into()).collect();
let amplification = parse_into!(u128, amplification);
let issuance = parse_into!(u128, share_issuance);
let fee = Permill::from_float(parse_into!(f64, fee));
// Parse 7th param
let pairs = match parse_pairs(&pegs) {
Some(p) => p,
None => return error(),
};
let result = hydra_dx_math::stableswap::calculate_shares_for_amount::<D_ITERATIONS>(
&balances,
idx_in.unwrap(),
amount_in,
amplification,
issuance,
fee,
&pairs,
);
if let Some(r) = result {
r.0.to_string()
} else {
error()
}
}
#[no_mangle]
pub fn Java_io_novafoundation_nova_hydra_1dx_1math_stableswap_StableSwapMathBridge_calculate_1add_1one_1asset<'a>(
jni_env: JNIEnv<'a>,
_: JClass,
reserves: JString,
shares: JString,
asset_in: jint,
amplification: JString,
share_issuance: JString,
fee: JString,
pegs: JString,
) -> JString<'a> {
let reserves = get_str(&jni_env, reserves);
let shares = get_str(&jni_env, shares);
let asset_in = asset_in as u32;
let amplification = get_str(&jni_env, amplification);
let share_issuance = get_str(&jni_env, share_issuance);
let fee = get_str(&jni_env, fee);
let pegs = get_str(&jni_env, pegs);
let result = calculate_add_one_asset(
reserves,
shares,
asset_in,
amplification,
share_issuance,
fee,
pegs,
);
jni_env.new_string(result).unwrap()
}
fn calculate_add_one_asset(
reserves: String,
shares: String,
asset_in: u32,
amplification: String,
share_issuance: String,
fee: String,
pegs: String,
) -> String {
let reserves: serde_json::Result<Vec<AssetBalance>> = serde_json::from_str(&reserves);
if reserves.is_err() {
return error();
}
let mut reserves = reserves.unwrap();
reserves.sort_by_key(|v| v.asset_id);
let idx_in = reserves.iter().position(|v| v.asset_id == asset_in);
if idx_in.is_none() {
return error();
}
let balances: Vec<AssetReserve> = reserves.iter().map(|v| v.into()).collect();
let shares = parse_into!(u128, shares);
let amplification = parse_into!(u128, amplification);
let issuance = parse_into!(u128, share_issuance);
let fee = Permill::from_float(parse_into!(f64, fee));
let pairs = match parse_pairs(&pegs) {
Some(p) => p,
None => return error(),
};
let result = hydra_dx_math::stableswap::calculate_add_one_asset::<D_ITERATIONS, Y_ITERATIONS>(
&balances,
shares,
idx_in.unwrap(),
issuance,
amplification,
fee,
&pairs,
);
if let Some(r) = result {
r.0.to_string()
} else {
error()
}
}
#[no_mangle]
pub fn Java_io_novafoundation_nova_hydra_1dx_1math_stableswap_StableSwapMathBridge_calculate_1liquidity_1out_1one_1asset<'a>(
jni_env: JNIEnv<'a>,
_: JClass,
reserves: JString,
shares: JString,
asset_out: jint,
amplification: JString,
share_issuance: JString,
withdraw_fee: JString,
pegs: JString,
) -> JString<'a> {
let reserves = get_str(&jni_env, reserves);
let shares = get_str(&jni_env, shares);
let asset_out = asset_out as u32;
let amplification = get_str(&jni_env, amplification);
let share_issuance = get_str(&jni_env, share_issuance);
let withdraw_fee = get_str(&jni_env, withdraw_fee);
let pegs = get_str(&jni_env, pegs);
let result = calculate_liquidity_out_one_asset(
reserves,
shares,
asset_out,
amplification,
share_issuance,
withdraw_fee,
pegs,
);
jni_env.new_string(result).unwrap()
}
fn calculate_liquidity_out_one_asset(
reserves: String,
shares: String,
asset_out: u32,
amplification: String,
share_issuance: String,
withdraw_fee: String,
pegs: String,
) -> String {
let reserves: serde_json::Result<Vec<AssetBalance>> = serde_json::from_str(&reserves);
if reserves.is_err() {
return error();
}
let mut reserves = reserves.unwrap();
reserves.sort_by_key(|v| v.asset_id);
let idx_out = reserves.iter().position(|v| v.asset_id == asset_out);
if idx_out.is_none() {
println!("idx_out error");
return error();
}
let shares_out = parse_into!(u128, shares);
let amplification = parse_into!(u128, amplification);
let issuance = parse_into!(u128, share_issuance);
let fee = Permill::from_float(parse_into!(f64, withdraw_fee));
let balances: Vec<AssetReserve> = reserves.iter().map(|v| v.into()).collect();
let pairs = match parse_pairs(&pegs) {
Some(p) => p,
None => { println!("parse_pairs error"); return error(); },
};
let result = hydra_dx_math::stableswap::calculate_withdraw_one_asset::<D_ITERATIONS, Y_ITERATIONS>(
&balances,
shares_out,
idx_out.unwrap(),
issuance,
amplification,
fee,
&pairs,
);
if let Some(r) = result {
r.0.to_string()
} else {
println!("final result error");
error()
}
}
/* ---------------- XYK ---------------------- */
#[no_mangle]
pub fn Java_io_novafoundation_nova_hydra_1dx_1math_xyk_HYKSwapMathBridge_calculate_1out_1given_1in<'a>(
jni_env: JNIEnv<'a>,
_: JClass,
balance_in: JString,
balance_out: JString,
amount_in: JString,
) -> JString<'a> {
let balance_in: String = get_str(&jni_env, balance_in);
let balance_out: String = get_str(&jni_env, balance_out);
let amount_in: String = get_str(&jni_env, amount_in);
let out = xyk_calculate_out_given_in(balance_in, balance_out, amount_in);
jni_env.new_string(out).unwrap()
}
fn xyk_calculate_out_given_in(balance_in: String, balance_out: String, amount_in: String) -> String {
let balance_in = parse_into!(u128, balance_in);
let balance_out = parse_into!(u128, balance_out);
let amount_in = parse_into!(u128, amount_in);
let result = hydra_dx_math::xyk::calculate_out_given_in(balance_in, balance_out, amount_in);
if let Ok(r) = result {
r.to_string()
} else {
error()
}
}
#[no_mangle]
pub fn Java_io_novafoundation_nova_hydra_1dx_1math_xyk_HYKSwapMathBridge_calculate_1in_1given_1out<'a>(
jni_env: JNIEnv<'a>,
_: JClass,
balance_in: JString,
balance_out: JString,
amount_in: JString,
) -> JString<'a> {
let balance_in: String = get_str(&jni_env, balance_in);
let balance_out: String = get_str(&jni_env, balance_out);
let amount_in: String = get_str(&jni_env, amount_in);
let out = xyk_calculate_in_given_out(balance_in, balance_out, amount_in);
jni_env.new_string(out).unwrap()
}
fn xyk_calculate_in_given_out(balance_in: String, balance_out: String, amount_out: String) -> String {
let balance_in = parse_into!(u128, balance_in);
let balance_out = parse_into!(u128, balance_out);
let amount_out = parse_into!(u128, amount_out);
let result = hydra_dx_math::xyk::calculate_in_given_out(balance_out, balance_in, amount_out);
if let Ok(r) = result {
r.to_string()
} else {
error()
}
}
#[no_mangle]
pub fn Java_io_novafoundation_nova_hydra_1dx_1math_xyk_HYKSwapMathBridge_calculate_1pool_1trade_1fee<'a>(
jni_env: JNIEnv<'a>,
_: JClass,
amount: JString,
fee_nominator: JString,
fee_denominator: JString,
) -> JString<'a> {
let amount: String = get_str(&jni_env, amount);
let fee_nominator: String = get_str(&jni_env, fee_nominator);
let fee_denominator: String = get_str(&jni_env, fee_denominator);
let out = calculate_pool_trade_fee(amount, fee_nominator, fee_denominator);
jni_env.new_string(out).unwrap()
}
fn calculate_pool_trade_fee(amount: String, fee_nominator: String, fee_denominator: String) -> String {
let amount = parse_into!(u128, amount);
let fee_nominator = parse_into!(u32, fee_nominator);
let fee_denominator = parse_into!(u32, fee_denominator);
let result = hydra_dx_math::fee::calculate_pool_trade_fee(amount, (fee_nominator, fee_denominator));
if let Some(r) = result {
r.to_string()
} else {
error()
}
}
@@ -0,0 +1,279 @@
package io.novafoundation.nova.hydra_dx_math.stableswap
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotEquals
import org.junit.Ignore
import org.junit.Test
class StableSwapTest {
@Test
fun shouldCalculateOutGivenIn() {
val data = """
[{
"asset_id": 1,
"amount": "1000000000000",
"decimals": 12
},
{
"asset_id": 0,
"amount": "1000000000000",
"decimals": 12
}
]
"""
val result = StableSwapMathBridge.calculate_out_given_in(
data,
0,
1,
"1000000000",
"1",
"0",
""
)
assertEquals("999500248", result)
}
@Test
fun shouldCalculateInGiveOut() {
val data = """
[{
"asset_id": 1,
"amount": "1000000000000",
"decimals": 12
},
{
"asset_id": 0,
"amount": "1000000000000",
"decimals": 12
}
]
"""
val result = StableSwapMathBridge.calculate_in_given_out(
data,
0,
1,
"1000000000",
"1",
"0",
""
)
assertNotEquals("-1", result)
}
@Test
fun shouldCalculateAmplification() {
val result = StableSwapMathBridge.calculate_amplification("10", "10", "0", "100", "50")
assertEquals("10", result)
}
@Test
fun shouldCalculateShares() {
val data = """
[{
"asset_id": 0,
"amount":"90000000000",
"decimals": 12
},
{
"asset_id": 1,
"amount": "5000000000000000000000",
"decimals": 12
}
]
"""
val assets = """
[{"asset_id":1,"amount":"43000000000000000000"}]
"""
val result = StableSwapMathBridge.calculate_shares(
data,
assets,
"1000",
"64839594451719860",
"0",
""
)
assertEquals("371541351762585", result.toString())
}
@Test
fun shouldCalculateSharesForAmount() {
val data = """
[
{
"asset_id": 0,
"amount": "10000000000000000",
"decimals": 12
},
{
"asset_id": 1,
"amount": "10000000000000000",
"decimals": 12
},
{
"asset_id": 2,
"amount": "10000000000000000",
"decimals": 12
},
{
"asset_id": 3,
"amount": "10000000000000000",
"decimals": 12
},
{
"asset_id": 4,
"amount": "10000000000000000",
"decimals": 12
}
]
"""
val result = StableSwapMathBridge.calculate_shares_for_amount(
data,
0,
"100000000000000",
"100",
"20000000000000000000000",
"0",
""
)
assertEquals("40001593768209443008", result.toString())
}
@Test
@Ignore("The test fails with last digit being 0 instead of 1. We need to check why it happens later")
fun shouldCalculateAddOneAsset() {
val data = """
[
{
"asset_id": 0,
"amount": "10000000000000000",
"decimals": 12
},
{
"asset_id": 1,
"amount": "10000000000000000",
"decimals": 12
},
{
"asset_id": 2,
"amount": "10000000000000000",
"decimals": 12
},
{
"asset_id": 3,
"amount": "10000000000000000",
"decimals": 12
},
{
"asset_id": 4,
"amount": "10000000000000000",
"decimals": 12
}
]
"""
val result = StableSwapMathBridge.calculate_add_one_asset(
data,
"399850144492663029649",
2,
"100",
"20000000000000000000000",
"0",
""
)
assertEquals("1000000000000001", result.toString())
}
@Test
fun shouldcalculateLiquidityOutOneAsset() {
val data = """
[
{
"asset_id": 0,
"amount": "10000000000000000",
"decimals": 12
},
{
"asset_id": 1,
"amount": "10000000000000000",
"decimals": 12
},
{
"asset_id": 2,
"amount": "10000000000000000",
"decimals": 12
},
{
"asset_id": 3,
"amount": "10000000000000000",
"decimals": 12
},
{
"asset_id": 4,
"amount": "10000000000000000",
"decimals": 12
}
]
"""
val result = StableSwapMathBridge.calculate_liquidity_out_one_asset(
data,
"40001593768209443008",
0,
"100",
"20000000000000000000000",
"0",
""
)
assertEquals("99999999999999", result.toString())
}
@Test
fun failingCase() {
val data = """
[{"amount":"2246975221087","decimals":6,"asset_id":10},{"amount":"2256486088023","decimals":6,"asset_id":22}]
"""
val result = StableSwapMathBridge.calculate_liquidity_out_one_asset(
data,
"1000000000",
10,
"100",
"4502091550542833181457210",
"0.00040",
""
)
assertEquals("99999999999999", result.toString())
}
@Test
fun failingCase2() {
val data = """
[{"amount":"505342304916","decimals":6,"asset_id":10},{"amount":"368030436758902944990436","decimals":18,"asset_id":18},{"amount":"410374848833","decimals":6,"asset_id":21},{"amount":"0","decimals":6,"asset_id":23}] """
val result = StableSwapMathBridge.calculate_shares_for_amount(
data,
10,
"10",
"320",
"1662219218861236418723363",
"0.00040",
""
)
assertEquals("99999999999999", result.toString())
}
}
@@ -0,0 +1 @@
<manifest />
@@ -0,0 +1,11 @@
package io.novafoundation.nova.hydra_dx_math
import io.novafoundation.nova.common.utils.atLeastZero
import java.math.BigInteger
object HydraDxMathConversions {
fun String.fromBridgeResultToBalance(): BigInteger? {
return if (this == "-1") null else toBigInteger().atLeastZero()
}
}
@@ -0,0 +1,75 @@
package io.novafoundation.nova.hydra_dx_math.stableswap;
public class StableSwapMathBridge {
static {
System.loadLibrary("hydra_dx_math_java");
}
public static native String calculate_out_given_in(
String reserves,
int asset_in,
int asset_out,
String amount_in,
String amplification,
String fee,
String pegs
);
public static native String calculate_in_given_out(
String reserves,
int asset_in,
int asset_out,
String amount_out,
String amplification,
String fee,
String pegs
);
public static native String calculate_amplification(
String initial_amplification,
String final_amplification,
String initial_block,
String final_block,
String current_block
);
public static native String calculate_shares(
String reserves,
String assets,
String amplification,
String share_issuance,
String fee,
String pegs
);
public static native String calculate_shares_for_amount(
String reserves,
int asset_in,
String amount,
String amplification,
String share_issuance,
String fee,
String pegs
);
public static native String calculate_add_one_asset(
String reserves,
String shares,
int asset_in,
String amplification,
String share_issuance,
String fee,
String pegs
);
public static native String calculate_liquidity_out_one_asset(
String reserves,
String shares,
int asset_out,
String amplification,
String share_issuance,
String withdraw_fee,
String pegs
);
}
@@ -0,0 +1,26 @@
package io.novafoundation.nova.hydra_dx_math.xyk;
public class HYKSwapMathBridge {
static {
System.loadLibrary("hydra_dx_math_java");
}
public static native String calculate_out_given_in(
String balanceIn,
String balanceOut,
String amountIn
);
public static native String calculate_in_given_out(
String balanceIn,
String balanceOut,
String amountOut
);
public static native String calculate_pool_trade_fee(
String amount,
String feeNumerator,
String feeDenominator
);
}
+1
View File
@@ -0,0 +1 @@
/build
+38
View File
@@ -0,0 +1,38 @@
apply plugin: 'org.mozilla.rust-android-gradle.rust-android'
android {
namespace 'io.novafoundation.nova.metadata_shortener'
ndkVersion "26.1.10909125"
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation kotlinDep
testImplementation jUnitDep
androidTestImplementation androidTestRunnerDep
androidTestImplementation androidTestRulesDep
androidTestImplementation androidJunitDep
}
cargo {
module = "rust/"
libname = "metadata_shortener_java"
targets = ["arm", "arm64", "x86", "x86_64"]
profile = "release"
pythonCommand = "python3"
}
tasks.matching { it.name.matches(/merge.*JniLibFolders/) }.configureEach {
it.inputs.dir(new File(buildDir, "rustJniLibs/android"))
it.dependsOn("cargoBuild")
}
+21
View File
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
@@ -0,0 +1,2 @@
.idea
target
+535
View File
@@ -0,0 +1,535 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "array-bytes"
version = "6.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d5dde061bd34119e902bbb2d9b90c5692635cf59fb91d582c2b68043f1b8293"
[[package]]
name = "arrayref"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545"
[[package]]
name = "arrayvec"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
[[package]]
name = "bitvec"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
dependencies = [
"funty",
"radium",
"tap",
"wyz",
]
[[package]]
name = "blake3"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30cca6d3674597c30ddf2c587bf8d9d65c9a84d2326d941cc79c9842dfe0ef52"
dependencies = [
"arrayref",
"arrayvec",
"cc",
"cfg-if",
"constant_time_eq",
]
[[package]]
name = "byte-slice-cast"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c"
[[package]]
name = "bytes"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9"
[[package]]
name = "cc"
version = "1.0.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695"
[[package]]
name = "cesu8"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "combine"
version = "4.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
dependencies = [
"bytes",
"memchr",
]
[[package]]
name = "constant_time_eq"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2"
[[package]]
name = "derive_more"
version = "0.99.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "error-chain"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc"
dependencies = [
"version_check",
]
[[package]]
name = "frame-metadata"
version = "16.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87cf1549fba25a6fcac22785b61698317d958e96cac72a59102ea45b9ae64692"
dependencies = [
"cfg-if",
"parity-scale-codec",
"scale-info",
"serde",
]
[[package]]
name = "funty"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
[[package]]
name = "hashbrown"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
[[package]]
name = "impl-trait-for-tuples"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "indexmap"
version = "2.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
dependencies = [
"equivalent",
"hashbrown",
]
[[package]]
name = "jni"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36bcc950632e48b86da402c5c077590583da5ac0d480103611d5374e7c967a3c"
dependencies = [
"cesu8",
"combine",
"error-chain",
"jni-sys",
"log",
"walkdir",
]
[[package]]
name = "jni-sys"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
[[package]]
name = "log"
version = "0.4.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
[[package]]
name = "memchr"
version = "2.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d0d8b92cd8358e8d229c11df9358decae64d137c5be540952c5ca7b25aea768"
[[package]]
name = "merkleized-metadata"
version = "0.1.0"
source = "git+https://github.com/Zondax/merkleized-metadata?rev=cd1363a2c4702abf34fcc461055f0059b3c32bec#cd1363a2c4702abf34fcc461055f0059b3c32bec"
dependencies = [
"array-bytes",
"blake3",
"frame-metadata",
"parity-scale-codec",
"scale-decode",
"scale-info",
]
[[package]]
name = "metadata-shortener-java"
version = "0.1.0"
dependencies = [
"array-bytes",
"frame-metadata",
"jni",
"merkleized-metadata",
"parity-scale-codec",
]
[[package]]
name = "parity-scale-codec"
version = "3.6.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee"
dependencies = [
"arrayvec",
"bitvec",
"byte-slice-cast",
"impl-trait-for-tuples",
"parity-scale-codec-derive",
"serde",
]
[[package]]
name = "parity-scale-codec-derive"
version = "3.6.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c"
dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "proc-macro-crate"
version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284"
dependencies = [
"toml_edit",
]
[[package]]
name = "proc-macro2"
version = "1.0.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [
"proc-macro2",
]
[[package]]
name = "radium"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]]
name = "scale-bits"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e57b1e7f6b65ed1f04e79a85a57d755ad56d76fdf1e9bddcc9ae14f71fcdcf54"
dependencies = [
"parity-scale-codec",
"scale-type-resolver",
]
[[package]]
name = "scale-decode"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e10e0d345101a013ca3af62c2d44d20213d543cc64d96080c68d931e54360c5"
dependencies = [
"derive_more",
"parity-scale-codec",
"scale-bits",
"scale-type-resolver",
"smallvec",
]
[[package]]
name = "scale-info"
version = "2.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024"
dependencies = [
"bitvec",
"cfg-if",
"derive_more",
"parity-scale-codec",
"scale-info-derive",
"serde",
]
[[package]]
name = "scale-info-derive"
version = "2.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62"
dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "scale-type-resolver"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0cded6518aa0bd6c1be2b88ac81bf7044992f0f154bfbabd5ad34f43512abcb"
[[package]]
name = "serde"
version = "1.0.203"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.203"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.66",
]
[[package]]
name = "smallvec"
version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "tap"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
[[package]]
name = "toml_datetime"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf"
[[package]]
name = "toml_edit"
version = "0.21.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1"
dependencies = [
"indexmap",
"toml_datetime",
"winnow",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "walkdir"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
dependencies = [
"same-file",
"winapi-util",
]
[[package]]
name = "winapi-util"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b"
dependencies = [
"windows-sys",
]
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
[[package]]
name = "windows_i686_gnu"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
[[package]]
name = "windows_i686_msvc"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
[[package]]
name = "winnow"
version = "0.5.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876"
dependencies = [
"memchr",
]
[[package]]
name = "wyz"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
dependencies = [
"tap",
]
@@ -0,0 +1,23 @@
[package]
authors = ['Novasama Technologies']
edition = '2021'
license = 'Apache 2.0'
name = "metadata-shortener-java"
repository = 'https://github.com/nova-wallet/nova-wallet-android'
version = "0.1.0"
[dependencies]
array-bytes = "6.2.2"
merkleized-metadata = { git = "https://github.com/Zondax/merkleized-metadata", default-features = false, rev = "cd1363a2c4702abf34fcc461055f0059b3c32bec" }
jni = { version = "0.17.0", default-features = false }
frame-metadata = { version = "16.0.0", features = [ "current" ] }
codec = { package = "parity-scale-codec", version = "3.6.9", features = [ "derive" ] }
[profile.release]
strip = true
lto = true
opt-level = "s"
[lib]
name = "metadata_shortener_java"
crate_type = ["cdylib"]
+214
View File
@@ -0,0 +1,214 @@
#![allow(non_snake_case)]
extern crate core;
extern crate jni;
extern crate merkleized_metadata;
use codec::{Decode, Encode};
use frame_metadata::{RuntimeMetadataPrefixed, OpaqueMetadata, RuntimeMetadata};
use jni::{errors::Result as JniResult, sys::jint};
use jni::objects::{JClass, JString};
use jni::sys::jbyteArray;
use jni::JNIEnv;
use merkleized_metadata::{generate_metadata_digest, generate_proof_for_extrinsic_parts, ExtraInfo, SignedExtrinsicData, FrameMetadataPrepared, Proof, ExtrinsicMetadata};
use std::ptr;
#[derive(Encode)]
pub struct MetadataProof {
proof: Proof,
extrinsic: ExtrinsicMetadata,
extra_info: ExtraInfo,
}
macro_rules! r#try_or_throw {
($jni_env: ident, $expr:expr, $ret: expr) => {
match $expr {
JniResult::Ok(val) => val,
JniResult::Err(err) => {
$jni_env
.throw_new("java/lang/Exception", err.description())
.unwrap();
return $ret;
}
}
};
($expr:expr,) => {
$crate::r#try!($expr)
};
}
macro_rules! r#try_or_throw_null {
($jni_env: ident, $expr:expr) => {
try_or_throw!($jni_env, $expr, ptr::null_mut())
};
}
#[no_mangle]
fn Java_io_novafoundation_nova_metadata_1shortener_MetadataShortener_generate_1extrinsic_1proof(
jni_env: JNIEnv,
_: JClass,
call: jbyteArray,
signed_extras: jbyteArray,
additional_signed: jbyteArray,
metadata: jbyteArray,
spec_version: jint,
spec_name: JString,
base58_prefix: jint,
decimals: jint,
token_symbol: JString,
) -> jbyteArray {
let Some(metadata) = decode_metadata(&jni_env, metadata) else {
return ptr::null_mut();
};
let included_in_extrinsic =
try_or_throw_null!(jni_env, jni_env.convert_byte_array(signed_extras));
let included_in_signed_data =
try_or_throw_null!(jni_env, jni_env.convert_byte_array(additional_signed));
let call_vec = try_or_throw_null!(jni_env, jni_env.convert_byte_array(call));
let signed_ext_data = SignedExtrinsicData {
included_in_extrinsic: included_in_extrinsic.as_slice(),
included_in_signed_data: included_in_signed_data.as_slice(),
};
let spec_version = spec_version as u32;
let spec_name = try_or_throw_null!(jni_env, jni_env.get_string(spec_name));
let base58_prefix = base58_prefix as u16;
let decimals = decimals as u8;
let token_symbol = try_or_throw_null!(jni_env, jni_env.get_string(token_symbol));
let extra_info = ExtraInfo {
spec_version: spec_version,
spec_name: spec_name.into(),
base58_prefix: base58_prefix,
decimals: decimals,
token_symbol: token_symbol.into(),
};
let extrinsic_metadata = FrameMetadataPrepared::prepare(&metadata)
.unwrap()
.as_type_information()
.unwrap()
.extrinsic_metadata;
let Ok(registry_proof) =
generate_proof_for_extrinsic_parts(call_vec.as_slice(), Some(signed_ext_data), &metadata)
else {
jni_env
.throw_new("java/lang/Exception", "Failed to construct proof")
.unwrap();
return ptr::null_mut();
};
let meta_proof = MetadataProof {
proof: registry_proof,
extrinsic: extrinsic_metadata,
extra_info: extra_info,
};
let prood_encoded = meta_proof.encode();
try_or_throw_null!(
jni_env,
jni_env.byte_array_from_slice(prood_encoded.as_slice().as_ref())
)
}
#[no_mangle]
fn Java_io_novafoundation_nova_metadata_1shortener_MetadataShortener_generate_1metadata_1digest(
jni_env: JNIEnv,
_: JClass,
metadata: jbyteArray,
spec_version: jint,
spec_name: JString,
base58_prefix: jint,
decimals: jint,
token_symbol: JString,
) -> jbyteArray {
let Some(metadata) = decode_metadata(&jni_env, metadata) else {
return ptr::null_mut();
};
let spec_version = spec_version as u32;
let spec_name = try_or_throw_null!(jni_env, jni_env.get_string(spec_name));
let base58_prefix = base58_prefix as u16;
let decimals = decimals as u8;
let token_symbol = try_or_throw_null!(jni_env, jni_env.get_string(token_symbol));
let extra_info = ExtraInfo {
spec_version: spec_version,
spec_name: spec_name.into(),
base58_prefix: base58_prefix,
decimals: decimals,
token_symbol: token_symbol.into(),
};
let Ok(digest) = generate_metadata_digest(&metadata, extra_info) else {
jni_env
.throw_new("java/lang/Exception", "Failed to generate digest")
.unwrap();
return ptr::null_mut();
};
let digest_hash = digest.hash();
try_or_throw_null!(
jni_env,
jni_env.byte_array_from_slice(digest_hash.as_slice().as_ref())
)
}
fn decode_metadata(jni_env: &JNIEnv, metadata: jbyteArray) -> Option<RuntimeMetadata> {
let metadata = try_or_throw!(jni_env, jni_env.convert_byte_array(metadata), None);
let Some(metadata) = Option::<OpaqueMetadata>::decode(&mut &metadata[..])
.ok()
.flatten() else {
jni_env
.throw_new("java/lang/Exception", "Failed to decode opaque metadata")
.unwrap();
return None;
};
let metadata = metadata.0;
let Ok(metadata) = RuntimeMetadataPrefixed::decode(&mut &metadata[..]) else {
jni_env
.throw_new("java/lang/Exception", "Failed to decode metadata")
.unwrap();
return None
};
Some(metadata.1)
}
// fn main() {
// let signed_extras = "15000000";
// let additional_signed = "104a0f001900000091b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c36c9f8deedd0c7f1aae4d1900c88456f23d9c224934e6b8c57f750c8b146997c1";
// let call = "050000010101010101010101010101010101010101010101010101010101010101010104";
// let metadata = "Metadata goes here";
// let signed_extras = hex2bytes(signed_extras).expect("Cant decode signed extras");
// let additional_signed = hex2bytes(additional_signed).expect("Cant decode additional signed");
// let call = hex2bytes(call).expect("Cant decode call");
// let metadata = hex2bytes(metadata).expect("Cant decode metadata");
// let metadata = Option::<OpaqueMetadata>::decode(&mut &metadata[..])
// .expect("Failed to decode opaque metadata")
// .expect("Metadata V15 support is required.")
// .0;
// let metadata = RuntimeMetadataPrefixed::decode(&mut &metadata[..]).expect("Failed to decode metadata");
// let signed_ext_data = SignedExtrinsicData {
// included_in_extrinsic: signed_extras.as_slice(),
// included_in_signed_data: additional_signed.as_slice(),
// };
// let proof = generate_proof_for_extrinsic_parts(call.as_slice(), Some(signed_ext_data), &metadata.1)
// .expect("Failed to generate proof");
// }
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>
@@ -0,0 +1,30 @@
package io.novafoundation.nova.metadata_shortener;
public class MetadataShortener {
static {
System.loadLibrary("metadata_shortener_java");
}
public static native byte[] generate_extrinsic_proof(
byte[] call,
byte[] signed_extras,
byte[] additional_signed,
byte[] metadata,
int spec_version,
String spec_name,
int base58_prefix,
int decimals,
String token_symbol
);
public static native byte[] generate_metadata_digest(
byte[] metadata,
int spec_version,
String spec_name,
int base58_prefix,
int decimals,
String token_symbol
);
}