Hi,
I was just wondering, is it possible to build a transaction with Cardano Serialization Lib where both payment and stake key will be required without involving any staking operation such as delegating a pool? I need this to prevent the Franken address attack.
Usually, when a build a simple transaction such as making a payment, the transaction usually requires the buyer’s payment key. Here is an example transaction I made with Cardano Serialization Lib.
// Payload from API user
const payload = {
address: 'addr_test...',
utxos: [...]
}
const whitelist = ['stake_test1...', 'stake12']
const paymentAddress = 'addr_test1';
const amount = 10 * 1000000
const buyerStakeAddress = RewardAddress.new(
Address.from_bech32(payload.address).network_id(),
BaseAddress.from_address(Address.from_bech32(payload.address)).stake_cred()
)
// Franken address will get pass this
if( !whitelist.includes(buyerStakeAddress.to_address().to_bech32()) )
return false
const protocol_params = await this.get_protocol_parameters(NetworkInfo.testnet_preprod().network_id())
const linearFee = LinearFee.new(
BigNum.from_str(protocol_params.min_fee_a.toString()),
BigNum.from_str(protocol_params.min_fee_b.toString()),
)
const txBuilderCfg = TransactionBuilderConfigBuilder.new()
.fee_algo(linearFee)
.pool_deposit(BigNum.from_str(protocol_params.pool_deposit))
.key_deposit(BigNum.from_str(protocol_params.key_deposit))
.max_value_size(parseInt(protocol_params.max_val_size))
.max_tx_size(protocol_params.max_tx_size)
.coins_per_utxo_word(BigNum.from_str(protocol_params.coins_per_utxo_word))
.build();
const txBuilder = TransactionBuilder.new(txBuilderCfg);
const inputs = TransactionUnspentOutputs.new()
payload.utxos.forEach(raw => {
inputs.add(TransactionUnspentOutput.from_hex(raw))
})
txBuilder.add_output(TransactionOutput.new(
Address.from_bech32(paymentAddress),
Value.new( BigNum.from_str(amount.toString()) )
))
txBuilder.add_inputs_from(inputs, CoinSelectionStrategyCIP2.RandomImprove)
txBuilder.set_ttl(protocol_params.slot + 3600)
txBuilder.add_change_if_needed(Address.from_bech32(payload.address));
const body = txBuilder.build()
const witnesses = TransactionWitnessSet.new();
const auxFinal = AuxiliaryData.new()
const transaction: Transaction = Transaction.new( body, witnesses, auxFinal )
return transaction.to_hex()
But this transaction is prone to a Franken address attack as it only requires a payment key signature. How do I build a transaction that will require both payment and staking signatures from the user?