Skip to content

fix api server Burn output and tx inspect freezable #1911

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions api-server/stack-test-suite/tests/v2/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -529,14 +529,14 @@ async fn mint_tokens(#[case] seed: Seed) {
TxInput::from_utxo(tx1_id.into(), 0),
empty_witness(&mut rng),
)
.add_output(TxOutput::Burn(OutputValue::TokenV1(
token_id,
amount_to_mint,
)))
.add_output(TxOutput::Transfer(
OutputValue::Coin(coins_after_mint),
Destination::AnyoneCanSpend,
))
.add_output(TxOutput::Transfer(
OutputValue::TokenV1(token_id, amount_to_mint),
Destination::AnyoneCanSpend,
))
.build();

let tx2_id = tx2.transaction().get_id();
Expand Down Expand Up @@ -615,5 +615,10 @@ async fn mint_tokens(#[case] seed: Seed) {
mint_amount
);

let outputs = body.get("outputs").unwrap().as_array().unwrap();
assert_eq!(outputs.len(), 2);
let burn_out = outputs.first().unwrap().as_object().unwrap();
assert_eq!(burn_out.get("type").unwrap().as_str().unwrap(), "Burn",);

task.abort();
}
2 changes: 1 addition & 1 deletion api-server/web-server/src/api/json_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ pub fn txoutput_to_json(
}
TxOutput::Burn(value) => {
json!({
"type": "LockThenTransfer",
"type": "Burn",
"value": outputvalue_to_json(value, chain_config, token_decimals),
})
}
Expand Down
4 changes: 2 additions & 2 deletions common/src/chain/transaction/output/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,8 @@ impl TextSummary for TxOutput {
TokenTotalSupply::Unlimited => "Unlimited".to_string(),
};
let fmt_tkn_frzble = |f: &IsTokenFreezable| match f {
IsTokenFreezable::No => "Yes".to_string(),
IsTokenFreezable::Yes => "No".to_string(),
IsTokenFreezable::No => "No".to_string(),
IsTokenFreezable::Yes => "Yes".to_string(),
};
let fmt_tkn_iss = |iss: &TokenIssuance| {
match iss {
Expand Down
11 changes: 6 additions & 5 deletions test/functional/test_framework/wallet_cli_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -329,14 +329,15 @@ async def issue_new_token(self,
metadata_uri: str,
destination_address: str,
token_supply: str = 'unlimited',
is_freezable: str = 'freezable') -> Tuple[Optional[str], Optional[str]]:
is_freezable: str = 'freezable') -> Tuple[Optional[str], Optional[str], Optional[str]]:
output = await self._write_command(f'token-issue-new "{token_ticker}" "{number_of_decimals}" "{metadata_uri}" {destination_address} {token_supply} {is_freezable}\n')
if output.startswith("A new token has been issued with ID"):
begin = output.find(':') + 2
end = output.find(' ', begin)
return output[begin:end], None
token_id_begin = output.find(':') + 2
token_id_end = output.find(' ', token_id_begin)
tx_id_begin = output.find(':', token_id_end) + 2
return output[token_id_begin:token_id_end], output[tx_id_begin:], None

return None, output
return None, None, output

async def mint_tokens(self, token_id: str, address: str, amount: int) -> str:
return await self._write_command(f"token-mint {token_id} {address} {amount}\n")
Expand Down
4 changes: 2 additions & 2 deletions test/functional/test_framework/wallet_rpc_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,9 +291,9 @@ async def issue_new_token(self,
])

if 'result' in result:
return result['result']['token_id'], None
return result['result']['token_id'], result['result']['tx_id'], None
else:
return None, result['error']
return None, None, result['error']

async def mint_tokens(self, token_id: str, address: str, amount: int) -> str:
return self._write_command("token_mint", [self.account, token_id, address, {'decimal': str(amount)}, {'in_top_x_mb': 5}])['result']
Expand Down
3 changes: 2 additions & 1 deletion test/functional/wallet_conflict.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,9 @@ async def async_test(self):
assert_in(f"Coins amount: {coins_to_send * 2 + token_fee}", await wallet.get_balance())

