initial commit

This commit is contained in:
amaqkkg 2025-01-03 23:49:03 +07:00
parent a390ba8f99
commit 834bebecb3
10 changed files with 174 additions and 106 deletions

6
.gitmodules vendored
View File

@ -1,3 +1,9 @@
[submodule "lib/forge-std"] [submodule "lib/forge-std"]
path = lib/forge-std path = lib/forge-std
url = https://github.com/foundry-rs/forge-std url = https://github.com/foundry-rs/forge-std
[submodule "lib/openzeppelin-contracts"]
path = lib/openzeppelin-contracts
url = https://github.com/openzeppelin/openzeppelin-contracts
[submodule "lib/openzeppelin-contracts-upgradeable"]
path = lib/openzeppelin-contracts-upgradeable
url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable

View File

@ -1,17 +1,7 @@
## Foundry ## IDRCoin
**Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.** Disclaimer: this is a part of Penerbangan Pertama educational content, DO NOT USE ON PRODUCTION as this project contains intentional bug.
Foundry consists of:
- **Forge**: Ethereum testing framework (like Truffle, Hardhat and DappTools).
- **Cast**: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data.
- **Anvil**: Local Ethereum node, akin to Ganache, Hardhat Network.
- **Chisel**: Fast, utilitarian, and verbose solidity REPL.
## Documentation
https://book.getfoundry.sh/
## Usage ## Usage
@ -27,40 +17,3 @@ $ forge build
$ forge test $ forge test
``` ```
### Format
```shell
$ forge fmt
```
### Gas Snapshots
```shell
$ forge snapshot
```
### Anvil
```shell
$ anvil
```
### Deploy
```shell
$ forge script script/Counter.s.sol:CounterScript --rpc-url <your_rpc_url> --private-key <your_private_key>
```
### Cast
```shell
$ cast <subcommand>
```
### Help
```shell
$ forge --help
$ anvil --help
$ cast --help
```

@ -0,0 +1 @@
Subproject commit 69c8def5f222ff96f2b5beff05dfba996368aa79

@ -0,0 +1 @@
Subproject commit fa525310e45f91eb20a6d3baa2644be8e0adba31

View File

@ -1,19 +0,0 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
import {Script, console} from "forge-std/Script.sol";
import {Counter} from "../src/Counter.sol";
contract CounterScript is Script {
Counter public counter;
function setUp() public {}
function run() public {
vm.startBroadcast();
counter = new Counter();
vm.stopBroadcast();
}
}

0
src/Bank.sol Normal file
View File

View File

@ -1,14 +0,0 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
contract Counter {
uint256 public number;
function setNumber(uint256 newNumber) public {
number = newNumber;
}
function increment() public {
number++;
}
}

152
src/IDRCoin.sol Normal file
View File

@ -0,0 +1,152 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {IUSDT} from "./interfaces/IUSDT.sol";
contract IDRCoin is ERC20 {
// mapping
mapping(address => uint256) balances;
mapping(address owner => mapping(address spender => uint256)) allowances;
// address state
address admin;
address taxCollector;
IUSDT usdt;
// constant
// convertion rate from USDT to IDR
uint256 constant CONVERSION_RATE = 16000;
// enforce ppn 12% for ALL transaction involving IDRC token
uint256 constant TAX = 12;
uint256 constant DENOMINATOR = 100;
modifier onlyAdmin() {
if (msg.sender != admin) {
revert notAdmin();
}
_;
}
// error
error notAdmin();
error insufficientBalance();
error insufficientAllowances();
error addressZero();
// event
// constructor
constructor(
address _admin,
address _taxCollector
) ERC20("IDRCoin", "IDRC") {
admin = _admin;
taxCollector = _taxCollector;
}
// external/public function
function convertUSDtoIDR(uint256 amountInUSD) external {
usdt.transfer(address(this), amountInUSD);
uint256 amountInIDR = amountInUSD * CONVERSION_RATE * decimals();
_mint(msg.sender, amountInIDR);
}
function approve(
address _spender,
uint256 amount
) public override returns (bool) {
allowances[msg.sender][_spender] = amount;
return true;
}
function transfer(
address _receiver,
uint256 _amount
) public override returns (bool) {
if (balanceOf(msg.sender) < _amount) {
revert insufficientBalance();
}
if (_receiver == address(0)) {
revert addressZero();
}
transfer_(msg.sender, _receiver, _amount);
return true;
}
function transferFrom(
address _owner,
address _receiver,
uint256 amount
) public override returns (bool) {
if (allowances[msg.sender][_owner] < amount) {
revert insufficientAllowances();
}
if (_receiver == address(0)) {
revert addressZero();
}
transfer_(_owner, _receiver, amount);
return true;
}
// internal function
function mint_(address _addr, uint256 amount) internal {
// calculating the tax amount and then collect it
uint256 tax = (amount * TAX) / DENOMINATOR;
balances[_addr] += amount - tax;
balances[taxCollector] += tax;
}
function transfer_(
address _sender,
address _receiver,
uint256 _amount
) internal {
uint256 balanceSenderBefore = balanceOf(_sender);
uint256 balanceReceiverBefore = balanceOf(_receiver);
balances[_sender] = balanceSenderBefore - _amount;
balances[_receiver] = balanceReceiverBefore + _amount;
// revert if the _amount is zero. we dont want user to waste gas
require(
balances[_sender] != balanceSenderBefore ||
balances[_receiver] != balanceReceiverBefore,
"cant transfer 0 amount"
);
}
// view function
function balanceOf(
address _addr
) public view override returns (uint256 amount) {
return balances[_addr];
}
// setter/admin function
function setUSDT(address _usdt) external onlyAdmin {
usdt = IUSDT(_usdt);
}
function changeOwner(address admin) external onlyAdmin {
admin = admin;
}
// collect USDT for public goods purpose
function withdrawUSDT(address _addr) external onlyAdmin {
// transfer usdt to admin specified address
uint256 amount = usdt.balanceOf(address(this));
usdt.transfer(_addr, amount);
}
// burn ALL corruptor IDRC with this function
function burn(address _account, uint256 _amount) public onlyAdmin {
transfer_(_account, address(0), _amount);
}
}

12
src/interfaces/IUSDT.sol Normal file
View File

@ -0,0 +1,12 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
interface IUSDT {
function decimals() external returns (uint);
function balanceOf(address who) external returns (uint);
function transfer(address to, uint value) external;
function approve(address spender, uint value) external;
}

View File

@ -1,24 +0,0 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
import {Test, console} from "forge-std/Test.sol";
import {Counter} from "../src/Counter.sol";
contract CounterTest is Test {
Counter public counter;
function setUp() public {
counter = new Counter();
counter.setNumber(0);
}
function test_Increment() public {
counter.increment();
assertEq(counter.number(), 1);
}
function testFuzz_SetNumber(uint256 x) public {
counter.setNumber(x);
assertEq(counter.number(), x);
}
}