Standalone
Calldata Spoofing
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...