address = await wallet.new_address()
token_id, err = await wallet.issue_new_token("XXX", 2, "http://uri", address)
token_id, tx_id, err = await wallet.issue_new_token("XXX", 2, "http://uri", address)
assert token_id is not None
assert tx_id is not None
assert err is None

self.generate_block()
Expand Down
2 changes: 1 addition & 1 deletion test/functional/wallet_htlc_refund.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ async def async_test(self):
# issue a valid token
token_ticker = "XXXX"
token_number_of_decimals = 2
token_id, _ = (await wallet.issue_new_token(token_ticker, token_number_of_decimals, "http://uri", alice_address))
token_id, _, _ = (await wallet.issue_new_token(token_ticker, token_number_of_decimals, "http://uri", alice_address))
assert token_id is not None
self.log.info(f"new token id: {token_id}")
token_id_hex = node.test_functions_reveal_token_id(token_id)
Expand Down
2 changes: 1 addition & 1 deletion test/functional/wallet_htlc_spend.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ async def async_test(self):
assert_not_in("Tokens", balance)

# issue a valid token
token_id, _ = (await wallet.issue_new_token("XXXX", 2, "http://uri", alice_address))
token_id, _, _ = (await wallet.issue_new_token("XXXX", 2, "http://uri", alice_address))
assert token_id is not None
self.log.info(f"new token id: {token_id}")

Expand Down
2 changes: 1 addition & 1 deletion test/functional/wallet_orders.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ async def async_test(self):
assert_not_in("Tokens", balance)

# issue a valid token
token_id, _ = (await wallet.issue_new_token("XXXX", 2, "http://uri", alice_address))
token_id, _, _ = (await wallet.issue_new_token("XXXX", 2, "http://uri", alice_address))
assert token_id is not None
self.log.info(f"new token id: {token_id}")

Expand Down
10 changes: 7 additions & 3 deletions test/functional/wallet_sweep_address.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,21 +172,25 @@ def make_locked_output(pub_key_bytes):

# issue some tokens to also transfer
tokens_address = await wallet.new_address()
token_id, err = await wallet.issue_new_token("XXX", 2, "http://uri", tokens_address)
token_id, tx_id, err = await wallet.issue_new_token("XXX", 2, "http://uri", tokens_address)
assert token_id is not None
assert tx_id is not None
assert err is None
self.log.info(f"new token id: {token_id}")
self.log.info(f"new token id: {token_id} tx_id: {tx_id}")
assert node.mempool_contains_tx(tx_id)
block_id = self.generate_block()
assert_in("Success", await wallet.sync())
assert_in("The transaction was submitted successfully", await wallet.mint_tokens(token_id, tokens_address, 10000))
addresses.append(tokens_address)

# issue some more tokens but freeze them
frozen_tokens_address = await wallet.new_address()
frozen_token_id, err = await wallet.issue_new_token("XXX", 2, "http://uri", frozen_tokens_address)
frozen_token_id, frozen_tx_id, err = await wallet.issue_new_token("XXX", 2, "http://uri", frozen_tokens_address)
assert frozen_token_id is not None
assert frozen_tx_id is not None
assert err is None
self.log.info(f"new token id: {frozen_token_id}")
assert node.mempool_contains_tx(frozen_tx_id)
block_id = self.generate_block()
assert_in("Success", await wallet.sync())
assert_in("The transaction was submitted successfully", await wallet.mint_tokens(frozen_token_id, frozen_tokens_address, 10000))
Expand Down
18 changes: 12 additions & 6 deletions test/functional/wallet_tokens.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,34 +117,39 @@ async def async_test(self):
# invalid ticker
# > max len
invalid_ticker = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(random.randint(13, 20)))
token_id, err = await wallet.issue_new_token(invalid_ticker, 2, "http://uri", address)
token_id, tx_id, err = await wallet.issue_new_token(invalid_ticker, 2, "http://uri", address)
assert token_id is None
assert tx_id is None
assert err is not None
assert_in("Invalid ticker length", err)
# non alphanumeric
invalid_ticker = "asd" + random.choice(r"#$%&'()*+,-./:;<=>?@[]^_`{|}~")
token_id, err = await wallet.issue_new_token("asd#", 2, "http://uri", address)
token_id, tx_id, err = await wallet.issue_new_token("asd#", 2, "http://uri", address)
assert token_id is None
assert tx_id is None
assert err is not None
assert_in("Invalid character in token ticker", err)

