|
|
|
@@ -20,7 +20,14 @@
|
|
|
|
|
{ value: 'takaful', label: 'Takaful / insurance nomination', note: 'Nomination as trust under Insurance Act 1996 s.166 (or Takaful equivalent) — pays the named beneficiary directly.' },
|
|
|
|
|
{ value: 'bank-mandate', label: 'Bank death mandate / joint account', note: 'Ask the bank for a death-benefit nomination, or hold as joint account with survivorship.' },
|
|
|
|
|
{ value: 'trust', label: 'Pre-funded trust / nominee holding', note: 'For land or illiquid assets with no nomination bypass — requires setting up a real trust or nominee entity now, while alive.' },
|
|
|
|
|
{ value: 'business-continuity', label: 'Business continuity instrument', note: 'A business dies with its structure by default: a sole proprietorship dies with the owner, a partnership dissolves on any partner\'s death unless the agreement says otherwise, and company shares fall into probate like any other asset unless a buy-sell or shareholder agreement already routes them.' }
|
|
|
|
|
{ value: 'business-continuity', label: 'Business continuity instrument', note: 'A business dies with its structure by default: a sole proprietorship dies with the owner, a partnership dissolves on any partner\'s death unless the agreement says otherwise, and company shares fall into probate like any other asset unless a buy-sell or shareholder agreement already routes them.' },
|
|
|
|
|
{ value: 'digital-custody', label: 'Digital custody plan', note: 'A single seed phrase known only to you is not a fast path — it is a total-loss risk if you die without sharing it. Use the exchange\'s own beneficiary feature where one exists, or a multi-sig / key-escrow arrangement with your executor for self-custody wallets.' }
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const CUSTODY_TYPES = [
|
|
|
|
|
{ value: 'exchange-beneficiary', label: 'Custodial exchange beneficiary feature', warning: null },
|
|
|
|
|
{ value: 'multisig', label: 'Self-custody multi-sig wallet', warning: 'Multi-sig only works if the co-signers are set up and able to act now — an executor who is a co-signer can release funds without waiting for probate, but only if the wallet was actually configured this way while you were alive.' },
|
|
|
|
|
{ value: 'key-escrow', label: 'Key-escrow with executor', warning: 'Never store the actual seed phrase or private key in this app or any single record your executor can\'t independently verify. This field should reference WHERE the key is escrowed (e.g. a sealed instruction with a lawyer, a hardware device with split-knowledge access) — not the key itself.' }
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const BUSINESS_STRUCTURES = [
|
|
|
|
@@ -34,7 +41,7 @@
|
|
|
|
|
{ value: 'waqf-enterprise', label: 'Dedicate as waqf-owned enterprise', note: 'Use the Family Waqf Designator for this instead — a waqf-owned enterprise survives you and serves your purpose in perpetuity, same as any other waqf corpus.' }
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const emptyForm = () => ({ linkedAssetId: '', type: 'epf', institution: '', nomineeeName: '', referenceNumber: '', trusteeName: '', successorTrustee: '', trustBeneficiaries: '', businessStructure: 'company', businessInstrument: 'shareholder-buy-sell', successorOwner: '', buySellTerms: '' });
|
|
|
|
|
const emptyForm = () => ({ linkedAssetId: '', type: 'epf', institution: '', nomineeeName: '', referenceNumber: '', trusteeName: '', successorTrustee: '', trustBeneficiaries: '', businessStructure: 'company', businessInstrument: 'shareholder-buy-sell', successorOwner: '', buySellTerms: '', custodyType: 'exchange-beneficiary', platform: '', keyHolderName: '', accessInstructionsRef: '' });
|
|
|
|
|
|
|
|
|
|
let nominations = $state(load('nominations', []));
|
|
|
|
|
let form = $state(emptyForm());
|
|
|
|
@@ -46,6 +53,8 @@
|
|
|
|
|
} else if (form.type === 'business-continuity') {
|
|
|
|
|
if (form.businessInstrument === 'waqf-enterprise') return; // redirect only, nothing to save here
|
|
|
|
|
if (!form.successorOwner) return;
|
|
|
|
|
} else if (form.type === 'digital-custody') {
|
|
|
|
|
if (!form.keyHolderName) return;
|
|
|
|
|
} else if (!form.nomineeeName) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
@@ -85,6 +94,37 @@
|
|
|
|
|
URL.revokeObjectURL(url);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function exportDigitalCustody(n) {
|
|
|
|
|
const asset = assets.find(a => a.id === n.linkedAssetId);
|
|
|
|
|
const custodyLabel = CUSTODY_TYPES.find(c => c.value === n.custodyType)?.label;
|
|
|
|
|
const lines = [
|
|
|
|
|
'DIGITAL CUSTODY PLAN — DRAFTING AID',
|
|
|
|
|
`Generated: ${new Date().toISOString().slice(0, 10)}`,
|
|
|
|
|
`Asset: ${asset ? asset.description : '(asset removed)'}`,
|
|
|
|
|
`Platform / wallet: ${n.platform || '________________________'}`,
|
|
|
|
|
`Custody type: ${custodyLabel}`,
|
|
|
|
|
`Key holder / executor: ${n.keyHolderName}`,
|
|
|
|
|
`Access instructions reference: ${n.accessInstructionsRef || '________________________'}`,
|
|
|
|
|
'',
|
|
|
|
|
n.custodyType === 'exchange-beneficiary'
|
|
|
|
|
? 'ACTION: File the death claim directly with the exchange/custodial platform using\nits own beneficiary/inheritance feature. This is a platform process, not a\nprobate filing — confirm the feature is actually activated on the account now,\nwhile you\'re alive, not assumed to exist.'
|
|
|
|
|
: n.custodyType === 'multisig'
|
|
|
|
|
? 'ACTION: The named co-signer(s) release funds per the wallet\'s multi-sig\nconfiguration once death is confirmed. This only works if the multi-sig was\nactually set up with a living co-signer — a single-key wallet has no fast path\nat all.'
|
|
|
|
|
: 'ACTION: Retrieve the escrowed access instructions from wherever they are held\n(named above) and follow them to access the wallet. This app does not, and must\nnot, store the seed phrase or private key itself.',
|
|
|
|
|
'',
|
|
|
|
|
'WARNING: never enter an actual seed phrase, private key, or password into this',
|
|
|
|
|
'app or any single document. This drafting aid should only ever reference WHERE',
|
|
|
|
|
'access is arranged, never the credential itself.',
|
|
|
|
|
'',
|
|
|
|
|
'DISCLAIMER: Not a fatwa. Not legal advice. Drafting aid only.'
|
|
|
|
|
];
|
|
|
|
|
const blob = new Blob([lines.join('\n')], { type: 'text/plain' });
|
|
|
|
|
const url = URL.createObjectURL(blob);
|
|
|
|
|
const a = document.createElement('a');
|
|
|
|
|
a.href = url; a.download = 'digital-custody-plan-draft.txt'; a.click();
|
|
|
|
|
URL.revokeObjectURL(url);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function exportTrustDeed(n) {
|
|
|
|
|
const asset = assets.find(a => a.id === n.linkedAssetId);
|
|
|
|
|
const lines = [
|
|
|
|
@@ -178,12 +218,26 @@
|
|
|
|
|
<label class="field"><span>Terms</span><input type="text" bind:value={form.buySellTerms} placeholder="e.g. valuation method, Takaful-funded buyout" /></label>
|
|
|
|
|
{/if}
|
|
|
|
|
</div>
|
|
|
|
|
{:else if form.type === 'digital-custody'}
|
|
|
|
|
<div class="trust-fields">
|
|
|
|
|
<label class="field"><span>Platform / wallet</span><input type="text" bind:value={form.platform} placeholder="e.g. Coinbase, Ledger self-custody" /></label>
|
|
|
|
|
<label class="field"><span>Custody type</span>
|
|
|
|
|
<select bind:value={form.custodyType}>
|
|
|
|
|
{#each CUSTODY_TYPES as c}<option value={c.value}>{c.label}</option>{/each}
|
|
|
|
|
</select>
|
|
|
|
|
</label>
|
|
|
|
|
{#if CUSTODY_TYPES.find(c => c.value === form.custodyType)?.warning}
|
|
|
|
|
<p class="business-warning">{CUSTODY_TYPES.find(c => c.value === form.custodyType).warning}</p>
|
|
|
|
|
{/if}
|
|
|
|
|
<label class="field"><span>Key holder / executor</span><input type="text" bind:value={form.keyHolderName} /></label>
|
|
|
|
|
<label class="field"><span>Access instructions reference (never the actual key)</span><input type="text" bind:value={form.accessInstructionsRef} placeholder="e.g. sealed letter with lawyer X, ref #123" /></label>
|
|
|
|
|
</div>
|
|
|
|
|
{:else}
|
|
|
|
|
<label class="field"><span>Institution</span><input type="text" bind:value={form.institution} placeholder="e.g. KWSP, Bank Islam, Takaful Ikhlas" /></label>
|
|
|
|
|
<label class="field"><span>Nominee name</span><input type="text" bind:value={form.nomineeeName} /></label>
|
|
|
|
|
<label class="field"><span>Reference / policy / account number</span><input type="text" bind:value={form.referenceNumber} /></label>
|
|
|
|
|
{/if}
|
|
|
|
|
<button class="btn-primary" disabled={form.type === 'business-continuity' && form.businessInstrument === 'waqf-enterprise'} onclick={addNomination}>Add {form.type === 'trust' ? 'trust setup' : form.type === 'business-continuity' ? 'business continuity instrument' : 'nomination'}</button>
|
|
|
|
|
<button class="btn-primary" disabled={form.type === 'business-continuity' && form.businessInstrument === 'waqf-enterprise'} onclick={addNomination}>Add {form.type === 'trust' ? 'trust setup' : form.type === 'business-continuity' ? 'business continuity instrument' : form.type === 'digital-custody' ? 'digital custody plan' : 'nomination'}</button>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{#each nominations as n (n.id)}
|
|
|
|
@@ -192,13 +246,16 @@
|
|
|
|
|
<div class="nomination-row">
|
|
|
|
|
<div class="nomination-info">
|
|
|
|
|
<strong>{asset ? asset.description : '(asset removed)'}</strong>
|
|
|
|
|
<span class="muted">{channelInfo?.label}{n.type !== 'trust' && n.type !== 'business-continuity' ? ` · ${n.institution || '—'}` : ''}</span>
|
|
|
|
|
<span class="muted">{channelInfo?.label}{!['trust', 'business-continuity', 'digital-custody'].includes(n.type) ? ` · ${n.institution || '—'}` : ''}</span>
|
|
|
|
|
{#if n.type === 'trust'}
|
|
|
|
|
<span class="muted">Trustee: {n.trusteeName} · Successor: {n.successorTrustee || '—'}</span>
|
|
|
|
|
<span class="muted">Beneficiaries: {n.trustBeneficiaries || '—'}</span>
|
|
|
|
|
{:else if n.type === 'business-continuity'}
|
|
|
|
|
<span class="muted">{BUSINESS_INSTRUMENTS.find(i => i.value === n.businessInstrument)?.label}</span>
|
|
|
|
|
<span class="muted">Successor: {n.successorOwner} · Terms: {n.buySellTerms || '—'}</span>
|
|
|
|
|
{:else if n.type === 'digital-custody'}
|
|
|
|
|
<span class="muted">{CUSTODY_TYPES.find(c => c.value === n.custodyType)?.label} · {n.platform || '—'}</span>
|
|
|
|
|
<span class="muted">Key holder: {n.keyHolderName}</span>
|
|
|
|
|
{:else}
|
|
|
|
|
<span class="muted">Nominee: {n.nomineeeName} · Ref: {n.referenceNumber || '—'}</span>
|
|
|
|
|
{/if}
|
|
|
|
@@ -206,6 +263,7 @@
|
|
|
|
|
<div class="row-actions">
|
|
|
|
|
{#if n.type === 'trust'}<button class="export-btn" onclick={() => exportTrustDeed(n)}>Export</button>{/if}
|
|
|
|
|
{#if n.type === 'business-continuity'}<button class="export-btn" onclick={() => exportBusinessContinuity(n)}>Export</button>{/if}
|
|
|
|
|
{#if n.type === 'digital-custody'}<button class="export-btn" onclick={() => exportDigitalCustody(n)}>Export</button>{/if}
|
|
|
|
|
<button onclick={() => remove(n.id)}>✕</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|