[TIL] 2023-05-25 DAY47
GIT 주소 : https://github.com/dowoo303/SOLIDITY
오늘 배운것들
- TEST9
1) 은행 앱 만들어보기
2) msg sender 이해- ERC20 학습
각종 팁
회고
- DAY46은 일때매 바빠서 pass함 ..
- 미리 공부하고 싶다?
슈노르 서명(Schnorr signature)
세그잇(SegWit)
탭루트(Taproot)
올디너스(Ordinals) 프로토콜(Protocol)
참고
approve 개념: A계좌에서 B계좌로 30원을 보낸다고 가정했을 때, 진짜 30원을 보내는 것처럼 보이지만 사실은 은행이 단순히 +-를 했을 뿐이다. 따라서 보내는 코드를 구성할 것이 아니라 30원이 +되고 -되는 것을 approve해주는 코드를 구성하기만 하면 된다.
코인 지갑들도 사실 지갑에 돈을 들고 있다고 표현하기는 애매하다.
비트 - 시드->프라이빗키->퍼블릭키->주소->UTXO들의 합
이더 - 머클 패트리시아 트리로 잔고 관리
bank라는 컨트랙트를 만들고 bank를 여러개 인스턴스화 시켜서 사용하면 각 인스턴스화가 은행이 되고 그 은행안의 balance라는 mapping이 각자 개인의 계좌가 되는 개념이다.
+수수료 부과하는법: modifier을 하나 만들어서 애초에 처음부터 수수료를 포함한 돈을 받으면 됨
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
// 은행에 입금을 하면 진짜 돈이 빠져나가는 case
contract APP {
mapping(address=>uint) balance; // 개인 잔액
// mapping(address=>mapping(address=>uint)) bankAccounts; // 은행 잔고
receive() external payable{} // 특정 함수를 통하지 않고 이 컨트랙트도 돈을 받을 일이 있음
modifier balCheck(address _a, uint _amount) {
balance[_a] >= _amount;
_;
}
// app 이용 수수료 부과하기
modifier Fee(uint _amount){
require(msg.value == _amount*101/100);
_;
}
// 입금 - 해당 App에게 얼만큼의 돈을 입금하겠다.
function depositToApp() public payable {
balance[msg.sender] += msg.value;
}
// 입금 - 특정 은행에게 얼만큼의 돈을 입금하겠다.
function depositToBank(address payable _bank, uint _amount) public payable Fee(_amount) {
Bank targetBank = Bank(_bank);
require(balance[msg.sender] >= _amount);
payable(targetBank).transfer(_amount); // App에서 뱅크로 트랜스퍼
balance[msg.sender] -= _amount;
targetBank.Deposit(msg.sender, _amount); // 특정 은행의 명령자의 계좌에 _amount만큼 입금
}
function _depositToBank(address payable _bank, address _to, uint _amount) public {
Bank targetBank = Bank(_bank);
require(balance[msg.sender] >= _amount);
payable(targetBank).transfer(_amount);
balance[msg.sender] -= _amount;
targetBank.Deposit(_to, _amount);
}
// 인출 - 해당 App에게 얼만큼의 돈을 출금하겠다.
function withdrawFromApp(uint _amount) public {
balance[msg.sender] -= _amount;
payable(msg.sender).transfer(_amount);
}
// 인출 - 특정 은행에서 얼만큼의 돈을 출금하겠다.
function withdrawFromBank(address payable _bank, uint _amount) public {
Bank targetBank = Bank(_bank);
targetBank.Withdraw(msg.sender, _amount);
balance[msg.sender] += _amount;
}
// 송금 - A가 B에게 돈을 보내는 것(직접)
function transferTo(address _bAccount, uint _amount) public balCheck(msg.sender, _amount) {
balance[msg.sender] -= _amount;
balance[_bAccount] += _amount;
}
// 은행송금 - A의 은행에서 B의 은행에게 돈을 보내는 것(은행끼리)
// 사용자의 A bank -> App -> B bank(받는사람)
function transferWire(address payable _aBank, address _bAccount, address payable _bBank, uint _amount) public {
withdrawFromBank(_aBank, _amount);
_depositToBank(_bBank, _bAccount, _amount);
}
}
contract Bank {
mapping(address=>uint) private balance; // 보안을 위하여 mapping(address=>uint) public balance;를 프라이빗으로
receive() payable external{}
// 잔고확인
function balanceOf() public view returns(uint) {
return balance[msg.sender]; // 내 지갑주소만 확인 가능
}
// 입금 - 얼만큼의 돈을 입금하겠다.
function deposit() public payable {
balance[msg.sender] += msg.value;
}
// 밑 타행송금에서 deposit을 하면 자기자신에게 돈을 입금하는 상황이 되므로 주소를 따로 받을 수 있는 _deposit생성
function _deposit(address _account, uint _amount) internal {
balance[_account] += _amount;
}
// 위 _deposit함수를 ERC20 형식으로 분리
function Deposit(address _account, uint _amount) public {
require(_amount != 0, "Amount should not be zero");
_deposit(_account, _amount);
}
// 인출 - 얼만큼의 돈을 출금하겠다.
function withdraw(uint _amount) public {
balance[msg.sender] -= _amount;
payable(msg.sender).transfer(_amount);
}
// 밑 타행송금에서 withdraw을 하면 자기자신에게 돈을 입금하는 상황이 되므로 주소를 따로 받을 수 있는 _withdraw생성
function _withdraw(address _account, uint _amount) internal {
balance[_account] -= _amount;
payable(msg.sender).transfer(_amount);
}
function _withdraw2(address _account, uint _amount) internal {
balance[_account] -= _amount;
payable(_account).transfer(_amount); // 위와 다르게 개인지갑으로 다이렉트
}
// 위 _withdraw함수를 ERC20 형식으로 분리
function Withdraw(address _account, uint _amount) public {
require(balance[_account] >= _amount, "Not enough money");
_withdraw(_account, _amount);
}
// 송금 - A가 B에게 돈을 보내는 것(동행)
function transferTo(address _bAccount, uint _amount) public {
balance[msg.sender] -= _amount;
balance[_bAccount] += _amount;
}
// 타행송금 - A가 B의 다른 은행에게 돈을 보내는 것(타행)
function transferWire(address _bAccount, address payable anotherBank, uint _amount) public {
Bank B = Bank(anotherBank);
balance[msg.sender] -= _amount;
payable(B).transfer(_amount); // B뱅크 컨트랙트로 트랜스퍼하겠다
B.Deposit(_bAccount,_amount); // B뱅크의 b계좌에 _amount만큼 입금
}
}
virtual: 나중에 덮어 쓸 수 있도록 만들어줌
override: 기존 함수를 받아와서 덮어 씌움
Context 안에 _msgSender가 들어있음
기본적으로 transfer, _transfer 처럼 안전을 위하여 꼭 경로를 한번 더 거치도록 코딩을 해놨다.
balancesOf: 누군가의 잔액을 보여줌
emit: 이벤트를 발생시킴(로그)
allowances: 일정량의 돈(currentAllowance)에 접근할 수 있도록 허락해주는 mapping
USDC 주소를 받아와서 ierc20에 있는 transferFrom 함수를 호출
allowance를 쓰는 이유: 일정량의 돈을 어디다가 맡기고 game을 할 수가 없기 때문에 얼마까지 돈을 가져갈 수 있는 권리를 allowance를 통해 설정(더블 매핑: _allowances)하고 그 제한된 범위 내에서만 transfer가 가능하도록 만듬.(제 3자의 역할을 스마트 컨트랙트를 통해 구현)