# invalid url
token_id, err = await wallet.issue_new_token("XXX", 2, "123 123", address)
token_id, tx_id, err = await wallet.issue_new_token("XXX", 2, "123 123", address)
assert token_id is None
assert tx_id is None
assert err is not None
assert_in("Incorrect metadata URI", err)

# invalid num decimals
token_id, err = await wallet.issue_new_token("XXX", 99, "http://uri", address)
token_id, tx_id, err = await wallet.issue_new_token("XXX", 99, "http://uri", address)
assert token_id is None
assert tx_id is None
assert err is not None
assert_in("Too many decimals", err)

# issue a valid token
valid_ticker = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(random.randint(1, 5)))
num_decimals = random.randint(1, 5)
token_id, err = await wallet.issue_new_token(valid_ticker, num_decimals, "http://uri", address)
token_id, tx_id, err = await wallet.issue_new_token(valid_ticker, num_decimals, "http://uri", address)
assert token_id is not None
assert tx_id is not None
assert err is None
self.log.info(f"new token id: {token_id}")

Expand Down Expand Up @@ -186,8 +191,9 @@ async def async_test(self):
assert_in(f"{token_id} amount: {token_balance_str}", await wallet.get_balance())

## try to issue a new token, should fail with not enough coins
token_id, err = await wallet.issue_new_token("XXX", 2, "http://uri", address)
token_id, tx_id, err = await wallet.issue_new_token("XXX", 2, "http://uri", address)
assert token_id is None
assert tx_id is None
assert err is not None
assert_in("Not enough funds", err)

Expand Down
3 changes: 2 additions & 1 deletion test/functional/wallet_tokens_change_authority.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,9 @@ async def async_test(self):
address = await wallet.new_address()

# issue a valid token
token_id, err = await wallet.issue_new_token("XXX", 2, "http://uri", address, token_supply='lockable')
token_id, tx_id, err = await wallet.issue_new_token("XXX", 2, "http://uri", address, token_supply='lockable')
assert token_id is not None
assert tx_id is not None
assert err is None
self.log.info(f"new token id: {token_id}")

Expand Down
3 changes: 2 additions & 1 deletion test/functional/wallet_tokens_change_metadata_uri.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,9 @@ async def async_test(self):
# issue a valid token
address = await wallet.new_address()
metadata_uri = "http://uri"
token_id, err = await wallet.issue_new_token("XXX", 2, metadata_uri, address, token_supply='lockable')
token_id, tx_id, err = await wallet.issue_new_token("XXX", 2, metadata_uri, address, token_supply='lockable')
assert token_id is not None
assert tx_id is not None
assert err is None
self.log.info(f"new token id: {token_id}")

Expand Down
15 changes: 10 additions & 5 deletions test/functional/wallet_tokens_change_supply.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,32 +115,37 @@ async def async_test(self):

# invalid ticker
# > max len
token_id, err = await wallet.issue_new_token("aaabbbcccddde", 2, "http://uri", address)
token_id, tx_id, err = await wallet.issue_new_token("aaabbbcccddde", 2, "http://uri", address)
assert token_id is None
assert tx_id is None
assert err is not None
assert_in("Invalid ticker length", err)
# non alphanumeric
token_id, err = await wallet.issue_new_token("asd#", 2, "http://uri", address)
token_id, tx_id, err = await wallet.issue_new_token("asd#", 2, "http://uri", address)
assert token_id is None
assert tx_id is None
assert err is not None
assert_in("Invalid character in token ticker", err)

