UNPKG

@patchworkdev/common

Version:

Patchwork Development Kit

278 lines (256 loc) 10.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DynamicRefFuncGen = void 0; const generator_1 = require("../generator"); const types_1 = require("../../types"); class DynamicRefFuncGen { gen(schema) { if (schema.hasLiteRef() && schema.liteRefArrayLength(0) === 0) { if (schema.features.includes(types_1.Feature.DYNAMICREFLIBRARY)) { return (0, generator_1.ind)(4, ` function addReference(uint256 ourTokenId, uint64 liteRef) public override { if (!_checkTokenWriteAuth(ourTokenId)) { revert IPatchworkProtocol.NotAuthorized(msg.sender); } PatchworkDynamicRefs.addReference(liteRef, _dynamicLiterefStorage[ourTokenId]); } function addReferenceBatch(uint256 ourTokenId, uint64[] calldata liteRefs) public override { if (!_checkTokenWriteAuth(ourTokenId)) { revert IPatchworkProtocol.NotAuthorized(msg.sender); } PatchworkDynamicRefs.addReferenceBatch(liteRefs, _dynamicLiterefStorage[ourTokenId]); } function removeReference(uint256 ourTokenId, uint64 liteRef) public override { if (!_checkTokenWriteAuth(ourTokenId)) { revert IPatchworkProtocol.NotAuthorized(msg.sender); } PatchworkDynamicRefs.removeReference(liteRef, _dynamicLiterefStorage[ourTokenId]); } function addReference(uint256 tokenId, uint64 liteRef, uint256 targetMetadataId) public override { if (targetMetadataId != 0) { revert UnsupportedMetadataId(); } addReference(tokenId, liteRef); } function removeReference(uint256 tokenId, uint64 liteRef, uint256 targetMetadataId) public override { if (targetMetadataId != 0) { revert UnsupportedMetadataId(); } removeReference(tokenId, liteRef); } function addReferenceBatch(uint256 tokenId, uint64[] calldata liteRefs, uint256 targetMetadataId) public override { if (targetMetadataId != 0) { revert UnsupportedMetadataId(); } addReferenceBatch(tokenId, liteRefs); } function loadReferenceAddressAndTokenId(uint256 ourTokenId, uint256 idx) public view returns (address addr, uint256 tokenId) { uint64 ref = PatchworkDynamicRefs.loadRef(idx, _dynamicLiterefStorage[ourTokenId]); (addr, tokenId) = getReferenceAddressAndTokenId(ref); } function getDynamicReferenceCount(uint256 tokenId) public view override returns (uint256 count) { count = PatchworkDynamicRefs.getDynamicReferenceCount(_dynamicLiterefStorage[tokenId]); } function loadDynamicReferencePage(uint256 tokenId, uint256 offset, uint256 count) public view override returns (address[] memory addresses, uint256[] memory tokenIds) { uint64[] memory refs = PatchworkDynamicRefs.loadRefPage(offset, count, _dynamicLiterefStorage[tokenId]); addresses = new address[](refs.length); tokenIds = new uint256[](refs.length); for (uint256 i = 0; i < refs.length; i++) { (address attributeAddress, uint256 attributeTokenId) = getReferenceAddressAndTokenId(refs[i]); addresses[i] = attributeAddress; tokenIds[i] = attributeTokenId; } }\n\n`); } else { return (0, generator_1.ind)(4, ` function addReference(uint256 ourTokenId, uint64 liteRef) public override { if (!_checkTokenWriteAuth(ourTokenId)) { revert IPatchworkProtocol.NotAuthorized(msg.sender); } // to append: find last slot, if it's not full, add, otherwise start a new slot. DynamicLiteRefs storage store = _dynamicLiterefStorage[ourTokenId]; uint256 slotsLen = store.slots.length; if (slotsLen == 0) { store.slots.push(uint256(liteRef)); store.idx[liteRef] = 0; } else { uint256 slot = store.slots[slotsLen-1]; if (slot >= (1 << 192)) { // new slot (pos 1) store.slots.push(uint256(liteRef)); store.idx[liteRef] = slotsLen; } else { store.idx[liteRef] = slotsLen-1; // Reverse search for the next empty subslot for (uint256 i = 3; i > 0; i--) { if (slot >= (1 << ((i-1) * 64))) { // pos 4 through 2 store.slots[slotsLen-1] = slot | uint256(liteRef) << (i*64); break; } } } } } function addReferenceBatch(uint256 ourTokenId, uint64[] calldata liteRefs) public override { if (!_checkTokenWriteAuth(ourTokenId)) { revert IPatchworkProtocol.NotAuthorized(msg.sender); } // do in batches of 4 with 1 remainder pass DynamicLiteRefs storage store = _dynamicLiterefStorage[ourTokenId]; uint256 slotsLen = store.slots.length; if (slotsLen > 0) { revert AlreadyLoaded(); } uint256 fullBatchCount = liteRefs.length / 4; uint256 remainder = liteRefs.length % 4; for (uint256 batch = 0; batch < fullBatchCount; batch++) { uint256 refIdx = batch * 4; uint256 slot = uint256(liteRefs[refIdx]) | (uint256(liteRefs[refIdx+1]) << 64) | (uint256(liteRefs[refIdx+2]) << 128) | (uint256(liteRefs[refIdx+3]) << 192); store.slots.push(slot); for (uint256 i = 0; i < 4; i++) { store.idx[liteRefs[refIdx + i]] = batch; } } uint256 rSlot; for (uint256 i = 0; i < remainder; i++) { uint256 idx = (fullBatchCount * 4) + i; rSlot = rSlot | (uint256(liteRefs[idx]) << (i * 64)); store.idx[liteRefs[idx]] = fullBatchCount; } store.slots.push(rSlot); } function removeReference(uint256 ourTokenId, uint64 liteRef) public override { if (!_checkTokenWriteAuth(ourTokenId)) { revert IPatchworkProtocol.NotAuthorized(msg.sender); } DynamicLiteRefs storage store = _dynamicLiterefStorage[ourTokenId]; uint256 slotsLen = store.slots.length; if (slotsLen == 0) { revert NotFound(); } uint256 count = getDynamicReferenceCount(ourTokenId); if (count == 1) { if (store.slots[0] == liteRef) { store.slots.pop(); delete store.idx[liteRef]; } else { revert NotFound(); } } else { // remember and remove the last ref uint256 lastIdx = slotsLen-1; uint256 slot = store.slots[lastIdx]; uint64 lastRef; for (uint256 i = 3; i > 0; i--) { uint256 shift = i * 64; if (slot >= (1 << shift)) { // pos 4 through 2 lastRef = uint64(slot >> shift); uint256 mask = ~uint256(0) >> (256 - shift); store.slots[lastIdx] = slot & mask; break; } } if (lastRef == 0) { // pos 1 lastRef = uint64(slot); store.slots.pop(); } if (lastRef == liteRef) { // it was the last ref. No need to replace anything. It's already cleared so just clear the index delete store.idx[liteRef]; } else { // Find the ref and replace it with lastRef then update indexes uint256 refSlotIdx = store.idx[liteRef]; slot = store.slots[refSlotIdx]; uint256 oldSlot = slot; for (uint256 i = 4; i > 0; i--) { uint256 shift = (i-1) * 64; if (uint64(slot >> shift) == liteRef) { uint256 mask = ~(uint256(0xFFFFFFFFFFFFFFFF) << shift); slot = (slot & mask) | (uint256(lastRef) << shift); break; } } if (oldSlot == slot) { revert StorageIntegrityError(); } store.slots[refSlotIdx] = slot; store.idx[lastRef] = refSlotIdx; delete store.idx[liteRef]; } } } function addReference(uint256 tokenId, uint64 liteRef, uint256 targetMetadataId) public override { if (targetMetadataId != 0) { revert UnsupportedMetadataId(); } addReference(tokenId, liteRef); } function removeReference(uint256 tokenId, uint64 liteRef, uint256 targetMetadataId) public override { if (targetMetadataId != 0) { revert UnsupportedMetadataId(); } removeReference(tokenId, liteRef); } function addReferenceBatch(uint256 tokenId, uint64[] calldata liteRefs, uint256 targetMetadataId) public override { if (targetMetadataId != 0) { revert UnsupportedMetadataId(); } addReferenceBatch(tokenId, liteRefs); } function loadReferenceAddressAndTokenId(uint256 ourTokenId, uint256 idx) public view returns (address addr, uint256 tokenId) { uint256[] storage slots = _dynamicLiterefStorage[ourTokenId].slots; uint slotNumber = idx / 4; // integer division will get the correct slot number uint shift = (idx % 4) * 64; // the remainder will give the correct shift uint64 ref = uint64(slots[slotNumber] >> shift); (addr, tokenId) = getReferenceAddressAndTokenId(ref); } function getDynamicReferenceCount(uint256 tokenId) public view override returns (uint256 count) { DynamicLiteRefs storage store = _dynamicLiterefStorage[tokenId]; uint256 slotsLen = store.slots.length; if (slotsLen == 0) { return 0; } else { uint256 slot = store.slots[slotsLen-1]; for (uint256 i = 4; i > 1; i--) { uint256 shift = (i-1) * 64; if (slot >= (1 << shift)) { return (slotsLen-1) * 4 + i; } } return (slotsLen-1) * 4 + 1; } } function loadDynamicReferencePage(uint256 tokenId, uint256 offset, uint256 count) public view override returns (address[] memory addresses, uint256[] memory tokenIds) { uint256 refCount = getDynamicReferenceCount(tokenId); if (offset >= refCount) { return (new address[](0), new uint256[](0)); } uint256 realCount = refCount - offset; if (realCount > count) { realCount = count; } addresses = new address[](realCount); tokenIds = new uint256[](realCount); uint256[] storage slots = _dynamicLiterefStorage[tokenId].slots; // start at offset for (uint256 i = 0; i < realCount; i++) { uint256 idx = offset + i; uint slotNumber = idx / 4; // integer division will get the correct slot number uint shift = (idx % 4) * 64; // the remainder will give the correct shift uint64 ref = uint64(slots[slotNumber] >> shift); (address attributeAddress, uint256 attributeTokenId) = getReferenceAddressAndTokenId(ref); addresses[i] = attributeAddress; tokenIds[i] = attributeTokenId; } }\n\n`); } ; } return ""; } } exports.DynamicRefFuncGen = DynamicRefFuncGen;