The GenoBank DNA Kit Activation system allows users to activate their DNA collection kits and mint BioNFTsβ’ on Story Protocol. The system supports two activation methods:
βββββββββββββββββββββββ βββββββββββββββββββββββ βββββββββββββββββββββββ
β β β β β β
β Laboratory/Lab ββββββΆβ GenoBank API ββββββΆβ Story Protocol β
β β β β β β
βββββββββββββββββββββββ βββββββββββββββββββββββ βββββββββββββββββββββββ
β β β
β 1. Create β 3. Validate β 4. Mint
β Magic Link β & Store β BioNFT
β β β
βΌ βΌ βΌ
βββββββββββββββββββββββ βββββββββββββββββββββββ βββββββββββββββββββββββ
β β β β β β
β DNA Kit with ββββββΆβ Activation Page ββββββΆβ BioNFTβ’ β
β Magic URL β β (Passkey Auth) β β β
β β β β β β
βββββββββββββββββββββββ βββββββββββββββββββββββ βββββββββββββββββββββββ
β β
β 2. User Clicks β
β Magic URL β
βββββββββββββββββββββββββββββ
POST https://genobank.app/create_magic_link
// Request
{
signature: "0x...", // Lab's Web3 signature
data: {
"prefix": "100",
"biosampleId": "55052008714049",
"physicalId": "10055052008714049",
"packageHashCode": "2xuE-AXCa-Z3D-tQb",
"domain": "https://genobank.io"
}
}
// Response
{
"url": "https://genobank.io/activate/?biosampleId=55052008714049&laboratoryId=39&physicalId=10055052008714049#67d6516e1229eee318e5032776377b639f1c2ee2fe93531164bf5706d56fdcf1"
}
https://genobank.io/activate/?
biosampleId=55052008714049& // Kit serial number
laboratoryId=39& // Lab/Permittee ID
physicalId=10055052008714049 // Physical kit ID
#67d6516e1229eee3... // HMAC-SHA256 secret
# Server-side HMAC generation
secret = hmac.new(
BIOSAMPLE_ACTIVATION_SECRET.encode('utf-8'),
str(biosampleId).encode(),
digestmod='sha256'
).hexdigest()
Pre-registered kits appear in the activation registry:
GET https://genobank.app/biosample_activations
// Response
{
"data": [{
"serial": 55052008714049,
"permitteeSerial": "39",
"physicalId": "10055052008714049",
"createdAt": "2025-03-12 18:45:08.580000",
"manufacturer": "DNA Genotek"
}]
}
The system uses Privy for passkey authentication:
// Configuration
const privy = new Privy({
appId: 'cmc5jn5sh01wel10ng0x5atlt',
config: {
loginMethods: ['passkey', 'email', 'google', 'apple'],
appearance: {
theme: 'light',
accentColor: '#667eea'
}
}
});
/recover?signature={sig}
/activate/passkey-activation.html
/activate/passkey-activate.js
// Check for magic URL on page load
function checkMagicLinkActivation() {
const urlParams = new URLSearchParams(window.location.search);
const biosampleId = urlParams.get('biosampleId');
const laboratoryId = urlParams.get('laboratoryId');
const physicalId = urlParams.get('physicalId');
const secret = window.location.hash.substring(1);
if (biosampleId && secret) {
window.magicLinkData = {
biosampleId,
laboratoryId,
physicalId,
secret
};
}
}
// Authenticate with passkey
async function authenticateWithPrivy() {
const user = await privy.login();
const wallet = await privy.getEmbeddedWallet();
const signature = await wallet.signMessage("I want to proceed");
// Store credentials
localStorage.setItem('user_sign', signature);
localStorage.setItem('user_address', wallet.address);
}
// Activate kit
async function activateKit() {
if (window.magicLinkData) {
// Use existing /claim endpoint
const tokenId = generateTokenId(biosampleId, walletAddress);
await fetch(`/claim/${tokenId}`, {
method: 'POST',
body: JSON.stringify({
secret: window.magicLinkData.secret,
physicalId: window.magicLinkData.physicalId,
laboratoryId: window.magicLinkData.laboratoryId
})
});
} else {
// Use new activation endpoint
await fetch(`/api_activation/`, {
method: 'POST',
body: JSON.stringify({
user_signature: userSignature,
barcode: currentBarcode,
manufacturer: detectManufacturer(currentBarcode).name
})
});
}
}
The system leverages existing GenoBank infrastructure:
# /production_api/plugins/activation/api_activate_kit.py
class ApiActivateKit:
def __init__(self):
self.signature_service = SignatureService()
self.biosample_service = BiosampleService()
self.biosample_dao = BiosampleDAO()
self.story_protocol = StoryIpManagerDAO()
@cherrypy.expose
def index(self):
# 1. Verify signature
wallet = self.signature_service.recover_from_signature(user_signature)
# 2. Create biosample record
biosample_data = {
"serial": barcode,
"owner": wallet,
"manufacturer": manufacturer,
"status": "ACTIVE"
}
# 3. Mint BioNFT on Story Protocol
mint_result = self.story_protocol.mint_and_register_ip({
"collection_address": self.biosample_collection,
"recipient": wallet,
"metadata_uri": metadata_uri
})
# 4. Save to database
self.biosample_dao.create(biosample_data)
POST /create_magic_link
Headers: Content-Type: application/json
Body: {
"signature": "0x...",
"data": {
"biosampleId": "55052008714049",
"physicalId": "10055052008714049",
"domain": "https://genobank.io"
}
}
POST /claim/{tokenId}
Headers: Content-Type: application/json
Body: {
"secret": "67d6516e1229eee3...",
"physicalId": "10055052008714049",
"laboratoryId": "39"
}
POST /api_activation/
Headers: Content-Type: application/json
Body: {
"user_signature": "0x...",
"barcode": "55052008714049",
"manufacturer": "DNA Genotek"
}
GET /recover?signature={signature}
Response: {
"wallet_address": "0x...",
"user": {...}
}
GET /biosample_activations?serial={serial}
Response: {
"data": [{
"serial": 55052008714049,
"permitteeSerial": "39",
"physicalId": "10055052008714049"
}]
}
# Visit with magic URL
https://genobank.io/activate/passkey-activation.html?biosampleId=55052008714049&laboratoryId=39&physicalId=10055052008714049#secret
# Should:
- Pre-fill barcode field
- Detect magic link
- Use /claim endpoint
# Visit directly
https://genobank.io/activate/passkey-activation.html
# Should:
- Show empty barcode field
- Accept any valid barcode
- Use /api_activation endpoint
// Valid formats
41221040804049 // DNA Genotek (412 prefix)
42221040804049 // Spectrum DNA (422 prefix)
43221040804049 // Mawi DNA (432 prefix)
55052008714049 // GenoBank Standard (550 prefix)
/biosamples?serial={serial}
Enable console logging:
// In browser console
localStorage.setItem('debug', 'true');
// Check stored data
console.log('Magic Link Data:', window.magicLinkData);
console.log('User Wallet:', localStorage.getItem('user_address'));
console.log('User Signature:', localStorage.getItem('user_sign'));
All errors display user-friendly messages:
function showError(message) {
const errorEl = document.getElementById('error-message');
errorEl.textContent = message;
errorEl.style.display = 'block';
setTimeout(() => errorEl.style.display = 'none', 5000);
}
Detected by barcode prefix (first 3 digits):
Prefix | Manufacturer | Kit Type |
---|---|---|
412 | DNA Genotek | Saliva Collection |
422 | Spectrum DNA | Saliva Collection |
432 | Mawi DNA | Saliva Collection |
442 | Norgen Biotek | Saliva Collection |
452 | Zymo Research | Saliva Collection |
550 | GenoBank Standard | Standard Kit |
For technical support:
/static/Genobank_API_Educational_Guide.html
This implementation is part of the GenoBank platform and subject to GenoBankβs terms of service.