# invalid url
token_id, err = await wallet.issue_new_token("XXX", 2, "123 123", address)
token_id, tx_id, err = await wallet.issue_new_token("XXX", 2, "123 123", address)
assert token_id is None
assert tx_id is None
assert err is not None
assert_in("Incorrect metadata URI", err)

# invalid num decimals
token_id, err = await wallet.issue_new_token("XXX", 99, "http://uri", address)
token_id, tx_id, err = await wallet.issue_new_token("XXX", 99, "http://uri", address)
assert token_id is None
assert tx_id is None
assert err is not None
assert_in("Too many decimals", err)

# issue a valid token
number_of_decimals = random.randrange(0, 4)
token_id, err = await wallet.issue_new_token("XXX", number_of_decimals, "http://uri", address, 'lockable')
token_id, tx_id, err = await wallet.issue_new_token("XXX", number_of_decimals, "http://uri", address, 'lockable')
assert token_id is not None
assert tx_id is not None
assert err is None
self.log.info(f"new token id: {token_id}")

Expand Down
12 changes: 11 additions & 1 deletion test/functional/wallet_tokens_freeze.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,21 @@ async def async_test(self):
address = await wallet.new_address()

# issue a valid token
token_id, err = await wallet.issue_new_token("XXX", 2, "http://uri", address)
ticker = "XXX"
decimals = 2
url = "http://uri"
token_id, tx_id, err = await wallet.issue_new_token(ticker, decimals, url, address)
assert token_id is not None
assert tx_id is not None
assert err is None
self.log.info(f"new token id: {token_id}")

hex_tx = await wallet.get_raw_signed_transaction(tx_id)
summary = await wallet.inspect_transaction(hex_tx)
assert_in(f"Ticker({ticker})", summary)
assert_in(f"Decimals({decimals})", summary)
assert_in("IsFreezable(Yes)", summary)

self.generate_block()
assert_in("Success", await wallet.sync())
assert_in("Coins amount: 400", await wallet.get_balance())
Expand Down
6 changes: 4 additions & 2 deletions test/functional/wallet_tokens_transfer_from_multisig_addr.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,14 +95,16 @@ async def setup_coins_and_tokens(self, node, wallet, coin_amount, foo_amount, ba
self.log.debug(f'Created address: {address}')

# Create token foo.
token_foo_id, err = await wallet.issue_new_token('FOO', 5, "http://uri", address)
token_foo_id, token_foo_tx_id, err = await wallet.issue_new_token('FOO', 5, "http://uri", address)
assert token_foo_id is not None
assert token_foo_tx_id is not None
assert err is None
self.log.debug(f"token foo id: {token_foo_id}")

# Create token bar.
token_bar_id, err = await wallet.issue_new_token('BAR', 10, "http://uri", address)
token_bar_id, token_bar_tx_id, err = await wallet.issue_new_token('BAR', 10, "http://uri", address)
assert token_bar_id is not None
assert token_bar_tx_id is not None
assert err is None
self.log.debug(f"token bar id: {token_bar_id}")

Expand Down
3 changes: 2 additions & 1 deletion test/functional/wallet_tx_intent.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,9 @@ async def setup_currency(self, node, wallet, coin_amount, min_token_amount_per_u
self.log.debug(f'token_issuer_address = {token_issuer_address}')

# Create the token.
token_id, err = await wallet.issue_new_token('FOO', 5, "http://uri", token_issuer_address)
token_id, tx_id, err = await wallet.issue_new_token('FOO', 5, "http://uri", token_issuer_address)
assert token_id is not None
assert tx_id is not None
assert err is None
self.log.debug(f"token id: {token_id}")

Expand Down