Skip to content

Instantly share code, notes, and snippets.

@Turupawn
Created March 26, 2025 17:58
Show Gist options
  • Save Turupawn/7c91b600eba7712c93ccf107c2f072df to your computer and use it in GitHub Desktop.
Save Turupawn/7c91b600eba7712c93ccf107c2f072df to your computer and use it in GitHub Desktop.
fe jam mar 26
use ingot::evm
use ingot::solidity
contract ERC20 {
pub balance: solidity::Mapping<evm::Address, u256>,
pub allowance: solidity::Mapping<(evm::Address, evm::Address), u256>,
pub TOTAL_SUPPLY: u256,
pub NAME: String<20>,
pub SYMBOL: String<5>,
pub DECIMALS: u8
}
impl ERC20 {
pub fn constructor(mut self) {
self.TOTAL_SUPPLY = 21_000_000 * 10**18
self.balance.new(slot: 0)
self.allowance.new(slot: 1)
let result = self.balance.set(key: evm::__caller(), value:self.TOTAL_SUPPLY)
}
pub fn name(self) -> String<20> {
self.NAME
}
pub fn symbol(self) -> String<5> {
self.SYMBOL
}
pub fn decimals(self) -> u8 {
self.DECIMALS
}
pub fn totalSupply(self) -> u256 {
self.TOTAL_SUPPLY
}
pub fn balanceOf(self, account : evm::Address) -> u256 {
self.balance.get(account)
}
pub fn transfer(mut self, to : evm::Address, value : u256) -> bool {
if self.balance.get(evm::__caller()) < value {
evm::__revert()
}
self.balance.set(evm::__caller(), self.balance.get(evm::__caller()) - value)
self.balance.set(to, self.balance.get(to) + value)
true
}
pub fn allowance(self, owner : evm::Address, spender : evm::Address) -> u256 {
self.allowance.get((owner, spender))
}
pub fn approve(mut self, spender : evm::Address, value : u256) -> bool {
self.allowance.set((evm::__caller(), spender), value)
true
}
pub fn transferFrom(mut self, from : evm::Address, to : evm::Address, value : u256) -> bool {
if (self.allowance.get((from, evm::__caller())) < value || self.balance.get(from) < value) {
evm::__revert()
}
self.allowance.set((from, evm::__caller()), self.allowance.get((from, evm::__caller())) - value)
self.balance.set(from, self.balance.get(from) - value)
self.balance.set(to, self.balance.get(to) + value)
true
}
}
const HASH_SCRATCH_OFFSET: u256 = 0x0
const SLOT_SIZE: usize = 32
pub type Address = u256
pub struct Wei { value: usize }
pub struct Ptr { pub location: usize }
pub struct Buf { pub offset: Ptr, pub len: usize }
impl Buf {
pub fn write_word(mut self, _ w: u256) {
__mstore(self.offset.location.upcast(), w)
}
}
// TODO: how to declare dynamic array?
extern {
pub fn __call(gas: Wei, address: Address, value: Wei, args: Buf, ret: Buf)
pub fn __mstore(_ loc: u256, _ data: u256)
pub fn __mload(_ loc: u256) -> u256
pub fn __sstore(_ loc: u256, _ data: u256)
pub fn __sload(_ loc: u256) -> u256
pub fn __keccak256(args: Buf) -> u256 // TODO: Should this use WordSlice?
pub fn __caller() -> Address
pub fn __revert()
//pub fn __sstore2(_ loc: StoragePtr, _ data: &[u8])
}
pub fn malloc(len: usize) -> Buf {
// TODO: initialize the free memory pointer
//let free_memory_pointer : StorageWords = __mload(WordSlice { offset: 0x40, length: 1 })
// TODO: can I use extern functions here?
let free_memory_pointer_location : usize //= u256_as_usize(free_memory_pointer.values[0])
Buf { offset: Ptr { location: free_memory_pointer_location }, len: 1}
}
pub fn salloc(len: usize) -> Buf {
// TODO: implement this
let free_storage_pointer_location : usize //= u256_as_usize(free_memory_pointer.values[0])
Buf { offset: Ptr { location: free_storage_pointer_location }, len: 1}
}
use ingot::evm
use ingot::map
pub struct Keccak256 {
pub slot: u256
}
impl map::Hasher for Keccak256 {
fn hash<T: map::Encode>(mut self, key: T) -> u256 {
let allocated_buffer = evm::malloc(len: 32 + T::encode_size())
let mut key_cursor = map::Cursor {
inner: map::MemBuffer {
ptr: allocated_buffer.offset,
len: allocated_buffer.len.upcast()
},
pos: 0
}
self.slot.encode(key_cursor)
key.encode(key_cursor)
let buf = evm::Buf { offset: allocated_buffer.offset, len: allocated_buffer.len }
let result: u256 = evm::__keccak256(args: buf)
result
}
}
pub struct SolidityHashMapStorage<T, U> {}
impl<T, U> map::HashMapStorage<T, U> for SolidityHashMapStorage<T, U>
where T: map::Encode, U: map::Encode, U: map::Decode
{
fn get(mut self, _: T) -> U {
let allocated_storage = evm::salloc(len: U::encode_size())
let value_cursor = map::Cursor {
inner: map::StorageBuffer { ptr: allocated_storage.offset, len: U::encode_size().upcast() },
pos: 0
}
U::decode(r: value_cursor)
}
fn set(mut self, _: T, _ value: U) -> bool {
let allocated_storage = evm::salloc(len: U::encode_size())
let value_cursor = map::Cursor {
inner: map::StorageBuffer { ptr: allocated_storage.offset, len: U::encode_size().upcast() },
pos: 0
}
value.encode(value_cursor)
}
}
pub type Mapping<T, U> = map::Map<T, U, Keccak256, SolidityHashMapStorage<T, U>>
impl<T, U> Mapping<T, U>
where T: map::Encode, U: map::Encode, U: map::Decode
{
pub fn new(mut self, slot: u256) {
self.hasher.slot = slot
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment