Skip to content

Commit 179b351

Browse files
Merge branch 'master' into s/ton-mnemonic
2 parents efb6e22 + 992b248 commit 179b351

File tree

7 files changed

+112
-9
lines changed

7 files changed

+112
-9
lines changed

include/TrustWalletCore/TWSolanaAddress.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@ void TWSolanaAddressDelete(struct TWSolanaAddress* _Nonnull address);
3535
TW_EXPORT_METHOD
3636
TWString* _Nullable TWSolanaAddressDefaultTokenAddress(struct TWSolanaAddress* _Nonnull address, TWString* _Nonnull tokenMintAddress);
3737

38+
/// Derive token 2022 address for token
39+
///
40+
/// \param address Non-null pointer to a Solana Address
41+
/// \param tokenMintAddress Non-null pointer to a token mint address as a string
42+
/// \return Null pointer if the token 2022 address for a token is not found, valid pointer otherwise
43+
TW_EXPORT_METHOD
44+
TWString* _Nullable TWSolanaAddressToken2022Address(struct TWSolanaAddress* _Nonnull address, TWString* _Nonnull tokenMintAddress);
45+
3846
/// Returns the address string representation.
3947
///
4048
/// \param address Non-null pointer to a Solana Address

rust/chains/tw_solana/src/program/stake_program.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,13 @@ impl StakeProgram {
3737
/// https://github.com/solana-labs/solana-program-library/blob/master/associated-token-account/program/src/lib.rs#L35
3838
pub fn get_associated_token_address(
3939
main_address: SolanaAddress,
40+
token_program_id: SolanaAddress,
4041
token_mint_address: SolanaAddress,
4142
) -> AddressResult<SolanaAddress> {
4243
SolanaAddress::find_program_address(
4344
&[
4445
main_address.bytes().as_slice(),
45-
TOKEN_PROGRAM_ID_ADDRESS.bytes().as_slice(),
46+
token_program_id.bytes().as_slice(),
4647
token_mint_address.bytes().as_slice(),
4748
],
4849
*ASSOCIATED_TOKEN_PROGRAM_ID_ADDRESS,

rust/chains/tw_solana/tests/get_default_token_address.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use std::str::FromStr;
66
use tw_solana::address::SolanaAddress;
77
use tw_solana::blockhash::Blockhash;
8+
use tw_solana::defined_addresses::TOKEN_PROGRAM_ID_ADDRESS;
89
use tw_solana::program::stake_program::StakeProgram;
910

1011
fn test_get_default_token_address_impl(
@@ -16,8 +17,12 @@ fn test_get_default_token_address_impl(
1617
let token_mint_address = SolanaAddress::from_str(token_mint_address).unwrap();
1718
let expected = SolanaAddress::from_str(expected).unwrap();
1819

19-
let actual = StakeProgram::get_associated_token_address(main_address, token_mint_address)
20-
.expect("!get_associated_token_address");
20+
let actual = StakeProgram::get_associated_token_address(
21+
main_address,
22+
*TOKEN_PROGRAM_ID_ADDRESS,
23+
token_mint_address,
24+
)
25+
.expect("!get_associated_token_address");
2126
assert_eq!(actual, expected);
2227
}
2328

rust/wallet_core_rs/src/ffi/solana/address.rs

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use tw_memory::ffi::tw_string::TWString;
99
use tw_memory::ffi::RawPtrTrait;
1010
use tw_misc::try_or_else;
1111
use tw_solana::address::SolanaAddress;
12+
use tw_solana::defined_addresses::{TOKEN_2022_PROGRAM_ID_ADDRESS, TOKEN_PROGRAM_ID_ADDRESS};
1213
use tw_solana::program::stake_program::StakeProgram;
1314

1415
/// Derive default token address for token
@@ -20,26 +21,50 @@ use tw_solana::program::stake_program::StakeProgram;
2021
pub unsafe extern "C" fn tw_solana_address_default_token_address(
2122
address: *const TWString,
2223
token_mint_address: *const TWString,
24+
) -> *mut TWString {
25+
tw_solana_address_token_address_impl(address, token_mint_address, *TOKEN_PROGRAM_ID_ADDRESS)
26+
}
27+
28+
/// Derive token 2022 address for token
29+
///
30+
/// \param address Non-null pointer to a Solana Address
31+
/// \param token_mint_address Non-null pointer to a token mint address as a string
32+
/// \return Null pointer if the token 2022 address for a token is not found, valid pointer otherwise
33+
#[no_mangle]
34+
pub unsafe extern "C" fn tw_solana_address_token_2022_address(
35+
address: *const TWString,
36+
token_mint_address: *const TWString,
37+
) -> *mut TWString {
38+
tw_solana_address_token_address_impl(
39+
address,
40+
token_mint_address,
41+
*TOKEN_2022_PROGRAM_ID_ADDRESS,
42+
)
43+
}
44+
45+
unsafe fn tw_solana_address_token_address_impl(
46+
address: *const TWString,
47+
token_mint_address: *const TWString,
48+
token_address: SolanaAddress,
2349
) -> *mut TWString {
2450
let main_address = try_or_else!(TWString::from_ptr_as_ref(address), std::ptr::null_mut);
2551
let main_address = try_or_else!(main_address.as_str(), std::ptr::null_mut);
52+
let main_address = try_or_else!(SolanaAddress::from_str(main_address), std::ptr::null_mut);
2653

2754
let token_mint_address = try_or_else!(
2855
TWString::from_ptr_as_ref(token_mint_address),
2956
std::ptr::null_mut
3057
);
3158
let token_mint_address = try_or_else!(token_mint_address.as_str(), std::ptr::null_mut);
32-
33-
let main_address = try_or_else!(SolanaAddress::from_str(main_address), std::ptr::null_mut);
3459
let token_mint_address = try_or_else!(
3560
SolanaAddress::from_str(token_mint_address),
3661
std::ptr::null_mut
3762
);
3863

39-
let token_address = try_or_else!(
40-
StakeProgram::get_associated_token_address(main_address, token_mint_address),
64+
let associated_token_address = try_or_else!(
65+
StakeProgram::get_associated_token_address(main_address, token_address, token_mint_address),
4166
std::ptr::null_mut
4267
);
4368

44-
TWString::from(token_address.to_string()).into_ptr()
69+
TWString::from(associated_token_address.to_string()).into_ptr()
4570
}

rust/wallet_core_rs/tests/solana/solana_address.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
// Copyright © 2017 Trust Wallet.
44

55
use tw_memory::test_utils::tw_string_helper::TWStringHelper;
6-
use wallet_core_rs::ffi::solana::address::tw_solana_address_default_token_address;
6+
use wallet_core_rs::ffi::solana::address::{
7+
tw_solana_address_default_token_address, tw_solana_address_token_2022_address,
8+
};
79

810
#[test]
911
fn test_solana_address_default_token_address() {
@@ -24,3 +26,23 @@ fn test_solana_address_default_token_address() {
2426

2527
assert_eq!(actual, "EDNd1ycsydWYwVmrYZvqYazFqwk1QjBgAUKFjBoz1jKP");
2628
}
29+
30+
#[test]
31+
fn test_solana_address_token_2022_address() {
32+
let main_address = "68dzdXkni9BrAwU1asAwurMEdQhXUJq6MNY8niDAny8t";
33+
let main_address = TWStringHelper::create(main_address);
34+
35+
let token_mint_address = "7atgF8KQo4wJrD5ATGX7t1V2zVvykPJbFfNeVf1icFv1";
36+
let token_mint_address = TWStringHelper::create(token_mint_address);
37+
38+
let actual = unsafe {
39+
TWStringHelper::wrap(tw_solana_address_token_2022_address(
40+
main_address.ptr(),
41+
token_mint_address.ptr(),
42+
))
43+
}
44+
.to_string()
45+
.expect("!tw_solana_address_associated_token_address returned a nullptr");
46+
47+
assert_eq!(actual, "3PaFQnebQMHBgthRScup2B932cMxA1GBP7m9roCkomHq");
48+
}

src/interface/TWSolanaAddress.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,25 @@ TWString* _Nullable TWSolanaAddressDefaultTokenAddress(struct TWSolanaAddress* _
3535
}
3636
}
3737

38+
TWString* _Nullable TWSolanaAddressToken2022Address(struct TWSolanaAddress* _Nonnull address, TWString* _Nonnull tokenMintAddress) {
39+
try {
40+
if (address == nullptr || tokenMintAddress == nullptr) {
41+
return nullptr;
42+
}
43+
Rust::TWStringWrapper tokenMintAddressWrapper = TWStringUTF8Bytes(tokenMintAddress);
44+
Rust::TWStringWrapper mainAddress = address->impl.string();
45+
46+
Rust::TWStringWrapper newTokenAddress = Rust::tw_solana_address_token_2022_address(mainAddress.get(), tokenMintAddressWrapper.get());
47+
48+
if (!newTokenAddress) {
49+
return nullptr;
50+
}
51+
return TWStringCreateWithUTF8Bytes(newTokenAddress.c_str());
52+
} catch (...) {
53+
return nullptr;
54+
}
55+
}
56+
3857
TWString* _Nonnull TWSolanaAddressDescription(struct TWSolanaAddress* _Nonnull address) {
3958
return TWStringCreateWithUTF8Bytes(address->impl.string().c_str());
4059
}

tests/chains/Solana/TWSolanaAddressTests.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,26 @@ TEST(TWSolanaProgram, defaultTokenAddressError) {
4747

4848
EXPECT_EQ(TWSolanaAddressDefaultTokenAddress(solanaAddress.get(), serumToken.get()), nullptr);
4949
}
50+
51+
TEST(TWSolanaProgram, token2022Address) {
52+
const auto solAddress = STRING("68dzdXkni9BrAwU1asAwurMEdQhXUJq6MNY8niDAny8t");
53+
const auto catwifhatToken = STRING("7atgF8KQo4wJrD5ATGX7t1V2zVvykPJbFfNeVf1icFv1");
54+
55+
auto solanaAddress = WRAP(TWSolanaAddress, TWSolanaAddressCreateWithString(solAddress.get()));
56+
auto description = WRAPS(TWSolanaAddressDescription(solanaAddress.get()));
57+
auto tokenAddress = WRAPS(TWSolanaAddressToken2022Address(solanaAddress.get(), catwifhatToken.get()));
58+
59+
assertStringsEqual(tokenAddress, "3PaFQnebQMHBgthRScup2B932cMxA1GBP7m9roCkomHq");
60+
assertStringsEqual(description, "68dzdXkni9BrAwU1asAwurMEdQhXUJq6MNY8niDAny8t");
61+
}
62+
63+
TEST(TWSolanaProgram, token2022AddressError) {
64+
const auto solAddress = STRING("68dzdXkni9BrAwU1asAwurMEdQhXUJq6MNY8niDAny8t");
65+
// Invalid token mint address.
66+
const auto catwifhatToken = STRING("7atgF8KQo4wJrD5ATGX7t1V2zVvykPJbFfNeVf1icF");
67+
68+
auto solanaAddress = WRAP(TWSolanaAddress, TWSolanaAddressCreateWithString(solAddress.get()));
69+
auto description = WRAPS(TWSolanaAddressDescription(solanaAddress.get()));
70+
71+
EXPECT_EQ(TWSolanaAddressToken2022Address(solanaAddress.get(), catwifhatToken.get()), nullptr);
72+
}

0 commit comments

Comments
 (0)