@lifestonelabs/tokensales 1.0.5 → 1.0.7
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/CHANGELOG.md +9 -0
- package/dist/config.d.ts +2 -2
- package/dist/constants/values.d.ts +2 -2
- package/dist/constants/values.d.ts.map +1 -1
- package/dist/functions/burn.d.ts.map +1 -1
- package/dist/functions/buyNFT.d.ts.map +1 -1
- package/dist/index.esm.js +143 -96
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +143 -96
- package/dist/index.js.map +1 -1
- package/dist/types/index.d.ts +2 -2
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/artifacts/TokenSales.cash +3 -4
- package/src/artifacts/TokenSales.json +39 -39
- package/src/artifacts/TokenSales_old2.cash +239 -0
- package/src/artifacts/TokenSales_old2.json +290 -0
- package/src/constants/values.ts +7 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
______________________________________________________________
|
|
3
|
+
## [1.0.7] - 2026-02-10
|
|
4
|
+
### Changed
|
|
5
|
+
- `buyNFT` fixed change fee calculation to take ticket price into account
|
|
6
|
+
______________________________________________________________
|
|
7
|
+
## [1.0.6] - 2026-02-09
|
|
8
|
+
### Changed
|
|
9
|
+
- `buyNFT` & `burn` made ticketMasterUtxo param optional. They now fetch the correct TokenSale UTXO from the contract if one is not provided.
|
|
10
|
+
Lets the frontend manage the contract UTXO fetching themselves if they want to limit the amount of electrum calls.
|
|
11
|
+
______________________________________________________________
|
|
3
12
|
## [1.0.5] - 2026-02-09
|
|
4
13
|
### Changed
|
|
5
14
|
- `buyNFT` fixed logic so that a MintingNFT owner for the categoryID can purchase tickets for 1000sats rather than paying full price.
|
package/dist/config.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export declare const DEFAULT_CONTRACT_ADDRESSES: {
|
|
2
|
-
readonly contract: "bitcoincash:
|
|
3
|
-
readonly token: "bitcoincash:
|
|
2
|
+
readonly contract: "bitcoincash:pdllrevwdxsngc2f6cqqhml2288580c2al8lqtq4cg9ywupyqqh5vz3syd0y9";
|
|
3
|
+
readonly token: "bitcoincash:rdllrevwdxsngc2f6cqqhml2288580c2al8lqtq4cg9ywupyqqh5vszv95waw";
|
|
4
4
|
};
|
|
5
5
|
/**
|
|
6
6
|
* Get contract address
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export declare const AddressTicketMaster = "bitcoincash:
|
|
2
|
-
export declare const AddressTicketMasterToken = "bitcoincash:
|
|
1
|
+
export declare const AddressTicketMaster = "bitcoincash:pdllrevwdxsngc2f6cqqhml2288580c2al8lqtq4cg9ywupyqqh5vz3syd0y9";
|
|
2
|
+
export declare const AddressTicketMasterToken = "bitcoincash:rdllrevwdxsngc2f6cqqhml2288580c2al8lqtq4cg9ywupyqqh5vszv95waw";
|
|
3
3
|
export declare const TICKET_LEVEL_DESCRIPTIONS: {
|
|
4
4
|
'01': {
|
|
5
5
|
name: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"values.d.ts","sourceRoot":"","sources":["../../src/constants/values.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"values.d.ts","sourceRoot":"","sources":["../../src/constants/values.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,mBAAmB,8EAA8E,CAAC;AAC/G,eAAO,MAAM,wBAAwB,8EAA8E,CAAC;AAIpH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;CAarC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"burn.d.ts","sourceRoot":"","sources":["../../src/functions/burn.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,8BAA8B,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"burn.d.ts","sourceRoot":"","sources":["../../src/functions/burn.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,8BAA8B,EAAE,MAAM,UAAU,CAAC;AAKtE;;;;;GAKG;AACH,wBAAsB,IAAI,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,8BAA8B,CAAC,CA+MtF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"buyNFT.d.ts","sourceRoot":"","sources":["../../src/functions/buyNFT.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,8BAA8B,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"buyNFT.d.ts","sourceRoot":"","sources":["../../src/functions/buyNFT.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,8BAA8B,EAAE,MAAM,UAAU,CAAC;AAKxE;;;;;GAKG;AACH,wBAAsB,MAAM,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,8BAA8B,CAAC,CAwV1F"}
|
package/dist/index.esm.js
CHANGED
|
@@ -212,6 +212,64 @@ function toLittleEndianHexString(number, byteCount) {
|
|
|
212
212
|
return hex.match(/../g)?.reverse().join('') ?? '';
|
|
213
213
|
}
|
|
214
214
|
|
|
215
|
+
// TokenSales_old1 contract addresses
|
|
216
|
+
//export const AddressTicketMaster = 'bitcoincash:pvh0yat7d2r9nf228fpns3mypydvstq9arftt9qlmma42xeq2eryszkdd99zq'; //address hash: 2ef2757e6a8659a54a3a43384764091ac82c05e8d2b5941fdefb551b20564648
|
|
217
|
+
//export const AddressTicketMasterToken = 'bitcoincash:rvh0yat7d2r9nf228fpns3mypydvstq9arftt9qlmma42xeq2eryss93vuymt';
|
|
218
|
+
// TokenSales_old2 contract addresses | simplified change fee calculation in purchaseNFT()
|
|
219
|
+
//export const AddressTicketMaster = 'bitcoincash:pdmta0t3lmeufrhjlmyxkx3ye648lvr08cdwmy36eqtkj4wzpagg2m4afvzlt'; //address hash: 76bebd71fef3c48ef2fec86b1a24ceaa7fb06f3e1aed923ac8176955c20f5085
|
|
220
|
+
//export const AddressTicketMasterToken = 'bitcoincash:rdmta0t3lmeufrhjlmyxkx3ye648lvr08cdwmy36eqtkj4wzpagg2fxpg4rxq';
|
|
221
|
+
// TokenSales contract addresses | fixed change fee calculation in purchaseNFT()
|
|
222
|
+
const AddressTicketMaster = 'bitcoincash:pdllrevwdxsngc2f6cqqhml2288580c2al8lqtq4cg9ywupyqqh5vz3syd0y9'; //address hash: 7ff1e58e69a1346149d6000befea51cf43bf0aefcff02c15c20a477024002f46
|
|
223
|
+
const AddressTicketMasterToken = 'bitcoincash:rdllrevwdxsngc2f6cqqhml2288580c2al8lqtq4cg9ywupyqqh5vszv95waw';
|
|
224
|
+
// Ticket Level Descriptions
|
|
225
|
+
const TICKET_LEVEL_DESCRIPTIONS = {
|
|
226
|
+
'01': {
|
|
227
|
+
name: 'Regular',
|
|
228
|
+
description: 'Regular tickets provide standard access to the event. This is the base level ticket option.'
|
|
229
|
+
},
|
|
230
|
+
'02': {
|
|
231
|
+
name: 'VIP',
|
|
232
|
+
description: 'VIP tickets offer enhanced benefits including priority access, exclusive areas, and additional perks.'
|
|
233
|
+
},
|
|
234
|
+
'03': {
|
|
235
|
+
name: 'Premium',
|
|
236
|
+
description: 'Premium tickets provide the highest level of access with all VIP benefits plus additional exclusive features.'
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* TokenSales contract addresses
|
|
242
|
+
* These are the addresses for the TokenSales (TicketMaster) contract
|
|
243
|
+
*/
|
|
244
|
+
const DEFAULT_CONTRACT_ADDRESSES = {
|
|
245
|
+
contract: AddressTicketMaster,
|
|
246
|
+
token: AddressTicketMasterToken
|
|
247
|
+
};
|
|
248
|
+
/**
|
|
249
|
+
* Get contract address
|
|
250
|
+
* @returns Contract address
|
|
251
|
+
*/
|
|
252
|
+
function getContractAddress() {
|
|
253
|
+
return AddressTicketMaster;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Get token address
|
|
257
|
+
* @returns Token address
|
|
258
|
+
*/
|
|
259
|
+
function getTokenAddress() {
|
|
260
|
+
return AddressTicketMasterToken;
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Get contract addresses
|
|
264
|
+
* @returns Object with contract and token addresses
|
|
265
|
+
*/
|
|
266
|
+
function getContractAddresses() {
|
|
267
|
+
return {
|
|
268
|
+
contract: AddressTicketMaster,
|
|
269
|
+
token: AddressTicketMasterToken
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
|
|
215
273
|
var contractName = "TokenSales";
|
|
216
274
|
var constructorInputs = [
|
|
217
275
|
];
|
|
@@ -257,11 +315,11 @@ var abi = [
|
|
|
257
315
|
]
|
|
258
316
|
}
|
|
259
317
|
];
|
|
260
|
-
var bytecode = "OP_DUP OP_0 OP_NUMEQUAL OP_IF OP_0 OP_UTXOBYTECODE OP_1 OP_UTXOBYTECODE OP_EQUALVERIFY OP_0 OP_UTXOTOKENCATEGORY 20 OP_SPLIT OP_2 OP_EQUALVERIFY OP_1 OP_UTXOTOKENCATEGORY OP_EQUALVERIFY OP_0 OP_UTXOTOKENCOMMITMENT 13 OP_SPLIT OP_DROP OP_15 OP_SPLIT OP_NIP OP_TXLOCKTIME OP_SWAP OP_BIN2NUM OP_LESSTHAN OP_VERIFY OP_TXINPUTCOUNT OP_3 OP_NUMEQUALVERIFY OP_TXOUTPUTCOUNT OP_4 OP_LESSTHANOREQUAL OP_VERIFY OP_0 OP_0 OP_3 OP_PICK OP_1 OP_EQUAL OP_IF OP_0 OP_UTXOTOKENCOMMITMENT OP_5 OP_SPLIT OP_DROP OP_1 OP_UTXOTOKENCOMMITMENT OP_1 OP_CAT OP_3 OP_ROLL OP_DROP OP_SWAP OP_TOALTSTACK OP_SWAP OP_FROMALTSTACK OP_DUP OP_BIN2NUM OP_ROT OP_DROP OP_NIP OP_ELSE OP_3 OP_PICK OP_2 OP_EQUAL OP_IF OP_0 OP_UTXOTOKENCOMMITMENT OP_10 OP_SPLIT OP_DROP OP_5 OP_SPLIT OP_NIP OP_DUP 000000000000 OP_EQUAL OP_NOT OP_VERIFY OP_DUP OP_BIN2NUM OP_ROT OP_DROP OP_SWAP OP_1 OP_UTXOTOKENCOMMITMENT OP_2 OP_CAT OP_3 OP_ROLL OP_DROP OP_SWAP OP_TOALTSTACK OP_SWAP OP_FROMALTSTACK OP_DROP OP_ELSE OP_3 OP_PICK OP_3 OP_EQUALVERIFY OP_0 OP_UTXOTOKENCOMMITMENT OP_15 OP_SPLIT OP_DROP OP_10 OP_SPLIT OP_NIP OP_DUP 000000000000 OP_EQUAL OP_NOT OP_VERIFY OP_DUP OP_BIN2NUM OP_ROT OP_DROP OP_SWAP OP_1 OP_UTXOTOKENCOMMITMENT OP_3 OP_CAT OP_3 OP_ROLL OP_DROP OP_SWAP OP_TOALTSTACK OP_SWAP OP_FROMALTSTACK OP_DROP OP_ENDIF OP_ENDIF OP_1 OP_OUTPUTTOKENCOMMITMENT OP_ROT OP_EQUALVERIFY OP_1 OP_OUTPUTBYTECODE OP_2 OP_UTXOBYTECODE OP_EQUALVERIFY OP_1 OP_OUTPUTTOKENCATEGORY OP_1 OP_UTXOTOKENCATEGORY OP_EQUALVERIFY OP_1 OP_OUTPUTTOKENAMOUNT OP_1 OP_UTXOTOKENAMOUNT OP_NUMEQUALVERIFY OP_1 OP_OUTPUTVALUE OP_1 OP_UTXOVALUE OP_NUMEQUALVERIFY OP_2 OP_UTXOTOKENCATEGORY OP_0 OP_EQUAL OP_2 OP_UTXOTOKENCATEGORY OP_0 OP_UTXOTOKENCATEGORY OP_EQUAL OP_DUP OP_ROT OP_BOOLOR OP_VERIFY OP_DUP OP_IF OP_TXOUTPUTCOUNT OP_4 OP_NUMEQUALVERIFY OP_ENDIF OP_IF e803 OP_NIP OP_ENDIF OP_0 OP_UTXOTOKENCOMMITMENT 27 OP_SPLIT OP_DROP 13 OP_SPLIT OP_NIP 76a914 OP_SWAP OP_CAT 88ac OP_CAT OP_2 OP_OUTPUTBYTECODE OP_EQUALVERIFY OP_2 OP_OUTPUTTOKENCATEGORY OP_0 OP_EQUALVERIFY OP_2 OP_OUTPUTVALUE OP_NUMEQUALVERIFY OP_0 OP_OUTPUTVALUE OP_0 OP_UTXOVALUE OP_NUMEQUALVERIFY OP_0 OP_OUTPUTBYTECODE OP_0 OP_UTXOBYTECODE OP_EQUALVERIFY OP_0 OP_OUTPUTTOKENCATEGORY OP_0 OP_UTXOTOKENCATEGORY OP_EQUALVERIFY OP_0 OP_OUTPUTTOKENAMOUNT OP_0 OP_UTXOTOKENAMOUNT OP_NUMEQUALVERIFY OP_0 OP_OUTPUTTOKENCOMMITMENT OP_0 OP_UTXOTOKENCOMMITMENT OP_EQUALVERIFY OP_2 OP_UTXOVALUE 1027 OP_SUB OP_0 OP_MAX OP_DUP e803 OP_GREATERTHAN OP_IF OP_3 OP_OUTPUTBYTECODE OP_2 OP_UTXOBYTECODE OP_EQUALVERIFY OP_3 OP_OUTPUTTOKENCATEGORY OP_2 OP_UTXOTOKENCATEGORY OP_EQUALVERIFY OP_3 OP_OUTPUTTOKENCOMMITMENT OP_2 OP_UTXOTOKENCOMMITMENT OP_EQUALVERIFY OP_3 OP_OUTPUTVALUE OP_OVER OP_GREATERTHANOREQUAL OP_VERIFY OP_ENDIF OP_2DROP OP_DROP OP_1 OP_ELSE OP_DUP OP_1 OP_NUMEQUAL OP_IF OP_INPUTINDEX OP_0 OP_NUMEQUALVERIFY OP_1 OP_UTXOTOKENCATEGORY OP_0 OP_UTXOTOKENCATEGORY OP_EQUALVERIFY OP_TXINPUTCOUNT OP_2 OP_NUMEQUALVERIFY OP_TXOUTPUTCOUNT OP_2 OP_NUMEQUALVERIFY OP_OVER OP_SIZE OP_NIP OP_5 OP_NUMEQUALVERIFY OP_2 OP_PICK OP_SIZE OP_NIP OP_5 OP_NUMEQUALVERIFY OP_3 OP_PICK OP_SIZE OP_NIP OP_5 OP_NUMEQUALVERIFY OP_4 OP_PICK OP_SIZE OP_NIP OP_4 OP_NUMEQUALVERIFY OP_0 OP_UTXOTOKENCOMMITMENT 27 OP_SPLIT OP_DROP 13 OP_SPLIT OP_NIP OP_0 OP_OUTPUTTOKENCOMMITMENT OP_3 OP_ROLL OP_4 OP_ROLL OP_CAT OP_4 OP_ROLL OP_CAT OP_4 OP_ROLL OP_CAT OP_ROT OP_CAT OP_EQUALVERIFY OP_0 OP_OUTPUTBYTECODE OP_0 OP_UTXOBYTECODE OP_EQUALVERIFY OP_0 OP_OUTPUTTOKENCATEGORY OP_0 OP_UTXOTOKENCATEGORY OP_EQUALVERIFY OP_0 OP_OUTPUTTOKENAMOUNT OP_0 OP_UTXOTOKENAMOUNT OP_NUMEQUALVERIFY OP_0 OP_OUTPUTVALUE OP_0 OP_UTXOVALUE OP_NUMEQUALVERIFY OP_1 OP_OUTPUTTOKENCOMMITMENT OP_1 OP_UTXOTOKENCOMMITMENT OP_EQUALVERIFY OP_1 OP_OUTPUTBYTECODE OP_1 OP_UTXOBYTECODE OP_EQUALVERIFY OP_1 OP_OUTPUTTOKENCATEGORY OP_1 OP_UTXOTOKENCATEGORY OP_EQUALVERIFY OP_1 OP_OUTPUTTOKENAMOUNT OP_1 OP_UTXOTOKENAMOUNT OP_NUMEQUALVERIFY OP_1 OP_OUTPUTVALUE OP_1 OP_UTXOVALUE 1027 OP_SUB OP_GREATERTHANOREQUAL OP_NIP OP_ELSE OP_DUP OP_2 OP_NUMEQUAL OP_IF OP_1 OP_UTXOTOKENCATEGORY 20 OP_SPLIT OP_2 OP_EQUALVERIFY OP_0 OP_UTXOTOKENCATEGORY OP_1 OP_UTXOTOKENCATEGORY OP_EQUALVERIFY OP_INPUTINDEX OP_1ADD OP_TXINPUTCOUNT OP_OVER OP_GREATERTHAN OP_IF OP_DUP OP_UTXOTOKENCATEGORY OP_2 OP_PICK OP_EQUALVERIFY OP_ENDIF OP_0 OP_OUTPUTTOKENCOMMITMENT OP_0 OP_UTXOTOKENCOMMITMENT OP_EQUALVERIFY OP_0 OP_OUTPUTBYTECODE OP_0 OP_UTXOBYTECODE OP_EQUALVERIFY OP_0 OP_OUTPUTTOKENCATEGORY OP_0 OP_UTXOTOKENCATEGORY OP_EQUALVERIFY OP_0 OP_OUTPUTTOKENAMOUNT OP_0 OP_UTXOTOKENAMOUNT OP_NUMEQUALVERIFY OP_0 OP_OUTPUTVALUE OP_0 OP_UTXOVALUE 1027 OP_SUB OP_GREATERTHANOREQUAL OP_VERIFY OP_TXOUTPUTCOUNT OP_1 OP_NUMEQUAL OP_NIP OP_NIP OP_NIP OP_ELSE OP_3 OP_NUMEQUALVERIFY cc9b01 OP_CHECKSEQUENCEVERIFY OP_DROP OP_TXOUTPUTCOUNT OP_1 OP_NUMEQUALVERIFY OP_0 OP_OUTPUTTOKENCATEGORY OP_0 OP_EQUAL OP_ENDIF OP_ENDIF OP_ENDIF";
|
|
261
|
-
var source = "pragma cashscript ^0.12.0;\r\n\r\ncontract TokenSales() {\r\n// Single-contract NFT Marketplace on Bitcoin Cash\r\n// \r\n// 1. Sale owner creates a `TokenSale` MintingNFT of the same category as the NFTs to be sold. The TokenSale MintingNFT must have its commitment setup as:\r\n//\r\n /* --- State `TokenSale` Minting NFT ---\r\n bytes5 priceType1\r\n bytes5 priceType2\r\n bytes5 priceType3\r\n bytes4 endSale \r\n bytes20 adminPubKeyHash\r\n */\r\n//\r\n// 2. Sale owner sends the immutableNFTs to be sold of the same categoory to this contract. (mutableNFT's will be stuck in the contract until they are reclaim()'d)\r\n// 3. Users can purchase any NFT and can choose what `type` the NFT will be, paying the appropriate price.\r\n// Purchases require the sale is active (endSale block has not yet been reached).\r\n// Up to 3 NFT types with different prices can be set. If a types price is set to 0 the type will not be available for purchase.\r\n// 4. Each sales BCH price is sent to the adminPubKeyHash address.\r\n// 5. Admin can perform the following actions at any time:\r\n// - Change the price of the three NFT types.\r\n// - Change the endSale block number, including stopping a currently-active sale, re-starting a stopped sale, and extending a sale.\r\n// - Burn the TokenSaleNFT ('the sale') and any remaining NFTs of the same category.\r\n// - Purchase a NFT for 1000sats by providing another MintingNFT of the same category. (so adminsPubKeyHash address will have an entry for all sold NFTs, even those that admin took for 'free')\r\n//\r\n// Additionally, a reclaim() function is provided to reclaim the satoshis from UTXOs on this contract that have been abandoned for 2 years.\r\n// This is a workaround for any stray UTXOs that are sent to or left on the contract (e.g. if NFT's are not included in the burnTokenSale() function)\r\n\r\n //////////////////////////////////////////////////////////////////////////////////////////\r\n ////////////////////////////////// Purchase a NFT ///////////////////////////////////\r\n//////////////////////////////////////////////////////////////////////////////////////////\r\n// User purchases a NFT. Must include a MintingNFT of the same category (`TokenSale`). \r\n// Updates NFT commitment with the type of NFT purchased. \r\n// Enforces any change back to user.\r\n// Admin can provide another MintingNFT (with BCH on it) of the same category instead of a BCH UTXO to buy an NFT of any type for free.\r\n// ------------------------------------------------------------------------------------\r\n//inputs: \r\n// 0 TokenSale [NFT]-Minting (from TokenSale contract)\r\n// 1 NFT [NFT] (from TokenSale contract)\r\n// [2 userUTXO [BCH] (from user)\r\n// OR] adminUTXO [NFT]-Minting (from admin)\r\n//outputs:\r\n// 0 TokenSale [NFT]-Minting (to TokenSale contract)\r\n// 1 NFT [NFT] (to user)\r\n// 2 payment [BCH] (to adminPkh)\r\n// [3 {optional} change [BCH] (to user)\r\n// OR] adminUTXO [NFT]-Minting (to admin)\r\n//////////////////////////////////////////////////////////////////////////////////////////\r\n function purchaseNFT(byte nftType) {\r\n // verify input0 is the MintingNFT from this contract. (also forces TokenSaleNFT as input0 rather than an adminNFT)\r\n require(tx.inputs[0].lockingBytecode == tx.inputs[1].lockingBytecode);\r\n bytes tokenSaleCategoryID, bytes tokenSaleCapability = tx.inputs[0].tokenCategory.split(32);\r\n require(tokenSaleCapability == 0x02);\r\n\r\n // verify NFT is for this tokenSaleCategoryID\r\n require(tx.inputs[1].tokenCategory == tokenSaleCategoryID);\r\n\r\n // require sale has not ended\r\n bytes endSale = tx.inputs[0].nftCommitment.slice(15,19);\r\n require(tx.locktime < int(endSale));\r\n\r\n // verify tx limits\r\n require(tx.inputs.length == 3);\r\n require(tx.outputs.length <= 4);\r\n\r\n bytes newNFTCommitment = 0x;\r\n int nftPrice = 0;\r\n // buy NFT based on type \r\n if (nftType == 0x01) {\r\n bytes5 priceType1 = tx.inputs[0].nftCommitment.split(5)[0];\r\n newNFTCommitment = tx.inputs[1].nftCommitment + 0x01;\r\n nftPrice = int(priceType1);\r\n } else if (nftType == 0x02) {\r\n bytes5 priceType2 = tx.inputs[0].nftCommitment.slice(5,10);\r\n require(priceType2 != 0x000000000000);\r\n nftPrice = int(priceType2);\r\n newNFTCommitment = tx.inputs[1].nftCommitment + 0x02;\r\n } else {\r\n require(nftType == 0x03);\r\n bytes5 priceType3 = tx.inputs[0].nftCommitment.slice(10,15);\r\n require(priceType3 != 0x000000000000);\r\n nftPrice = int(priceType3);\r\n newNFTCommitment = tx.inputs[1].nftCommitment + 0x03;\r\n }\r\n\r\n // send NFT to user with updated type\r\n require(tx.outputs[1].nftCommitment == newNFTCommitment);\r\n require(tx.outputs[1].lockingBytecode == tx.inputs[2].lockingBytecode);\r\n require(tx.outputs[1].tokenCategory == tx.inputs[1].tokenCategory);\r\n require(tx.outputs[1].tokenAmount == tx.inputs[1].tokenAmount);\r\n require(tx.outputs[1].value == tx.inputs[1].value);\r\n\r\n // verify user providing either pure BCH or adminNFT\r\n bool isPureBCH = tx.inputs[2].tokenCategory == 0x;\r\n bool isAdmin = tx.inputs[2].tokenCategory == tx.inputs[0].tokenCategory;\r\n require(isAdmin || isPureBCH);\r\n\r\n // if admin, set nftPrice to 0 and prevent accidental burning of adminNFT\r\n if (isAdmin) require(tx.outputs.length == 4);\r\n if (isAdmin) nftPrice = 1000;\r\n \r\n // send payment to adminPkh\r\n bytes20 adminPkh = tx.inputs[0].nftCommitment.slice(19,39);\r\n bytes adminAddress = new LockingBytecodeP2PKH(adminPkh); \r\n require(tx.outputs[2].lockingBytecode == adminAddress);\r\n require(tx.outputs[2].tokenCategory == 0x);\r\n require(tx.outputs[2].value == nftPrice);\r\n\r\n // recreate TokenSale MintingNFT\r\n require(tx.outputs[0].value == tx.inputs[0].value);\r\n require(tx.outputs[0].lockingBytecode == tx.inputs[0].lockingBytecode);\r\n require(tx.outputs[0].tokenCategory == tx.inputs[0].tokenCategory);\r\n require(tx.outputs[0].tokenAmount == tx.inputs[0].tokenAmount); \r\n require(tx.outputs[0].nftCommitment == tx.inputs[0].nftCommitment);\r\n\r\n // determine how much change exists after reserving up to 10_000 sats for miner fee\r\n int change = max((tx.inputs[2].value - 10000), 0);\r\n // return change to user\r\n if (change > 1000) {\r\n require(tx.outputs[3].lockingBytecode == tx.inputs[2].lockingBytecode);\r\n require(tx.outputs[3].tokenCategory == tx.inputs[2].tokenCategory);\r\n require(tx.outputs[3].nftCommitment == tx.inputs[2].nftCommitment);\r\n require(tx.outputs[3].value >= change);\r\n }\r\n }\r\n\r\n //////////////////////////////////////////////////////////////////////////////////////////\r\n ////////////////////////////// Modify TokenSale NFT //////////////////////////////\r\n//////////////////////////////////////////////////////////////////////////////////////////\r\n// Admin can change the `TokenSale` NFT type prices and endSale block number.\r\n// Requires 2000sats extra on the adminNFT to cover tx fee.\r\n// ------------------------------------------------------------------------------------\r\n//inputs: \r\n// 0 TokenSale [NFT]-Minting (from TokenSale contract)\r\n// 1 adminNFT [NFT]-Minting (from admin)\r\n//outputs:\r\n// 0 TokenSale [NFT]-Minting (to TokenSale contract) \r\n// 1 adminNFT [NFT]-Minting (to admin)\r\n//////////////////////////////////////////////////////////////////////////////////////////\r\n//parameters:\r\n// priceType1: the price of a type1 NFT (in satoshis)\r\n// priceType2: the price of a type2 NFT (in satoshis)\r\n// priceType3: the price of a type3 NFT (in satoshis)\r\n// endSale: the block number to end sale at\r\n//////////////////////////////////////////////////////////////////////////////////////////\r\n function modifyTokenSale(bytes5 priceType1, bytes5 priceType2, bytes5 priceType3, bytes4 endSale) {\r\n // verify input0 is from this contract\r\n require(this.activeInputIndex == 0);\r\n\r\n // verify adminNFT is for this TokenSaleCategoryID\r\n require(tx.inputs[1].tokenCategory == tx.inputs[0].tokenCategory);\r\n\r\n // verify tx limits\r\n require(tx.inputs.length == 2);\r\n require(tx.outputs.length == 2); \r\n\r\n // verify parameters are correct lengths\r\n require(priceType1.length == 5);\r\n require(priceType2.length == 5);\r\n require(priceType3.length == 5);\r\n require(endSale.length == 4);\r\n\r\n // recreate TokenSale. Implicitly enforces that input0 is not an immutableNFT\r\n bytes20 adminPkh = tx.inputs[0].nftCommitment.slice(19,39);\r\n require(tx.outputs[0].nftCommitment == priceType1 + priceType2 + priceType3 + endSale + adminPkh);\r\n require(tx.outputs[0].lockingBytecode == tx.inputs[0].lockingBytecode);\r\n require(tx.outputs[0].tokenCategory == tx.inputs[0].tokenCategory);\r\n require(tx.outputs[0].tokenAmount == tx.inputs[0].tokenAmount);\r\n require(tx.outputs[0].value == tx.inputs[0].value);\r\n\r\n // recreate adminNFT\r\n require(tx.outputs[1].nftCommitment == tx.inputs[1].nftCommitment);\r\n require(tx.outputs[1].lockingBytecode == tx.inputs[1].lockingBytecode);\r\n require(tx.outputs[1].tokenCategory == tx.inputs[1].tokenCategory);\r\n require(tx.outputs[1].tokenAmount == tx.inputs[1].tokenAmount);\r\n require(tx.outputs[1].value >= tx.inputs[1].value - 10000);\r\n }\r\n\r\n //////////////////////////////////////////////////////////////////////////////////////////\r\n /////////////////////////////// Burn TokenSale ///////////////////////////////////\r\n//////////////////////////////////////////////////////////////////////////////////////////\r\n// Admin can burn the `TokenSale` NFT and any remaining NFTs of this category.\r\n// No other inputs besides NFTs of this category are permitted for inputs2+.\r\n// ------------------------------------------------------------------------------------\r\n//inputs: \r\n// 0 adminNFT [NFT]-Minting (from admin)\r\n// 1 TokenSale [NFT]-Minting (from TokenSale contract)\r\n// N NFTs [NFT] (from TokenSale contract)\r\n//outputs:\r\n// 0 adminNFT [NFT]-Minting (to admin)\r\n//////////////////////////////////////////////////////////////////////////////////////////\r\n function burnTokenSale() {\r\n // verify input1 is a MintingNFT\r\n bytes tokenSaleCategoryID, bytes tokenSaleCapability = tx.inputs[1].tokenCategory.split(32);\r\n require(tokenSaleCapability == 0x02);\r\n\r\n // verify adminNFT is for this TokenSale\r\n require(tx.inputs[0].tokenCategory == tx.inputs[1].tokenCategory);\r\n\r\n //require next input is a NFT of this category\r\n int nextIndex = this.activeInputIndex + 1;\r\n if (tx.inputs.length > nextIndex) {\r\n require(tx.inputs[nextIndex].tokenCategory == tokenSaleCategoryID);\r\n }\r\n\r\n // recreate adminNFT\r\n require(tx.outputs[0].nftCommitment == tx.inputs[0].nftCommitment);\r\n require(tx.outputs[0].lockingBytecode == tx.inputs[0].lockingBytecode);\r\n require(tx.outputs[0].tokenCategory == tx.inputs[0].tokenCategory);\r\n require(tx.outputs[0].tokenAmount == tx.inputs[0].tokenAmount);\r\n require(tx.outputs[0].value >= tx.inputs[0].value - 10000);\r\n\r\n // verify tx limits\r\n require(tx.outputs.length == 1); \r\n }\r\n\r\n //////////////////////////////////////////////////////////////////////////////////////////\r\n //////////////////////////// Reclaim Expired Inputs /////////////////////////////////\r\n//////////////////////////////////////////////////////////////////////////////////////////\r\n// Anyone can reclaim the satoshis from utxos on this contract that have been abandoned for 2 years.\r\n// ------------------------------------------------------------------------------------\r\n//inputs: \r\n// 0+ UTXO [Any] (from TokenSale contract)\r\n//outputs:\r\n// 0 UTXO [BCH] (to anyone)\r\n//////////////////////////////////////////////////////////////////////////////////////////\r\n function reclaim() {\r\n require(this.age >= 105420);\r\n\r\n // verify tx limits\r\n require(tx.outputs.length == 1); \r\n\r\n // enforce output\r\n require(tx.outputs[0].tokenCategory == 0x);\r\n\r\n }\r\n}";
|
|
318
|
+
var bytecode = "OP_DUP OP_0 OP_NUMEQUAL OP_IF OP_0 OP_UTXOBYTECODE OP_1 OP_UTXOBYTECODE OP_EQUALVERIFY OP_0 OP_UTXOTOKENCATEGORY 20 OP_SPLIT OP_2 OP_EQUALVERIFY OP_1 OP_UTXOTOKENCATEGORY OP_EQUALVERIFY OP_0 OP_UTXOTOKENCOMMITMENT 13 OP_SPLIT OP_DROP OP_15 OP_SPLIT OP_NIP OP_TXLOCKTIME OP_SWAP OP_BIN2NUM OP_LESSTHAN OP_VERIFY OP_TXINPUTCOUNT OP_3 OP_NUMEQUALVERIFY OP_TXOUTPUTCOUNT OP_4 OP_LESSTHANOREQUAL OP_VERIFY OP_0 OP_0 OP_3 OP_PICK OP_1 OP_EQUAL OP_IF OP_0 OP_UTXOTOKENCOMMITMENT OP_5 OP_SPLIT OP_DROP OP_1 OP_UTXOTOKENCOMMITMENT OP_1 OP_CAT OP_3 OP_ROLL OP_DROP OP_SWAP OP_TOALTSTACK OP_SWAP OP_FROMALTSTACK OP_DUP OP_BIN2NUM OP_ROT OP_DROP OP_NIP OP_ELSE OP_3 OP_PICK OP_2 OP_EQUAL OP_IF OP_0 OP_UTXOTOKENCOMMITMENT OP_10 OP_SPLIT OP_DROP OP_5 OP_SPLIT OP_NIP OP_DUP 000000000000 OP_EQUAL OP_NOT OP_VERIFY OP_DUP OP_BIN2NUM OP_ROT OP_DROP OP_SWAP OP_1 OP_UTXOTOKENCOMMITMENT OP_2 OP_CAT OP_3 OP_ROLL OP_DROP OP_SWAP OP_TOALTSTACK OP_SWAP OP_FROMALTSTACK OP_DROP OP_ELSE OP_3 OP_PICK OP_3 OP_EQUALVERIFY OP_0 OP_UTXOTOKENCOMMITMENT OP_15 OP_SPLIT OP_DROP OP_10 OP_SPLIT OP_NIP OP_DUP 000000000000 OP_EQUAL OP_NOT OP_VERIFY OP_DUP OP_BIN2NUM OP_ROT OP_DROP OP_SWAP OP_1 OP_UTXOTOKENCOMMITMENT OP_3 OP_CAT OP_3 OP_ROLL OP_DROP OP_SWAP OP_TOALTSTACK OP_SWAP OP_FROMALTSTACK OP_DROP OP_ENDIF OP_ENDIF OP_1 OP_OUTPUTTOKENCOMMITMENT OP_ROT OP_EQUALVERIFY OP_1 OP_OUTPUTBYTECODE OP_2 OP_UTXOBYTECODE OP_EQUALVERIFY OP_1 OP_OUTPUTTOKENCATEGORY OP_1 OP_UTXOTOKENCATEGORY OP_EQUALVERIFY OP_1 OP_OUTPUTTOKENAMOUNT OP_1 OP_UTXOTOKENAMOUNT OP_NUMEQUALVERIFY OP_1 OP_OUTPUTVALUE OP_1 OP_UTXOVALUE OP_NUMEQUALVERIFY OP_2 OP_UTXOTOKENCATEGORY OP_0 OP_EQUAL OP_2 OP_UTXOTOKENCATEGORY OP_0 OP_UTXOTOKENCATEGORY OP_EQUAL OP_DUP OP_ROT OP_BOOLOR OP_VERIFY OP_DUP OP_IF OP_TXOUTPUTCOUNT OP_4 OP_NUMEQUALVERIFY OP_ENDIF OP_IF e803 OP_NIP OP_ENDIF OP_0 OP_UTXOTOKENCOMMITMENT 27 OP_SPLIT OP_DROP 13 OP_SPLIT OP_NIP 76a914 OP_SWAP OP_CAT 88ac OP_CAT OP_2 OP_OUTPUTBYTECODE OP_EQUALVERIFY OP_2 OP_OUTPUTTOKENCATEGORY OP_0 OP_EQUALVERIFY OP_2 OP_OUTPUTVALUE OP_NUMEQUALVERIFY OP_0 OP_OUTPUTVALUE OP_0 OP_UTXOVALUE OP_NUMEQUALVERIFY OP_0 OP_OUTPUTBYTECODE OP_0 OP_UTXOBYTECODE OP_EQUALVERIFY OP_0 OP_OUTPUTTOKENCATEGORY OP_0 OP_UTXOTOKENCATEGORY OP_EQUALVERIFY OP_0 OP_OUTPUTTOKENAMOUNT OP_0 OP_UTXOTOKENAMOUNT OP_NUMEQUALVERIFY OP_0 OP_OUTPUTTOKENCOMMITMENT OP_0 OP_UTXOTOKENCOMMITMENT OP_EQUALVERIFY OP_2 OP_UTXOVALUE OP_2 OP_OUTPUTVALUE OP_SUB 1027 OP_SUB OP_0 OP_MAX OP_DUP e803 OP_GREATERTHAN OP_IF OP_3 OP_OUTPUTBYTECODE OP_2 OP_UTXOBYTECODE OP_EQUALVERIFY OP_3 OP_OUTPUTTOKENCATEGORY OP_2 OP_UTXOTOKENCATEGORY OP_EQUALVERIFY OP_3 OP_OUTPUTTOKENCOMMITMENT OP_2 OP_UTXOTOKENCOMMITMENT OP_EQUALVERIFY OP_3 OP_OUTPUTVALUE OP_OVER OP_GREATERTHANOREQUAL OP_VERIFY OP_ENDIF OP_2DROP OP_DROP OP_1 OP_ELSE OP_DUP OP_1 OP_NUMEQUAL OP_IF OP_INPUTINDEX OP_0 OP_NUMEQUALVERIFY OP_1 OP_UTXOTOKENCATEGORY OP_0 OP_UTXOTOKENCATEGORY OP_EQUALVERIFY OP_TXINPUTCOUNT OP_2 OP_NUMEQUALVERIFY OP_TXOUTPUTCOUNT OP_2 OP_NUMEQUALVERIFY OP_OVER OP_SIZE OP_NIP OP_5 OP_NUMEQUALVERIFY OP_2 OP_PICK OP_SIZE OP_NIP OP_5 OP_NUMEQUALVERIFY OP_3 OP_PICK OP_SIZE OP_NIP OP_5 OP_NUMEQUALVERIFY OP_4 OP_PICK OP_SIZE OP_NIP OP_4 OP_NUMEQUALVERIFY OP_0 OP_UTXOTOKENCOMMITMENT 27 OP_SPLIT OP_DROP 13 OP_SPLIT OP_NIP OP_0 OP_OUTPUTTOKENCOMMITMENT OP_3 OP_ROLL OP_4 OP_ROLL OP_CAT OP_4 OP_ROLL OP_CAT OP_4 OP_ROLL OP_CAT OP_ROT OP_CAT OP_EQUALVERIFY OP_0 OP_OUTPUTBYTECODE OP_0 OP_UTXOBYTECODE OP_EQUALVERIFY OP_0 OP_OUTPUTTOKENCATEGORY OP_0 OP_UTXOTOKENCATEGORY OP_EQUALVERIFY OP_0 OP_OUTPUTTOKENAMOUNT OP_0 OP_UTXOTOKENAMOUNT OP_NUMEQUALVERIFY OP_0 OP_OUTPUTVALUE OP_0 OP_UTXOVALUE OP_NUMEQUALVERIFY OP_1 OP_OUTPUTTOKENCOMMITMENT OP_1 OP_UTXOTOKENCOMMITMENT OP_EQUALVERIFY OP_1 OP_OUTPUTBYTECODE OP_1 OP_UTXOBYTECODE OP_EQUALVERIFY OP_1 OP_OUTPUTTOKENCATEGORY OP_1 OP_UTXOTOKENCATEGORY OP_EQUALVERIFY OP_1 OP_OUTPUTTOKENAMOUNT OP_1 OP_UTXOTOKENAMOUNT OP_NUMEQUALVERIFY OP_1 OP_OUTPUTVALUE OP_1 OP_UTXOVALUE 1027 OP_SUB OP_GREATERTHANOREQUAL OP_NIP OP_ELSE OP_DUP OP_2 OP_NUMEQUAL OP_IF OP_1 OP_UTXOTOKENCATEGORY 20 OP_SPLIT OP_2 OP_EQUALVERIFY OP_0 OP_UTXOTOKENCATEGORY OP_1 OP_UTXOTOKENCATEGORY OP_EQUALVERIFY OP_INPUTINDEX OP_1ADD OP_TXINPUTCOUNT OP_OVER OP_GREATERTHAN OP_IF OP_DUP OP_UTXOTOKENCATEGORY OP_2 OP_PICK OP_EQUALVERIFY OP_ENDIF OP_0 OP_OUTPUTTOKENCOMMITMENT OP_0 OP_UTXOTOKENCOMMITMENT OP_EQUALVERIFY OP_0 OP_OUTPUTBYTECODE OP_0 OP_UTXOBYTECODE OP_EQUALVERIFY OP_0 OP_OUTPUTTOKENCATEGORY OP_0 OP_UTXOTOKENCATEGORY OP_EQUALVERIFY OP_0 OP_OUTPUTTOKENAMOUNT OP_0 OP_UTXOTOKENAMOUNT OP_NUMEQUALVERIFY OP_0 OP_OUTPUTVALUE OP_0 OP_UTXOVALUE 1027 OP_SUB OP_GREATERTHANOREQUAL OP_VERIFY OP_TXOUTPUTCOUNT OP_1 OP_NUMEQUAL OP_NIP OP_NIP OP_NIP OP_ELSE OP_3 OP_NUMEQUALVERIFY cc9b01 OP_CHECKSEQUENCEVERIFY OP_DROP OP_TXOUTPUTCOUNT OP_1 OP_NUMEQUALVERIFY OP_0 OP_OUTPUTTOKENCATEGORY OP_0 OP_EQUAL OP_ENDIF OP_ENDIF OP_ENDIF";
|
|
319
|
+
var source = "pragma cashscript ^0.12.0;\r\n\r\ncontract TokenSales() {\r\n// Single-contract NFT Marketplace on Bitcoin Cash\r\n// \r\n// 1. Sale owner creates a `TokenSale` MintingNFT of the same category as the NFTs to be sold. The TokenSale MintingNFT must have its commitment setup as:\r\n//\r\n /* --- State `TokenSale` Minting NFT ---\r\n bytes5 priceType1\r\n bytes5 priceType2\r\n bytes5 priceType3\r\n bytes4 endSale \r\n bytes20 adminPubKeyHash\r\n */\r\n//\r\n// 2. Sale owner sends the immutableNFTs to be sold of the same categoory to this contract. (mutableNFT's will be stuck in the contract until they are reclaim()'d)\r\n// 3. Users can purchase any NFT and can choose what `type` the NFT will be, paying the appropriate price.\r\n// Purchases require the sale is active (endSale block has not yet been reached).\r\n// Up to 3 NFT types with different prices can be set. If a types price is set to 0 the type will not be available for purchase.\r\n// 4. Each sales BCH price is sent to the adminPubKeyHash address.\r\n// 5. Admin can perform the following actions at any time:\r\n// - Change the price of the three NFT types.\r\n// - Change the endSale block number, including stopping a currently-active sale, re-starting a stopped sale, and extending a sale.\r\n// - Burn the TokenSaleNFT ('the sale') and any remaining NFTs of the same category.\r\n// - Purchase a NFT for 1000sats by providing another MintingNFT of the same category. (so adminsPubKeyHash address will have an entry for all sold NFTs, even those that admin took for 'free')\r\n//\r\n// Additionally, a reclaim() function is provided to reclaim the satoshis from UTXOs on this contract that have been abandoned for 2 years.\r\n// This is a workaround for any stray UTXOs that are sent to or left on the contract (e.g. if NFT's are not included in the burnTokenSale() function)\r\n\r\n //////////////////////////////////////////////////////////////////////////////////////////\r\n ////////////////////////////////// Purchase a NFT ///////////////////////////////////\r\n//////////////////////////////////////////////////////////////////////////////////////////\r\n// User purchases a NFT. Must include a MintingNFT of the same category (`TokenSale`). \r\n// Updates NFT commitment with the type of NFT purchased. \r\n// Enforces any change back to user.\r\n// Admin can provide another MintingNFT (with BCH on it) of the same category instead of a BCH UTXO to buy an NFT of any type for free.\r\n// ------------------------------------------------------------------------------------\r\n//inputs: \r\n// 0 TokenSale [NFT]-Minting (from TokenSale contract)\r\n// 1 NFT [NFT] (from TokenSale contract)\r\n// [2 userUTXO [BCH] (from user)\r\n// OR] adminUTXO [NFT]-Minting (from admin)\r\n//outputs:\r\n// 0 TokenSale [NFT]-Minting (to TokenSale contract)\r\n// 1 NFT [NFT] (to user)\r\n// 2 payment [BCH] (to adminPkh)\r\n// [3 {optional} change [BCH] (to user)\r\n// OR] adminUTXO [NFT]-Minting (to admin)\r\n//////////////////////////////////////////////////////////////////////////////////////////\r\n function purchaseNFT(byte nftType) {\r\n // verify input0 is the MintingNFT from this contract. (also forces TokenSaleNFT as input0 rather than an adminNFT)\r\n require(tx.inputs[0].lockingBytecode == tx.inputs[1].lockingBytecode);\r\n bytes tokenSaleCategoryID, bytes tokenSaleCapability = tx.inputs[0].tokenCategory.split(32);\r\n require(tokenSaleCapability == 0x02);\r\n\r\n // verify NFT is for this tokenSaleCategoryID\r\n require(tx.inputs[1].tokenCategory == tokenSaleCategoryID);\r\n\r\n // require sale has not ended\r\n bytes endSale = tx.inputs[0].nftCommitment.slice(15,19);\r\n require(tx.locktime < int(endSale));\r\n\r\n // verify tx limits\r\n require(tx.inputs.length == 3);\r\n require(tx.outputs.length <= 4);\r\n\r\n bytes newNFTCommitment = 0x;\r\n int nftPrice = 0;\r\n // buy NFT based on type \r\n if (nftType == 0x01) {\r\n bytes5 priceType1 = tx.inputs[0].nftCommitment.split(5)[0];\r\n newNFTCommitment = tx.inputs[1].nftCommitment + 0x01;\r\n nftPrice = int(priceType1);\r\n } else if (nftType == 0x02) {\r\n bytes5 priceType2 = tx.inputs[0].nftCommitment.slice(5,10);\r\n require(priceType2 != 0x000000000000);\r\n nftPrice = int(priceType2);\r\n newNFTCommitment = tx.inputs[1].nftCommitment + 0x02;\r\n } else {\r\n require(nftType == 0x03);\r\n bytes5 priceType3 = tx.inputs[0].nftCommitment.slice(10,15);\r\n require(priceType3 != 0x000000000000);\r\n nftPrice = int(priceType3);\r\n newNFTCommitment = tx.inputs[1].nftCommitment + 0x03;\r\n }\r\n\r\n // send NFT to user with updated type\r\n require(tx.outputs[1].nftCommitment == newNFTCommitment);\r\n require(tx.outputs[1].lockingBytecode == tx.inputs[2].lockingBytecode);\r\n require(tx.outputs[1].tokenCategory == tx.inputs[1].tokenCategory);\r\n require(tx.outputs[1].tokenAmount == tx.inputs[1].tokenAmount);\r\n require(tx.outputs[1].value == tx.inputs[1].value);\r\n\r\n // verify user providing either pure BCH or adminNFT\r\n bool isPureBCH = tx.inputs[2].tokenCategory == 0x;\r\n bool isAdmin = tx.inputs[2].tokenCategory == tx.inputs[0].tokenCategory;\r\n require(isAdmin || isPureBCH);\r\n\r\n // if admin, set nftPrice to 0 and prevent accidental burning of adminNFT\r\n if (isAdmin) require(tx.outputs.length == 4);\r\n if (isAdmin) nftPrice = 1000;\r\n \r\n // send payment to adminPkh\r\n bytes20 adminPkh = tx.inputs[0].nftCommitment.slice(19,39);\r\n bytes adminAddress = new LockingBytecodeP2PKH(adminPkh); \r\n require(tx.outputs[2].lockingBytecode == adminAddress);\r\n require(tx.outputs[2].tokenCategory == 0x);\r\n require(tx.outputs[2].value == nftPrice);\r\n\r\n // recreate TokenSale MintingNFT\r\n require(tx.outputs[0].value == tx.inputs[0].value);\r\n require(tx.outputs[0].lockingBytecode == tx.inputs[0].lockingBytecode);\r\n require(tx.outputs[0].tokenCategory == tx.inputs[0].tokenCategory);\r\n require(tx.outputs[0].tokenAmount == tx.inputs[0].tokenAmount); \r\n require(tx.outputs[0].nftCommitment == tx.inputs[0].nftCommitment);\r\n\r\n // determine how much change exists after reserving up to 10_000 sats for miner fee\r\n int change = max((tx.inputs[2].value - tx.outputs[2].value - 10000), 0);\r\n // return change to user\r\n if (change > 1000) {\r\n require(tx.outputs[3].lockingBytecode == tx.inputs[2].lockingBytecode);\r\n require(tx.outputs[3].tokenCategory == tx.inputs[2].tokenCategory);\r\n require(tx.outputs[3].nftCommitment == tx.inputs[2].nftCommitment);\r\n require(tx.outputs[3].value >= change);\r\n }\r\n }\r\n\r\n //////////////////////////////////////////////////////////////////////////////////////////\r\n ////////////////////////////// Modify TokenSale NFT //////////////////////////////\r\n//////////////////////////////////////////////////////////////////////////////////////////\r\n// Admin can change the `TokenSale` NFT type prices and endSale block number.\r\n// Requires 2000sats extra on the adminNFT to cover tx fee.\r\n// ------------------------------------------------------------------------------------\r\n//inputs: \r\n// 0 TokenSale [NFT]-Minting (from TokenSale contract)\r\n// 1 adminNFT [NFT]-Minting (from admin)\r\n//outputs:\r\n// 0 TokenSale [NFT]-Minting (to TokenSale contract) \r\n// 1 adminNFT [NFT]-Minting (to admin)\r\n//////////////////////////////////////////////////////////////////////////////////////////\r\n//parameters:\r\n// priceType1: the price of a type1 NFT (in satoshis)\r\n// priceType2: the price of a type2 NFT (in satoshis)\r\n// priceType3: the price of a type3 NFT (in satoshis)\r\n// endSale: the block number to end sale at\r\n//////////////////////////////////////////////////////////////////////////////////////////\r\n function modifyTokenSale(bytes5 priceType1, bytes5 priceType2, bytes5 priceType3, bytes4 endSale) {\r\n // verify input0 is from this contract\r\n require(this.activeInputIndex == 0);\r\n\r\n // verify adminNFT is for this TokenSaleCategoryID\r\n require(tx.inputs[1].tokenCategory == tx.inputs[0].tokenCategory);\r\n\r\n // verify tx limits\r\n require(tx.inputs.length == 2);\r\n require(tx.outputs.length == 2); \r\n\r\n // verify parameters are correct lengths\r\n require(priceType1.length == 5);\r\n require(priceType2.length == 5);\r\n require(priceType3.length == 5);\r\n require(endSale.length == 4);\r\n\r\n // recreate TokenSale. Implicitly enforces that input0 is not an immutableNFT\r\n bytes20 adminPkh = tx.inputs[0].nftCommitment.slice(19,39);\r\n require(tx.outputs[0].nftCommitment == priceType1 + priceType2 + priceType3 + endSale + adminPkh);\r\n require(tx.outputs[0].lockingBytecode == tx.inputs[0].lockingBytecode);\r\n require(tx.outputs[0].tokenCategory == tx.inputs[0].tokenCategory);\r\n require(tx.outputs[0].tokenAmount == tx.inputs[0].tokenAmount);\r\n require(tx.outputs[0].value == tx.inputs[0].value);\r\n\r\n // recreate adminNFT\r\n require(tx.outputs[1].nftCommitment == tx.inputs[1].nftCommitment);\r\n require(tx.outputs[1].lockingBytecode == tx.inputs[1].lockingBytecode);\r\n require(tx.outputs[1].tokenCategory == tx.inputs[1].tokenCategory);\r\n require(tx.outputs[1].tokenAmount == tx.inputs[1].tokenAmount);\r\n require(tx.outputs[1].value >= tx.inputs[1].value - 10000);\r\n }\r\n\r\n //////////////////////////////////////////////////////////////////////////////////////////\r\n /////////////////////////////// Burn TokenSale ///////////////////////////////////\r\n//////////////////////////////////////////////////////////////////////////////////////////\r\n// Admin can burn the `TokenSale` NFT and any remaining NFTs of this category.\r\n// No other inputs besides NFTs of this category are permitted for inputs2+.\r\n// ------------------------------------------------------------------------------------\r\n//inputs: \r\n// 0 adminNFT [NFT]-Minting (from admin)\r\n// 1 TokenSale [NFT]-Minting (from TokenSale contract)\r\n// N NFTs [NFT] (from TokenSale contract)\r\n//outputs:\r\n// 0 adminNFT [NFT]-Minting (to admin)\r\n//////////////////////////////////////////////////////////////////////////////////////////\r\n function burnTokenSale() {\r\n // verify input1 is a MintingNFT\r\n bytes tokenSaleCategoryID, bytes tokenSaleCapability = tx.inputs[1].tokenCategory.split(32);\r\n require(tokenSaleCapability == 0x02);\r\n\r\n // verify adminNFT is for this TokenSale\r\n require(tx.inputs[0].tokenCategory == tx.inputs[1].tokenCategory);\r\n\r\n //require next input is a NFT of this category\r\n int nextIndex = this.activeInputIndex + 1;\r\n if (tx.inputs.length > nextIndex) {\r\n require(tx.inputs[nextIndex].tokenCategory == tokenSaleCategoryID);\r\n }\r\n\r\n // recreate adminNFT\r\n require(tx.outputs[0].nftCommitment == tx.inputs[0].nftCommitment);\r\n require(tx.outputs[0].lockingBytecode == tx.inputs[0].lockingBytecode);\r\n require(tx.outputs[0].tokenCategory == tx.inputs[0].tokenCategory);\r\n require(tx.outputs[0].tokenAmount == tx.inputs[0].tokenAmount);\r\n require(tx.outputs[0].value >= tx.inputs[0].value - 10000);\r\n\r\n // verify tx limits\r\n require(tx.outputs.length == 1); \r\n }\r\n\r\n //////////////////////////////////////////////////////////////////////////////////////////\r\n //////////////////////////// Reclaim Expired Inputs /////////////////////////////////\r\n//////////////////////////////////////////////////////////////////////////////////////////\r\n// Anyone can reclaim the satoshis from utxos on this contract that have been abandoned for 2 years.\r\n// ------------------------------------------------------------------------------------\r\n//inputs: \r\n// 0+ UTXO [Any] (from TokenSale contract)\r\n//outputs:\r\n// 0 UTXO [BCH] (to anyone)\r\n//////////////////////////////////////////////////////////////////////////////////////////\r\n function reclaim() {\r\n require(this.age >= 105420);\r\n\r\n // verify tx limits\r\n require(tx.outputs.length == 1); \r\n\r\n // enforce output\r\n require(tx.outputs[0].tokenCategory == 0x);\r\n\r\n }\r\n}";
|
|
262
320
|
var debug = {
|
|
263
|
-
bytecode: "
|
|
264
|
-
sourceMap: "50:4:126:4;;;;52:26:52:27;:16::44:1;:58::59:0;:48::76:1;:8::78;53:73:53:74:0;:63::89:1;:96::98:0;:63::99:1;54:39:54:43:0;:8::45:1;57:26:57:27:0;:16::42:1;:8::67;60:34:60:35:0;:24::50:1;:60::62:0;:24::63:1;;:57::59:0;:24::63:1;;61:16:61:27:0;:34::41;:30::42:1;:16;:8::44;64:16:64:32:0;:36::37;:8::39:1;65:16:65:33:0;:37::38;:16:::1;:8::40;67:33:67:35:0;68:23:68:24;70:12:70:19;;:23::27;:12:::1;:29:74:9:0;71:42:71:43;:32::58:1;:65::66:0;:32::67:1;:::70;72:41:72:42:0;:31::57:1;:60::64:0;:31:::1;:12::65;;;;;;;73:27:73:37:0;:23::38:1;:12::39;;70:29:74:9;74:15:85::0;:19:74:26;;:30::34;:19:::1;:36:79:9:0;75:42:75:43;:32::58:1;:67::69:0;:32::70:1;;:65::66:0;:32::70:1;;76:20:76:30:0;:34::48;:20:::1;;:12::50;77:27:77:37:0;:23::38:1;:12::39;;;78:41:78:42:0;:31::57:1;:60::64:0;:31:::1;:12::65;;;;;;;74:36:79:9;79:15:85::0;80:20:80:27;;:31::35;:12::37:1;81:42:81:43:0;:32::58:1;:68::70:0;:32::71:1;;:65::67:0;:32::71:1;;82:20:82:30:0;:34::48;:20:::1;;:12::50;83:27:83:37:0;:23::38:1;:12::39;;;84:41:84:42:0;:31::57:1;:60::64:0;:31:::1;:12::65;;;;;;;79:15:85:9;;74;88:27:88:28:0;:16::43:1;:47::63:0;:8::65:1;89:27:89:28:0;:16::45:1;:59::60:0;:49::77:1;:8::79;90:27:90:28:0;:16::43:1;:57::58:0;:47::73:1;:8::75;91:27:91:28:0;:16::41:1;:55::56:0;:45::69:1;:8::71;92:27:92:28:0;:16::35:1;:49::50:0;:39::57:1;:8::59;95:35:95:36:0;:25::51:1;:55::57:0;:25:::1;96:33:96:34:0;:23::49:1;:63::64:0;:53::79:1;:23;97:16:97:23:0;:27::36;:16:::1;:8::38;100:12:100:19:0;:21::53;:29::46;:50::51;:21::53:1;;101::101:37:0;:32::36;:21::37:1;;104:37:104:38:0;:27::53:1;:63::65:0;:27::66:1;;:60::62:0;:27::66:1;;105:29:105:63:0;:54::62;:29::63:1;;;106:27:106:28:0;:16::45:1;:8::63;107:27:107:28:0;:16::43:1;:47::49:0;:8::51:1;108:27:108:28:0;:16::35:1;:8::49;111:27:111:28:0;:16::35:1;:49::50:0;:39::57:1;:8::59;112:27:112:28:0;:16::45:1;:59::60:0;:49::77:1;:8::79;113:27:113:28:0;:16::43:1;:57::58:0;:47::73:1;:8::75;114:27:114:28:0;:16::41:1;:55::56:0;:45::69:1;:8::71;115:27:115:28:0;:16::43:1;:57::58:0;:47::73:1;:8::75;118:36:118:37:0;:26::44:1;:47::
|
|
321
|
+
bytecode: "76009c6300c751c78800ce01207f528851ce8800cf01137f755f7f77c57c819f69c3539dc454a1690000537951876300cf557f7551cf517e537a757c6b7c6c76817b757767537952876300cf5a7f75557f77760600000000000087916976817b757c51cf527e537a757c6b7c6c75675379538800cf5f7f755a7f77760600000000000087916976817b757c51cf537e537a757c6b7c6c75686851d27b8851cd52c78851d151ce8851d351d09d51cc51c69d52ce008752ce00ce87767b9b697663c4549d686302e803776800cf01277f7501137f770376a9147c7e0288ac7e52cd8852d1008852cc9d00cc00c69d00cd00c78800d100ce8800d300d09d00d200cf8852c652cc940210279400a47602e803a06353cd52c78853d152ce8853d252cf8853cc78a269686d75516776519c63c0009d51ce00ce88c3529dc4529d788277559d52798277559d53798277559d54798277549d00cf01277f7501137f7700d2537a547a7e547a7e547a7e7b7e8800cd00c78800d100ce8800d300d09d00cc00c69d51d251cf8851cd51c78851d151ce8851d351d09d51cc51c602102794a2776776529c6351ce01207f528800ce51ce88c08bc378a06376ce5279886800d200cf8800cd00c78800d100ce8800d300d09d00cc00c602102794a269c4519c77777767539d03cc9b01b275c4519d00d10087686868",
|
|
322
|
+
sourceMap: "50:4:126:4;;;;52:26:52:27;:16::44:1;:58::59:0;:48::76:1;:8::78;53:73:53:74:0;:63::89:1;:96::98:0;:63::99:1;54:39:54:43:0;:8::45:1;57:26:57:27:0;:16::42:1;:8::67;60:34:60:35:0;:24::50:1;:60::62:0;:24::63:1;;:57::59:0;:24::63:1;;61:16:61:27:0;:34::41;:30::42:1;:16;:8::44;64:16:64:32:0;:36::37;:8::39:1;65:16:65:33:0;:37::38;:16:::1;:8::40;67:33:67:35:0;68:23:68:24;70:12:70:19;;:23::27;:12:::1;:29:74:9:0;71:42:71:43;:32::58:1;:65::66:0;:32::67:1;:::70;72:41:72:42:0;:31::57:1;:60::64:0;:31:::1;:12::65;;;;;;;73:27:73:37:0;:23::38:1;:12::39;;70:29:74:9;74:15:85::0;:19:74:26;;:30::34;:19:::1;:36:79:9:0;75:42:75:43;:32::58:1;:67::69:0;:32::70:1;;:65::66:0;:32::70:1;;76:20:76:30:0;:34::48;:20:::1;;:12::50;77:27:77:37:0;:23::38:1;:12::39;;;78:41:78:42:0;:31::57:1;:60::64:0;:31:::1;:12::65;;;;;;;74:36:79:9;79:15:85::0;80:20:80:27;;:31::35;:12::37:1;81:42:81:43:0;:32::58:1;:68::70:0;:32::71:1;;:65::67:0;:32::71:1;;82:20:82:30:0;:34::48;:20:::1;;:12::50;83:27:83:37:0;:23::38:1;:12::39;;;84:41:84:42:0;:31::57:1;:60::64:0;:31:::1;:12::65;;;;;;;79:15:85:9;;74;88:27:88:28:0;:16::43:1;:47::63:0;:8::65:1;89:27:89:28:0;:16::45:1;:59::60:0;:49::77:1;:8::79;90:27:90:28:0;:16::43:1;:57::58:0;:47::73:1;:8::75;91:27:91:28:0;:16::41:1;:55::56:0;:45::69:1;:8::71;92:27:92:28:0;:16::35:1;:49::50:0;:39::57:1;:8::59;95:35:95:36:0;:25::51:1;:55::57:0;:25:::1;96:33:96:34:0;:23::49:1;:63::64:0;:53::79:1;:23;97:16:97:23:0;:27::36;:16:::1;:8::38;100:12:100:19:0;:21::53;:29::46;:50::51;:21::53:1;;101::101:37:0;:32::36;:21::37:1;;104:37:104:38:0;:27::53:1;:63::65:0;:27::66:1;;:60::62:0;:27::66:1;;105:29:105:63:0;:54::62;:29::63:1;;;106:27:106:28:0;:16::45:1;:8::63;107:27:107:28:0;:16::43:1;:47::49:0;:8::51:1;108:27:108:28:0;:16::35:1;:8::49;111:27:111:28:0;:16::35:1;:49::50:0;:39::57:1;:8::59;112:27:112:28:0;:16::45:1;:59::60:0;:49::77:1;:8::79;113:27:113:28:0;:16::43:1;:57::58:0;:47::73:1;:8::75;114:27:114:28:0;:16::41:1;:55::56:0;:45::69:1;:8::71;115:27:115:28:0;:16::43:1;:57::58:0;:47::73:1;:8::75;118:36:118:37:0;:26::44:1;:58::59:0;:47::66:1;:26;:69::74:0;:26:::1;:77::78:0;:21::79:1;120:12:120:18:0;:21::25;:12:::1;:27:125:9:0;121:31:121:32;:20::49:1;:63::64:0;:53::81:1;:12::83;122:31:122:32:0;:20::47:1;:61::62:0;:51::77:1;:12::79;123:31:123:32:0;:20::47:1;:61::62:0;:51::77:1;:12::79;124:31:124:32:0;:20::39:1;:43::49:0;:20:::1;:12::51;120:27:125:9;50:4:126:4;;;;147::178:5:0;;;;149:16:149:37;:41::42;:8::44:1;152:26:152:27:0;:16::42:1;:56::57:0;:46::72:1;:8::74;155:16:155:32:0;:36::37;:8::39:1;156:16:156:33:0;:37::38;:8::40:1;159:16:159:26:0;:::33:1;;:37::38:0;:8::40:1;160:16:160:26:0;;:::33:1;;:37::38:0;:8::40:1;161:16:161:26:0;;:::33:1;;:37::38:0;:8::40:1;162:16:162:23:0;;:::30:1;;:34::35:0;:8::37:1;165:37:165:38:0;:27::53:1;:63::65:0;:27::66:1;;:60::62:0;:27::66:1;;166::166:28:0;:16::43:1;:47::57:0;;:60::70;;:47:::1;:73::83:0;;:47:::1;:86::93:0;;:47:::1;:96::104:0;:47:::1;:8::106;167:27:167:28:0;:16::45:1;:59::60:0;:49::77:1;:8::79;168:27:168:28:0;:16::43:1;:57::58:0;:47::73:1;:8::75;169:27:169:28:0;:16::41:1;:55::56:0;:45::69:1;:8::71;170:27:170:28:0;:16::35:1;:49::50:0;:39::57:1;:8::59;173:27:173:28:0;:16::43:1;:57::58:0;:47::73:1;:8::75;174:27:174:28:0;:16::45:1;:59::60:0;:49::77:1;:8::79;175:27:175:28:0;:16::43:1;:57::58:0;:47::73:1;:8::75;176:27:176:28:0;:16::41:1;:55::56:0;:45::69:1;:8::71;177:27:177:28:0;:16::35:1;:49::50:0;:39::57:1;:60::65:0;:39:::1;:8::67;147:4:178:5;;193::216::0;;;;195:73:195:74;:63::89:1;:96::98:0;:63::99:1;196:39:196:43:0;:8::45:1;199:26:199:27:0;:16::42:1;:56::57:0;:46::72:1;:8::74;202:24:202:45:0;:::49:1;203:12:203:28:0;:31::40;:12:::1;:42:205:9:0;204:30:204:39;:20::54:1;:58::77:0;;:12::79:1;203:42:205:9;208:27:208:28:0;:16::43:1;:57::58:0;:47::73:1;:8::75;209:27:209:28:0;:16::45:1;:59::60:0;:49::77:1;:8::79;210:27:210:28:0;:16::43:1;:57::58:0;:47::73:1;:8::75;211:27:211:28:0;:16::41:1;:55::56:0;:45::69:1;:8::71;212:27:212:28:0;:16::35:1;:49::50:0;:39::57:1;:60::65:0;:39:::1;:16;:8::67;215:16:215:33:0;:37::38;:8::40:1;193:4:216:5;;;;228::237::0;;229:28:229:34;:8::36:1;;232:16:232:33:0;:37::38;:8::40:1;235:27:235:28:0;:16::43:1;:47::49:0;:8::51:1;3:0:238:1;;",
|
|
265
323
|
logs: [
|
|
266
324
|
],
|
|
267
325
|
requires: [
|
|
@@ -362,139 +420,139 @@ var debug = {
|
|
|
362
420
|
line: 115
|
|
363
421
|
},
|
|
364
422
|
{
|
|
365
|
-
ip:
|
|
423
|
+
ip: 251,
|
|
366
424
|
line: 121
|
|
367
425
|
},
|
|
368
426
|
{
|
|
369
|
-
ip:
|
|
427
|
+
ip: 256,
|
|
370
428
|
line: 122
|
|
371
429
|
},
|
|
372
430
|
{
|
|
373
|
-
ip:
|
|
431
|
+
ip: 261,
|
|
374
432
|
line: 123
|
|
375
433
|
},
|
|
376
434
|
{
|
|
377
|
-
ip:
|
|
435
|
+
ip: 266,
|
|
378
436
|
line: 124
|
|
379
437
|
},
|
|
380
438
|
{
|
|
381
|
-
ip:
|
|
439
|
+
ip: 278,
|
|
382
440
|
line: 149
|
|
383
441
|
},
|
|
384
442
|
{
|
|
385
|
-
ip:
|
|
443
|
+
ip: 283,
|
|
386
444
|
line: 152
|
|
387
445
|
},
|
|
388
446
|
{
|
|
389
|
-
ip:
|
|
447
|
+
ip: 286,
|
|
390
448
|
line: 155
|
|
391
449
|
},
|
|
392
450
|
{
|
|
393
|
-
ip:
|
|
451
|
+
ip: 289,
|
|
394
452
|
line: 156
|
|
395
453
|
},
|
|
396
454
|
{
|
|
397
|
-
ip:
|
|
455
|
+
ip: 294,
|
|
398
456
|
line: 159
|
|
399
457
|
},
|
|
400
458
|
{
|
|
401
|
-
ip:
|
|
459
|
+
ip: 300,
|
|
402
460
|
line: 160
|
|
403
461
|
},
|
|
404
462
|
{
|
|
405
|
-
ip:
|
|
463
|
+
ip: 306,
|
|
406
464
|
line: 161
|
|
407
465
|
},
|
|
408
466
|
{
|
|
409
|
-
ip:
|
|
467
|
+
ip: 312,
|
|
410
468
|
line: 162
|
|
411
469
|
},
|
|
412
470
|
{
|
|
413
|
-
ip:
|
|
471
|
+
ip: 336,
|
|
414
472
|
line: 166
|
|
415
473
|
},
|
|
416
474
|
{
|
|
417
|
-
ip:
|
|
475
|
+
ip: 341,
|
|
418
476
|
line: 167
|
|
419
477
|
},
|
|
420
478
|
{
|
|
421
|
-
ip:
|
|
479
|
+
ip: 346,
|
|
422
480
|
line: 168
|
|
423
481
|
},
|
|
424
482
|
{
|
|
425
|
-
ip:
|
|
483
|
+
ip: 351,
|
|
426
484
|
line: 169
|
|
427
485
|
},
|
|
428
486
|
{
|
|
429
|
-
ip:
|
|
487
|
+
ip: 356,
|
|
430
488
|
line: 170
|
|
431
489
|
},
|
|
432
490
|
{
|
|
433
|
-
ip:
|
|
491
|
+
ip: 361,
|
|
434
492
|
line: 173
|
|
435
493
|
},
|
|
436
494
|
{
|
|
437
|
-
ip:
|
|
495
|
+
ip: 366,
|
|
438
496
|
line: 174
|
|
439
497
|
},
|
|
440
498
|
{
|
|
441
|
-
ip:
|
|
499
|
+
ip: 371,
|
|
442
500
|
line: 175
|
|
443
501
|
},
|
|
444
502
|
{
|
|
445
|
-
ip:
|
|
503
|
+
ip: 376,
|
|
446
504
|
line: 176
|
|
447
505
|
},
|
|
448
506
|
{
|
|
449
|
-
ip:
|
|
507
|
+
ip: 384,
|
|
450
508
|
line: 177
|
|
451
509
|
},
|
|
452
510
|
{
|
|
453
|
-
ip:
|
|
511
|
+
ip: 395,
|
|
454
512
|
line: 196
|
|
455
513
|
},
|
|
456
514
|
{
|
|
457
|
-
ip:
|
|
515
|
+
ip: 400,
|
|
458
516
|
line: 199
|
|
459
517
|
},
|
|
460
518
|
{
|
|
461
|
-
ip:
|
|
519
|
+
ip: 411,
|
|
462
520
|
line: 204
|
|
463
521
|
},
|
|
464
522
|
{
|
|
465
|
-
ip:
|
|
523
|
+
ip: 417,
|
|
466
524
|
line: 208
|
|
467
525
|
},
|
|
468
526
|
{
|
|
469
|
-
ip:
|
|
527
|
+
ip: 422,
|
|
470
528
|
line: 209
|
|
471
529
|
},
|
|
472
530
|
{
|
|
473
|
-
ip:
|
|
531
|
+
ip: 427,
|
|
474
532
|
line: 210
|
|
475
533
|
},
|
|
476
534
|
{
|
|
477
|
-
ip:
|
|
535
|
+
ip: 432,
|
|
478
536
|
line: 211
|
|
479
537
|
},
|
|
480
538
|
{
|
|
481
|
-
ip:
|
|
539
|
+
ip: 440,
|
|
482
540
|
line: 212
|
|
483
541
|
},
|
|
484
542
|
{
|
|
485
|
-
ip:
|
|
543
|
+
ip: 444,
|
|
486
544
|
line: 215
|
|
487
545
|
},
|
|
488
546
|
{
|
|
489
|
-
ip:
|
|
547
|
+
ip: 451,
|
|
490
548
|
line: 229
|
|
491
549
|
},
|
|
492
550
|
{
|
|
493
|
-
ip:
|
|
551
|
+
ip: 455,
|
|
494
552
|
line: 232
|
|
495
553
|
},
|
|
496
554
|
{
|
|
497
|
-
ip:
|
|
555
|
+
ip: 460,
|
|
498
556
|
line: 235
|
|
499
557
|
}
|
|
500
558
|
]
|
|
@@ -503,7 +561,7 @@ var compiler = {
|
|
|
503
561
|
name: "cashc",
|
|
504
562
|
version: "0.12.1"
|
|
505
563
|
};
|
|
506
|
-
var updatedAt = "2026-02-
|
|
564
|
+
var updatedAt = "2026-02-10T19:15:57.383Z";
|
|
507
565
|
var contractArtifact = {
|
|
508
566
|
contractName: contractName,
|
|
509
567
|
constructorInputs: constructorInputs,
|
|
@@ -522,7 +580,7 @@ var contractArtifact = {
|
|
|
522
580
|
* @throws Error if validation fails or transaction building fails
|
|
523
581
|
*/
|
|
524
582
|
async function buyNFT(params) {
|
|
525
|
-
const { electrumProvider, usersAddress, ticketMasterUtxo, ticketUtxo, ticketType, isAdmin } = params;
|
|
583
|
+
const { electrumProvider, usersAddress, ticketMasterUtxo: providedTicketMasterUtxo, ticketUtxo, ticketType, isAdmin } = params;
|
|
526
584
|
if (!electrumProvider) {
|
|
527
585
|
throw new Error('Electrum provider not available');
|
|
528
586
|
}
|
|
@@ -531,6 +589,28 @@ async function buyNFT(params) {
|
|
|
531
589
|
provider: electrumProvider,
|
|
532
590
|
addressType: 'p2sh32'
|
|
533
591
|
});
|
|
592
|
+
// If ticketMasterUtxo is not provided or is not a valid Utxo, fetch it from the contract
|
|
593
|
+
let ticketMasterUtxo;
|
|
594
|
+
if (providedTicketMasterUtxo?.token?.category === ticketUtxo.token?.category
|
|
595
|
+
&& providedTicketMasterUtxo?.token?.nft?.capability === 'minting') {
|
|
596
|
+
ticketMasterUtxo = providedTicketMasterUtxo;
|
|
597
|
+
}
|
|
598
|
+
else {
|
|
599
|
+
// Get the contract token address
|
|
600
|
+
const contractTokenAddress = getTokenAddress();
|
|
601
|
+
// Get all UTXOs from the contract token address
|
|
602
|
+
const contractUtxos = await electrumProvider.getUtxos(contractTokenAddress);
|
|
603
|
+
// Filter to find the TicketMaster UTXO with matching category ID
|
|
604
|
+
const matchingCategoryId = ticketUtxo.token?.category;
|
|
605
|
+
if (!matchingCategoryId) {
|
|
606
|
+
throw new Error('ticketUtxo must have a token category');
|
|
607
|
+
}
|
|
608
|
+
ticketMasterUtxo = contractUtxos.find(utxo => utxo.token?.category === matchingCategoryId &&
|
|
609
|
+
utxo.token?.nft?.capability === 'minting');
|
|
610
|
+
if (!ticketMasterUtxo) {
|
|
611
|
+
throw new Error(`No TicketMaster UTXO found for category ${matchingCategoryId}`);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
534
614
|
// Parse TicketMaster commitment to get price and admin address
|
|
535
615
|
const commitment = ticketMasterUtxo.token?.nft?.commitment || '';
|
|
536
616
|
if (commitment.length !== 78) {
|
|
@@ -975,7 +1055,7 @@ async function modifyTokenSale(params) {
|
|
|
975
1055
|
* @throws Error if validation fails or transaction building fails
|
|
976
1056
|
*/
|
|
977
1057
|
async function burn(params) {
|
|
978
|
-
const { electrumProvider, usersAddress, ticketMasterUtxo, userMintingNFT, tickets } = params;
|
|
1058
|
+
const { electrumProvider, usersAddress, ticketMasterUtxo: providedTicketMasterUtxo, userMintingNFT, tickets } = params;
|
|
979
1059
|
if (!electrumProvider) {
|
|
980
1060
|
throw new Error('Electrum provider not available');
|
|
981
1061
|
}
|
|
@@ -984,6 +1064,28 @@ async function burn(params) {
|
|
|
984
1064
|
provider: electrumProvider,
|
|
985
1065
|
addressType: 'p2sh32'
|
|
986
1066
|
});
|
|
1067
|
+
// If ticketMasterUtxo is not provided or is not a valid Utxo, fetch it from the contract
|
|
1068
|
+
let ticketMasterUtxo;
|
|
1069
|
+
if (providedTicketMasterUtxo?.token?.category === userMintingNFT.token?.category
|
|
1070
|
+
&& providedTicketMasterUtxo?.token?.nft?.capability === 'minting') {
|
|
1071
|
+
ticketMasterUtxo = providedTicketMasterUtxo;
|
|
1072
|
+
}
|
|
1073
|
+
else {
|
|
1074
|
+
// Get the contract token address
|
|
1075
|
+
const contractTokenAddress = getTokenAddress();
|
|
1076
|
+
// Get all UTXOs from the contract token address
|
|
1077
|
+
const contractUtxos = await electrumProvider.getUtxos(contractTokenAddress);
|
|
1078
|
+
// Filter to find the TicketMaster UTXO with matching category ID
|
|
1079
|
+
const matchingCategoryId = userMintingNFT.token?.category;
|
|
1080
|
+
if (!matchingCategoryId) {
|
|
1081
|
+
throw new Error('userMintingNFT must have a token category');
|
|
1082
|
+
}
|
|
1083
|
+
ticketMasterUtxo = contractUtxos.find(utxo => utxo.token?.category === matchingCategoryId &&
|
|
1084
|
+
utxo.token?.nft?.capability === 'minting');
|
|
1085
|
+
if (!ticketMasterUtxo) {
|
|
1086
|
+
throw new Error(`No TicketMaster UTXO found for category ${matchingCategoryId}`);
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
987
1089
|
// Get contract address from compiled contract
|
|
988
1090
|
const contractAddr = ticketMasterContract.address;
|
|
989
1091
|
// Creating lockingBytecode for contract address
|
|
@@ -1270,28 +1372,6 @@ async function addSatoshis(params) {
|
|
|
1270
1372
|
return wcTransactionObj;
|
|
1271
1373
|
}
|
|
1272
1374
|
|
|
1273
|
-
// TokenSales_old1 contract addresses
|
|
1274
|
-
//export const AddressTicketMaster = 'bitcoincash:pvh0yat7d2r9nf228fpns3mypydvstq9arftt9qlmma42xeq2eryszkdd99zq'; //address hash: 2ef2757e6a8659a54a3a43384764091ac82c05e8d2b5941fdefb551b20564648
|
|
1275
|
-
//export const AddressTicketMasterToken = 'bitcoincash:rvh0yat7d2r9nf228fpns3mypydvstq9arftt9qlmma42xeq2eryss93vuymt';
|
|
1276
|
-
// TokenSales contract addresses | simplified change fee calculation in purchaseNFT()
|
|
1277
|
-
const AddressTicketMaster = 'bitcoincash:pdmta0t3lmeufrhjlmyxkx3ye648lvr08cdwmy36eqtkj4wzpagg2m4afvzlt'; //address hash: 76bebd71fef3c48ef2fec86b1a24ceaa7fb06f3e1aed923ac8176955c20f5085
|
|
1278
|
-
const AddressTicketMasterToken = 'bitcoincash:rdmta0t3lmeufrhjlmyxkx3ye648lvr08cdwmy36eqtkj4wzpagg2fxpg4rxq';
|
|
1279
|
-
// Ticket Level Descriptions
|
|
1280
|
-
const TICKET_LEVEL_DESCRIPTIONS = {
|
|
1281
|
-
'01': {
|
|
1282
|
-
name: 'Regular',
|
|
1283
|
-
description: 'Regular tickets provide standard access to the event. This is the base level ticket option.'
|
|
1284
|
-
},
|
|
1285
|
-
'02': {
|
|
1286
|
-
name: 'VIP',
|
|
1287
|
-
description: 'VIP tickets offer enhanced benefits including priority access, exclusive areas, and additional perks.'
|
|
1288
|
-
},
|
|
1289
|
-
'03': {
|
|
1290
|
-
name: 'Premium',
|
|
1291
|
-
description: 'Premium tickets provide the highest level of access with all VIP benefits plus additional exclusive features.'
|
|
1292
|
-
}
|
|
1293
|
-
};
|
|
1294
|
-
|
|
1295
1375
|
/**
|
|
1296
1376
|
* Create a new TicketMaster listing
|
|
1297
1377
|
* @param params - CreateListingParams object containing all required parameters
|
|
@@ -1431,39 +1511,6 @@ async function createListing(params) {
|
|
|
1431
1511
|
return wcTransactionObj;
|
|
1432
1512
|
}
|
|
1433
1513
|
|
|
1434
|
-
/**
|
|
1435
|
-
* TokenSales contract addresses
|
|
1436
|
-
* These are the addresses for the TokenSales (TicketMaster) contract
|
|
1437
|
-
*/
|
|
1438
|
-
const DEFAULT_CONTRACT_ADDRESSES = {
|
|
1439
|
-
contract: AddressTicketMaster,
|
|
1440
|
-
token: AddressTicketMasterToken
|
|
1441
|
-
};
|
|
1442
|
-
/**
|
|
1443
|
-
* Get contract address
|
|
1444
|
-
* @returns Contract address
|
|
1445
|
-
*/
|
|
1446
|
-
function getContractAddress() {
|
|
1447
|
-
return AddressTicketMaster;
|
|
1448
|
-
}
|
|
1449
|
-
/**
|
|
1450
|
-
* Get token address
|
|
1451
|
-
* @returns Token address
|
|
1452
|
-
*/
|
|
1453
|
-
function getTokenAddress() {
|
|
1454
|
-
return AddressTicketMasterToken;
|
|
1455
|
-
}
|
|
1456
|
-
/**
|
|
1457
|
-
* Get contract addresses
|
|
1458
|
-
* @returns Object with contract and token addresses
|
|
1459
|
-
*/
|
|
1460
|
-
function getContractAddresses() {
|
|
1461
|
-
return {
|
|
1462
|
-
contract: AddressTicketMaster,
|
|
1463
|
-
token: AddressTicketMasterToken
|
|
1464
|
-
};
|
|
1465
|
-
}
|
|
1466
|
-
|
|
1467
1514
|
/**
|
|
1468
1515
|
* List available tickets for purchase from a TokenSale
|
|
1469
1516
|
* @param params - ListAvailableTicketsParams object containing all required parameters
|