Skip to content

Commit

Permalink
add SWEEP support
Browse files Browse the repository at this point in the history
  • Loading branch information
jdogresorg committed Apr 25, 2024
1 parent fc381e8 commit 6f91d67
Show file tree
Hide file tree
Showing 5 changed files with 319 additions and 24 deletions.
22 changes: 11 additions & 11 deletions docs/actions/SWEEP.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,28 @@
This command transfers all `token` balances and/or ownerships to a destination address

## PARAMS
| Name | Type | Description |
| ----------------- | ------ | ----------------------------------------------------------------- |
| `VERSION` | String | Broadcast Format Version |
| `DESTINATION` | String | address where `token` shall be swept |
| `SWEEP_BALANCES` | String | Indicates if address `token` balances should be swept (default=1) |
| `SWEEP_OWNERSHIP` | String | Indicates if address `token` balances should be swept (default=1) |
| `MEMO` | String | Optional memo to include |
| Name | Type | Description |
| ------------- | ------ | ------------------------------------------------------------------ |
| `VERSION` | String | Broadcast Format Version |
| `DESTINATION` | String | address where `token` shall be swept |
| `BALANCES` | String | Indicates if address `token` balances should be swept (default=1) |
| `OWNERSHIPS` | String | Indicates if address `token` ownership should be swept (default=1) |
| `MEMO` | String | Optional memo to include |

## Formats

### Version `0`
- `VERSION|DESTINATION|SWEEP_BALANCES|SWEEP_OWNERSHIP|MEMO`
- `VERSION|DESTINATION|BALANCES|OWNERSHIPS|MEMO`

## Examples
```
bt:SWEEP|0|1JDogZS6tQcSxwfxhv6XKKjcyicYA4Feev|1|1
This example sweeps both token balances and ownership from the broadcasting address to 1JDogZS6tQcSxwfxhv6XKKjcyicYA4Feev
This example sweeps both token balances and ownerships from the broadcasting address to 1JDogZS6tQcSxwfxhv6XKKjcyicYA4Feev
```

