Standalone

Calldata Spoofing

close button

Calldata Spoofing

Download quests in Questplay

View the contracts and any other additional content from your IDE.

Casting a PortalSpell is easy. You just need to call PortalSpell::cast with the following portal data.

[ 0: { location: 'TAVERN', details: [ 'OPEN', 'PORTAL' ] }, 1: { location: 'HOME', details: [ 'CLOSE', 'PORTAL' ] } ]

However, DrunkenMage is too intoxicated to even recall the simplest portal spell. Take a look, it is not using the right spell interface! Can you find a way home?

Your Task

Send the DrunkenMage home. (i.e., set is_home in DrunkenMage to true)

Contract Code

#[starknet::interface] trait IDrunkenMage<TContractState> { fn is_home(self: @TContractState) -> bool; fn cast_portal( ref self: TContractState, origin: Array<felt252>, destination: Array<felt252> ); } #[starknet::contract] mod DrunkenMage { use starknet::ContractAddress; // This isn't the right interface... #[starknet::interface] trait IDrunkenSpell<TContractState> { fn cast( ref self: TContractState, origin: Array<felt252>, destination: Array<felt252> ) -> bool; } #[storage] struct Storage { spell_address: ContractAddress, is_home: bool } #[constructor] fn constructor(ref self: ContractState, spell_address: ContractAddress) { self.spell_address.write(spell_address); } #[abi(embed_v0)] impl DrunkenMageImpl of super::IDrunkenMage<ContractState> { fn is_home(self: @ContractState) -> bool { self.is_home.read() } fn cast_portal( ref self: ContractState, origin: Array<felt252>, destination: Array<felt252> ) { let drunk_spell = IDrunkenSpellDispatcher { contract_address: self.spell_address.read() }; self.is_home.write( drunk_spell.cast(origin, destination) ); } } }
#[derive(Drop, Serde)] struct PortalData { location: felt252, details: Array<felt252> } #[starknet::interface] trait IPortalSpell<TContractState> { fn cast( self: @TContractState, portal_data: Array<PortalData> ) -> bool; } #[starknet::contract] mod PortalSpell { use array::ArrayTrait; use option::OptionTrait; use super::PortalData; #[storage] struct Storage { } #[abi(embed_v0)] impl PortalSpellImpl of super::IPortalSpell<ContractState> { // Returns true if given the correct portal_data... fn cast(self: @ContractState, portal_data: Array<PortalData>) -> bool { check_origin(portal_data[0]) && check_destination(portal_data[1]) } } fn check_origin(portal_data: @PortalData) -> bool { *portal_data.location == 'TAVERN' && portal_data.details.len() == 2 && *portal_data.details[0] == 'OPEN' && *portal_data.details[1] == 'PORTAL' } fn check_destination(portal_data: @PortalData) -> bool { *portal_data.location == 'HOME' && portal_data.details.len() == 2 && *portal_data.details[0] == 'CLOSE' && *portal_data.details[1] == 'PORTAL' } }

The tavern is closing, you will need to portal home...