@tradelayerprotocol/tradelayer 1.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +13 -0
- package/.claude/skills/tl-algo/SKILL.md +255 -0
- package/.gitattributes +2 -0
- package/.github/workflows/publish.yaml +26 -0
- package/4mm.js +163 -0
- package/LICENSE +21 -0
- package/NPMSwapRefactor.zip +0 -0
- package/README.md +217 -0
- package/address.sh +26 -0
- package/algoAPI.js +581 -0
- package/analyzepsbt.js +92 -0
- package/apiEx.js +99 -0
- package/bb_hyperscalper.js +290 -0
- package/bbo_demo.js +111 -0
- package/buyer.js +622 -0
- package/client.js +50 -0
- package/createTxTest.js +26 -0
- package/createWallet.js +75 -0
- package/daytrader.js +531 -0
- package/decodeTest.js +69 -0
- package/fundingManager.js +144 -0
- package/index.js +4 -0
- package/listener.js +27 -0
- package/litecoreTxBuilder.js +1128 -0
- package/mmEx.js +356 -0
- package/networks.js +51 -0
- package/orderbook.js +200 -0
- package/package.json +34 -0
- package/perTradeQueue.js +36 -0
- package/projectsTLNPMTLNPM/package-lock.json +162 -0
- package/projectsTLNPMTLNPM/package.json +5 -0
- package/quick.js +32 -0
- package/quickFut.js +37 -0
- package/quickSell.js +37 -0
- package/relayerClient.js +117 -0
- package/run4mm.js +80 -0
- package/run_bbo_tracker.js +241 -0
- package/seller.js +443 -0
- package/session.js +45 -0
- package/setup-lin-ltc.sh +139 -0
- package/setup-lin.sh +203 -0
- package/setup-win-ltc.bat +108 -0
- package/setup-win.bat +167 -0
- package/spam_screamer_futures.js +222 -0
- package/tradelayer.js/.gitattributes +2 -0
- package/tradelayer.js/README.md +2 -0
- package/tradelayer.js/oldTests/activationTest.js +6 -0
- package/tradelayer.js/oldTests/base58.test.js +23 -0
- package/tradelayer.js/oldTests/base64Decode.test.js +16 -0
- package/tradelayer.js/oldTests/blocksRefactor.js +140 -0
- package/tradelayer.js/oldTests/checkVestBalance.js +25 -0
- package/tradelayer.js/oldTests/consensusHashProto.js +151 -0
- package/tradelayer.js/oldTests/contractOrderbook.js +243 -0
- package/tradelayer.js/oldTests/createPayload.js +0 -0
- package/tradelayer.js/oldTests/createTestnetAddr.js +43 -0
- package/tradelayer.js/oldTests/decode.js +205 -0
- package/tradelayer.js/oldTests/decodeTest.js +50 -0
- package/tradelayer.js/oldTests/displayTallyMap.js +19 -0
- package/tradelayer.js/oldTests/encodeDecode.js +340 -0
- package/tradelayer.js/oldTests/expressTest.js +29 -0
- package/tradelayer.js/oldTests/extractBlocksVanilla.js +214 -0
- package/tradelayer.js/oldTests/extractBlocksVanillaa.js +179 -0
- package/tradelayer.js/oldTests/extractPubkeyTest.js +60 -0
- package/tradelayer.js/oldTests/fillInputCacheProto.js +111 -0
- package/tradelayer.js/oldTests/getRawTxTest.js +22 -0
- package/tradelayer.js/oldTests/indexTest.js +26 -0
- package/tradelayer.js/oldTests/initTokensTest.js +32 -0
- package/tradelayer.js/oldTests/interfaceChild.js +129 -0
- package/tradelayer.js/oldTests/listenerChild.js +112 -0
- package/tradelayer.js/oldTests/opdecode.js +26 -0
- package/tradelayer.js/oldTests/options.js +79 -0
- package/tradelayer.js/oldTests/optxtest.js +116 -0
- package/tradelayer.js/oldTests/optxtest1.js +64 -0
- package/tradelayer.js/oldTests/oracle.test.js +32 -0
- package/tradelayer.js/oldTests/orderbook.test.js +36 -0
- package/tradelayer.js/oldTests/parsing.js +93 -0
- package/tradelayer.js/oldTests/payload.js +13 -0
- package/tradelayer.js/oldTests/persistenceUnitTest.js +23 -0
- package/tradelayer.js/oldTests/property.test.js +53 -0
- package/tradelayer.js/oldTests/propertyLevel.js +75 -0
- package/tradelayer.js/oldTests/propertyTest.js +32 -0
- package/tradelayer.js/oldTests/queryAddressTest.js +17 -0
- package/tradelayer.js/oldTests/salter.js +14 -0
- package/tradelayer.js/oldTests/tally.js +81 -0
- package/tradelayer.js/oldTests/tally.test.js +48 -0
- package/tradelayer.js/oldTests/tally2.js +124 -0
- package/tradelayer.js/oldTests/tally3.js +142 -0
- package/tradelayer.js/oldTests/tallyDiag.js +38 -0
- package/tradelayer.js/oldTests/testGetRaw.js +40 -0
- package/tradelayer.js/oldTests/testHexConvert.js +47 -0
- package/tradelayer.js/oldTests/testNewEncoding.js +96 -0
- package/tradelayer.js/oldTests/testNewEncoding2.js +113 -0
- package/tradelayer.js/oldTests/testNewEncoding3 +112 -0
- package/tradelayer.js/oldTests/testNewEncoding3.js +168 -0
- package/tradelayer.js/oldTests/testOPReturn.js +102 -0
- package/tradelayer.js/oldTests/testPayload.js +23 -0
- package/tradelayer.js/oldTests/testRaw.js +50 -0
- package/tradelayer.js/oldTests/testSendTooMuch.js +20 -0
- package/tradelayer.js/oldTests/testTxBuild +28 -0
- package/tradelayer.js/oldTests/testTxBuild.js +42 -0
- package/tradelayer.js/oldTests/tokenOrderbook.js +243 -0
- package/tradelayer.js/oldTests/txUtilsA.js +515 -0
- package/tradelayer.js/oldTests/validityUnitTest.js +53 -0
- package/tradelayer.js/oldTests/vaults.js +72 -0
- package/tradelayer.js/oldTests/volumeIndex.js +117 -0
- package/tradelayer.js/oldTests/volumeIndex2.js +88 -0
- package/tradelayer.js/output_base64.txt +1 -0
- package/tradelayer.js/package-lock.json +9967 -0
- package/tradelayer.js/package.json +61 -0
- package/tradelayer.js/server/index.js +88 -0
- package/tradelayer.js/server/litecoind.exe +0 -0
- package/tradelayer.js/src/activation.js +303 -0
- package/tradelayer.js/src/adjuster.js +77 -0
- package/tradelayer.js/src/amm.js +400 -0
- package/tradelayer.js/src/base256.js +55 -0
- package/tradelayer.js/src/base94.js +79 -0
- package/tradelayer.js/src/channels.js +1163 -0
- package/tradelayer.js/src/clearing.js +3109 -0
- package/tradelayer.js/src/clearlist.js +364 -0
- package/tradelayer.js/src/client.js +295 -0
- package/tradelayer.js/src/consensus.js +613 -0
- package/tradelayer.js/src/contractRegistry.js +964 -0
- package/tradelayer.js/src/db.js +89 -0
- package/tradelayer.js/src/init.js +24 -0
- package/tradelayer.js/src/insurance.js +347 -0
- package/tradelayer.js/src/interface.js +218 -0
- package/tradelayer.js/src/interfaceExpress.js +178 -0
- package/tradelayer.js/src/iou.js +509 -0
- package/tradelayer.js/src/listener.js +226 -0
- package/tradelayer.js/src/logic.js +1702 -0
- package/tradelayer.js/src/main.js +927 -0
- package/tradelayer.js/src/marginMap.js +2165 -0
- package/tradelayer.js/src/options.js +126 -0
- package/tradelayer.js/src/oracle.js +394 -0
- package/tradelayer.js/src/orderbook.js +4123 -0
- package/tradelayer.js/src/persistence.js +554 -0
- package/tradelayer.js/src/property.js +411 -0
- package/tradelayer.js/src/reOrg.js +41 -0
- package/tradelayer.js/src/scaling.js +145 -0
- package/tradelayer.js/src/tally.js +1275 -0
- package/tradelayer.js/src/tradeHistoryManager.js +552 -0
- package/tradelayer.js/src/txDecoder.js +584 -0
- package/tradelayer.js/src/txEncoder.js +610 -0
- package/tradelayer.js/src/txIndex.js +502 -0
- package/tradelayer.js/src/txUtils.js +1392 -0
- package/tradelayer.js/src/types.js +429 -0
- package/tradelayer.js/src/validity.js +3077 -0
- package/tradelayer.js/src/vaults.js +430 -0
- package/tradelayer.js/src/vesting.js +491 -0
- package/tradelayer.js/src/volumeIndex.js +618 -0
- package/tradelayer.js/src/walletInterface.js +220 -0
- package/tradelayer.js/src/walletListener.js +665 -0
- package/tradelayer.js/tests/256decode.js +82 -0
- package/tradelayer.js/tests/UTXOracle.js +205 -0
- package/tradelayer.js/tests/base94test.js +23 -0
- package/tradelayer.js/tests/cancelTxTest.js +62 -0
- package/tradelayer.js/tests/contractInterfaceTest.js +48 -0
- package/tradelayer.js/tests/decimalTest.js +65 -0
- package/tradelayer.js/tests/decoderTest.js +100 -0
- package/tradelayer.js/tests/deltaCount.js +47 -0
- package/tradelayer.js/tests/deltaCount2.js +60 -0
- package/tradelayer.js/tests/interfaceTest.js +37 -0
- package/tradelayer.js/tests/mainTest.js +53 -0
- package/tradelayer.js/tests/makeActivationTest.js +24 -0
- package/tradelayer.js/tests/maxHeightTest.js +49 -0
- package/tradelayer.js/tests/reverseHash.js +72 -0
- package/tradelayer.js/tests/sensitiveConsoleOutput.txt +267 -0
- package/tradelayer.js/tests/tallyTest.js +40 -0
- package/tradelayer.js/tests/testBuybacks.js +46 -0
- package/tradelayer.js/tests/testCodeHash.js +49 -0
- package/tradelayer.js/tests/testConsensusHash.js +91 -0
- package/tradelayer.js/tests/testDecode.js +30 -0
- package/tradelayer.js/tests/testEncodingLengths.js +129 -0
- package/tradelayer.js/tests/testGetTx +32 -0
- package/tradelayer.js/tests/testGetTx.js +32 -0
- package/tradelayer.js/tests/testHexHash.js +32 -0
- package/tradelayer.js/tests/testIndexHash.js +35 -0
- package/tradelayer.js/tests/testInitContracts.js +38 -0
- package/tradelayer.js/tests/testMaxConsensus.js +12 -0
- package/tradelayer.js/tests/testMaxSynth.js +44 -0
- package/tradelayer.js/tests/testMint.js +21 -0
- package/tradelayer.js/tests/testNetwork.js +33 -0
- package/tradelayer.js/tests/testOrderbookLoad.js +62 -0
- package/tradelayer.js/tests/testRebates.js +32 -0
- package/tradelayer.js/tests/testRedeem.js +22 -0
- package/tradelayer.js/tests/testTokenTrade.js +39 -0
- package/tradelayer.js/tests/testTxBuild.js +42 -0
- package/tradelayer.js/tests/testUTXOTrade.js +27 -0
- package/tradelayer.js/tests/tokenTradeHistory.js +27 -0
- package/tradelayer.js/tests/tradeFutures.js +40 -0
- package/tradelayer.js/tests/tradeHistoryExample.js +35 -0
- package/tradelayer.js/tests/tradeHistoryLoad.js +15 -0
- package/tradelayer.js/tests/txScanTest.js +134 -0
- package/tradelayer.js/tests/validateTest.js +136 -0
- package/tradelayer.js/tests/vestingTest.js +37 -0
- package/tradelayer.js/utils/activateMainnet.js +59 -0
- package/tradelayer.js/utils/activateMainnetDoge.js +63 -0
- package/tradelayer.js/utils/autocompactdb.js +23 -0
- package/tradelayer.js/utils/base64toHex.js +32 -0
- package/tradelayer.js/utils/broadcastDoge.js +38 -0
- package/tradelayer.js/utils/calcRedeem.js +19 -0
- package/tradelayer.js/utils/checkNetwork.js +27 -0
- package/tradelayer.js/utils/createAddress.js +48 -0
- package/tradelayer.js/utils/createAttestation.js +133 -0
- package/tradelayer.js/utils/createContract.js +118 -0
- package/tradelayer.js/utils/createOracle.js +94 -0
- package/tradelayer.js/utils/createwallet.js +20 -0
- package/tradelayer.js/utils/crossFuturesTrades.js +57 -0
- package/tradelayer.js/utils/crossTokenTrades.js +62 -0
- package/tradelayer.js/utils/dumpPriv.js +29 -0
- package/tradelayer.js/utils/generateChannel.js +34 -0
- package/tradelayer.js/utils/getInfo.js +21 -0
- package/tradelayer.js/utils/hardWipe.js +20 -0
- package/tradelayer.js/utils/hexTo64.js +16 -0
- package/tradelayer.js/utils/importAddress.js +28 -0
- package/tradelayer.js/utils/importpriv.js +20 -0
- package/tradelayer.js/utils/issueOracleContract.js +67 -0
- package/tradelayer.js/utils/issueTokens.js +41 -0
- package/tradelayer.js/utils/listunspent.js +66 -0
- package/tradelayer.js/utils/litecoinClient.js +30 -0
- package/tradelayer.js/utils/loadwallet.js +20 -0
- package/tradelayer.js/utils/publishOracle.js +113 -0
- package/tradelayer.js/utils/sendActivation.js +21 -0
- package/tradelayer.js/utils/sendChannelContractTrade.js +34 -0
- package/tradelayer.js/utils/sendChannelTokenTrade.js +34 -0
- package/tradelayer.js/utils/sendCommit.js +24 -0
- package/tradelayer.js/utils/sendDoge.js +62 -0
- package/tradelayer.js/utils/sendDogeMain.js +67 -0
- package/tradelayer.js/utils/sendDogeTx.js +46 -0
- package/tradelayer.js/utils/sendLTC.js +63 -0
- package/tradelayer.js/utils/sendMainnet.js +62 -0
- package/tradelayer.js/utils/sendTransfer.js +19 -0
- package/tradelayer.js/utils/sendVestTest.js +88 -0
- package/tradelayer.js/utils/sendWithdrawal.js +26 -0
- package/tradelayer.js/utils/simpleStart.js +8 -0
- package/tradelayer.js/utils/startStop.js +27 -0
- package/tradelayer.js/utils/structuredTrades.js +136 -0
- package/tradelayer.js/utils/verifySignature.js +90 -0
- package/tradelayer.js/utils/verifyWitnessAndScriptPubkey.js +41 -0
- package/tradelayer.js/utils/walletCache.js +172 -0
- package/tradelayer.js/utils/walletContractInterface.js +48 -0
- package/tradelayer.js/utils/walletFetchTxs.js +66 -0
- package/tradelayer.js/utils/walletUtils.js +97 -0
- package/tradelayer.js/utils/wipeDB.js +55 -0
- package/tradelayer.js/utils/wipeDBNotTx.js +50 -0
- package/txEncoder.js +529 -0
- package/utility.js +28 -0
- package/verifymessage.js +38 -0
- package/ws-transport.js +311 -0
|
@@ -0,0 +1,1702 @@
|
|
|
1
|
+
|
|
2
|
+
const TradeChannels = require('./channels.js')
|
|
3
|
+
const Activation = require('./activation.js')
|
|
4
|
+
const activation = Activation.getInstance();
|
|
5
|
+
// Custom modules for TradeLayer
|
|
6
|
+
//const Clearing =require('./clearing.js')
|
|
7
|
+
//const Persistence = require('./Persistence.js'); // Handles data persistence
|
|
8
|
+
const Orderbook = require('./orderbook.js'); // Manages the order book
|
|
9
|
+
//const InsuranceFund = require('./insurance.js'); // Manages the insurance fund
|
|
10
|
+
//const VolumeIndex = require('./VolumeIndex.js'); // Tracks and indexes trading volumes
|
|
11
|
+
const TradeLayerManager = require('./vesting.js'); // Handles vesting logic
|
|
12
|
+
//const ReOrgChecker = require('./reOrg.js');
|
|
13
|
+
const OracleList = require('./oracle.js')
|
|
14
|
+
// Additional modules
|
|
15
|
+
const fs = require('fs'); // File system module
|
|
16
|
+
|
|
17
|
+
const Validity = require('./validity.js'); // Module for checking transaction validity
|
|
18
|
+
const TxUtils = require('./txUtils.js'); // Utility functions for transactions
|
|
19
|
+
const TxIndex = require('./txIndex.js') // Indexes TradeLayer transactions
|
|
20
|
+
const TallyMap = require('./tally.js'); // Manages Tally Mapping
|
|
21
|
+
const MarginMap = require('./marginMap.js'); // Manages Margin Mapping
|
|
22
|
+
const PropertyManager = require('./property.js'); // Manages properties
|
|
23
|
+
const ContractRegistry = require('./contractRegistry.js'); // Registry for contracts
|
|
24
|
+
const ClearList = require('./clearlist.js')
|
|
25
|
+
const Scaling = require('./scaling.js')
|
|
26
|
+
//const Consensus = require('./consensus.js'); // Functions for handling consensus
|
|
27
|
+
const Channels = require('./channels.js')
|
|
28
|
+
const Encode = require('./txEncoder.js'); // Encodes transactions
|
|
29
|
+
const Types = require('./types.js'); // Defines different types used in the system
|
|
30
|
+
const Decode = require('./txDecoder.js'); // Decodes transactionsconst db = require('./db.js'); // Adjust the path if necessary
|
|
31
|
+
const db = require('./db.js'); // Adjust the path if necessary
|
|
32
|
+
const BigNumber = require('bignumber.js')
|
|
33
|
+
const VolumeIndex = require('./volumeIndex.js')
|
|
34
|
+
const SynthRegistry = require('./vaults.js')
|
|
35
|
+
const TradeHistory = require('./tradeHistoryManager.js')
|
|
36
|
+
const OptionsEngine = require('./options.js');
|
|
37
|
+
|
|
38
|
+
// logic.js
|
|
39
|
+
const Logic = {
|
|
40
|
+
//here we have a kinda stupid structure where instead of passing the params obj. I break it down into its sub-properties
|
|
41
|
+
//and have to map the subsequent function's parameter sequence to how I have it here
|
|
42
|
+
//I've wasted a lot of time fixing small bugs relating to getting this right for each functiom, would do it differently
|
|
43
|
+
//Anyway, here we branch into each logic function.
|
|
44
|
+
async typeSwitch(txNumber, params){
|
|
45
|
+
if(params.valid == false){return null}
|
|
46
|
+
console.log('tx number and params ' +txNumber, params)
|
|
47
|
+
switch (txNumber) {
|
|
48
|
+
case 0:
|
|
49
|
+
await Logic.activateTradeLayer(params.txTypesToActivate, params.block, params.codeHash);
|
|
50
|
+
break;
|
|
51
|
+
case 1:
|
|
52
|
+
await Logic.tokenIssue(params.senderAddress, params.initialAmount, params.ticker, params.url, params.whitelistId, params.isManaged, params.backupAddress, params.isNFT, params.block);
|
|
53
|
+
break;
|
|
54
|
+
case 2:
|
|
55
|
+
await Logic.sendToken(params.sendAll, params.senderAddress, params.address, params.propertyIds, params.amounts,params.block);
|
|
56
|
+
break;
|
|
57
|
+
case 3:
|
|
58
|
+
console.log('about to call utxo trade logic '+JSON.stringify(params))
|
|
59
|
+
await Logic.tradeTokenForUTXO(params.senderAddress, params.satsPaymentAddress, params.propertyId, params.amount, params.columnA, params.satsExpected, params.tokenDeliveryAddress, params.satsReceived, params.price, params.paymentPercent, params.tagWithdraw, params.block, params.txid);
|
|
60
|
+
break;
|
|
61
|
+
case 4:
|
|
62
|
+
console.log('in the commit case '+params.txid)
|
|
63
|
+
await Logic.commitToken(params.senderAddress, params.channelAddress, params.propertyId, params.amount, params.payEnabled, params.clearLists, params.block, params.txid);
|
|
64
|
+
break;
|
|
65
|
+
case 5:
|
|
66
|
+
await Logic.onChainTokenToToken(params.senderAddress, params.propertyIdOffered, params.propertyIdDesired, params.amountOffered, params.amountExpected, params.txid, params.block, params.stop, params.post);
|
|
67
|
+
break;
|
|
68
|
+
case 6:
|
|
69
|
+
await Logic.cancelOrder(params.senderAddress, params.isContract, params.offeredPropertyId, params.desiredPropertyId, params.cancelAll, params.cancelParams, params.block);
|
|
70
|
+
break;
|
|
71
|
+
case 7:
|
|
72
|
+
await Logic.createClearList(sender, params.name, params.url, params.description, params.backupAddress, params.block);
|
|
73
|
+
break;
|
|
74
|
+
case 8:
|
|
75
|
+
await Logic.updateAdmin(params.whitelist, params.token, params.oracle, params.id, params.newAddress, params.updateBackup, params.block);
|
|
76
|
+
break;
|
|
77
|
+
case 9:
|
|
78
|
+
await Logic.issueOrRevokeAttestation(params.sender, params.id, params.targetAddress, params.metaData, params.revoke, params.block);
|
|
79
|
+
break;
|
|
80
|
+
case 10:
|
|
81
|
+
await Logic.AMMPool(params.senderAddress, params.block, params.isRedeem, params.isContract, params.id1, params.amount, params.id2, params.amount2);
|
|
82
|
+
break;
|
|
83
|
+
case 11:
|
|
84
|
+
await Logic.grantManagedToken(params.propertyId, params.amount, params.recipientAddress, params.propertyManager, params.senderAddress, params.block);
|
|
85
|
+
break;
|
|
86
|
+
case 12:
|
|
87
|
+
await Logic.redeemManagedToken(params.propertyId, params.amount, params.propertyManager, params.senderAddress, params.block);
|
|
88
|
+
break;
|
|
89
|
+
case 13:
|
|
90
|
+
await Logic.createOracle(params.senderAddress, params.ticker, params.url, params.backupAddress, params.clearlists, params.lag, params.oracleRegistry, params.block);
|
|
91
|
+
break;
|
|
92
|
+
case 14:
|
|
93
|
+
await Logic.publishOracleData(params.oracleId, params.price, params.high, params.low, params.close, params.block);
|
|
94
|
+
break;
|
|
95
|
+
case 15:
|
|
96
|
+
await Logic.closeOracle(params.oracleId, params.oracleRegistry, params.block);
|
|
97
|
+
break;
|
|
98
|
+
case 16:
|
|
99
|
+
await Logic.createContractSeries(params.senderAddress, params.native, params.underlyingOracleId, params.onChainData, params.notionalPropertyId, params.notionalValue, params.collateralPropertyId, params.leverage, params.expiryPeriod, params.series, params.inverse, params.fee, params.block, params.whitelist);
|
|
100
|
+
break;
|
|
101
|
+
case 17:
|
|
102
|
+
await Logic.exerciseDerivative(params.contractId, params.amount, params.contractsRegistry,params.senderAddress, params.block);
|
|
103
|
+
break;
|
|
104
|
+
case 18:
|
|
105
|
+
await Logic.tradeContractOnchain(params.contractId, params.price, params.amount, params.sell, params.insurance, params.block, params.txid, params.senderAddress, params.reduce, params.post, params.stop,params.block);
|
|
106
|
+
break;
|
|
107
|
+
case 19:
|
|
108
|
+
await Logic.tradeContractChannel(params.contractId, params.price, params.amount, params.columnAIsSeller, params.expiryBlock, params.insurance, params.senderAddress, params.block,params.txid,params.columnAIsMaker);
|
|
109
|
+
break;
|
|
110
|
+
case 20:
|
|
111
|
+
await Logic.tradeTokensChannel(params.propertyIdOffered, params.propertyIdDesired, params.amountOffered, params.amountDesired, params.expiryBlock, params.columnAIsOfferer, params.senderAddress, params.block,params.txid,params.columnAIsMaker);
|
|
112
|
+
break;
|
|
113
|
+
case 21:
|
|
114
|
+
await Logic.withdrawal(params.withdrawAll, params.channelAddress, params.propertyId, params.amount, params.senderAddress, params.block, params.columnIsB);
|
|
115
|
+
break;
|
|
116
|
+
case 22:
|
|
117
|
+
await Logic.transfer(params.senderAddress, params.toChannelAddress, params.propertyId, params.amount, params.isColumnA, params.pay, params.payRefAddress, params.block,params.txid);
|
|
118
|
+
break;
|
|
119
|
+
case 23:
|
|
120
|
+
await Logic.settleChannelPNL(params.channelAddress, params.txParams, params.block,params.txid);
|
|
121
|
+
break;
|
|
122
|
+
case 24:
|
|
123
|
+
await Logic.mintSynthetic(params.senderAddress, params.propertyId, params.contractId, params.amount, params.block, params.grossRequired, params.contracts, params.margin);
|
|
124
|
+
break;
|
|
125
|
+
case 25:
|
|
126
|
+
await Logic.redeemSynthetic(params.senderAddress, params.propertyId, params.contractId, params.amount, params.block);
|
|
127
|
+
break;
|
|
128
|
+
case 26:
|
|
129
|
+
await Logic.payToTokens(params.tallyMap, params.propertyIdTarget, params.propertyIdUsed, params.amount, params.block);
|
|
130
|
+
break;
|
|
131
|
+
case 27:
|
|
132
|
+
await processOptionTrade(sender, params, txid);
|
|
133
|
+
break;
|
|
134
|
+
case 28:
|
|
135
|
+
await Logic.tradeBaiUrbun(params.channelAddress, params.propertyIdDownPayment, params.propertyIdToBeSold, params.downPaymentPercent, params.amount, params.expiryBlock, params.tradeExpiryBlock, params.block);
|
|
136
|
+
break;
|
|
137
|
+
case 29:
|
|
138
|
+
await Logic.tradeMurabaha(params.channelAddress, params.buyerAddress, params.sellerAddress, params.propertyId, params.costPrice, params.profitMargin, params.paymentBlockHeight, params.block);
|
|
139
|
+
break;
|
|
140
|
+
case 30:
|
|
141
|
+
await Logic.issueInvoice(params.propertyManager, params.invoiceRegistry, params.propertyIdToReceivePayment, params.amount, params.dueDateBlock, params.propertyIdCollateral, params.receivesPayToToken, params.issuerNonce, params.block);
|
|
142
|
+
break;
|
|
143
|
+
case 31:
|
|
144
|
+
Logic.batchSettlement(params);
|
|
145
|
+
break;
|
|
146
|
+
case 32:
|
|
147
|
+
await Logic.batchMoveZkRollup(params.zkVerifier, params.rollupData, params.zkProof, params.block);
|
|
148
|
+
break;
|
|
149
|
+
case 33:
|
|
150
|
+
Logic.coloredCoin(params);
|
|
151
|
+
break;
|
|
152
|
+
case 34:
|
|
153
|
+
Logic.crossLayerBridge(params);
|
|
154
|
+
break;
|
|
155
|
+
case 35:
|
|
156
|
+
Logic.smartContractBind(params);
|
|
157
|
+
break;
|
|
158
|
+
default:
|
|
159
|
+
console.log(`Unhandled transaction type: ${txNumber}`);
|
|
160
|
+
}
|
|
161
|
+
return
|
|
162
|
+
},
|
|
163
|
+
|
|
164
|
+
async activateTradeLayer(txTypes, block, codeHash) {
|
|
165
|
+
if (!Array.isArray(txTypes)) {
|
|
166
|
+
txTypes = [txTypes];
|
|
167
|
+
}
|
|
168
|
+
console.log('inside activate logic '+txTypes)
|
|
169
|
+
const results = [];
|
|
170
|
+
for (const txType of txTypes) {
|
|
171
|
+
console.log(`Activating txType: ${txType} at block: ${block}`);
|
|
172
|
+
const activationResult = await activation.activate(txType, block, codeHash);
|
|
173
|
+
console.log(`Activation result for txType ${txType}:`, activationResult);
|
|
174
|
+
results.push({ txType, result: activationResult });
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return results; // Return an array of results for further processing
|
|
178
|
+
},
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
async tokenIssue(sender, initialAmount, ticker, url = '', clearlistId = 0, isManaged = false, backupAddress = '', isNFT = false, block) {
|
|
182
|
+
const propertyManager = PropertyManager.getInstance();
|
|
183
|
+
|
|
184
|
+
// Determine the type of the token based on whether it's managed or an NFT
|
|
185
|
+
let tokenType = isNFT ? 'Non-Fungible' : isManaged ? 'Managed' : 'Fixed';
|
|
186
|
+
|
|
187
|
+
// Define the token data
|
|
188
|
+
const tokenData = {
|
|
189
|
+
ticker: ticker,
|
|
190
|
+
totalInCirculation: initialAmount,
|
|
191
|
+
type: tokenType,
|
|
192
|
+
clearlistId: clearlistId,
|
|
193
|
+
issuer: sender,
|
|
194
|
+
backupAddress: backupAddress
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
// Create the token in the property manager
|
|
198
|
+
try {
|
|
199
|
+
var newPropertyId = await propertyManager.createToken(ticker, initialAmount, tokenType, clearlistId, sender, backupAddress);
|
|
200
|
+
//console.log('created token, now creating the units at '+sender+ ' in amount '+initialAmount)
|
|
201
|
+
await TallyMap.updateBalance(sender, newPropertyId, initialAmount, 0, 0, 0,'issuance',block);
|
|
202
|
+
return `Token ${ticker} (ID: ${newPropertyId}) created. Type: ${tokenType}`;
|
|
203
|
+
} catch (error) {
|
|
204
|
+
console.error('Error creating token:', error);
|
|
205
|
+
return error.message;
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
async sendToken(sendAll, senderAddress, recipientAddresses, propertyIdNumbers, amounts,block) {
|
|
211
|
+
console.log('send logic parameters '+sendAll + ' '+ senderAddress + ' '+ recipientAddresses + ' ' + propertyIdNumbers + ' '+ amounts)
|
|
212
|
+
if (sendAll) {
|
|
213
|
+
// Handle sending all available balances
|
|
214
|
+
//console.log('sendingAll')
|
|
215
|
+
await sendAll(senderAddress,recipientAddresses)
|
|
216
|
+
} else {
|
|
217
|
+
// Check if handling a multi-send or single send
|
|
218
|
+
const isMultiSend = Array.isArray(propertyIdNumbers) && Array.isArray(amounts);
|
|
219
|
+
if (isMultiSend) {
|
|
220
|
+
//console.log('multisend '+ isMultiSend + ' is this an array? '+propertyIdNumbers+ ' what about amounts '+amounts)
|
|
221
|
+
// Ensure arrays are of the same length
|
|
222
|
+
if (propertyIdNumbers.length !== amounts.length || propertyIdNumbers.length !== recipientAddresses.length) {
|
|
223
|
+
throw new Error('Property IDs, amounts, and recipient addresses arrays must have the same length.');
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Process each send in the multi-send transaction
|
|
227
|
+
for (let i = 0; i < propertyIdNumbers.length; i++) {
|
|
228
|
+
const propertyId = propertyIdNumbers[i];
|
|
229
|
+
const amount = amounts[i];
|
|
230
|
+
const recipientAddress = recipientAddresses[i];
|
|
231
|
+
console.log('checking block before process send' +block)
|
|
232
|
+
await processSend(senderAddress, recipientAddress, propertyId, amount,block);
|
|
233
|
+
}
|
|
234
|
+
} else {
|
|
235
|
+
// Special handling for TLVEST (Property ID 2)
|
|
236
|
+
//console.log('propertyIdnumbers ' +propertyIdNumbers)
|
|
237
|
+
if (propertyIdNumbers == 2||propertyIdNumbers==3) {
|
|
238
|
+
console.log('vesting single send '+senderAddress)
|
|
239
|
+
await this.vestingSend(senderAddress,recipientAddresses,propertyIdNumbers,amounts,block)
|
|
240
|
+
}else if(propertyIdNumbers!=undefined){
|
|
241
|
+
console.log('vanilla single send, block '+block)
|
|
242
|
+
await this.sendSingle(senderAddress, recipientAddresses, propertyIdNumbers, amounts,block);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Save the updated tally map to the database
|
|
248
|
+
//await TallyMap.recordTallyMapDelta(blockHeight, txId, address, propertyId, amountChange)
|
|
249
|
+
return console.log('sent')
|
|
250
|
+
},
|
|
251
|
+
|
|
252
|
+
async vestingSend(senderAddress, recipientAddresses, propertyIdNumbers, amounts,block){
|
|
253
|
+
// Get TLVEST and TL balances for the sender
|
|
254
|
+
|
|
255
|
+
const BigNumber = require('bignumber.js');
|
|
256
|
+
|
|
257
|
+
// Ensuring amount is a whole number
|
|
258
|
+
const roundedAmount = new BigNumber(amounts).integerValue(BigNumber.ROUND_DOWN);
|
|
259
|
+
|
|
260
|
+
if (roundedAmount.isLessThanOrEqualTo(0)) {
|
|
261
|
+
throw new Error("Amount must be greater than zero");
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const tlVestTally = await TallyMap.getTally(senderAddress, propertyIdNumbers);
|
|
265
|
+
|
|
266
|
+
// Calculate the amount of TL to move from vesting to available
|
|
267
|
+
const tlVestingMovement = this.calculateVestingMovement(amounts, tlVestTally)
|
|
268
|
+
|
|
269
|
+
await TallyMap.updateBalance(senderAddress, propertyIdNumbers, -amounts, 0, 0, 0,'vestingSend',block);
|
|
270
|
+
await TallyMap.updateBalance(recipientAddresses, propertyIdNumbers, amounts, 0, 0, 0,'vestingSend',block);
|
|
271
|
+
|
|
272
|
+
await TallyMap.updateBalance(senderAddress, propertyIdNumbers, 0, 0, 0, -tlVestingMovement,'vestingDrag',block);
|
|
273
|
+
await TallyMap.updateBalance(recipientAddresses, propertyIdNumbers, 0, 0, 0, tlVestingMovement,'vestingFollow',block);
|
|
274
|
+
return
|
|
275
|
+
},
|
|
276
|
+
|
|
277
|
+
calculateVestingMovement(amount, tlVestTally) {
|
|
278
|
+
// Convert all values to BigNumber for accurate calculation
|
|
279
|
+
const amountBN = new BigNumber(amount);
|
|
280
|
+
const tlVestAvailableBN = new BigNumber(tlVestTally.available);
|
|
281
|
+
const tlVestingBN = new BigNumber(tlVestTally.vesting);
|
|
282
|
+
|
|
283
|
+
// Calculate the proportion of TLVEST being moved
|
|
284
|
+
// Using BigNumber's division method for precision
|
|
285
|
+
const proportionBN = amountBN.dividedBy(tlVestAvailableBN);
|
|
286
|
+
|
|
287
|
+
// Calculate the amount of TL to move from vesting to available
|
|
288
|
+
// Ensure result is rounded down to avoid fractional vesting movement
|
|
289
|
+
const tlVestingMovementBN = tlVestingBN.multipliedBy(proportionBN).integerValue(BigNumber.ROUND_DOWN);
|
|
290
|
+
console.log('inside calc vesting mov '+tlVestingMovementBN+' '+tlVestingBN+' '+proportionBN+' '+amountBN+' '+tlVestAvailableBN+' '+amount+' '+tlVestTally.available+' '+tlVestTally.vesting)
|
|
291
|
+
return tlVestingMovementBN.toString(); // Convert back to string for further processing
|
|
292
|
+
},
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
roundToEightDecimals(number) {
|
|
296
|
+
return Math.floor(number * 1e8) / 1e8;
|
|
297
|
+
},
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
async sendSingle(senderAddress, receiverAddress, propertyId, amount,block) {
|
|
301
|
+
const tallyMapInstance = await TallyMap.getInstance();
|
|
302
|
+
|
|
303
|
+
// Check if sender has enough balance
|
|
304
|
+
const senderBalance = TallyMap.getTally(senderAddress, propertyId);
|
|
305
|
+
console.log('checking balance before sending ' +JSON.stringify(senderBalance))
|
|
306
|
+
if (senderBalance < amount) {
|
|
307
|
+
/*throw new Error*/console.log("Insufficient balance");
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Perform the send operation
|
|
311
|
+
await TallyMap.updateBalance(senderAddress, propertyId, -amount, 0, 0, 0,'send', block);
|
|
312
|
+
await TallyMap.updateBalance(receiverAddress, propertyId, amount, 0, 0, 0,'receive', block);
|
|
313
|
+
|
|
314
|
+
// Handle special case for TLVEST
|
|
315
|
+
if (propertyId === 2) {
|
|
316
|
+
// Update the vesting column of TL accordingly
|
|
317
|
+
// Logic for updating TL vesting...
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
return "Send operation successful";
|
|
321
|
+
},
|
|
322
|
+
|
|
323
|
+
async sendAll(senderAddress, receiverAddress) {
|
|
324
|
+
const tallyMapInstance = await TallyMap.getInstance();
|
|
325
|
+
|
|
326
|
+
// Get all balances for the sender
|
|
327
|
+
const senderBalances = tallyMapInstance.getAddressBalances(senderAddress);
|
|
328
|
+
|
|
329
|
+
if (senderBalances.length === 0) {
|
|
330
|
+
throw new Error("No balances to send");
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Iterate through each token balance and send it to the receiver
|
|
334
|
+
for (const balance of senderBalances) {
|
|
335
|
+
const { propertyId, amount } = balance;
|
|
336
|
+
if (amount > 0) {
|
|
337
|
+
await TallyMap.updateBalance(senderAddress, propertyId, -amount, 0, 0, 0, 'sendAll');
|
|
338
|
+
await TallyMap.updateBalance(receiverAddress, propertyId, amount, 0, 0, 0,'receiveAll');
|
|
339
|
+
|
|
340
|
+
// Handle special case for TLVEST
|
|
341
|
+
if (propertyId === 'TLVEST') {
|
|
342
|
+
// Update the vesting column of TL accordingly
|
|
343
|
+
// Logic for updating TL vesting...
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
return "All balances sent successfully";
|
|
349
|
+
},
|
|
350
|
+
|
|
351
|
+
// Helper function to process a single send operation
|
|
352
|
+
async processSend(senderAddress, recipientAddress, propertyId, amount,block) {
|
|
353
|
+
|
|
354
|
+
const availableBalance = tallyMap.getAvailableBalance(senderAddress, propertyId);
|
|
355
|
+
if (availableBalance < amount) {
|
|
356
|
+
throw new Error('Insufficient available balance for transaction.');
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
await TallyMap.updateBalance(senderAddress, propertyId, -amount,0,0,0,'multi-send',block);
|
|
360
|
+
await TallyMap.updateBalance(recipientAddress, propertyId, amount,0,0,0,'multi-send',block);
|
|
361
|
+
console.log(`Transferred ${amount} of property ${propertyId} from ${senderAddress} to ${recipientAddress}`);
|
|
362
|
+
return
|
|
363
|
+
},
|
|
364
|
+
|
|
365
|
+
async tradeTokenForUTXO(senderAddress, receiverAddress, propertyId, tokenAmount, columnA, satsExpected, tokenDeliveryAddress, satsReceived, price, paymentPercent, tagWithdraw, block, txid) {
|
|
366
|
+
// Calculate the number of tokens to deliver based on the LTC received
|
|
367
|
+
const receiverLTCReceivedBigNumber = new BigNumber(satsReceived);
|
|
368
|
+
const satsExpectedBigNumber = new BigNumber(satsExpected);
|
|
369
|
+
const decodedTokenAmountBigNumber = new BigNumber(tokenAmount);
|
|
370
|
+
const tradeHistoryManager = new TradeHistory()
|
|
371
|
+
|
|
372
|
+
const tokensToDeliver = Number(tokenAmount)
|
|
373
|
+
//console.log('values in utxo logic '+tokenAmount+' '+decodedTokenAmountBigNumber+' '+satsExpected+' '+satsExpectedBigNumber+' '+satsReceived+' '+receiverLTCReceivedBigNumber)
|
|
374
|
+
//look at the channel balance where the commited tokens we're selling for LTC exist
|
|
375
|
+
|
|
376
|
+
console.log('inside logic for UTXO trade '+tokensToDeliver+' '+price, columnA)
|
|
377
|
+
let channel = await Channels.getChannel(senderAddress);
|
|
378
|
+
if(!channel){
|
|
379
|
+
console.log('failed UTXO trade no commited tokens ')
|
|
380
|
+
return
|
|
381
|
+
}
|
|
382
|
+
let channelBalance;
|
|
383
|
+
|
|
384
|
+
// Default to column with balance if specified column has none
|
|
385
|
+
if (columnA === true) {
|
|
386
|
+
channelBalance = channel["A"]?.[propertyId] || 0;
|
|
387
|
+
if (channelBalance === 0) {
|
|
388
|
+
console.log(`No balance in column A. Defaulting to column B.`);
|
|
389
|
+
columnA = false; // Switch to column B
|
|
390
|
+
channelBalance = channel["B"]?.[propertyId] || 0;
|
|
391
|
+
}
|
|
392
|
+
} else if (columnA === false) {
|
|
393
|
+
channelBalance = channel["B"]?.[propertyId] || 0;
|
|
394
|
+
if (channelBalance === 0) {
|
|
395
|
+
console.log(`No balance in column B. Defaulting to column A.`);
|
|
396
|
+
columnA = true; // Switch to column A
|
|
397
|
+
channelBalance = channel["A"]?.[propertyId] || 0;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// If both columns are empty, handle the failure
|
|
402
|
+
if (channelBalance === 0) {
|
|
403
|
+
console.log(`No balance available in either column for property ID ${propertyId}`);
|
|
404
|
+
return; // Exit early, or set tokensToDeliver to 0 as appropriate
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// Ensure tokensToDeliver does not exceed available balance
|
|
408
|
+
if (tokensToDeliver > channelBalance) {
|
|
409
|
+
tokensToDeliver = channelBalance;
|
|
410
|
+
}
|
|
411
|
+
console.log(`${tokensToDeliver} tokens to deliver out of ${channelBalance} available`);
|
|
412
|
+
|
|
413
|
+
// Debit tokens from the correct column
|
|
414
|
+
if (columnA === true) {
|
|
415
|
+
channel["A"][propertyId] -= tokensToDeliver;
|
|
416
|
+
} else if (columnA === false) {
|
|
417
|
+
channel["B"][propertyId] -= tokensToDeliver;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// Save updated channel state
|
|
421
|
+
await Channels.setChannel(senderAddress, channel);
|
|
422
|
+
|
|
423
|
+
console.log('channel adjusted for token sale '+JSON.stringify(channel["A"])+' '+JSON.stringify(channel["B"]))
|
|
424
|
+
//the tokens exist both as channel object balances and reserve balance on the channel address, which is the sender
|
|
425
|
+
//So we debit there and then credit them to the token delivery address, which we took in the parsing
|
|
426
|
+
//From the token delivery vOut and analyzing the actual transaction, usually the change address of the LTC spender
|
|
427
|
+
await TallyMap.updateChannelBalance(senderAddress,propertyId,-tokensToDeliver,'UTXOTokenTradeDebit',block)
|
|
428
|
+
const feeRateBN = new BigNumber(0.00005)
|
|
429
|
+
const fee = new BigNumber(tokenAmount).times(feeRateBN).decimalPlaces(8).toNumber()
|
|
430
|
+
const netDelivery = new BigNumber(tokensToDeliver).minus(fee).decimalPlaces(8).toNumber()
|
|
431
|
+
if(tagWithdraw!=null&&typeof tagWithdraw==="string" ){
|
|
432
|
+
await TallyMap.updateChannelBalance(tokenDeliveryAddress,propertyId,netDelivery,'UTXOTokenTradeCredit',block)
|
|
433
|
+
await Channels.recordCommitToChannel(tokenDeliveryAddress, tagWithdraw, propertyId, tokenAmount, false, null, block)
|
|
434
|
+
}else{
|
|
435
|
+
await TallyMap.updateBalance(tokenDeliveryAddress,propertyId,netDelivery,0,0,0,'UTXOTokenTradeCredit',block)
|
|
436
|
+
}
|
|
437
|
+
await TallyMap.updateBalance(tokenDeliveryAddress, propertyId, -fee, 0, 0, 0, "utxoFee", block,txid)
|
|
438
|
+
console.log('about to apply fee cache '+propertyId+' '+fee)
|
|
439
|
+
await TallyMap.updateFeeCache(propertyId,fee,1,block)
|
|
440
|
+
const key = '0-'+propertyId
|
|
441
|
+
console.log('saving volume in volume Index '+key+' '+satsReceived)
|
|
442
|
+
const coinAdj = new BigNumber(satsReceived).div(1e8).decimalPlaces(8, BigNumber.ROUND_DOWN)
|
|
443
|
+
console.log(' price in UTXO '+price)
|
|
444
|
+
if (!Number.isFinite(Number(price))) {
|
|
445
|
+
price = coinAdj.div(tokenAmount).decimalPlaces(8).toNumber();
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
await VolumeIndex.saveVolumeDataById(
|
|
449
|
+
key,
|
|
450
|
+
tokenAmount,
|
|
451
|
+
coinAdj.toNumber(),
|
|
452
|
+
price,
|
|
453
|
+
block,
|
|
454
|
+
'UTXO')
|
|
455
|
+
|
|
456
|
+
const trade = {
|
|
457
|
+
offeredPropertyId: 0,
|
|
458
|
+
desiredPropertyId: propertyId,
|
|
459
|
+
amountOffered: tokenAmount, // or appropriate amount
|
|
460
|
+
amountExpected: coinAdj.toNumber(), // or appropriate amount
|
|
461
|
+
price: price,
|
|
462
|
+
takerFee: fee,
|
|
463
|
+
block: block,
|
|
464
|
+
buyer: tokenDeliveryAddress,
|
|
465
|
+
seller: receiverAddress,
|
|
466
|
+
takerTxId: txid
|
|
467
|
+
};
|
|
468
|
+
const orderbook = await Orderbook.getOrderbookInstance(key)
|
|
469
|
+
await orderbook.recordTokenTrade(trade,block,txid)
|
|
470
|
+
TallyMap.updateFeeCache(propertyId,fee,1,block)
|
|
471
|
+
const isListedA = await ClearList.isAddressInClearlist(2, senderAddress);
|
|
472
|
+
const isListedB = await ClearList.isAddressInClearlist(2, receiverAddress)
|
|
473
|
+
let isTokenListed = false
|
|
474
|
+
if (String(propertyId).startsWith('s-')) {
|
|
475
|
+
isTokenListed = true //need to add logic to look up the contractId inline to the synth id and then look up its pairs
|
|
476
|
+
// and then look up if those tokens are listed
|
|
477
|
+
}else{
|
|
478
|
+
let propertyInfo = PropertyManager.getPropertyData(propertyId)
|
|
479
|
+
if(propertyInfo.issuer){
|
|
480
|
+
isTokenListed = await ClearList.isAddressInClearlist(1, propertyInfo.issuer);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
console.log('is token/address listed for liquidity reward '+isListedA+' '+isListedB+' '+isTokenListed)
|
|
484
|
+
if(isTokenListed){
|
|
485
|
+
const liqRewardBaseline1= await VolumeIndex.baselineLiquidityReward(satsReceived,0.000025,0)
|
|
486
|
+
const liqRewardBaseline2= await VolumeIndex.baselineLiquidityReward(tokenAmount,0.000025,propertyId)
|
|
487
|
+
TallyMap.updateBalance(senderAddress,3,liqRewardBaseline1,0,0,0,'baselineLiquidityReward')
|
|
488
|
+
TallyMap.updateBalance(receiverAddress,3,liqRewardBaseline2,0,0,0,'baselineLiquidityReward')
|
|
489
|
+
}
|
|
490
|
+
if(isListedA){
|
|
491
|
+
const liqReward1= await VolumeIndex.calculateLiquidityReward(satsReceived,0)
|
|
492
|
+
TallyMap.updateBalance(senderAddress,3,liqReward1,0,0,0,'enhancedLiquidityReward')
|
|
493
|
+
}
|
|
494
|
+
if(isListedB){
|
|
495
|
+
const liqReward2= await VolumeIndex.calculateLiquidityReward(tokenAmount,propertyId)
|
|
496
|
+
TallyMap.updateBalance(receiverAddress,3,liqReward2,0,0,0,'enhancedLiquidityReward')
|
|
497
|
+
|
|
498
|
+
}
|
|
499
|
+
return
|
|
500
|
+
},
|
|
501
|
+
// commitToken: Commits tokens for a specific purpose
|
|
502
|
+
async commitToken(senderAddress, channelAddress, propertyId, tokenAmount, payEnabled, clearLists, block, txid) {
|
|
503
|
+
|
|
504
|
+
// Deduct tokens from sender's available balance
|
|
505
|
+
await TallyMap.updateBalance(senderAddress, propertyId, -tokenAmount, 0, 0, 0,'commit',block);
|
|
506
|
+
|
|
507
|
+
// Add tokens to the channel's balance
|
|
508
|
+
await TallyMap.updateChannelBalance(channelAddress, propertyId, tokenAmount,'channelReceive',block);
|
|
509
|
+
console.log('commiting tokens '+tokenAmount+' '+block+' '+txid)
|
|
510
|
+
// Determine which column (A or B) to assign the tokens in the channel registry
|
|
511
|
+
await Channels.recordCommitToChannel(channelAddress, senderAddress, propertyId, tokenAmount, payEnabled, clearLists, block, txid);
|
|
512
|
+
|
|
513
|
+
console.log(`Committed ${tokenAmount} tokens of propertyId ${propertyId} from ${senderAddress} to channel ${channelAddress}`);
|
|
514
|
+
return;
|
|
515
|
+
},
|
|
516
|
+
|
|
517
|
+
async onChainTokenToToken(fromAddress, offeredPropertyId, desiredPropertyId, amountOffered, amountExpected, txid, blockHeight, stop,post){
|
|
518
|
+
const pairKey = `${offeredPropertyId}-${desiredPropertyId}`;
|
|
519
|
+
|
|
520
|
+
const txInfo = await TxUtils.getRawTransaction(txid);
|
|
521
|
+
const confirmedBlock = await TxUtils.getBlockHeight(txInfo.blockhash);
|
|
522
|
+
|
|
523
|
+
if (stop === true && post === true) {
|
|
524
|
+
post = false;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
const order = {
|
|
528
|
+
offeredPropertyId:offeredPropertyId,
|
|
529
|
+
desiredPropertyId:desiredPropertyId,
|
|
530
|
+
amountOffered:amountOffered,
|
|
531
|
+
amountExpected:amountExpected,
|
|
532
|
+
blockTime: confirmedBlock,
|
|
533
|
+
sender: fromAddress,
|
|
534
|
+
stop: stop,
|
|
535
|
+
post: post
|
|
536
|
+
};
|
|
537
|
+
|
|
538
|
+
console.log('queueing on-chain token order ' + JSON.stringify(order), txid);
|
|
539
|
+
|
|
540
|
+
// Do NOT mutate the book immediately; just enqueue
|
|
541
|
+
await Orderbook.queueOnChainTokenOrder(
|
|
542
|
+
pairKey,
|
|
543
|
+
fromAddress,
|
|
544
|
+
order,
|
|
545
|
+
blockHeight,
|
|
546
|
+
txid
|
|
547
|
+
);
|
|
548
|
+
|
|
549
|
+
return order;
|
|
550
|
+
},
|
|
551
|
+
|
|
552
|
+
async cancelOrder(fromAddress, isContract, offeredPropertyId, desiredPropertyId, cancelAll, cancelParams,block) {
|
|
553
|
+
let cancelledOrders = [];
|
|
554
|
+
let key
|
|
555
|
+
if(isContract==true){
|
|
556
|
+
key = offeredPropertyId
|
|
557
|
+
}else if(isContract==false){
|
|
558
|
+
key = offeredPropertyId+'-'+desiredPropertyId
|
|
559
|
+
}
|
|
560
|
+
let orderbook = new Orderbook(key)
|
|
561
|
+
// Handle contract cancellation if only one property ID is provided
|
|
562
|
+
console.log('in logic function for cancelOrder '+fromAddress + ' '+isContract +' '+offeredPropertyId+' '+desiredPropertyId +' '+cancelAll+ ' '+JSON.stringify(cancelParams))
|
|
563
|
+
if(isContract==true){
|
|
564
|
+
// Contract cancellation logic here
|
|
565
|
+
if(cancelAll){
|
|
566
|
+
cancelledOrders = await orderbook.cancelAllContractOrders(fromAddress,offeredPropertyId,block)
|
|
567
|
+
//console.log('contract cancel all'+JSON.stringify(cancelledOrders))
|
|
568
|
+
}
|
|
569
|
+
if(cancelParams.txid){
|
|
570
|
+
cancelledOrders = await orderbook.cancelContractOrderByTxid(fromAddress,offeredPropertyId,cancelParams.txid,block)
|
|
571
|
+
}
|
|
572
|
+
if(cancelParams.price){
|
|
573
|
+
if(cancelParams.buy){
|
|
574
|
+
cancelledOrders = await orderbook.cancelContractBuyOrdersByPrice(fromAddress,offeredPropertyId,cancelParams.price,cancelParams.buy,block)
|
|
575
|
+
}
|
|
576
|
+
if(cancelParams.sell){
|
|
577
|
+
cancelledOrders = await orderbook.cancelContractSellOrdersByPrice(fromAddress,offeredPropertyId,cancelParams.price,cancelParams.sell,block)
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
await orderbook.saveOrderBook(`${offeredPropertyId}`);
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
if(isContract==false){
|
|
584
|
+
//normalize the order of propertyIds
|
|
585
|
+
|
|
586
|
+
if (cancelAll && offeredPropertyId && desiredPropertyId) {
|
|
587
|
+
console.log('canceling all orders for '+fromAddress + offeredPropertyId+ desiredPropertyId)
|
|
588
|
+
cancelledOrders = await orderbook.cancelAllTokenOrders(fromAddress, offeredPropertyId, desiredPropertyId,block);
|
|
589
|
+
}
|
|
590
|
+
// Cancel a specific order by txid
|
|
591
|
+
if (cancelParams.txid) {
|
|
592
|
+
cancelledOrders = await orderbook.cancelTokenOrdersByTxid(fromAddress,offeredPropertyId,desiredPropertyId, cancelParams.txid,block);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
// Cancel orders by price or order type
|
|
596
|
+
if (cancelParams.price || cancelParams.orderType) {
|
|
597
|
+
if (cancelParams.price) {
|
|
598
|
+
// Cancel sell orders greater than or equal to the price
|
|
599
|
+
cancelledOrders = await orderbook.cancelTokenSellOrdersByPrice(fromAddress, offeredPropertyId, desiredPropertyId, cancelParams.price,block);
|
|
600
|
+
|
|
601
|
+
// Cancel buy orders less than or equal to the price
|
|
602
|
+
cancelledOrders = await orderbook.cancelTokenBuyOrdersByPrice(fromAddress, offeredPropertyId, desiredPropertyId, cancelParams.price,block);
|
|
603
|
+
}
|
|
604
|
+
// Add more conditions based on your cancel params if needed
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
// Save the updated order book to the database
|
|
608
|
+
await orderbook.saveOrderBook(`${offeredPropertyId}-${desiredPropertyId}`);
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
// Log the cancellation for record-keeping
|
|
612
|
+
//console.log(`Cancelled orders: ${JSON.stringify(cancelledOrders)}`);
|
|
613
|
+
|
|
614
|
+
// Return the details of the cancelled orders
|
|
615
|
+
return cancelledOrders;
|
|
616
|
+
},
|
|
617
|
+
/**
|
|
618
|
+
* Creates a new clearlist.
|
|
619
|
+
*
|
|
620
|
+
* @param {Object} params - Parameters for creating the clearlist
|
|
621
|
+
* @param {string} params.adminAddress - The address of the admin for this clearlist
|
|
622
|
+
* @param {string} [params.name] - Optional name for the clearlist
|
|
623
|
+
* @param {Array} [params.criteria] - Optional criteria for inclusion in the clearlist
|
|
624
|
+
* @param {string} [params.backupAddress] - Optional backup address for admin operations
|
|
625
|
+
* @returns {Object} - The result of the clearlist creation
|
|
626
|
+
*/
|
|
627
|
+
async createClearList(adminAddress, name, url, description, backupAddress, block){
|
|
628
|
+
|
|
629
|
+
// Validate input parameters
|
|
630
|
+
if (!adminAddress) {
|
|
631
|
+
return console.log('Admin address is required to create a clearlist');
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// Create the clearlist
|
|
635
|
+
const clearlistData = await ClearList.createclearlist({
|
|
636
|
+
adminAddress,
|
|
637
|
+
name,
|
|
638
|
+
url,
|
|
639
|
+
description,
|
|
640
|
+
backupAddress
|
|
641
|
+
});
|
|
642
|
+
|
|
643
|
+
// Return a message with the new clearlist ID
|
|
644
|
+
return {
|
|
645
|
+
message: `clearlist created successfully with ID: ${clearlistData.id}`
|
|
646
|
+
};
|
|
647
|
+
},
|
|
648
|
+
|
|
649
|
+
async updateAdmin(whitelist,token,oracle, newAddress, id, updateBackup, block) {
|
|
650
|
+
|
|
651
|
+
if(whitelist){
|
|
652
|
+
await ClearList.updateAdmin(id, newAddress,updateBackup);
|
|
653
|
+
}else if(token){
|
|
654
|
+
await PropertyList.updateAdmin(id, newAddress,updateBackup);
|
|
655
|
+
}else if(oracle){
|
|
656
|
+
await OracleList.updateAdmin(entityId, newAddress, updateBackup);
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
console.log(`Admin updated for ${entityType} ${entityId}`);
|
|
660
|
+
return
|
|
661
|
+
},
|
|
662
|
+
|
|
663
|
+
|
|
664
|
+
async issueOrRevokeAttestation(sender, clearlistId, targetAddress, metaData, revoke, block) {
|
|
665
|
+
const admin = activation.getAdmin()
|
|
666
|
+
if(sender==admin&&clearlistId==0){
|
|
667
|
+
console.log('admin updating banlist')
|
|
668
|
+
await updateBannedCountries(metaData,block)
|
|
669
|
+
return
|
|
670
|
+
}
|
|
671
|
+
if(!revoke){
|
|
672
|
+
console.log('params in add attest '+clearlistId,targetAddress,metaData,revoke,block)
|
|
673
|
+
await ClearList.addAttestation(clearlistId, targetAddress,metaData, block);
|
|
674
|
+
console.log(`Address ${targetAddress} added to clearlist ${clearlistId}`);
|
|
675
|
+
}else if(revoke==true){
|
|
676
|
+
await ClearList.revokeAttestation(clearlistId,targetAddress,metaData, block)
|
|
677
|
+
}
|
|
678
|
+
return
|
|
679
|
+
},
|
|
680
|
+
|
|
681
|
+
async updateBannedCountries(bannedCountriesGlobal, block) {
|
|
682
|
+
// Validate input: Must be an array of two-character strings
|
|
683
|
+
if (!Array.isArray(bannedCountriesGlobal) || !bannedCountriesGlobal.every(code => typeof code === 'string' && code.length === 2)) {
|
|
684
|
+
return console.log('Invalid input: bannedCountriesGlobal must be an array of two-character strings.');
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
console.log('Using default global Banlist:', bannedCountriesGlobal);
|
|
688
|
+
await Clearlist.setBanList(bannedCountriesGlobal,block); // Update Clearlist object with default
|
|
689
|
+
},
|
|
690
|
+
|
|
691
|
+
|
|
692
|
+
async AMMPool(sender, block, isRedeem, isContract, id, amount, id2, amount2) {
|
|
693
|
+
let ammInstance;
|
|
694
|
+
|
|
695
|
+
if (isContract) {
|
|
696
|
+
ammInstance = await ContractRegistry.getAMM(id);
|
|
697
|
+
} else {
|
|
698
|
+
ammInstance = await PropertyRegistry.getAMM(id, id2);
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
if (!ammInstance) {
|
|
702
|
+
throw new Error('AMM instance not found');
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
if (isRedeem&&isContract) {
|
|
706
|
+
await ammInstance.redeemCapital(sender, id, amount, isContract, block);
|
|
707
|
+
}else if(isRedeem&&!isContract){
|
|
708
|
+
await ammInstance.redeemCapital(sender, id, amount, isContract, id2, amount2, block)
|
|
709
|
+
}else if(!isRedeem&&isContract){
|
|
710
|
+
await ammInstance.addCapital(sender, id, amount, isContract, block);
|
|
711
|
+
}else if(!isRedeem&&!isContract){
|
|
712
|
+
await ammInstance.addCapital(sender, id, amount,isContract, id2, amount2,block)
|
|
713
|
+
}
|
|
714
|
+
},
|
|
715
|
+
|
|
716
|
+
async grantManagedToken(propertyId, amount, recipientAddress, propertyManager,block) {
|
|
717
|
+
|
|
718
|
+
// Verify if the property is a managed type
|
|
719
|
+
const isManaged = await propertyManager.verifyIfManaged(propertyId);
|
|
720
|
+
if (!isManaged) {
|
|
721
|
+
throw new Error('Property is not a managed type');
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
// Logic to grant tokens to the recipient
|
|
725
|
+
await PropertyManager.grantTokens(propertyId, recipientAddress, amount,block);
|
|
726
|
+
console.log(`Granted ${amount} tokens of property ${propertyId} to ${recipientAddress}`);
|
|
727
|
+
return
|
|
728
|
+
},
|
|
729
|
+
|
|
730
|
+
async redeemManagedToken(propertyId, amount, address,block) {
|
|
731
|
+
|
|
732
|
+
// Verify if the property is a managed type
|
|
733
|
+
const isManaged = await propertyManager.verifyIfManaged(propertyId);
|
|
734
|
+
if (!isManaged) {
|
|
735
|
+
throw new Error('Property is not a managed type');
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
// Logic to redeem tokens from the admin's balance
|
|
739
|
+
await PropertyManager.redeemTokens(address, propertyId, amount,block);
|
|
740
|
+
console.log(`Redeemed ${amount} tokens of property ${propertyId}`);
|
|
741
|
+
return
|
|
742
|
+
},
|
|
743
|
+
|
|
744
|
+
async createOracle(adminAddress, ticker, url, backupAddress, clearlists, lag, oracleRegistry,block) {
|
|
745
|
+
|
|
746
|
+
// Create a new oracle
|
|
747
|
+
const oracleId = await OracleList.createOracle({adminAddress, ticker, url, backupAddress, clearlists, lag});
|
|
748
|
+
console.log(`Oracle created with ID: ${oracleId}`);
|
|
749
|
+
return oracleId;
|
|
750
|
+
},
|
|
751
|
+
|
|
752
|
+
async publishOracleData(oracleId, price, high, low, close, block) {
|
|
753
|
+
console.log('publishing Oracle Data '+oracleId + ' '+ price)
|
|
754
|
+
// Publish data to the oracle
|
|
755
|
+
await OracleList.publishData(oracleId, price, high, low, close, block);
|
|
756
|
+
console.log(`Data published to oracle ${oracleId}`);
|
|
757
|
+
return
|
|
758
|
+
},
|
|
759
|
+
|
|
760
|
+
async closeOracle(oracleId, block) {
|
|
761
|
+
|
|
762
|
+
// Close the specified oracle
|
|
763
|
+
await OracleList.closeOracle(oracleId);
|
|
764
|
+
console.log(`Oracle ${oracleId} has been closed`);
|
|
765
|
+
return
|
|
766
|
+
},
|
|
767
|
+
|
|
768
|
+
async createContractSeries(sender, native, underlyingOracleId, onChainData, notionalPropertyId, notionalValue, collateralPropertyId, leverage, expiryPeriod, series, inverse, fee, block, whitelist) {
|
|
769
|
+
// Create a new future contract series
|
|
770
|
+
|
|
771
|
+
const params = {
|
|
772
|
+
sender: sender,
|
|
773
|
+
native:native,
|
|
774
|
+
underlyingOracleId: underlyingOracleId,
|
|
775
|
+
onChainData: onChainData,
|
|
776
|
+
notionalPropertyId: notionalPropertyId,
|
|
777
|
+
notionalValue: notionalValue,
|
|
778
|
+
collateralPropertyId: collateralPropertyId,
|
|
779
|
+
leverage:leverage,
|
|
780
|
+
expiryPeriod: expiryPeriod,
|
|
781
|
+
series:series,
|
|
782
|
+
inverse: inverse,
|
|
783
|
+
fee: fee,
|
|
784
|
+
block: block,
|
|
785
|
+
whitelist:whitelist
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
const futureContractSeriesId = await ContractRegistry.createContractSeries(
|
|
789
|
+
sender, params, block
|
|
790
|
+
);
|
|
791
|
+
console.log(`Future contract series created with ID: ${futureContractSeriesId}`);
|
|
792
|
+
return futureContractSeriesId;
|
|
793
|
+
},
|
|
794
|
+
|
|
795
|
+
async exerciseDerivative(contractId, amount, contractsRegistry,block) {
|
|
796
|
+
if (!contractId || !amount || !contractsRegistry) {
|
|
797
|
+
throw new Error('Missing required parameters');
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
// Exercise the derivative contract
|
|
801
|
+
await ContractRegistry.exerciseDerivative(contractId, amount);
|
|
802
|
+
console.log(`Derivative contract ${contractId} exercised for amount ${amount}`);
|
|
803
|
+
},
|
|
804
|
+
|
|
805
|
+
async tradeContractOnchain(contractId, price, amount, sell, insurance, blockTime, txid, sender, isLiq, reduce, post, stop) {
|
|
806
|
+
const params = {
|
|
807
|
+
contractId,
|
|
808
|
+
price,
|
|
809
|
+
amount,
|
|
810
|
+
sell,
|
|
811
|
+
insurance,
|
|
812
|
+
blockTime,
|
|
813
|
+
isLiq,
|
|
814
|
+
reduce,
|
|
815
|
+
post,
|
|
816
|
+
stop
|
|
817
|
+
};
|
|
818
|
+
|
|
819
|
+
console.log('queueing on-chain contract order ' + JSON.stringify(params), txid);
|
|
820
|
+
|
|
821
|
+
// Again: no immediate addContractOrder; just enqueue
|
|
822
|
+
await Orderbook.queueOnChainContractOrder(
|
|
823
|
+
contractId,
|
|
824
|
+
sender,
|
|
825
|
+
params,
|
|
826
|
+
blockTime, // if you want strict height, pass blockHeight instead
|
|
827
|
+
txid
|
|
828
|
+
);
|
|
829
|
+
|
|
830
|
+
return;
|
|
831
|
+
},
|
|
832
|
+
|
|
833
|
+
async tradeContractChannel(
|
|
834
|
+
contractId,
|
|
835
|
+
price,
|
|
836
|
+
amount,
|
|
837
|
+
columnAIsSeller,
|
|
838
|
+
expiryBlock,
|
|
839
|
+
insurance,
|
|
840
|
+
channelAddress,
|
|
841
|
+
block,
|
|
842
|
+
txid,
|
|
843
|
+
columnAIsMaker
|
|
844
|
+
) {
|
|
845
|
+
const { commitAddressA, commitAddressB } = await Channels.getCommitAddresses(channelAddress);
|
|
846
|
+
const orderbook = await Orderbook.getOrderbookInstance(contractId);
|
|
847
|
+
|
|
848
|
+
const initMarginPerContract = await ContractRegistry.getInitialMargin(contractId, price);
|
|
849
|
+
const initMarginBN = new BigNumber(initMarginPerContract);
|
|
850
|
+
const amountBN = new BigNumber(amount);
|
|
851
|
+
const marginUsed = amountBN.times(initMarginBN).toNumber();
|
|
852
|
+
let buyerAddress, sellerAddress;
|
|
853
|
+
if (columnAIsSeller) {
|
|
854
|
+
sellerAddress = commitAddressA;
|
|
855
|
+
buyerAddress = commitAddressB;
|
|
856
|
+
} else {
|
|
857
|
+
sellerAddress = commitAddressB;
|
|
858
|
+
buyerAddress = commitAddressA;
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
const isInverse = ContractRegistry.isInverse(contractId);
|
|
862
|
+
|
|
863
|
+
// Figure out maker/taker roles based on columnAIsMaker
|
|
864
|
+
const sellerMaker = columnAIsSeller ? !!columnAIsMaker : !columnAIsMaker;
|
|
865
|
+
const buyerMaker = columnAIsSeller ? !columnAIsMaker : !!columnAIsMaker;
|
|
866
|
+
|
|
867
|
+
console.log('flags in trade logic '+sellerMaker+' '+buyerMaker+' '+columnAIsSeller+' '+columnAIsMaker)
|
|
868
|
+
|
|
869
|
+
const sellOrder = {
|
|
870
|
+
contractId,
|
|
871
|
+
amount,
|
|
872
|
+
price,
|
|
873
|
+
block,
|
|
874
|
+
sellSide: true,
|
|
875
|
+
marginUsed,
|
|
876
|
+
sellerAddress,
|
|
877
|
+
txid,
|
|
878
|
+
maker: sellerMaker // ← attach flag
|
|
879
|
+
};
|
|
880
|
+
|
|
881
|
+
const buyOrder = {
|
|
882
|
+
contractId,
|
|
883
|
+
amount,
|
|
884
|
+
price,
|
|
885
|
+
block,
|
|
886
|
+
buySide: true,
|
|
887
|
+
marginUsed,
|
|
888
|
+
buyerAddress,
|
|
889
|
+
txid,
|
|
890
|
+
maker: buyerMaker // ← attach flag
|
|
891
|
+
};
|
|
892
|
+
|
|
893
|
+
const match = {
|
|
894
|
+
sellOrder,
|
|
895
|
+
buyOrder,
|
|
896
|
+
price,
|
|
897
|
+
channelAddress,
|
|
898
|
+
tradePrice: price,
|
|
899
|
+
txid
|
|
900
|
+
};
|
|
901
|
+
|
|
902
|
+
const matches = [match];
|
|
903
|
+
|
|
904
|
+
// Trade the contract within a channel
|
|
905
|
+
await orderbook.processContractMatches(matches, block, true);
|
|
906
|
+
|
|
907
|
+
console.log(
|
|
908
|
+
`Traded contract ${contractId} in channel with price ${price} and amount ${amount}. SellerMaker=${sellerMaker}, BuyerMaker=${buyerMaker}`
|
|
909
|
+
);
|
|
910
|
+
|
|
911
|
+
return;
|
|
912
|
+
},
|
|
913
|
+
|
|
914
|
+
async tradeTokensChannel(
|
|
915
|
+
offeredPropertyId,
|
|
916
|
+
desiredPropertyId,
|
|
917
|
+
amountOffered,
|
|
918
|
+
amountDesired,
|
|
919
|
+
expiryBlock,
|
|
920
|
+
columnAIsOfferer, // true if Column A is the one offering
|
|
921
|
+
channelAddress,
|
|
922
|
+
block,
|
|
923
|
+
txid,
|
|
924
|
+
columnAIsMaker // new param: true if Column A was the maker
|
|
925
|
+
) {
|
|
926
|
+
const { commitAddressA, commitAddressB } = await Channels.getCommitAddresses(channelAddress);
|
|
927
|
+
console.log('inside tokens channel', commitAddressA, commitAddressB, 'channel addr', channelAddress);
|
|
928
|
+
|
|
929
|
+
const key = `${offeredPropertyId}-${desiredPropertyId}`;
|
|
930
|
+
const orderbook = await Orderbook.getOrderbookInstance(key);
|
|
931
|
+
|
|
932
|
+
let buyerAddress, sellerAddress;
|
|
933
|
+
if (columnAIsOfferer) {
|
|
934
|
+
sellerAddress = commitAddressA;
|
|
935
|
+
buyerAddress = commitAddressB;
|
|
936
|
+
} else {
|
|
937
|
+
sellerAddress = commitAddressB;
|
|
938
|
+
buyerAddress = commitAddressA;
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
// Maker assignment
|
|
942
|
+
const sellerMaker = columnAIsOfferer && columnAIsMaker;
|
|
943
|
+
const buyerMaker = !columnAIsOfferer && columnAIsMaker;
|
|
944
|
+
|
|
945
|
+
const sellOrder = {
|
|
946
|
+
offeredPropertyId,
|
|
947
|
+
desiredPropertyId,
|
|
948
|
+
amountOffered,
|
|
949
|
+
amountExpected: amountDesired,
|
|
950
|
+
blockTime: block,
|
|
951
|
+
sender: sellerAddress,
|
|
952
|
+
maker: sellerMaker // attach maker flag
|
|
953
|
+
};
|
|
954
|
+
|
|
955
|
+
const buyOrder = {
|
|
956
|
+
offeredPropertyId,
|
|
957
|
+
desiredPropertyId,
|
|
958
|
+
amountOffered: amountDesired,
|
|
959
|
+
amountExpected: amountOffered,
|
|
960
|
+
blockTime: block,
|
|
961
|
+
sender: buyerAddress,
|
|
962
|
+
maker: buyerMaker // attach maker flag
|
|
963
|
+
};
|
|
964
|
+
|
|
965
|
+
const amountOfferedBN = new BigNumber(amountOffered);
|
|
966
|
+
const amountDesiredBN = new BigNumber(amountDesired);
|
|
967
|
+
|
|
968
|
+
const tradePrice = amountOfferedBN.dividedBy(amountDesiredBN);
|
|
969
|
+
|
|
970
|
+
const match = {
|
|
971
|
+
sellOrder,
|
|
972
|
+
buyOrder,
|
|
973
|
+
amountOfTokenA: amountOfferedBN.toNumber(),
|
|
974
|
+
amountOfTokenB: amountDesiredBN.toNumber(),
|
|
975
|
+
tradePrice: tradePrice.toNumber(),
|
|
976
|
+
channel: channelAddress,
|
|
977
|
+
buyerTx: txid,
|
|
978
|
+
sellerTx: txid
|
|
979
|
+
};
|
|
980
|
+
|
|
981
|
+
const matches = [match];
|
|
982
|
+
|
|
983
|
+
// Update balances in the channel columns and commitment addresses
|
|
984
|
+
console.log('about to process token match in channel', JSON.stringify(matches), block);
|
|
985
|
+
await orderbook.processTokenMatches(matches, block, txid, true);
|
|
986
|
+
|
|
987
|
+
const ltcValueOfToken = VolumeIndex.getTokenPriceInLTC(desiredPropertyId);
|
|
988
|
+
const ltcValueOfTokens = new BigNumber(ltcValueOfToken)
|
|
989
|
+
.times(amountDesiredBN)
|
|
990
|
+
.decimalPlaces(8)
|
|
991
|
+
.toNumber();
|
|
992
|
+
|
|
993
|
+
await VolumeIndex.saveVolumeDataById(
|
|
994
|
+
key,
|
|
995
|
+
amountOffered,
|
|
996
|
+
ltcValueOfTokens,
|
|
997
|
+
tradePrice,
|
|
998
|
+
block,
|
|
999
|
+
'token'
|
|
1000
|
+
);
|
|
1001
|
+
|
|
1002
|
+
return `Trade executed in channel ${channelAddress}`;
|
|
1003
|
+
},
|
|
1004
|
+
|
|
1005
|
+
|
|
1006
|
+
withdrawal(withdrawAll, channelAddress, propertyId, amount, sender, block, columnIsB) {
|
|
1007
|
+
const channel = Channels.getChannel(channelAddress);
|
|
1008
|
+
// Assuming channel object has a map of property balances
|
|
1009
|
+
Channels.addToWithdrawalQueue(block, sender, amount, channelAddress,propertyId, withdrawAll, columnIsB)
|
|
1010
|
+
return
|
|
1011
|
+
},
|
|
1012
|
+
|
|
1013
|
+
async transfer(fromChannelAddress, toChannelAddress, propertyId, amount, isColumnA, pay, payRefAddress, block,txid) {
|
|
1014
|
+
let fromChannel = await Channels.getChannel(fromChannelAddress);
|
|
1015
|
+
|
|
1016
|
+
console.log(`To channel ${toChannelAddress} not found. Adding to registry.`);
|
|
1017
|
+
await Channels.recordCommitToChannel(toChannelAddress, fromChannelAddress, propertyId, amount, false, '', block,txid);
|
|
1018
|
+
let toChannel = await Channels.getChannel(toChannelAddress);
|
|
1019
|
+
console.log(JSON.stringify(toChannel))
|
|
1020
|
+
// Determine the correct column to deduct from in the fromChannel
|
|
1021
|
+
const fromColumn = isColumnA ? 'A' : 'B';
|
|
1022
|
+
let channelColumn = ' '
|
|
1023
|
+
if(toChannel.participants.A==fromChannel.participants[fromColumn]){
|
|
1024
|
+
channelColumn = 'A'
|
|
1025
|
+
}else if (toChannel.participants.B==fromChannel.participants[fromColumn]){
|
|
1026
|
+
channelColumn = 'B'
|
|
1027
|
+
}
|
|
1028
|
+
// Check if the fromChannel has enough balance
|
|
1029
|
+
|
|
1030
|
+
// Assign columns in the toChannel based on the address
|
|
1031
|
+
//await Channels.assignColumnBasedOnAddress(toChannelAddress, toChannelAddress);
|
|
1032
|
+
|
|
1033
|
+
// Update balances in from channel
|
|
1034
|
+
fromChannel[fromColumn][propertyId] -= amount;
|
|
1035
|
+
// Assign the commit address based on pay status
|
|
1036
|
+
if (pay && payRefAddress) {
|
|
1037
|
+
// If pay is true and payRefAddress is provided, set it as the commit address
|
|
1038
|
+
toChannel.participants[channelColumn] = payRefAddress;
|
|
1039
|
+
console.log(`Setting commit address in toChannel ${channelColumn} as payRefAddress: ${payRefAddress}`);
|
|
1040
|
+
} else {
|
|
1041
|
+
// Otherwise, use the fromChannel's participant address
|
|
1042
|
+
const senderCommitAddress = fromChannel.participants[fromColumn];
|
|
1043
|
+
toChannel.participants[channelColumn] = senderCommitAddress;
|
|
1044
|
+
console.log(`Setting commit address in toChannel ${channelColumn} as fromChannel participant address: ${senderCommitAddress}`);
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
TallyMap.updateChannelBalance(fromChannelAddress, propertyId, -amount,'transferDebit', block)
|
|
1048
|
+
TallyMap.updateChannelBalance(toChannelAddress, propertyId, amount, 'transferCredit', block)
|
|
1049
|
+
|
|
1050
|
+
// Save updated channel states back to the registry
|
|
1051
|
+
Channels.channelsRegistry.set(fromChannelAddress, fromChannel);
|
|
1052
|
+
|
|
1053
|
+
await Channels.saveChannelsRegistry();
|
|
1054
|
+
return
|
|
1055
|
+
},
|
|
1056
|
+
|
|
1057
|
+
async settleChannelPNL(channelAddress, txParams, block,txid) {
|
|
1058
|
+
const {
|
|
1059
|
+
txidNeutralized1,
|
|
1060
|
+
txidNeutralized2,
|
|
1061
|
+
markPrice,
|
|
1062
|
+
close
|
|
1063
|
+
} = txParams;
|
|
1064
|
+
|
|
1065
|
+
if(txidNeutralized2){
|
|
1066
|
+
const settlement = await Scaling.nuetralizeSettlement(channel,txidNeutralized2)
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
const trade = await Scaling.isTradePublished(txidNeutralized1)
|
|
1070
|
+
let offset
|
|
1071
|
+
if(trade.status=="unpublished"){
|
|
1072
|
+
await Scaling.settlementLimbo(txid) //Must check settlement limbo for references in logic of channel trades
|
|
1073
|
+
}else if(trade.status=="expiredContract"){
|
|
1074
|
+
await Logic.typeSwitch(19,trade.params)
|
|
1075
|
+
}else if(trade.status=="expiredToken"){
|
|
1076
|
+
await Logic.typeSwitch(20,trade.params)
|
|
1077
|
+
}else if((trade.status=="liveContract"||trade.status=="expiredContract")&&close==true){
|
|
1078
|
+
offset = Scaling.generateOffset(trade.params,markPrice)
|
|
1079
|
+
await Logic.typeSwitch(19,offset.params)
|
|
1080
|
+
}else if((trade.status=="liveContract"||trade.status=="expiredContract")&&close==true){
|
|
1081
|
+
offset = Scaling.generateOffset(trade.params,markPrice)
|
|
1082
|
+
await Logic.typeSwitch(20,offset.params)
|
|
1083
|
+
}else if(trade.status=="live"&&!close){
|
|
1084
|
+
const last = await Scaling.queryPriorSettlements(txidNuetralized1, txidNeutralized2, channelAddress)
|
|
1085
|
+
const settlement = await Scaling.settlePNL(last,mark,txidNuetralized1)
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
console.log(`PNL settled for channel ${channelAddress}, contract ${contractId}`);
|
|
1089
|
+
return
|
|
1090
|
+
},
|
|
1091
|
+
|
|
1092
|
+
exerciseDerivative(sender, txParams,block) {
|
|
1093
|
+
const { contractId, amount } = txParams;
|
|
1094
|
+
|
|
1095
|
+
// Check if the contractId has more hyphens and contains 'P' or 'C'
|
|
1096
|
+
const hyphenCount = (contractId.match(/-/g) || []).length;
|
|
1097
|
+
const hasPOrC = /[PC]/.test(contractId);
|
|
1098
|
+
const isOption = Boolean(hyphenCount >= 2 && hasPOrC);
|
|
1099
|
+
const marginMap = MarginMap.getInstance(contractId)
|
|
1100
|
+
if(!isOption){
|
|
1101
|
+
this.deliverContract(sender, contractId, amount,block);
|
|
1102
|
+
}else if(isOption){
|
|
1103
|
+
this.handleOptionExercise(sender,contractId, amount,block);
|
|
1104
|
+
}
|
|
1105
|
+
},
|
|
1106
|
+
|
|
1107
|
+
|
|
1108
|
+
deliverContract(contractId, amount,block) {
|
|
1109
|
+
// Logic for contract delivery
|
|
1110
|
+
// This would involve transferring tokens from the contract to the exercising party
|
|
1111
|
+
// Eliminate the contract positions
|
|
1112
|
+
|
|
1113
|
+
// Retrieve contract details and involved parties' balances
|
|
1114
|
+
// Assume existence of functions getContractDetails and getAddressBalance
|
|
1115
|
+
const contractDetails = ContractRegistry.getContractDetails(contractId);
|
|
1116
|
+
const senderBalance = this.getAddressBalance(contractDetails.senderAddress, propertyId);
|
|
1117
|
+
const receiverBalance = this.getAddressBalance(contractDetails.receiverAddress, propertyId);
|
|
1118
|
+
|
|
1119
|
+
// Transfer tokens based on contract terms
|
|
1120
|
+
if (senderBalance >= amount) {
|
|
1121
|
+
this.updateBalance(contractDetails.senderAddress, propertyId, -amount, 0 ,0,0,'deliver');
|
|
1122
|
+
this.updateBalance(contractDetails.receiverAddress, propertyId, amount,0,0,0,'receiveExercise');
|
|
1123
|
+
} else {
|
|
1124
|
+
throw new Error('Insufficient balance for contract delivery');
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
// Eliminate the contract
|
|
1128
|
+
this.removeContract(contractId);
|
|
1129
|
+
},
|
|
1130
|
+
|
|
1131
|
+
handleOptionExercise(contractId, propertyId1, propertyId2, numberOfContracts, block) {
|
|
1132
|
+
// Logic for handling option exercise
|
|
1133
|
+
// Notional value of the contract is based on the strike price
|
|
1134
|
+
// Eliminate the contract positions
|
|
1135
|
+
|
|
1136
|
+
// Retrieve contract details
|
|
1137
|
+
const contractDetails = this.getContractDetails(contractId);
|
|
1138
|
+
const strikePrice = contractDetails.strikePrice; // The strike price of the option
|
|
1139
|
+
|
|
1140
|
+
// Calculate the notional value based on the strike price
|
|
1141
|
+
const notionalValue = numberOfContracts * strikePrice;
|
|
1142
|
+
|
|
1143
|
+
// Retrieve balances of involved parties
|
|
1144
|
+
const balanceProperty1 = this.getAddressBalance(contractDetails.holderAddress, propertyId1);
|
|
1145
|
+
const balanceProperty2 = this.getAddressBalance(contractDetails.writerAddress, propertyId2);
|
|
1146
|
+
|
|
1147
|
+
// Execute the exchange if balances are sufficient
|
|
1148
|
+
if (balanceProperty1 >= notionalValue && balanceProperty2 >= numberOfContracts) {
|
|
1149
|
+
// Holder of the option (buyer) exercises the option
|
|
1150
|
+
this.updateBalance(contractDetails.holderAddress, propertyId1, -notionalValue);
|
|
1151
|
+
this.updateBalance(contractDetails.holderAddress, propertyId2, numberOfContracts);
|
|
1152
|
+
|
|
1153
|
+
// Writer of the option (seller) fulfills the option
|
|
1154
|
+
this.updateBalance(contractDetails.writerAddress, propertyId1, notionalValue);
|
|
1155
|
+
this.updateBalance(contractDetails.writerAddress, propertyId2, -numberOfContracts);
|
|
1156
|
+
} else {
|
|
1157
|
+
throw new Error('Insufficient balance for option exercise');
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
// Eliminate the contract
|
|
1161
|
+
this.removeContract(contractId);
|
|
1162
|
+
},
|
|
1163
|
+
|
|
1164
|
+
|
|
1165
|
+
// Mint Synthetic execution
|
|
1166
|
+
async mintSynthetic(address, propertyId, contractId, amount, block, grossRequired, contracts, margin) {
|
|
1167
|
+
const syntheticTokenId = `s-${propertyId}-${contractId}`;
|
|
1168
|
+
const propertyManager = PropertyManager.getInstance();
|
|
1169
|
+
|
|
1170
|
+
// Clamp values symmetrically
|
|
1171
|
+
amount = BigNumber(Math.abs(amount)).decimalPlaces(8, BigNumber.ROUND_DOWN).toNumber(); // minted synth
|
|
1172
|
+
margin = BigNumber(Math.abs(margin)).decimalPlaces(8, BigNumber.ROUND_DOWN).toNumber(); // credited margin
|
|
1173
|
+
|
|
1174
|
+
const marginMap = await MarginMap.getInstance(contractId);
|
|
1175
|
+
let propertyInfo = await PropertyManager.getPropertyData(propertyId);
|
|
1176
|
+
let ticker = propertyInfo.ticker;
|
|
1177
|
+
let synthTicker = 's' + ticker + '-' + contractId;
|
|
1178
|
+
const contractInfo = await ContractRegistry.getContractInfo(contractId);
|
|
1179
|
+
|
|
1180
|
+
await propertyManager.addProperty(
|
|
1181
|
+
syntheticTokenId,
|
|
1182
|
+
synthTicker,
|
|
1183
|
+
amount,
|
|
1184
|
+
'Synthetic',
|
|
1185
|
+
contractInfo.whitelist,
|
|
1186
|
+
syntheticTokenId,
|
|
1187
|
+
null
|
|
1188
|
+
);
|
|
1189
|
+
|
|
1190
|
+
let contractsAndMargin = await marginMap.moveMarginAndContractsForMint(
|
|
1191
|
+
address,
|
|
1192
|
+
propertyId,
|
|
1193
|
+
contractId,
|
|
1194
|
+
contracts,
|
|
1195
|
+
margin,
|
|
1196
|
+
block
|
|
1197
|
+
);
|
|
1198
|
+
|
|
1199
|
+
grossRequired = BigNumber(grossRequired)
|
|
1200
|
+
.plus(contractsAndMargin.excess)
|
|
1201
|
+
.decimalPlaces(8, BigNumber.ROUND_UP) // debit side
|
|
1202
|
+
.toNumber();
|
|
1203
|
+
|
|
1204
|
+
await TallyMap.updateBalance(
|
|
1205
|
+
address,
|
|
1206
|
+
syntheticTokenId,
|
|
1207
|
+
BigNumber(amount).decimalPlaces(8, BigNumber.ROUND_DOWN).toNumber(), // credit side
|
|
1208
|
+
0,0,0,'issueSynth',block
|
|
1209
|
+
);
|
|
1210
|
+
|
|
1211
|
+
await TallyMap.updateBalance(
|
|
1212
|
+
address,
|
|
1213
|
+
propertyId,
|
|
1214
|
+
BigNumber(-grossRequired).decimalPlaces(8, BigNumber.ROUND_UP).toNumber(), // debit side
|
|
1215
|
+
0,
|
|
1216
|
+
BigNumber(-contractsAndMargin.margin).decimalPlaces(8, BigNumber.ROUND_UP).toNumber(), // debit side
|
|
1217
|
+
0,
|
|
1218
|
+
'issueSynth',block
|
|
1219
|
+
);
|
|
1220
|
+
|
|
1221
|
+
let exists = await SynthRegistry.exists(syntheticTokenId);
|
|
1222
|
+
|
|
1223
|
+
if (!exists) {
|
|
1224
|
+
console.log('creating new synth ' + syntheticTokenId);
|
|
1225
|
+
await SynthRegistry.createVault(propertyId, contractId);
|
|
1226
|
+
await SynthRegistry.registerSyntheticToken(syntheticTokenId, contractId, propertyId);
|
|
1227
|
+
console.log('about to update new vault ' + syntheticTokenId + ' ' + contractsAndMargin + ' ' + amount);
|
|
1228
|
+
await SynthRegistry.updateVault(syntheticTokenId, contractsAndMargin, amount, grossRequired);
|
|
1229
|
+
} else {
|
|
1230
|
+
console.log('about to update existing vault ' + syntheticTokenId + ' ' + contractsAndMargin + ' ' + amount);
|
|
1231
|
+
await SynthRegistry.updateVault(syntheticTokenId, contractsAndMargin, amount, grossRequired);
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
console.log(`Minted ${amount} of synthetic token ${syntheticTokenId}`);
|
|
1235
|
+
return;
|
|
1236
|
+
},
|
|
1237
|
+
|
|
1238
|
+
async redeemSynthetic(address, propertyId, contractId, amount,block) {
|
|
1239
|
+
|
|
1240
|
+
// Split the string by hyphens
|
|
1241
|
+
const parts = propertyId.split('-');
|
|
1242
|
+
|
|
1243
|
+
// The middle part (index 1) is the collateral property
|
|
1244
|
+
const collateralProperty = parseInt(parts[1], 10);
|
|
1245
|
+
|
|
1246
|
+
// Redeem the synthetic token
|
|
1247
|
+
const vault = await SynthRegistry.getVault(propertyId);
|
|
1248
|
+
console.log('inside redeem synthetic logic '+vault.outstanding+' '+JSON.stringify(vault))
|
|
1249
|
+
if (!vault) {
|
|
1250
|
+
console.log('no vault found')
|
|
1251
|
+
return Error('Synthetic token vault not found');
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
if (vault.outstanding < amount) {
|
|
1255
|
+
console.log('vault shortfall')
|
|
1256
|
+
throw new Error('Insufficient synthetic token balance for redemption');
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
const marginMap = await MarginMap.getInstance(contractId)
|
|
1260
|
+
const contractInfo = await ContractRegistry.getContractInfo(contractId)
|
|
1261
|
+
let mark = 0
|
|
1262
|
+
if(contractInfo.native){
|
|
1263
|
+
let pair = contractInfo.onChainData[0][0]+"-"+contractInfo.onChainData[0][1]
|
|
1264
|
+
mark = await VolumeIndex.getLastPrice(pair,block)
|
|
1265
|
+
}else{
|
|
1266
|
+
mark = OracleList.getOraclePrice(contractInfo.underlyingOracleId)
|
|
1267
|
+
}
|
|
1268
|
+
const initMarginPerContract= await ContractRegistry.getInitialMargin(contractId, mark)
|
|
1269
|
+
|
|
1270
|
+
const notionalValue = contractInfo.notionalValue
|
|
1271
|
+
let contractsAndMargin = await marginMap.moveMarginAndContractsForRedeem(address, propertyId, contractId, amount,vault,notionalValue,initMarginPerContract,mark)
|
|
1272
|
+
|
|
1273
|
+
// Update synthetic token property
|
|
1274
|
+
await PropertyManager.updateTotalInCirculation(propertyId, -amount);
|
|
1275
|
+
await TallyMap.updateBalance(address, propertyId,-amount,0,0,0,'redeemSynth',block)
|
|
1276
|
+
await TallyMap.updateBalance(address, collateralProperty,contractsAndMargin.available,0,contractsAndMargin.margin,0,'redeemSynth',block)
|
|
1277
|
+
|
|
1278
|
+
if(contractsAndMargin.rPNL!=0){
|
|
1279
|
+
await TallyMap.updateBalance(address, collateralProperty, contractsAndMargin.rPNL, 0, 0, 0, 'closingLongsWithRedemption',block)
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
if(contractsAndMargin.reduction!=0){
|
|
1283
|
+
await TallyMap.updateBalance(address, collateralProperty, contractsAndMargin.reduction, 0, -contractsAndMargin.reduction, 0, 'contractRedeemMarginReturn',block)
|
|
1284
|
+
}
|
|
1285
|
+
console.log('contracts and Margin before update Vault '+JSON.stringify(contractsAndMargin))
|
|
1286
|
+
await SynthRegistry.updateVaultRedeem(propertyId, contractsAndMargin,-amount);
|
|
1287
|
+
|
|
1288
|
+
|
|
1289
|
+
// Log the redemption of the synthetic token
|
|
1290
|
+
console.log(`Redeemed ${amount} of synthetic token ${propertyId}`);
|
|
1291
|
+
return
|
|
1292
|
+
},
|
|
1293
|
+
|
|
1294
|
+
// payToTokens: Distributes propertyIdUsed tokens to holders of propertyIdTarget tokens
|
|
1295
|
+
async payToTokens(propertyIdTarget, propertyIdUsed, amount,address,block) {
|
|
1296
|
+
// Check if enough tokens of propertyIdUsed are available for distribution
|
|
1297
|
+
const totalAvailable = tallyMap.totalTokens(propertyIdUsed);
|
|
1298
|
+
if (totalAvailable < amount) {
|
|
1299
|
+
throw new Error('Insufficient tokens for distribution');
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
// Calculate total holdings of propertyIdTarget
|
|
1303
|
+
const totalHoldingTarget = tallyMap.totalTokens(propertyIdTarget);
|
|
1304
|
+
if (totalHoldingTarget <= 0) {
|
|
1305
|
+
throw new Error('No holders for target token');
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
// Calculate and distribute tokens to each holder
|
|
1309
|
+
let remainingAmount = new BigNumber(amount);
|
|
1310
|
+
for (const [address, balances] of tallyMap.addresses.entries()) {
|
|
1311
|
+
const targetBalance = balances[propertyIdTarget];
|
|
1312
|
+
if (targetBalance && targetBalance.available > 0) {
|
|
1313
|
+
// Calculate the holder's share
|
|
1314
|
+
const share = new BigNumber(targetBalance.available).dividedBy(totalHoldingTarget);
|
|
1315
|
+
const payout = share.multipliedBy(amount);
|
|
1316
|
+
|
|
1317
|
+
// Distribute if the payout is significant (>= 0.00000001)
|
|
1318
|
+
if (payout.isGreaterThanOrEqualTo(new BigNumber('0.00000001'))) {
|
|
1319
|
+
// Update balances
|
|
1320
|
+
TallyMap.updateBalance(address, propertyIdUsed, -payout.toNumber(),0,0,0, 'payToTokens',block);
|
|
1321
|
+
remainingAmount = remainingAmount.minus(payout);
|
|
1322
|
+
|
|
1323
|
+
console.log(`Distributed ${payout.toFixed()} of token ${propertyIdUsed} to holder ${address}`);
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
// Handle any remaining amount, possibly due to rounding
|
|
1329
|
+
if (!remainingAmount.isZero()) {
|
|
1330
|
+
// Choose a strategy to distribute the remaining amount
|
|
1331
|
+
// For example, add to a general pool, burn it, or send to a specific address
|
|
1332
|
+
// Example: send to a designated address
|
|
1333
|
+
const designatedAddress = 'some_designated_address';
|
|
1334
|
+
TallyMap.updateBalance(address, propertyIdUsed, remainingAmount.toNumber(),0,0,0,'payToTokensRounding',block);
|
|
1335
|
+
console.log(`Remaining ${remainingAmount.toFixed()} of token ${propertyIdUsed} sent to ${designatedAddress}`);
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
// Save the updated state of the TallyMap
|
|
1339
|
+
await tallyMap.save(currentBlockHeight); // Replace currentBlockHeight with actual block height
|
|
1340
|
+
},
|
|
1341
|
+
|
|
1342
|
+
// inside logic.j
|
|
1343
|
+
|
|
1344
|
+
async processOptionTrade(sender, params, txid){
|
|
1345
|
+
// Validate first (also populates creditMargin, reduce/flip flags, rPNL, closed sizes)
|
|
1346
|
+
const res = await Validity.validateOptionTrade(sender, params, txid);
|
|
1347
|
+
if (!res.valid) return res;
|
|
1348
|
+
|
|
1349
|
+
const tMeta = OptionsEngine.parseTicker(params.contractId);
|
|
1350
|
+
const seriesInfo = await ContractRegistry.getContractInfo(tMeta.seriesId);
|
|
1351
|
+
const collateralPropertyId = seriesInfo.collateralPropertyId;
|
|
1352
|
+
|
|
1353
|
+
// Resolve commits
|
|
1354
|
+
const { commitAddressA, commitAddressB } = await Channels.getCommitAddresses(sender);
|
|
1355
|
+
const AIsSeller = (params.columnAIsSeller===true || params.columnAIsSeller===1 || params.columnAIsSeller==="1");
|
|
1356
|
+
const sellerAddr = AIsSeller ? commitAddressA : commitAddressB;
|
|
1357
|
+
const buyerAddr = AIsSeller ? commitAddressB : commitAddressA;
|
|
1358
|
+
|
|
1359
|
+
// 1) Premium transfer (buyer -> seller), if present
|
|
1360
|
+
if (Number(params.netPremium||0) !== 0) {
|
|
1361
|
+
const np = Number(params.netPremium);
|
|
1362
|
+
// buyer pays (available -)
|
|
1363
|
+
await TallyMap.updateBalance(
|
|
1364
|
+
buyerAddr, collateralPropertyId,
|
|
1365
|
+
-np, 0, 0, 0,
|
|
1366
|
+
'optionPremiumPay', params.blockHeight, txid
|
|
1367
|
+
);
|
|
1368
|
+
// seller receives (available +)
|
|
1369
|
+
await TallyMap.updateBalance(
|
|
1370
|
+
sellerAddr, collateralPropertyId,
|
|
1371
|
+
+np, 0, 0, 0,
|
|
1372
|
+
'optionPremiumReceive', params.blockHeight, txid
|
|
1373
|
+
);
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
// 2) Margin moves on seller
|
|
1377
|
+
// - If reducing: free margin and realize PnL into available
|
|
1378
|
+
// - Else opening/adding: lock margin (available -> margin)
|
|
1379
|
+
const credit = Number(params.creditMargin || 0);
|
|
1380
|
+
|
|
1381
|
+
if (params.sellerReducing) {
|
|
1382
|
+
const r = Number(params.rpnlSeller || 0);
|
|
1383
|
+
await TallyMap.updateBalance(
|
|
1384
|
+
sellerAddr, collateralPropertyId,
|
|
1385
|
+
r, // availableChange (realized PnL)
|
|
1386
|
+
0,
|
|
1387
|
+
-credit, // marginChange (unlock)
|
|
1388
|
+
0,
|
|
1389
|
+
'optionReduceSeller', params.blockHeight, txid
|
|
1390
|
+
);
|
|
1391
|
+
} else if (credit > 0) {
|
|
1392
|
+
await TallyMap.updateBalance(
|
|
1393
|
+
sellerAddr, collateralPropertyId,
|
|
1394
|
+
-credit, 0, +credit, 0,
|
|
1395
|
+
'optionMarginLock', params.blockHeight, txid
|
|
1396
|
+
);
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
// 3) Buyer reduce (rare but allowed if they were short and are buying to cover)
|
|
1400
|
+
if (params.buyerReducing) {
|
|
1401
|
+
const r = Number(params.rpnlBuyer || 0);
|
|
1402
|
+
// buyer realized PnL goes to available; if they had margin locked (short), also unlock proportional credit
|
|
1403
|
+
await TallyMap.updateBalance(
|
|
1404
|
+
buyerAddr, collateralPropertyId,
|
|
1405
|
+
r, 0, 0, 0, // we’re not adjusting buyer margin here (credit is seller’s requirement)
|
|
1406
|
+
'optionReduceBuyer', params.blockHeight, txid
|
|
1407
|
+
);
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1410
|
+
// 4) Record positions into margin map (hybrid, nested by ticker)
|
|
1411
|
+
const mm = await MarginMap.getInstance(tMeta.seriesId);
|
|
1412
|
+
await mm.applyOptionTrade(
|
|
1413
|
+
sellerAddr, // we write positions for both sides below
|
|
1414
|
+
params.contractId,
|
|
1415
|
+
-Math.abs(params.amount || 0), // seller delta negative (short if SELL)
|
|
1416
|
+
params.price,
|
|
1417
|
+
params.blockHeight,
|
|
1418
|
+
credit
|
|
1419
|
+
);
|
|
1420
|
+
await mm.applyOptionTrade(
|
|
1421
|
+
buyerAddr,
|
|
1422
|
+
params.contractId,
|
|
1423
|
+
+Math.abs(params.amount || 0), // buyer delta positive
|
|
1424
|
+
params.price,
|
|
1425
|
+
params.blockHeight,
|
|
1426
|
+
0 // buyer doesn’t post credit margin in our model
|
|
1427
|
+
);
|
|
1428
|
+
|
|
1429
|
+
// 5) Combo leg: if it’s an option, do same; if it’s a perp/future, route to contract trade
|
|
1430
|
+
if (params.comboTicker && params.comboAmount) {
|
|
1431
|
+
const cMeta = OptionsEngine.parseTicker(params.comboTicker);
|
|
1432
|
+
if (cMeta && cMeta.type) {
|
|
1433
|
+
// Option combo leg: mirror deltas (typically opposite side)
|
|
1434
|
+
await mm.applyOptionTrade(
|
|
1435
|
+
sellerAddr,
|
|
1436
|
+
params.comboTicker,
|
|
1437
|
+
-(Math.abs(params.comboAmount||0)), // seller side consistent
|
|
1438
|
+
params.comboPrice || 0,
|
|
1439
|
+
params.blockHeight,
|
|
1440
|
+
0 // margin included in credit for the package already
|
|
1441
|
+
);
|
|
1442
|
+
await mm.applyOptionTrade(
|
|
1443
|
+
buyerAddr,
|
|
1444
|
+
params.comboTicker,
|
|
1445
|
+
+(Math.abs(params.comboAmount||0)),
|
|
1446
|
+
params.comboPrice || 0,
|
|
1447
|
+
params.blockHeight,
|
|
1448
|
+
0
|
|
1449
|
+
);
|
|
1450
|
+
} else {
|
|
1451
|
+
// Perp/future combo leg → use existing contract trade pathway
|
|
1452
|
+
await tradeContractChannel(sender, {
|
|
1453
|
+
contractId: params.comboTicker,
|
|
1454
|
+
amount: params.comboAmount,
|
|
1455
|
+
price: params.comboPrice || 0,
|
|
1456
|
+
columnAIsSeller: params.columnAIsSeller,
|
|
1457
|
+
expiryBlock: params.expiryBlock,
|
|
1458
|
+
isMaker: params.isMaker,
|
|
1459
|
+
blockHeight: params.blockHeight
|
|
1460
|
+
}, txid);
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1464
|
+
// 6) (Optional) Persist trade history w/ rPNL fields for auditing
|
|
1465
|
+
if (typeof TradeHistory?.recordTrade === 'function') {
|
|
1466
|
+
await TradeHistory.recordTrade(
|
|
1467
|
+
sellerAddr, params.contractId,
|
|
1468
|
+
-Math.abs(params.amount||0), params.price,
|
|
1469
|
+
Number(params.rpnlSeller||0),
|
|
1470
|
+
params.blockHeight, txid
|
|
1471
|
+
);
|
|
1472
|
+
await TradeHistory.recordTrade(
|
|
1473
|
+
buyerAddr, params.contractId,
|
|
1474
|
+
+Math.abs(params.amount||0), params.price,
|
|
1475
|
+
Number(params.rpnlBuyer||0),
|
|
1476
|
+
params.blockHeight, txid
|
|
1477
|
+
);
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
return res;
|
|
1481
|
+
},
|
|
1482
|
+
|
|
1483
|
+
async tradeBaiUrbun(tallyMap, marginMap, channelRegistry, channelAddress, propertyIdDownPayment, propertyIdToBeSold, downPaymentPercentage, price, amount, expiryBlock, tradeExpiryBlock) {
|
|
1484
|
+
// Validate inputs and check balances
|
|
1485
|
+
if (!channelRegistry.hasChannel(channelAddress)) {
|
|
1486
|
+
throw new Error('Invalid channel address');
|
|
1487
|
+
}
|
|
1488
|
+
|
|
1489
|
+
const channel = channelRegistry.getChannel(channelAddress);
|
|
1490
|
+
const { committerA, committerB } = channel; // Assuming the channel has committerA and committerB
|
|
1491
|
+
|
|
1492
|
+
// Calculate down payment amount
|
|
1493
|
+
const downPaymentAmount = (downPaymentPercentage / 10000) * amount; // Convert basis points to actual amount
|
|
1494
|
+
|
|
1495
|
+
// Check if committers have enough balance for the trade
|
|
1496
|
+
if (!tallyMap.hasSufficientBalance(committerA, propertyIdToBeSold, amount)) {
|
|
1497
|
+
throw new Error('Seller (Committer A) has insufficient token balance for the property to be sold');
|
|
1498
|
+
}
|
|
1499
|
+
if (!tallyMap.hasSufficientBalance(committerB, propertyIdDownPayment, downPaymentAmount)) {
|
|
1500
|
+
throw new Error('Buyer (Committer B) has insufficient token balance for down payment');
|
|
1501
|
+
}
|
|
1502
|
+
|
|
1503
|
+
const baiUrbunContract = {
|
|
1504
|
+
type: 'BaiUrbun',
|
|
1505
|
+
propertyIdDownPayment,
|
|
1506
|
+
propertyIdToBeSold,
|
|
1507
|
+
downPaymentPercent,
|
|
1508
|
+
downPaymentAmount,
|
|
1509
|
+
totalAmount: amount,
|
|
1510
|
+
expiryBlock,
|
|
1511
|
+
tradeExpiryBlock,
|
|
1512
|
+
contractId: `B-${propertyIdToBeSold}-${propertyIdDownPayment}-${expiryBlock}`
|
|
1513
|
+
};
|
|
1514
|
+
|
|
1515
|
+
// Add the contract to the Bai Urbun registry
|
|
1516
|
+
await contractsRegistry.baiUrbun.addContract(baiUrbunContract);
|
|
1517
|
+
|
|
1518
|
+
// Generate contract ID for Bai Urbun
|
|
1519
|
+
const contractId = `B-${propertyIdToBeSold}-${propertyIdDownPayment}-${expiryBlock}`;
|
|
1520
|
+
|
|
1521
|
+
// Reserve the property and down payment in the tallyMap
|
|
1522
|
+
tallyMap.updateBalance(committerA, propertyIdToBeSold, -amount, 'available');
|
|
1523
|
+
tallyMap.updateBalance(committerA, propertyIdToBeSold, amount, 'reserved');
|
|
1524
|
+
tallyMap.updateBalance(committerB, propertyIdDownPayment, -downPaymentAmount, 'available');
|
|
1525
|
+
tallyMap.updateBalance(committerB, propertyIdDownPayment, downPaymentAmount, 'reserved');
|
|
1526
|
+
|
|
1527
|
+
// Update marginMap for Bai Urbun contract
|
|
1528
|
+
marginMap.updateContractBalance(committerA, contractId, amount, 'positive');
|
|
1529
|
+
marginMap.updateContractBalance(committerB, contractId, amount, 'negative');
|
|
1530
|
+
|
|
1531
|
+
console.log(`Created Bai Urbun contract with ID ${contractId} in channel ${channelAddress}`);
|
|
1532
|
+
|
|
1533
|
+
// Record the contract creation in the BaiUrbun registry
|
|
1534
|
+
// Additional logic to add the contract to the BaiUrbun registry
|
|
1535
|
+
// ...
|
|
1536
|
+
|
|
1537
|
+
return contractId;
|
|
1538
|
+
},
|
|
1539
|
+
|
|
1540
|
+
|
|
1541
|
+
tradeMurabaha(channelAddress, buyerAddress, sellerAddress, propertyId, costPrice, profitMargin, paymentBlockHeight) {
|
|
1542
|
+
// Check if the channel exists
|
|
1543
|
+
const channel = this.channelsRegistry.get(channelAddress);
|
|
1544
|
+
if (!channel) {
|
|
1545
|
+
throw new Error('Channel not found');
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1548
|
+
// Validate addresses and amounts
|
|
1549
|
+
TxUtils.validateAddresses(buyerAddress, sellerAddress);
|
|
1550
|
+
TxUtils.validateAmounts(costPrice, profitMargin);
|
|
1551
|
+
// Example: Update margin at the time of agreement
|
|
1552
|
+
marginMap.updateMargin(buyerAddress, propertyId, -(costPrice + profitMargin)); // Buyer's margin decreases by total payment amount
|
|
1553
|
+
marginMap.updateMargin(sellerAddress, propertyId, costPrice); // Seller's margin increases by the cost price
|
|
1554
|
+
|
|
1555
|
+
|
|
1556
|
+
// Logic for Murabaha contract
|
|
1557
|
+
// Record the cost and profit margin
|
|
1558
|
+
channel.contracts.push({
|
|
1559
|
+
type: 'Murabaha',
|
|
1560
|
+
buyerAddress,
|
|
1561
|
+
sellerAddress,
|
|
1562
|
+
propertyId,
|
|
1563
|
+
costPrice,
|
|
1564
|
+
profitMargin,
|
|
1565
|
+
paymentBlockHeight
|
|
1566
|
+
});
|
|
1567
|
+
|
|
1568
|
+
console.log(`Murabaha contract created in channel ${channelAddress}`);
|
|
1569
|
+
},
|
|
1570
|
+
|
|
1571
|
+
issueInvoice(propertyManager, invoiceRegistry, propertyIdToReceivePayment, amount, dueDateBlock, propertyIdCollateral = null, receivesPayToToken = false, issuerNonce) {
|
|
1572
|
+
// Validate input parameters
|
|
1573
|
+
if (!propertyManager.isPropertyIdValid(propertyIdToReceivePayment)) {
|
|
1574
|
+
throw new Error('Invalid property ID to receive payment');
|
|
1575
|
+
}
|
|
1576
|
+
if (propertyIdCollateral && !propertyManager.isPropertyIdValid(propertyIdCollateral)) {
|
|
1577
|
+
throw new Error('Invalid property ID for collateral');
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1580
|
+
// Generate an invoice ID
|
|
1581
|
+
const invoiceId = `${propertyIdToReceivePayment}-${dueDateBlock}-${issuerNonce}`;
|
|
1582
|
+
|
|
1583
|
+
// Create the invoice object
|
|
1584
|
+
const invoice = {
|
|
1585
|
+
invoiceId,
|
|
1586
|
+
propertyIdToReceivePayment,
|
|
1587
|
+
amount,
|
|
1588
|
+
dueDateBlock,
|
|
1589
|
+
collateral: propertyIdCollateral ? {
|
|
1590
|
+
propertyId: propertyIdCollateral,
|
|
1591
|
+
locked: receivesPayToToken,
|
|
1592
|
+
} : null,
|
|
1593
|
+
};
|
|
1594
|
+
|
|
1595
|
+
// Register the invoice in the invoice registry
|
|
1596
|
+
invoiceRegistry.registerInvoice(invoice);
|
|
1597
|
+
|
|
1598
|
+
console.log(`Invoice issued with ID: ${invoiceId}`);
|
|
1599
|
+
|
|
1600
|
+
// Optionally, if collateral is involved and receives payToToken, lock the collateral
|
|
1601
|
+
if (invoice.collateral && receivesPayToToken) {
|
|
1602
|
+
// Logic to lock collateral in association with this invoice
|
|
1603
|
+
// This might involve updating a collateral registry or similar system
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
// Return the invoice ID for reference
|
|
1607
|
+
return invoiceId;
|
|
1608
|
+
},
|
|
1609
|
+
|
|
1610
|
+
batchMoveZkRollup(zkVerifier, rollupData, zkProof) {
|
|
1611
|
+
// Parse the Zero-Knowledge rollup data
|
|
1612
|
+
let transactions;
|
|
1613
|
+
try {
|
|
1614
|
+
transactions = JSON.parse(rollupData); // Assuming rollupData is a JSON string
|
|
1615
|
+
} catch (error) {
|
|
1616
|
+
throw new Error('Invalid rollup data format');
|
|
1617
|
+
}
|
|
1618
|
+
|
|
1619
|
+
// Validate the structure of the parsed data
|
|
1620
|
+
if (!isValidRollupDataStructure(transactions)) {
|
|
1621
|
+
throw new Error('Invalid rollup data structure');
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1624
|
+
// Verify the Zero-Knowledge proof
|
|
1625
|
+
if (!zkVerifier.verify(zkProof, transactions)) {
|
|
1626
|
+
throw new Error('Invalid Zero-Knowledge proof');
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1629
|
+
// Process each transaction in the batch
|
|
1630
|
+
transactions.forEach(transaction => {
|
|
1631
|
+
const { fromAddress, toAddress, propertyId, amount } = transaction;
|
|
1632
|
+
|
|
1633
|
+
// Perform necessary checks and balances updates for each transaction
|
|
1634
|
+
// For example, debiting from one address and crediting to another
|
|
1635
|
+
// This will involve interaction with a ledger or database
|
|
1636
|
+
});
|
|
1637
|
+
|
|
1638
|
+
console.log('Batched transactions processed successfully');
|
|
1639
|
+
|
|
1640
|
+
// Placeholder for additional proof logics to be parsed later
|
|
1641
|
+
// Implement as per the specific requirements of the rollup data and proofs
|
|
1642
|
+
|
|
1643
|
+
// Return success or a summary of the processed transactions
|
|
1644
|
+
return { status: 'success', transactionsProcessed: transactions.length };
|
|
1645
|
+
},
|
|
1646
|
+
|
|
1647
|
+
// Helper function to validate the structure of the rollup data
|
|
1648
|
+
isValidRollupDataStructure(transactions) {
|
|
1649
|
+
// Implement validation logic based on expected format
|
|
1650
|
+
// For example, checking for required fields in each transaction object
|
|
1651
|
+
return transactions.every(transaction =>
|
|
1652
|
+
transaction.hasOwnProperty('fromAddress') &&
|
|
1653
|
+
transaction.hasOwnProperty('toAddress') &&
|
|
1654
|
+
transaction.hasOwnProperty('propertyId') &&
|
|
1655
|
+
transaction.hasOwnProperty('amount')
|
|
1656
|
+
);
|
|
1657
|
+
},
|
|
1658
|
+
|
|
1659
|
+
batchSettlement(sender, params, txid, block){
|
|
1660
|
+
|
|
1661
|
+
},
|
|
1662
|
+
|
|
1663
|
+
publishNewTx(ordinalRevealJSON, jsCode) {
|
|
1664
|
+
// Validate the input JSON and JavaScript code
|
|
1665
|
+
if (!isValidJSON(ordinalRevealJSON)) {
|
|
1666
|
+
throw new Error('Invalid Ordinal Reveal JSON');
|
|
1667
|
+
}
|
|
1668
|
+
if (!isValidJavaScript(jsCode)) {
|
|
1669
|
+
throw new Error('Invalid JavaScript code');
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1672
|
+
// Minify the JavaScript code (assuming a minification function exists)
|
|
1673
|
+
const minifiedJsCode = minifyJavaScript(jsCode);
|
|
1674
|
+
|
|
1675
|
+
// Assign a new transaction type ID
|
|
1676
|
+
const newTxTypeId = getNextTxTypeId();
|
|
1677
|
+
|
|
1678
|
+
// Construct the new transaction with the ordinal reveal JSON and minified JS code
|
|
1679
|
+
const newTx = {
|
|
1680
|
+
txTypeId: newTxTypeId,
|
|
1681
|
+
ordinalRevealJSON: ordinalRevealJSON,
|
|
1682
|
+
smartContractCode: minifiedJsCode
|
|
1683
|
+
};
|
|
1684
|
+
|
|
1685
|
+
// Save the new transaction to the system's registry
|
|
1686
|
+
// Assuming a function to save the transaction exists
|
|
1687
|
+
saveNewTransaction(newTx);
|
|
1688
|
+
|
|
1689
|
+
console.log(`Published new transaction type ID ${newTxTypeId}`);
|
|
1690
|
+
|
|
1691
|
+
// Return the new transaction type ID and details
|
|
1692
|
+
return { newTxTypeId, newTx };
|
|
1693
|
+
},
|
|
1694
|
+
|
|
1695
|
+
bindSmartContract(){},
|
|
1696
|
+
|
|
1697
|
+
mintColoredCoin(/* parameters */) { /* ... */ }
|
|
1698
|
+
};
|
|
1699
|
+
|
|
1700
|
+
module.exports = Logic;
|
|
1701
|
+
|
|
1702
|
+
// Example function to create and register a new token
|