Skip to content

Commit

Permalink
Rewrite ERC677 as a component
Browse files Browse the repository at this point in the history
  • Loading branch information
archseer committed Jan 9, 2024
1 parent ad4bd9d commit 693b677
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 28 deletions.
56 changes: 34 additions & 22 deletions contracts/src/libraries/token/erc677.cairo
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
use starknet::ContractAddress;

#[starknet::interface]
trait IERC677<TContractState> {
fn transfer_and_call(
ref self: TContractState, to: ContractAddress, value: u256, data: Array<felt252>
) -> bool;
}

#[starknet::interface]
trait IERC677Receiver<TContractState> {
fn on_token_transfer(
Expand All @@ -9,10 +16,10 @@ trait IERC677Receiver<TContractState> {
fn supports_interface(ref self: TContractState, interface_id: u32) -> bool;
}

#[starknet::contract]
mod ERC677 {
#[starknet::component]
mod ERC677Component {
use starknet::ContractAddress;
// use openzeppelin::token::erc20::ERC20Component;
use openzeppelin::token::erc20::interface::IERC20;
use array::ArrayTrait;
use array::SpanTrait;
use clone::Clone;
Expand All @@ -30,37 +37,42 @@ mod ERC677 {
#[event]
#[derive(Drop, starknet::Event)]
enum Event {
Transfer: Transfer,
TransferAndCall: TransferAndCall,
}

#[derive(Drop, starknet::Event)]
struct Transfer {
struct TransferAndCall {
from: ContractAddress,
to: ContractAddress,
value: u256,
data: Array<felt252>
}

fn transfer_and_call(
ref self: ContractState, to: ContractAddress, value: u256, data: Array<felt252>
) -> bool {
let sender = starknet::info::get_caller_address();
#[embeddable_as(ERC677Impl)]
impl ERC677<
TContractState, +HasComponent<TContractState>, +IERC20<TContractState>, +Drop<TContractState>,
> of super::IERC677<ComponentState<TContractState>> {
fn transfer_and_call(
ref self: ComponentState<TContractState>, to: ContractAddress, value: u256, data: Array<felt252>
) -> bool {
let sender = starknet::info::get_caller_address();

let mut state = ERC20::unsafe_new_contract_state();
ERC20::ERC20Impl::transfer(ref state, to, value);
self
.emit(
Event::Transfer(
Transfer { from: sender, to: to, value: value, data: data.clone(), }
)
);
let mut contract = self.get_contract_mut();
contract.transfer(to, value);
self
.emit(
Event::TransferAndCall(
TransferAndCall { from: sender, to: to, value: value, data: data.clone(), }
)
);

let receiver = IERC677ReceiverDispatcher { contract_address: to };
let receiver = IERC677ReceiverDispatcher { contract_address: to };

let supports = receiver.supports_interface(IERC677_RECEIVER_ID);
if supports {
receiver.on_token_transfer(sender, value, data);
let supports = receiver.supports_interface(IERC677_RECEIVER_ID);
if supports {
receiver.on_token_transfer(sender, value, data);
}
true
}
true
}
}
9 changes: 6 additions & 3 deletions contracts/src/tests/test_erc677.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ use core::result::ResultTrait;

use chainlink::token::mock::valid_erc667_receiver::ValidReceiver;
use chainlink::token::mock::invalid_erc667_receiver::InvalidReceiver;
use chainlink::libraries::token::erc677::ERC677;
use chainlink::libraries::token::erc677::ERC677Component;
use chainlink::libraries::token::erc677::ERC677Component::ERC677Impl;

#[starknet::interface]
trait MockInvalidReceiver<TContractState> {
Expand Down Expand Up @@ -54,11 +55,13 @@ fn setup_invalid_receiver() -> (ContractAddress, MockInvalidReceiverDispatcher)
(address, contract)
}

type ComponentState = ERC677Component::ComponentState<chainlink::token::link_token::LinkToken::ContractState>;

fn transfer_and_call(receiver: ContractAddress) {
let data = ArrayTrait::<felt252>::new();
// have to send 0 because ERC20 is not initialized with starting supply when using this library by itself
let mut erc677 = ERC677::unsafe_new_contract_state();
// TODO: ERC677::transfer_and_call(ref erc677, receiver, u256 { high: 0, low: 0 }, data);
let mut state: ComponentState = ERC677Component::component_state_for_testing();
state.transfer_and_call(receiver, u256 { high: 0, low: 0 }, data);
}

#[test]
Expand Down
15 changes: 12 additions & 3 deletions contracts/src/token/link_token.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ mod LinkToken {
use zeroable::Zeroable;

use openzeppelin::token::erc20::interface::{IERC20, IERC20Dispatcher, IERC20DispatcherTrait};
use chainlink::libraries::token::erc677::ERC677;
use chainlink::libraries::token::erc677::ERC677Component;
use chainlink::libraries::ownable::{Ownable, IOwnable};
use chainlink::libraries::upgradeable::{Upgradeable, IUpgradeable};

Expand All @@ -24,13 +24,17 @@ mod LinkToken {
use starknet::class_hash::ClassHash;

component!(path: ERC20Component, storage: erc20, event: ERC20Event);
component!(path: ERC677Component, storage: erc677, event: ERC677Event);

#[abi(embed_v0)]
impl ERC20Impl = ERC20Component::ERC20Impl<ContractState>;
#[abi(embed_v0)]
impl ERC20MetadataImpl = ERC20Component::ERC20MetadataImpl<ContractState>;
impl ERC20InternalImpl = ERC20Component::InternalImpl<ContractState>;

#[abi(embed_v0)]
impl ERC677Impl = ERC677Component::ERC677Impl<ContractState>;

const NAME: felt252 = 'ChainLink Token';
const SYMBOL: felt252 = 'LINK';

Expand All @@ -39,14 +43,19 @@ mod LinkToken {
_minter: ContractAddress,

#[substorage(v0)]
erc20: ERC20Component::Storage
erc20: ERC20Component::Storage,

#[substorage(v0)]
erc677: ERC677Component::Storage
}

#[event]
#[derive(Drop, starknet::Event)]
enum Event {
#[flat]
ERC20Event: ERC20Component::Event
ERC20Event: ERC20Component::Event,
#[flat]
ERC677Event: ERC677Component::Event
}

//
Expand Down

0 comments on commit 693b677

Please sign in to comment.