Skip to content

Commit

Permalink
Add YASRouter contract (#120)
Browse files Browse the repository at this point in the history
* add externals token_0 & token_1 in YASPool

* add ERC20 contract

* add YASRouter contract
  • Loading branch information
dpinones authored Sep 29, 2023
1 parent 721b485 commit a758011
Show file tree
Hide file tree
Showing 4 changed files with 413 additions and 0 deletions.
244 changes: 244 additions & 0 deletions src/contracts/yas_erc20.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts for Cairo v0.7.0 (token/erc20/erc20.cairo)
use starknet::ContractAddress;

#[starknet::interface]
trait IERC20<TState> {
fn name(self: @TState) -> felt252;
fn symbol(self: @TState) -> felt252;
fn decimals(self: @TState) -> u8;
fn totalSupply(self: @TState) -> u256;
fn balanceOf(self: @TState, account: ContractAddress) -> u256;
fn allowance(self: @TState, owner: ContractAddress, spender: ContractAddress) -> u256;
fn transfer(ref self: TState, recipient: ContractAddress, amount: u256) -> bool;
fn transferFrom(
ref self: TState, sender: ContractAddress, recipient: ContractAddress, amount: u256
) -> bool;
fn approve(ref self: TState, spender: ContractAddress, amount: u256) -> bool;
}

#[starknet::contract]
mod ERC20 {
use super::IERC20;

use integer::BoundedInt;
use starknet::ContractAddress;
use starknet::get_caller_address;

#[storage]
struct Storage {
ERC20_name: felt252,
ERC20_symbol: felt252,
ERC20_total_supply: u256,
ERC20_balances: LegacyMap<ContractAddress, u256>,
ERC20_allowances: LegacyMap<(ContractAddress, ContractAddress), u256>,
}

#[event]
#[derive(Drop, starknet::Event)]
enum Event {
Transfer: Transfer,
Approval: Approval,
}

#[derive(Drop, starknet::Event)]
struct Transfer {
from: ContractAddress,
to: ContractAddress,
value: u256
}

#[derive(Drop, starknet::Event)]
struct Approval {
owner: ContractAddress,
spender: ContractAddress,
value: u256
}

mod Errors {
const APPROVE_FROM_ZERO: felt252 = 'ERC20: approve from 0';
const APPROVE_TO_ZERO: felt252 = 'ERC20: approve to 0';
const TRANSFER_FROM_ZERO: felt252 = 'ERC20: transfer from 0';
const TRANSFER_TO_ZERO: felt252 = 'ERC20: transfer to 0';
const BURN_FROM_ZERO: felt252 = 'ERC20: burn from 0';
const MINT_TO_ZERO: felt252 = 'ERC20: mint to 0';
}

#[constructor]
fn constructor(
ref self: ContractState,
name: felt252,
symbol: felt252,
initial_supply: u256,
recipient: ContractAddress
) {
self.initializer(name, symbol);
self._mint(recipient, initial_supply);
}

//
// External
//

#[external(v0)]
impl ERC20Impl of IERC20<ContractState> {
fn name(self: @ContractState) -> felt252 {
self.ERC20_name.read()
}

fn symbol(self: @ContractState) -> felt252 {
self.ERC20_symbol.read()
}

fn decimals(self: @ContractState) -> u8 {
18
}

fn totalSupply(self: @ContractState) -> u256 {
self.ERC20_total_supply.read()
}

fn balanceOf(self: @ContractState, account: ContractAddress) -> u256 {
self.ERC20_balances.read(account)
}

fn allowance(
self: @ContractState, owner: ContractAddress, spender: ContractAddress
) -> u256 {
self.ERC20_allowances.read((owner, spender))
}

fn transfer(ref self: ContractState, recipient: ContractAddress, amount: u256) -> bool {
let sender = get_caller_address();
self._transfer(sender, recipient, amount);
true
}

fn transferFrom(
ref self: ContractState,
sender: ContractAddress,
recipient: ContractAddress,
amount: u256
) -> bool {
let caller = get_caller_address();
self._spend_allowance(sender, caller, amount);
self._transfer(sender, recipient, amount);
true
}

fn approve(ref self: ContractState, spender: ContractAddress, amount: u256) -> bool {
let caller = get_caller_address();
self._approve(caller, spender, amount);
true
}
}

#[external(v0)]
fn increase_allowance(
ref self: ContractState, spender: ContractAddress, added_value: u256
) -> bool {
self._increase_allowance(spender, added_value)
}

#[external(v0)]
fn increaseAllowance(
ref self: ContractState, spender: ContractAddress, addedValue: u256
) -> bool {
increase_allowance(ref self, spender, addedValue)
}

#[external(v0)]
fn decrease_allowance(
ref self: ContractState, spender: ContractAddress, subtracted_value: u256
) -> bool {
self._decrease_allowance(spender, subtracted_value)
}

#[external(v0)]
fn decreaseAllowance(
ref self: ContractState, spender: ContractAddress, subtractedValue: u256
) -> bool {
decrease_allowance(ref self, spender, subtractedValue)
}

//
// Internal
//

#[generate_trait]
impl InternalImpl of InternalTrait {
fn initializer(ref self: ContractState, name: felt252, symbol: felt252) {
self.ERC20_name.write(name);
self.ERC20_symbol.write(symbol);
}

fn _increase_allowance(
ref self: ContractState, spender: ContractAddress, added_value: u256
) -> bool {
let caller = get_caller_address();
self
._approve(
caller, spender, self.ERC20_allowances.read((caller, spender)) + added_value
);
true
}

fn _decrease_allowance(
ref self: ContractState, spender: ContractAddress, subtracted_value: u256
) -> bool {
let caller = get_caller_address();
self
._approve(
caller,
spender,
self.ERC20_allowances.read((caller, spender)) - subtracted_value
);
true
}

fn _mint(ref self: ContractState, recipient: ContractAddress, amount: u256) {
assert(!recipient.is_zero(), Errors::MINT_TO_ZERO);
self.ERC20_total_supply.write(self.ERC20_total_supply.read() + amount);
self.ERC20_balances.write(recipient, self.ERC20_balances.read(recipient) + amount);
self.emit(Transfer { from: Zeroable::zero(), to: recipient, value: amount });
}

fn _burn(ref self: ContractState, account: ContractAddress, amount: u256) {
assert(!account.is_zero(), Errors::BURN_FROM_ZERO);
self.ERC20_total_supply.write(self.ERC20_total_supply.read() - amount);
self.ERC20_balances.write(account, self.ERC20_balances.read(account) - amount);
self.emit(Transfer { from: account, to: Zeroable::zero(), value: amount });
}

fn _approve(
ref self: ContractState, owner: ContractAddress, spender: ContractAddress, amount: u256
) {
assert(!owner.is_zero(), Errors::APPROVE_FROM_ZERO);
assert(!spender.is_zero(), Errors::APPROVE_TO_ZERO);
self.ERC20_allowances.write((owner, spender), amount);
self.emit(Approval { owner, spender, value: amount });
}

fn _transfer(
ref self: ContractState,
sender: ContractAddress,
recipient: ContractAddress,
amount: u256
) {
assert(!sender.is_zero(), Errors::TRANSFER_FROM_ZERO);
assert(!recipient.is_zero(), Errors::TRANSFER_TO_ZERO);
self.ERC20_balances.write(sender, self.ERC20_balances.read(sender) - amount);
self.ERC20_balances.write(recipient, self.ERC20_balances.read(recipient) + amount);
self.emit(Transfer { from: sender, to: recipient, value: amount });
}

fn _spend_allowance(
ref self: ContractState, owner: ContractAddress, spender: ContractAddress, amount: u256
) {
let current_allowance = self.ERC20_allowances.read((owner, spender));
if current_allowance != BoundedInt::max() {
self._approve(owner, spender, current_allowance - amount);
}
}
}
}
10 changes: 10 additions & 0 deletions src/contracts/yas_pool.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ trait IYASPool<TContractState> {
amount: u128,
data: Array<felt252>
) -> (u256, u256);
fn token_0(self: @TContractState) -> ContractAddress;
fn token_1(self: @TContractState) -> ContractAddress;
}

#[starknet::contract]
Expand Down Expand Up @@ -190,6 +192,14 @@ mod YASPool {

#[external(v0)]
impl YASPoolImpl of IYASPool<ContractState> {
fn token_0(self: @ContractState) -> ContractAddress {
self.token_0.read()
}

fn token_1(self: @ContractState) -> ContractAddress {
self.token_1.read()
}

/// @notice Sets the initial price for the pool
/// @dev price is represented as a sqrt(amount_token_1/amount_token_0) Q64.96 value
/// @param sqrt_price_X96 the initial sqrt price of the pool as a Q64.96
Expand Down
Loading

0 comments on commit a758011

Please sign in to comment.