ETH Price: $2,445.03 (-0.05%)

Contract Diff Checker

Contract Name:
Payphone1923

Contract Source Code:

File 1 of 1 : Payphone1923

// PAYPHONE dialer extension for SOUND MACHINES session
// by 0xDEAFBEEF
// March 2024

//SPDX-License-Identifier: MIT

pragma solidity ^0.8.4;

abstract contract extPhoneCard  {
  function balanceOf(address owner) external virtual view returns (uint256);
  function tokenOfOwnerByIndex(address owner, uint256 i) external virtual view returns (uint256);
}

contract Payphone1923  {
  extPhoneCard public phonecard;

  uint256 public last_dial_ts;
  uint256 public dial_index;
  uint256 public callsRemaining;

  uint256 public phonecard_range_lo;
  uint256 public phonecard_range_hi;    
  address _owner;
  address _owner2;

  uint256 public callRateLimit;
  uint256 public callRateLimit_phonecard;
  bool public inTheOffice;
  uint256 _dialCost1;
  uint256 _dialCost2;
  uint256 _dialCostMode;
  uint256 _dialCostBegin;  
  uint256 _dialCostLen;

  uint256 public maxMsgLength;
  event DialEvent(address from, string m,uint256 dial_id, uint256 phoneCardID);

  struct dialStruct {
    address from;
    uint256 ts;
    string m; //optionally store the message in contract storage
  }
   
  mapping (uint256 => dialStruct) public dials;
  mapping (address => uint256) public last_dial_ts_phonecard;

  modifier onlyOwner() {
    require(_owner == msg.sender || _owner2 == msg.sender, "only owner");
    _;
  }

  constructor() {
    address _phonecard_contract_address = 0x1D9787369B1DCf709f92Da1d8743c2A4b6028a83;
    phonecard = extPhoneCard(_phonecard_contract_address);
    _owner = msg.sender;
    _owner2 = 0x95FDE6CF0d305078B7EEaC44182A931c169DD947;

    dial_index = 1000000; 
    inTheOffice = false;
    callsRemaining = 0;
    callRateLimit = 10; //communal rate limit for public
    callRateLimit_phonecard = 60*1; // individual rate limits for phone card holders
    _dialCost1 = 25000000000; //calls cost 25 Gwei, unless you have a prepaid phonecard
    maxMsgLength=2000;

    phonecard_range_lo = 339348595130070749814751437599411258966098496;
    phonecard_range_hi = 339348595130070749814751437599411258966098525;
  }

  function hasPhoneCard(address a) public view returns (bool) {
    return (phoneCardID(a) > 0);
  }
  function phoneCardID(address a) public view returns (uint256) {
    if (address(phonecard)==0x0000000000000000000000000000000000000000) return 0;
    uint256 n = phonecard.balanceOf(a);
    if (n==0) return 0;
    for (uint256 i=0;i<n;i++) {
      uint256 tid = phonecard.tokenOfOwnerByIndex(a,i);
      if (tid >= phonecard_range_lo && tid <= phonecard_range_hi) {
        return tid % 1000;
      }
    }
    return 0;
  }
  
  function dial(string calldata m) payable public {
    require(inTheOffice==true,"Please call back during business hours.");
    require(callsRemaining > 0,"Order book is full for now. Call back later.");
    require(bytes(m).length < maxMsgLength, "Message too long");
        
    if (hasPhoneCard(msg.sender)) {
      //no cost for prepaid phonecard holders.

      //rate limit is on individual basis. only one call every 3 minutes.
      require(block.timestamp - last_dial_ts_phonecard[msg.sender] > callRateLimit_phonecard,"Phone card holders have priority, but are limited to 1 call per minute. Wait [callRateLimit_phoneCard] seconds before calling back.");

      last_dial_ts_phonecard[msg.sender] = block.timestamp;
    } else {
      // 
      require(msg.value>=dialCost(), "Must send [dialCost] to dial");
      require(block.timestamp - last_dial_ts > callRateLimit,"Busy signal. Wait [callRateLimit] seconds before calling back.");

      last_dial_ts = block.timestamp;
    }
        
    dial_index++;
    callsRemaining--;
    emit DialEvent(msg.sender,m,dial_index-1,phoneCardID(msg.sender));    
  }

  //seconds remaining in rate limiting
  function timeRemaining() public view returns (uint256) { 
    uint256 a = block.timestamp - last_dial_ts;
    if (a > callRateLimit) {
      return 0;
    }  else {
      return callRateLimit - a;
    }
  }

  //seconds remaining in phonecard holder rate limiting (on per user basis)
  function timeRemaining_phonecard(address a) public view returns (uint256) { 
    if (!hasPhoneCard(a)) return 999999; //if not phonecard holder, time remaining is infinite

    uint256 t = block.timestamp - last_dial_ts_phonecard[a];
    if (t > callRateLimit_phonecard) {
      return 0;
    }  else {
      return callRateLimit_phonecard - t;
    }
  }

  function setMaxMsgLength(uint256 a) public onlyOwner {
    maxMsgLength=a;
  }
  
  function setDialCost(uint256 mode, uint256 t, uint256 a, uint256 b) public onlyOwner {
    _dialCost1 = a;
    _dialCost2 = b;
    _dialCostMode = mode;
    _dialCostBegin = block.timestamp;
    if (t <= 0) t = 1;
    
    _dialCostLen = t;
  }

  function dialCost() public view returns (uint256) {
    //in mode 0, fixed dialCost equal to _dialCost1
    if (_dialCostMode ==0) return _dialCost1;

    //in mode 1, linearly descending cost from _dialCost1 to _dialCost2 over time _dialCostLen 
    uint256 am = ((block.timestamp - _dialCostBegin)*1000) / _dialCostLen;
    if (am > 1000 ) am = 1000; //clamp to 1000;
    if (am < 0) am = 0;
    uint256 cost = _dialCost2*am + _dialCost1 * (1000-am);
    cost /= 1000;
    return cost;
  }

    // all calls get event logged as DialEvent, but for prompts that interpreted, also manually
    // permanently store details, including the message, in contract storage

    function storeDialMessage(uint256 dialId, address from, uint256 ts, string calldata m) public onlyOwner {
        require(dialId < dial_index, "Dial Index out of range.");
        dials[dialId].m = m;
        dials[dialId].ts = ts;
        dials[dialId].from = from;
    }

  //enable
  function setInTheOffice(bool a) public onlyOwner {
    inTheOffice = a;
  }

  //set the number of calls allowed during a shift
  function setCallsRemaining(uint256 a) public onlyOwner {
    callsRemaining = a;
  }
    
  function withdraw() public onlyOwner {
    payable(msg.sender).transfer(address(this).balance);
  }

  //set the allowable minimum number of seconds between calls
  function setCallRateLimit(uint256 a) public onlyOwner {
    callRateLimit = a;
  }

  //set the allowable minimum number of seconds between calls
  function setCallRateLimit_phonecard(uint256 a) public onlyOwner {
    callRateLimit_phonecard = a;
  }
  
  function setPhoneCardContractAddress(address _phonecard_contract_address) public onlyOwner {
    phonecard = extPhoneCard(_phonecard_contract_address);
  }

  //Set inclusive token ID range
  function setPhoneCardTokenRange(uint256 lo, uint256 hi) public onlyOwner {
    phonecard_range_lo = lo;
    phonecard_range_hi = hi;
  }
  
}

Please enter a contract address above to load the contract details and source code.

Context size (optional):