```
bt:SWEEP|0|1BoogrfDADPLQpq8LMASmWQUVYDp4t2hF9|0|1`
This example sweeps only token ownership from the broadcasting address to 1JDogZS6tQcSxwfxhv6XKKjcyicYA4Feev
bt:SWEEP|0|1BoogrfDADPLQpq8LMASmWQUVYDp4t2hF9|0|1
This example sweeps only token ownerships from the broadcasting address to 1BoogrfDADPLQpq8LMASmWQUVYDp4t2hF9
```

## Rules
Expand Down
180 changes: 172 additions & 8 deletions indexer/includes/actions/sweep.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,182 @@
* sweep.php - SWEEP command
*
* PARAMS:
* VERSION - Broadcast Format Version
* DESTINATION - address where `token` shall be swept
* SWEEP_BALANCES - Indicates if address `token` balances should be swept (default=1)
* SWEEP_OWNERSHIP - Indicates if address `token` balances should be swept (default=1)
* MEMO - Optional memo to include
* VERSION - Broadcast Format Version
* DESTINATION - address where `token` shall be swept
* BALANCES - Indicates if address `token` balances should be swept (default=1)
* OWNERSHIPS - Indicates if address `token` ownerships should be swept (default=1)
* MEMO - Optional memo to include
*
* FORMATS:
* 0 = VERSION|DESTINATION|SWEEP_BALANCES|SWEEP_OWNERSHIP|MEMO
* 0 = VERSION|DESTINATION|BALANCES|OWNERSHIP|MEMO
********************************************************************/
function btnsSweep($params=null, $data=null, $error=null){
global $mysqli, $reparse;
// Coming soon
global $mysqli, $reparse, $addresses, $tickers;

// Define list of known FORMATS
$formats = array(
0 => 'VERSION|DESTINATION|BALANCES|OWNERSHIPS|MEMO'
);

/*****************************************************************
* DEBUGGING - Force params
****************************************************************/
// $str = "0|JDOG|1|";
// $params = explode('|',$str);

// Validate that broadcast format is known
$format = getFormatVersion($params[0]);
if(!$error && ($format===NULL || !in_array($format,array_keys($formats))))
$error = 'invalid: VERSION (unknown)';

// Parse PARAMS using given VERSION format and update BTNS transaction data object
if(!$error)
$data = setActionParams($data, $params, $formats[$format]);

// Get SOURCE address preferences, balances, and ownership information
$preferences = getAddressPreferences($data->SOURCE, $data->BLOCK_INDEX, $data->TX_INDEX);
$balances = getAddressBalances($data->SOURCE, null, $data->BLOCK_INDEX, $data->TX_INDEX);
$ownerships = getAddressOwnership($data->SOURCE, null, $data->BLOCK_INDEX, $data->TX_INDEX);

// Copy base BTNS transaction data object into fees object
$fees = clone($data);
$fees->TICK = 'GAS';
$fees->AMOUNT = 0;
$fees->METHOD = ($preferences->FEE_PREFERENCE==1) ? 1 : 2; // 1=Destroy, 2=Donate

/*****************************************************************
* FORMAT Validations
****************************************************************/

// Verify DESTINATION address format
if(!$error && isset($data->DESTINATION) && !isCryptoAddress($data->DESTINATION))
$error = "invalid: DESTINATION (format)";

// Verify BALANCES format is valid (0 or 1)
if(!$error && isset($data->BALANCES) && !in_array($data->BALANCES,array(0,1)))
$error = "invalid: BALANCES (format)";

// Verify OWNERSHIP format is valid (0 or 1)
if(!$error && isset($data->OWNERSHIP) && !in_array($data->OWNERSHIP,array(0,1)))
$error = "invalid: OWNERSHIP (format)";

// Set default values for BALANCES and OWNERSHIP (default = 1)
$data->BALANCES = (isset($data->BALANCES)) ? $data->BALANCES : 1;
$data->OWNERSHIPS = (isset($data->OWNERSHIPS)) ? $data->OWNERSHIPS : 1;

// Clone the raw data for storage in sweeps table
$sweep = clone($data);

/*****************************************************************
* General Validations
****************************************************************/

// Verify no pipe in MEMO (BTNS uses pipe as field delimiter)
if(!$error && strpos($data->MEMO,'|')!==false)
$error = 'invalid: MEMO (pipe)';

// Verify no semicolon in MEMO (BTNS uses semicolon as action delimiter)
if(!$error && strpos($data->MEMO,';')!==false)
$error = 'invalid: MEMO (semicolon)';

// Calculate total number of database hits for this SWEEP
$db_hits = 1; // 1 sweeps
$db_hits += ($data->BALANCES) ? bcmul(count($balances),3,0) : 0; // 1 debits, 1 credits, 1 balances
$db_hits += ($data->OWNERSHIP) ? count($ownerships) : 0; // 1 issues

// Determine total transaction FEE based on database hits
$data->FEE_TICK = 'GAS';
$data->FEE_AMOUNT = getTransactionFee($db_hits, $data->FEE_TICK);

// Verify SOURCE has enough balances to cover FEE AMOUNT
if(!$error && !hasBalance($balances, $data->FEE_TICK, $data->FEE_AMOUNT))
$error = 'invalid: insufficient funds (FEE)';

// Adjust balances to reduce by FEE amount
if(!$error)
$balances = debitBalances($balances, $data->FEE_TICK, $data->FEE_AMOUNT);

// Determine final status
$data->STATUS = $sweep->STATUS = $status = ($error) ? $error : 'valid';

// Print status message
print "\n\t SWEEP : {$data->DESTINATION} : {$data->STATUS}";

// Create record in sweeps table
createSweep($sweep);

// If this was a valid transaction, then handle the actual sweep actions
if($status=='valid'){

// Store the SOURCE and FEE_TICK in addresses and tickers arrays
addAddressTicker($data->SOURCE, $data->FEE_TICK);

// Debit FEE_AMOUNT from SOURCE address
createDebit('SWEEP', $data->BLOCK_INDEX, $data->TX_HASH, $data->FEE_TICK, $data->FEE_AMOUNT, $data->SOURCE);

// Transfer Balances
if($data->BALANCES==1){
foreach($balances as $tick_id => $amount){
$tick = getTicker($tick_id);

// Debit token amount from SOURCE and credit to DESTINATION
createDebit('SWEEP', $data->BLOCK_INDEX, $data->TX_HASH, $tick, $amount, $data->SOURCE);
createCredit('SWEEP', $data->BLOCK_INDEX, $data->TX_HASH, $tick, $amount, $data->DESTINATION);

// Store the SOURCE, DESTINATION and TICK in addresses and tickers arrays
addAddressTicker($data->SOURCE, $tick);
addAddressTicker($data->DESTINATION, $tick);
}
}

// Transfer token ownerships
if($data->OWNERSHIPS==1){
// Copy base BTNS transaction data object into issue object
$issue = $data;
$issue->TRANSFER = $data->DESTINATION;
foreach($ownerships as $tick){
$issue->TICK = $tick;

// Create issue record for transfer of ownership
createIssue($issue);

// Store the DESTINATION and TICK in addresses and tickers arrays
addAddressTicker($data->DESTINATION, $tick);
}
}

// Update FEES object with to AMOUNT
$fees->AMOUNT = bcadd($fees->AMOUNT, $data->FEE_AMOUNT, 8);

// Handle using FEE according the the users ADDRESS preferences
if($preferences->FEE_PREFERENCE>1){

// Determine what address to donate to
$address = ($preferences->FEE_PREFERENCE==2) ? DONATE_ADDRESS_1 : DONATE_ADDRESS_2;

// Update the $fees object with the destination address
$fees->DESTINATION = $address;

// Store the donation ADDRESS and TICK in addresses list
addAddressTicker($address, $data->FEE_TICK);

// Credit donation address with FEE_AMOUNT
createCredit('SWEEP', $data->BLOCK_INDEX, $data->TX_HASH, $data->FEE_TICK, $data->FEE_AMOUNT, $fees->DESTINATION);
}

// Create record of FEE in `fees` table
createFeeRecord($fees);

// If this is a reparse, bail out before updating balances and token information
if($reparse)
return;

// Update address balances
updateBalances(array_keys($addresses));

// Update supply for tokens
updateTokens($tickers);
}
}

?>
118 changes: 114 additions & 4 deletions indexer/includes/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -1795,8 +1795,9 @@ function hasBalance($balances=null, $tick=null, $amount=null){

// Handle deducting TICK AMOUNT from balances and return updated balances array
function debitBalances($balances=null, $tick=null, $amount=null){
$balance = (isset($balances[$tick])) ? $balances[$tick] : 0;
$balances[$tick] = $balance - $amount;
$tick_id = createTicker($tick);
$balance = (isset($balances[$tick_id])) ? $balances[$tick_id] : 0;
$balances[$tick_id] = $balance - $amount;
return $balances;
}

Expand Down Expand Up @@ -1853,9 +1854,9 @@ function sanityCheck( $block=null ){
$supplyB = getTokenSupplyBalance($tick); // Supply from balances table
$supplyC = getTokenSupply($tick); // Supply from credits/debits tables
if($supplyA!=$supplyB)
byeLog("SanityError: balances table supply does not match token supply : {$tick}");
byeLog("SanityError: balances table supply does not match token supply : {$tick} ({$supplyB} != {$supplyA})");
if($supplyA!=$supplyC)
byeLog("SanityError: credits/debits table supply does not match token supply : {$tick}");
byeLog("SanityError: credits/debits table supply does not match token supply : {$tick} ({$supplyC} != {$supplyA})");
}
}

Expand Down Expand Up @@ -2479,4 +2480,113 @@ function createDividend( $data=null ){
}
}

// Get list of tokens owned by a given address
function getAddressOwnership($address=null, $block_index=null, $tx_index=null){
global $mysqli;
$address_id = createAddress($address);
$data = [];
$whereSql = "";
if(isset($block_index) && is_numeric($block_index))
$whereSql .= " AND block_index <= {$block_index}";
if(isset($tx_index) && is_numeric($tx_index))
$whereSql .= " AND tx_index < '{$tx_index}'";
// get list of issuances where address is SOURCE or TRANSFER (list of tokens)
$sql = "SELECT
t.tick,
i.tick_id
FROM
issues i,
index_tickers t
WHERE
t.id=i.tick_id AND
(source_id='{$address_id}' OR transfer_id='{$address_id}')
{$whereSql}
ORDER BY tick DESC";
$results = $mysqli->query($sql);
if($results){
if($results->num_rows){
while($row = $results->fetch_assoc()){
$row = (object) $row;
$info = getTokenInfo($row->tick, null, $block_index, $tx_index);
if($info->OWNER==$address)
array_push($data, $row->tick);
}
}
} else {
byeLog('Error while trying to lookup records in issues table');
}
return $data;
}


// Create record in `sweeps` table
function createSweep( $data=null ){
global $mysqli;
$tick_id = createTicker($data->TICK);
$source_id = createAddress($data->SOURCE);
$destination_id = createAddress($data->DESTINATION);
$tx_hash_id = createTransaction($data->TX_HASH);
$memo_id = createMemo($data->MEMO);
$status_id = createStatus($data->STATUS);
$tx_index = $mysqli->real_escape_string($data->TX_INDEX);
$balances = $mysqli->real_escape_string($data->BALANCES);
$ownerships = $mysqli->real_escape_string($data->OWNERSHIPS);
$block_index = $mysqli->real_escape_string($data->BLOCK_INDEX);
// Check if record already exists
$sql = "SELECT
tx_index
FROM
sweeps
WHERE
source_id='{$source_id}' AND
tx_hash_id='{$tx_hash_id}'";
$results = $mysqli->query($sql);
if($results){
if($results->num_rows){
// UPDATE record
$sql = "UPDATE
sweeps
SET
tx_index='{$tx_index}',
block_index='{$block_index}',
destination_id='{$destination_id}',
balances='{$balances}',
ownerships='{$ownerships}',
memo_id='{$memo_id}',
status_id='{$status_id}'
WHERE
source_id='{$source_id}' AND
tx_hash_id='{$tx_hash_id}'";
} else {
// INSERT record
$sql = "INSERT INTO sweeps (tx_index, source_id, destination_id, balances, ownerships, memo_id, tx_hash_id, block_index, status_id) values ('{$tx_index}', '{$source_id}','{$destination_id}', '{$balances}', '{$ownerships}', '{$memo_id}', '{$tx_hash_id}', '{$block_index}', '{$status_id}')";
}
$results = $mysqli->query($sql);
if(!$results)
byeLog('Error while trying to create / update a record in the dividends table');
} else {
byeLog('Error while trying to lookup record in dividends table');
}
}

// Get TICK for a given tick_id
function getTicker( $tick_id=null ){
global $mysqli;
if(!isset($tick_id) || $tick_id=='')
return 0;
// Truncate description to 250 chars
$tick_id = $mysqli->real_escape_string($tick_id);
$results = $mysqli->query("SELECT tick FROM index_tickers WHERE id='{$tick_id}' LIMIT 1");
if($results){
if($results->num_rows){
$row = $results->fetch_assoc();
return $row['tick'];
}
} else {
byeLog('Error while trying to lookup ticker in index_tickers table');
}
}



?>
2 changes: 1 addition & 1 deletion indexer/includes/protocol_changes.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
'RUG' => array(0, 10, 0, 9999999, 999999999),
'SEND' => array(0, 10, 0, 789742, 2473585),
'SLEEP' => array(0, 10, 0, 9999999, 999999999),
'SWEEP' => array(0, 10, 0, 9999999, 999999999),
'SWEEP' => array(0, 10, 0, 789742, 2473585),

// Define protocol changes (ALL LOWER Case)
// 'name' => array(0, 10, 0, 0, 0),
Expand Down
Loading

0 comments on commit 6f91d67

Please sign in to comment.