Skip to content

Instantly share code, notes, and snippets.

@zarutian

zarutian/000.md Secret

Last active January 30, 2024 02:35
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zarutian/6ac6b7576af041dd5dc5b95f1f8d1f0f to your computer and use it in GitHub Desktop.
Save zarutian/6ac6b7576af041dd5dc5b95f1f8d1f0f to your computer and use it in GitHub Desktop.
Various smart contracts (see https://github.com/Agoric/agoric-sdk/issues/395 )

Index:

  1. Cascade Contract

  2. Payment Driven Counter

    Provides a kind of TimerService, which is driven onward with payment into it. A reversal of the adage, time is money, so to speak.

  3. Loan with collateral

  4. Namespace Contract.

    A bit like single level dns but for mapping human memorable names to objects. Only creator can register unassigned names. After that, those names can be traded.

  5. Proportional Spliter - payins are split proportionally and paid out to partcipants. TBD: percentagewise? by ratios?

  6. Junk bin

  7. Interlock

    Basically works like an safety key interlock. What are those? A device with key retaining locks where the master(s) controling one frees the others to be used to unlock, say, electrical cabinat while capturing the master(s). See https://youtube.com/watch?v=7fkeOPQK6Vc for an example. Perhaps handy in governence smart contracts. (Impl.note: the „keys“ would be non-fungible tokens possibly issued by a mint internal to this smart contract)

  8. Assurance contract.

    At deadline ( terms.deadline and terms.timer ) either payes out to beneficiary ( a seat ) if and only if certain minimum amount ( terms.minimumAmount ) has been deposited ( publicFacet.getDepositInvitation() ). Otherwise depositors get refunded. ( publicFacet.subscribeToDepositedAmount() see @agoric/notifier/subscriber-kit, finishes when deadline is reached by timer ) ( {utf8-string} terms.purpose what the assurance contract is for. (tbdecided: terms.description instead?)) A version of this where there is no deadline but depositors can exit() out at anytime. Then the beneficiary gets payout the moment a deposit occurs and the minimum is reached.

  9. Assurance Art Asset contract.

    Builds on Assurance contract but requires an minimally trusted third parties off (public) chain or otherwise off the non-veiled computation substrate. Those third parties are running each a clueless software agent spefic to both them and this contract. The CSAs are of the form: basic_csa(««depositAmountSubscription» >= «minAmount»», n-of-m_csa(«(tbdesigned: some sort of nonces both revealed and sent via the smart contract)», onlyBefore_csa(«csa_timeService, p-value, expiryTimestamp», «payload: jsE.sendOnly(aRevaltoryFacet).reveal(«artAssetDecryptionKeyShare») plus some payment to the third party for their trouble))) Like with the deadline less version of assurance contract, the onlyBefore_csa() is omitted out. The art asset is encrypted and kept off chain and out of the contract. When minimum amount is reached (at deadline or optionally not) the decryption key is revealed. This contract would be handy for web comic authors or authors that write serialized stories, or other such where interested parties can combine their fidicuary disposable cash to assure that the author/artist(s) get paid.

  10. Smart contract to implement fractionalization of NFTs.

    Example: Own a millionth of a MoonCat NFT

  11. Lotto contract

  12. Motovator contract.

    Lets say you want to get into a habbit of doing something spefic. You ask your friend(s) (tbd: support quorum monotonic logic circuit or such for weighting inputs? jsonlogic encoded?) to pull the trigger iff you do not which results in ERTP assets locked in the contract to be donated to a company/polity/charity/entity you do not like. At some later date (and/or condition) these get returned to you. Basically like a swearing jar whose tips will go to cause you dislike.

  13. This is a contract that handles "cheques" in the form of certificates


Design musings and such.

--- 2020-09-24 02:50Z ---

Been noticing a bit of a pattern where there will be repeated payments through a contract. I am tentitively calling it the coinslot pattern. This might be rarefied into two faceted object. The facets being the frontside, the payer facet, and the backside, the payee facet. Still mulling on it though.

Zarutian

--- 2020-11-15 06:30Z ---

Það er spurning um að skella ActiveCapCert túlk inn í tveggja kera snjallsamning. Ytra kerið er utan um langlíft tilvik snjallsamningsins og heldur utan um dreifilykkla, handoff tables, og aðgang að board. Innri ker eru tilvikuð þegar cert koma inn og hvert ker sér um eitt "umslagar" cert. (tbd: eða bara um eitt cert hver). Spurning um að nota bara seqblock eða þá Agoric/justin fyrir kóða og openpgp.js og eða jwt(pubkey) eða það sem myetherwallet notar fyrir stafrænar undirskriftir og dreifilykkla. Væri hentugt fyrir DTN og sneakernet high latency notkun.

-Zarutian.

--- 2021-10-26 ---

Fyrir innsigluð tilboð í sealed bid uppboði mætti nota þetta:

Tveggja parta Trent (trusted third party). Einn parturinn er ker á keðju en annar er SMPC sequential boolean logic rás.

Keðjukerið er escrow sjóður sem keðjunóður votta um innlagnir og úttektir til SMPC hlutans.

Hægt er via public facet að fá invitation sem býr til úttektarsæti. Öll úttektarsæti eru númeruð og þekkt.

Við innlögn þarf einn af undirskriftar dreifilyklum innleggjarans að vera tilgreindur.

Einkalykilinn sem er af því lyklapari er svo notaður til að skrifa undir úttektarsætisval.

Það undirskrifaða val er síðan secret shared (random sum frá SMPC made simple) til SMPC nóðanna sem eitt af inntaks gildum fyrir SMPC rásina.

Þegar SMPC rásin sér loks valið þá gefur hún keðjukers partinum skipun um að búa til innlagnar seðil (NFT) og setja hann í það sæti.

Úttekt er á sama máta nema innlagnar seðillinn er breytt aftur í hvað sem það var sem var lagt inn í upphafi.

Slíkir seðlar hafa raðnúmer sem hægt er að nota til að spyrja hvort tveir seðlar séu fyrir jafn miklum verðmætum eða hvor þeirra sé verðmætari.

Verst að AmountMath er ekki Far eins og var í upphaflegri hönnun ERTP og því vesen með að innleiða þetta í venjulega snjallsamninga svo sem uppboð. (Var fyrst E(issuer).getAmountMath()js minnir mig en er nú annað hvort E(issuer).getAssetKind() eða E.get(E(brand).getDisplayInfo()).AssetKind sem AmountMath fær sem inntak til að velja mathHelper sem AmountMath notar síðan)

-Zarutian

2023-02-03T07:20Z

Hmm... væri hægt að hafa útgáfu af þessum Trent þar sem þátttakendur geta lagt inn áður en innlagnar frestur uppboðs er liðinn (eða sá frestur er lokið af uppboðs snjallsamninginum). Fresturinn verður að vera úti áður enn uppboð hefst.

Þáværi hægt að nota custom mathHelper sem ber saman gildi innlagnarseðlanna á eftirfarandi hátt:

Hvert gildi er raðnúmer seðils og saltedCryptoHashSet af öllum þeim raðnúmerum sem þetta gildi er GreaterThanOrEqual. (söltunin er per seðilsins)

Sé raðnúmer seðils A í hashSetti seðils B þá er gildi seðils B hærra eða jafnt gildi seðils A.

Sé svo ekki þá er gildi seðils B lægra en gildi seðils A.

Handy references:

// Disclaimer: Use at your own risk! -Zarutian
import harden from "@agoric/harden";
import { E } from "@agoric/eventual-send";
import { makePromiseKit } from "@agoric/promise";
/**
* @typedef Tier
* @property {boolean} inviteGiven
* @property {number} priority
* @property {Amount} amount
* @property {ZoeInvitation} payeeInvite
* @property {ZcfSeat} payeeSeat
* @property {PromiseResolver} resolver
* @property {Amount} totalAmountPaid
*/
/** @type {ContractStartFn} */
const start = (zcf, privateArgs) => {
const terms = zcf.getTerms();
const currency = terms.issuers.Currency;
const reiknir = zcf.getAmountMath(zcf.getBrandForIssuer(currency));
/** @type {Tier[]} */
const tiers = terms.tiers.map((can, idx) => {
const tier = { inviteGiven: false, priority: idx, amount: can.amount };
tier.totalAmountPaid = reiknir.getEmpty();
const makePayeeInvite = () => {
tier.payeeInvite = zcf.makeInvitation((payeeSeat) => {
tier.payeeSeat = payeeSeat;
let updateCount = undefined;
const recurr = () => {
E(E(tier.payeeSeat).getNotifier()).getUpdateSince(updateHandle).then((update) => {
if (tier.payeeSeat.hasExited()) {
tier.resolver.resolve(
harden({ invite: makePayeeInvite() })
);
} else {
updateCount = update.updateCount;
recurr();
}
});
}
tier.inviteGiven = true;
tier.payeeInvite = undefined;
const { promise, resolver } = makePromiseKit();
tier.resolver = resolver;
return promise;
},
"cascadeTierInvitation",
harden({
amount: can.amount,
priority: idx
}));
return tier.payeeInvite;
}
makePayeeInvite();
return tier;
});
const payIntoHandler = (payingSeat) => {
let currAmount = payingSeat.getProposal().give.Currency;
const payeeStagings = []; // FlexList
const payeeSeats = []; // FlexList
tiers.filter((tier) => tier.inviteGiven)).forEach(
(tier) => {
if (reiknir.isEmpty(currAmount)) { return; }
const amount = reiknir.isGTE(tier.amount, currAmount) ? currAmount : tier.amount ;
const newAlloc = harden({ Currency: amount });
if (tier.payeeSeat.isOfferSafe(newAlloc)) {
currAmount = reiknir.subtract(currAmount, amount);
payeeStagings.push(tier.payeeSeat.stage(newAlloc));
payeeSeats.push(tier.payeeSeat);
tier.totalAmountPaid = reiknir.add(tier.totalAmountPaid, amount);
} else {
tier.payeeSeat.fail("Ya asked for too much");
}
}
);
const payerStaging = payerSeat.stage(harden({ Currency: currAmount }));
zcf.reallocate(payeeStagings.concat(payerStaging));
payeeSeats.forEach((ps) => ps.exit());
payingSeat.exit();
return "Done";
}
const creatorFacet = Far("creatorFacet", {
makePayIntoOffer: () => zcf.makeInvitation(payIntoHandler, "payIntoCascade"),
getCascadePayeeUnclaimedInvites: () => harden(tiers.filter((tier) => !tier.inviteGiven).map((tier) => tier.payeeInvite)),
shutdown: () => harden({
confirmShutdown: () => zcf.shutdown()
})
});
const publicFacet = Far("publicFacet", {
getTotalAmountsPaidOut: () => harden(tiers.map((tier) => tier.totalAmountPaid))
});
return harden({ creatorFacet, publicFacet });
}
harden(start);
export { start };
// @ts-check
// handwritten bundle, not usually done
// See https://gist.github.com/zarutian/2c3b0789b71c7599ec9515f0d50da04f for explainer on ActiveCapCerts.
const modules = new Map();
const moduleFuncs = new Map();
const { innerRequire, moduleExists } = (() => {
const outerRequire = require; // capture require before it gets shadowed
const innerRequire = async (moduleSpecifier) => {
if (modules.has(moduleSpecifier)) {
return modules.get(moduleSpecifier);
}
if (moduleFuncs.has(moduleSpecifier)) {
const exports = await (moduleFuncs.get(moduleSpecifier))();
modules.set(moduleSpecifier, exports);
return exports;
}
return outerRequire(moduleSpecifier);
};
const moduleExists = (moduleSpecifier) => {
const exports = outerRequire(moduleSpecifier);
return (Object.entries(exports).length > 0);
}
return { innerRequire, moduleExists };
})();
const require = innerRequire; // shadow require in this scope
moduleFuncs.set("@zarutian/SingleAssignMap", async () => {
let exports = {};
const module = { exports };
const { harden } = await require("@agoric/harden");
exports.makeSingleAssignMap = (iterable) => {
const backing = new Map(iterable);
return harden({
has: (key) => backing.has(key),
get: (key) => backing.get(key),
set: (key, item) => {
if (backing.has(key)) {
throw new Error("key in SingleAssignMap has already been assigned a value");
}
return backing.set(key, item);
},
delete: (key) => { throw new Error("keys can not be removed from SingleAssignMap once asigned a value"); }
[Symbol.iterator]: () => backing[Symbol.iterator](),
keys: () => backing.keys(),
values: () => backing.values(),
entries: () => backing.entries(),
});
}
return module.exports;
});
moduleFuncs.set("@zarutian/seqBlock", async () => {
let exports = {};
const { makeSingleAssignMap } = await require("@zarutian/SingleAssignMap");
const { E, Far } = await require("@endo/eventual-send");
const makeSeqBlock = (sequenceBlock, environ = {}) => {
return (...sb_args) => {
const results = makeSingleAssignMap();
let lastQId = undefined;
const i = (it) => {
switch (it[0]) {
case "@qid": return results.get(it[1]);
case "@sba": return sb_args[it[1]];
case "@ref": // fallthrough
case "@dat": return it[1];
case "@arr": return it.slice(1).map(i);
case "@rec": return Object.fromEntries(i(it[1]));
case "@env":
if (it.length === 1) {
return environ;
} else {
return it.slice(1).reduce((acc, idx) => acc[i(idx)], environ);
}
case "@sqb": return makeSeqBlock(i(it[1]), i(it[2]));
default: throw new Error("i(): no such it[0] recognized");
}
}
Array.prototype.forEach.apply(sequenceBlock, (form) => {
const [first, ...rest] = form;
switch (first) {
case "applyMethodSendOnly": {
const [target, verb, args] = rest;
E.sendOnly(i(target))[verb](i(args));
}; break;
case "applyMethod": {
const [qid, target, verb, args] = rest;
const result = E(i(target))[verb](i(args));
results.set(qid, result);
lastQId = qid;
}; break;
case "applyFunctionSendOnly": {
const [target, args] = rest;
(E.sendOnly(i(target)))(i(args));
}; break;
case "applyFunction": {
const [qid, target, args] = rest;
const result = (E(i(target)))(i(args));
results.set(qid, result);
lastQId = qid;
}; break;
case "get": {
const [qid, target, prop] = rest;
const result = E.get(i(target))[i(prop)];
results.set(qid, result);
lastQId = qid;
}; break;
case "assignOnce": {
const [qid, val] = rest;
results.set(qid, i(val));
lastQId = qid;
}; break;
// 2022-05-24T02:08Z tbdecided #1 -byrjun-
case "assignInEnv": {
const [idxs, val] = rest;
const it = i(idxs);
if (it.length === 0) {
environ = i(val);
} else {
it.reduce((acc, idx) => acc[i(idx)], environ) = i(val);
}
}; break;
// -lok-
default: throw new Error("unrecognizable form in seqBlock");
};
});
return results.get(lastQId);
}
}
exports.makeSeqBlock = makeSeqBlock;
return exports;
});
moduleFuncs.set("@zarutian/seqBlock/cost-calculator", async () => {
let exports = {};
const costCalculate = (sequenceBlock) => {
let tally = BigInt(0);
tally += BigInt(sequenceBlock.length);
const i = (it) => {
switch (it[0]) {
case "@qid":
case "@sba":
case "@ref": // fallthrough
case "@dat": tally += BigInt(1); break;
case "@arr": tally += BigInt(1); it.slice(1).forEach(i); break;
case "@rec": tally += BigInt(1); i(it[1]); break;
case "@env":
tally += BigInt(1);
if (it.length === 1) {
} else {
it.slice(1).forEach(i);
}
break;
case "@sqb":
tally += BigInt(1);
i(it[1]); i(it[2]);
break;
default:
};
};
Array.prototype.forEach.apply(sequenceBlock, (form) => {
const [first, ...rest] = form;
switch (first) {
case "applyMethodSendOnly": {
const [target, verb, args] = rest;
i(target); i(args);
}; break;
case "applyMethod": {
const [qid, target, verb, args] = rest;
i(target); i(args);
}; break;
case "applyFunctionSendOnly": {
const [target, args] = rest;
i(target); i(args);
}; break;
case "applyFunction": {
const [qid, target, args] = rest;
i(target); i(args);
}; break;
case "get": {
const [qid, target, prop] = rest;
i(target); i(prop);
}; break;
case "assignOnce": {
const [qid, val] = rest;
i(val);
}; break;
// 2022-05-24T02:08Z tbdecided #1 -byrjun-
case "assignInEnv": {
const [idxs, val] = rest;
i(idxs); i(val);
}; break;
// -lok-
}
});
return tally;
};
exports.costCalculate = costCalculate;
return exports;
});
moduleFuncs.set("@zarutian/handoff-tables", async () => {
let exports = {};
const module = { exports };
const { harden } = await require("@agoric/harden");
const { makePromiseKit } = await require("@agoric/promise-kit");
const { E, Far } = await require("@endo/eventual-send");
exports.makeHandoffTable = () => {
const recipiants = new Map();
const lookup = (g, r, n) => {
if (!recipiants.has(r)) { return undefined; }
const givers = recipiants.get(r);
if (!givers.has(g)) { return undefined; }
const gifts = givers.get(g);
if (!gifts.has(n)) { return undefined; }
return gifts.get(n);
}
const assign = (g, r, n, item) => {
if (!recipiants.has(r)) { recipiants.set(r, (new Map())); }
const givers = recipiants.get(r);
if (!givers.has(g)) { givers.set(g, (new Map())); }
const gifts = givers.get(g);
gifts.set(n, item);
}
const remove = (g, r, n) => {
if (!recipiants.has(r)) { return; }
const givers = recipiants.get(r);
if (!givers.has(g)) { return; }
const gifts = givers.get(g);
if (!gifts.has(n)) { return; }
gifts.delete(n);
if (gifts.size == 0) {
givers.delete(g);
if (givers.size == 0) {
recipiants.delete(r);
}
}
}
return harden({
provideFor: (giver, recipiant, nynce, gift) => {
const dufuhola = lookup(giver, recipiant, nynce);
if (dufuhola === undefined) {
assign(giver, recipiant, nynce, { kind: "gift", gift });
} else {
if (dufuhola.kind === "gift") {
if (dufuhola.gift !== gift) {
throw new Error("ya kannea 'ssign same nynce for the same recipiant to two diffrent gifts");
}
} else {
if (dufuhola.kind == "promiseKit") {
const { resolve } = dufuhola.promiseKit;
resolve(harden({ getGift: () => gift }));
remove(giver, recipiant, nynce);
E.sendOnly(dufuhola.vine)._react();
return harden({ _react: () => {} });
}
}
}
const vine = Far("Vine", { _react: () => { gift = undefined; } });
return vine; // might be pointless;
},
acceptFrom: (giver, recipiant, nynce, vine) => {
const dufuhola = lookup(giver, recipiant, nynce);
if (dufuhola === undefined) {
const promiseKit = makePromiseKit();
assign(giver, recipiant, nynce, { kind: "promiseKit", promiseKit, vine });
return promiseKit.promise;
} else {
if (dufuhola.kind === "promiseKit") {
return dufuhola.promiseKit.promise;
}
if (dufuhola.kind === "gift") {
const gift = dufuhola.gift;
remove(giver, recipiant, nynce);
E.sendOnly(vine)._react();
return Promise.resolve(harden({ getGift: () => gift }));
}
}
},
isGiftWaiting: (giver, recipiant, nynce) => {
const dufuhola = lookup(giver, recipiant, nynce);
if (dufuhola === undefined) { return false; }
if (dufuhola.kind === "gift") { return true; }
return false;
},
});
};
exports.makeHandoffFacet = (handoffTable, ident) => {
return Far("HandoffTableFacet", {
provideFor: (recipiant, nynce, gift) => handoffTable.provideFor(ident, recipiant, nynce, gift),
acceptFrom: (giver, nynce, vine) => handoffTable.acceptFrom(giver, ident, nynce, vine),
isGiftWaiting: (giver, nynce) => handoffTable.isGiftWaiting(giver, ident, nynce),
});
};
return module.exports;
});
moduleFuncs.set("@zarutian/ForwardingDelegatedPromise", async () => {
// 2021-11-19T16:49Z todo: Þarf að breyta þessu í Promise.delegated() form
// 2023-02-03T05:24Z byrjaður á því
let exports = {};
const module = { exports };
const { harden } = await require("@agoric/harden");
const { E } = await require("@endo/eventual-send");
const forward = {
applyMethod(result, promiseKit, verb, args) {
E.when(
(E(result)[verb])(...args),
promiseKit.resolve,
promiseKit.reject,
);
},
applyMethodOnly(result, verb, args) {
(E.sendOnly(result)[verb])(...args);
},
apply(result, promiseKit, args) {
E.when(
(E(result))(...args),
promiseKit.resolve,
promiseKit.reject,
);
},
applyOnly(result, args) {
(E.sendOnly(result))(...args);
},
get(result, promiseKit, property) {
E.when(
(E.get(result))[property],
promiseKit.resolve,
promiseKit.reject,
);
},
setOnly(result, property, newValue) {
E.setOnly(result, property, newValue);
},
};
const makeForwardingDelegatedPromise = (ERef, executor) => {
let queue = []; // :FlexList
const add2queue = (item) => { queue.push(item); };
const forwardingHandler = {
applyMethod(target, verb, args) {
// eventualSend
const p1 = (E(ERef)[verb])(...args);
const p2 = makeForwardingDelegatedPromiseKit(p1);
add2queue(["applyMethod", p2, verb, args])
return p2.promise;
},
applyMethodOnly(target, verb, args) {
// eventualSendOnly
(E.sendOnly(ERef)[verb])(...args);
add2queue(["applyMethodOnly", verb, args]);
},
apply(target, args) {
// eventualApply
const p1 = (E(ERef))(...args);
const p2 = makeForwardingDelegatedPromiseKit(p1);
add2queue(["apply", p2, args]);
return p2.promise;
},
applyOnly(target, args) {
// eventualApplyOnly
(E.sendOnly(ERef))(...args);
add2queue(["applyOnly", args]);
},
get(target, property) {
// eventualGet
const p1 = (E.get(ERef))[property];
const p2 = makeForwardingDelegatedPromiseKit(p1);
add2queue(["get", p2, property]);
return p2.promise;
},
set(target, property, newValue): {
// eventualSet, should actually never be invoked but does the default behaviour
E.setOnly(ERef, property, newValue);
add2queue(["setOnly", property, newValue]);
return newValue;
},
setOnly(target, property, newValue): {
// eventualSetOnly
E.setOnly(ERef, property, newValue);
add2queue(["setOnly", property, newValue]);
},
};
return Promise.delegated((resolve, reject, rWp) => {
const resolveAndResend = (result) => {
queue.forEach(pending => {
forward[pending[0]](result, ...pending.slice(1));
});
queue = null;
return resolve(result);
};
const leysa = (result) => { queue = null; return resolve(result); };
const rWp2 = (...args) => { queue = null; return rWp(...args); };
return executor(leysa, reject, rWp2, resolveAndResend);
}, forwardingHandler);
};
const makeForwardingDelegatedPromiseKit = (ERef) => {
let resolve = undefined;
let reject = undefined;
let resolveAndResend = undefined;
let resolveWithPresence = undefined;
const promise = makeForwardingDelegatedPromise(ERef, (leysa, hafna, rWp, leysaOgEndursenda) => {
resolve = leysa; reject = hafna;
resolveAndResend = leysaOgEndursenda;
resolveWithPresence = rWp;
});
return harden({ promise, resolve, reject, resolveAndResend, resolveWithPresence });
};
exports = { ...exports, makeForwardingDelegatedPromiseKit, makeForwardingDelegatedPromise };
return exports;
});
moduleFuncs.set("@zarutian/async-ops", async () => {
const { E } = await require("@endo/eventual-send");
const { makeForwardingDelegatedPromiseKit } = await require("@zarutian/ForwardingDelegatedPromise");
const someArgsAwaitForMethod = async (target, verb, args, which) => {
const someSettled = await Promise.all(args.map((arg, idx) => (which[idx] ? arg : null )));
const newArgs = which.map((w, idx) => (w ? someSettled[idx] : args[idx]));
return (E(target)[verb])(...newArgs);
};
const someArgsAwaitForFunction = async (target, args, which) => {
const someSettled = await Promise.all(args.map((arg, idx) => (which[idx] ? arg : null )));
const newArgs = which.map((w, idx) => (w ? someSettled[idx] : args[idx]));
return (E(target))(...newArgs);
};
const awaitForProperty = async (target, prop) => {
const p = await prop;
return (E.get(target))[p];
};
const async_listen = (promise, resolvementListener) => {
return E.when(
promise,
(value) => E(resolvementListener).resolve(value),
(err) => E(resolvementListener).reject(err),
);
};
const async_attempt = (opts) => {
const {target, verb, args, awaitFor, fallback} = opts;
const t1 = E(target)[verb](...args);
const t2 = makeForwardingDelegatedPromiseKit(t1);
E.when(
t1,
result => t2.resolve(result),
err => {
E.when(
awaitFor,
r => { t2.resolveAndResend(fallback(r, ...args)); },
t2.reject,
);
},
);
return t2.promise;
};
const async_arrayAt = (arr, idx) => {
return async_attempt({
target: arr,
verb: "at",
args: [idx],
awaitFor: Promise.all([idx]),
fallback: ([i]) => E.get(arr)[i],
});
};
exports.async_arrayAt = async_arrayAt;
const async_pick = (selector, conseq, altern) => {
return async_attempt({
target: selector,
verb: "pick",
args: [conseq, altern],
awaitFor: selector,
fallback: (theBool, conseq, altern) => (theBool ? conseq : altern),
});
};
exports.async_pick = async_pick;
exports.async_NOT = a => async_pick(a, false, true);
exports.async_OR = (a, b) => {
const c = async_pick(a, [true, true], [true, false]);
return async_pick(b, E.get(c)[0], E.get(c)[1]);
};
exports.async_AND = (a, b) => {
const c = async_pick(a, [true, false], [false, false]);
return async_pick(b, E.get(c)[0], E.get(c)[1]);
};
exports.async_XOR = (a, b) => {
const c = async_pick(a, [false, true], [true, false]);
return async_pick(b, E.get(c)[0], E.get(c)[1]);
};
// 2023-06-07T02:50 Added -begin-
exports.async_If_v1 = (selector, conseqCallback, alternCallback) => {
let used = false;
const common = () => {
if (used) {
throw new Error("conseqCallback or alternCallback of an async_If already invoked");
}
used = true;
};
const ccb = () => {
common();
(E(conseqCallback))();
};
const acb = () => {
common();
(E(alternCallback))();
};
const t1 = async_pick(selector, ccb, acb);
return (E(t1))();
};
exports.async_switch_v1 = (selector, cases, defaultCase) => {
const t1 = (E(cases)[Symbol.asyncIterator])();
const t2 = () => {
};
const t3 = () => {
const t4 = E.get(E(t1).next());
const t5 = () => (E(defaultCase))();
const t6 = async_pick(t4.done, t5, t3);
const t7 = E.get(t4.value);
const t8 = exports.async_sameYet(t7[0], selector);
const t9 = async_pick(t8, t7[1], t2);
const tA = (E(t9))();
const tB = async_pick(t8, t2, t6);
return (E(tB))();
}
};
// -end-
exports.async_add = (a, b) => {
return async_attempt({
target: a,
verb: "add",
args: [b],
awaitFor: Promise.all([a, b]),
fallback: ([anum, bnum]) => (BigInt(anum) + BigInt(bnum)),
});
}
exports.async_subtract = (a, b) => {
return async_attempt({
target: a,
verb: "subtract",
args: [b],
awaitFor: Promise.all([a, b]),
fallback: ([anum, bnum]) => (BigInt(anum) - BigInt(bnum)),
});
};
exports.async_multiply = (a, b) => {
return async_attempt({
target: a,
verb: "multiply",
args: [b],
awaitFor: Promise.all([a, b]),
fallback: ([anum, bnum]) => (BigInt(anum) * BigInt(bnum)),
});
};
exports.async_divide = (a, b) => {
return async_attempt({
target: a,
verb: "divide",
args: [b],
awaitFor: Promise.all([a, b]),
fallback: ([anum, bnum]) => (BigInt(anum) / BigInt(bnum)),
});
};
exports.async_modulo = (a, b) => {
return async_attempt({
target: a,
verb: "modulo",
args: [b],
awaitFor: Promise.all([a, b]),
fallback: ([anum, bnum]) => (BigInt(anum) % BigInt(bnum)),
});
};
exports.async_negate = (a) => {
return async_attempt({
target: a,
verb: "negate",
args: [],
awaitFor: Promise.all([a]),
fallback: ([anum]) => (-BigInt(anum)),
});
};
exports.async_exponate = (a, b) => {
return async_attempt({
target: a,
verb: "exponate",
args: [b],
awaitFor: Promise.all([a, b]),
fallback: ([anum, bnum]) => (BigInt(anum) ** BigInt(bnum)),
});
};
exports.async_bitwiseNot = (a) => {
return async_attempt({
target: a,
verb: "bitwiseNot",
args: [],
awaitFor: Promise.all([a]),
fallback: ([anum]) => (~BigInt(anum)),
});
};
exports.async_bitwiseAnd = (a, b) => {
return async_attempt({
target: a,
verb: "bitwiseAnd",
args: [b],
awaitFor: Promise.all([a, b]),
fallback: ([anum, bnum]) => (BigInt(anum) & BigInt(bnum)),
});
};
exports.async_bitwiseOr = (a, b) => {
return async_attempt({
target: a,
verb: "bitwiseOr",
args: [b],
awaitFor: Promise.all([a, b]),
fallback: ([anum, bnum]) => (BigInt(anum) | BigInt(bnum)),
});
};
exports.async_bitwiseXor = (a, b) => {
return async_attempt({
target: a,
verb: "bitwiseXor",
args: [b],
awaitFor: Promise.all([a, b]),
fallback: ([anum, bnum]) => (BigInt(anum) ^ BigInt(bnum)),
});
};
const numToBoolArray = (num, nrOfBits = 32) => {
var v = num;
const r = [];
while (nrOfBits > 0) {
r.push(((v & 0x1) == 0x1));
v = v >> 1;
nrOfBits--;
}
return r;
};
const async_numToBoolArray = (num, nrOfBits = 32) => {
return async_attempt({
target: num,
verb: "toBoolArray",
args: [nrOfBits],
awaitFor: Promise.all([num]),
fallback: ([n]) => (numToBoolArray(BigInt(n), nrOfBits)),
});
};
/*
const numFromBoolArray = (arr) => {
var n = BigInt(0);
while (arr.length > 0) {
n = n << 1n;
n = n + (arr.pop() ? BigInt(1) : BigInt(0));
}
return n;
};
*/
const numFromBoolArray = (arr) => {
return arr.reduceRight((acc, item) => ((acc << 1n) + (item ? BigInt(1) : BigInt(0))), BigInt(0));
};
/* exports.async_numFromBoolArray = (arr) => {
return E(arr).reduceRight(NakedNomad((acc, item) => ((acc << 1n) + (item ? BigInt(1) : BigInt(0)))), BigInt(0));
}; */
exports.async_numFromBoolArray = (arr) => {
const K = (first, second) => second;
const recurse = (idxP, numP) => {
const contP = exports.async_numIsZero(idxP);
const t2 = exports.async_pick(contP, BigInt(0), BigInt(1));
const idxP1 = exports.async_subtract(idxP, t2);
const bitP = exports.async_arrayAt(arr, idxP);
const bitnumP = exports.async_pick(bitP, BigInt(1), BigInt(0));
const numP1 = exports.async_multiply(numP, BigInt(2));
const numP2 = exports.async_add(numP1, bitnumP);
const t3 = exports.async_pick(contP, K, recurse);
return E(t3)(idxP1, numP2);
}
return recurse(E.get(arr).length, Promise.resolve(BigInt(0)));
}
exports.async_numIsZero = (num) => {
return async_attempt({
target: num,
verb: "isZero",
args: [],
awaitFor: Promise.all([num]),
fallback: ([n]) => (BigInt(n) == BigInt(0)),
});
};
exports.async_numIsGreaterThan = (a, b) => {
return async_attempt({
target: a,
verb: "isGreaterThan",
args: [b],
awaitFor: Promise.all([a, b]),
fallback: ([anum, bnum]) => (BigInt(anum) > BigInt(bnum)),
});
};
exports.async_numIsLessThan = (a, b) => {
return async_attempt({
target: a,
verb: "isLessThan",
args: [b],
awaitFor: Promise.all([a, b]),
fallback: ([anum, bnum]) => (BigInt(anum) < BigInt(bnum)),
});
};
exports.async_numIsEqual = function (a, b) {
return async_attempt({
target: a,
verb: "isEqual",
args: [b],
awaitFor: Promise.all([a, b]),
fallback: ([anum, bnum]) => (BigInt(anum) == BigInt(bnum)),
});
};
exports.pipe = (...funs) =>
(input) => Array.prototype.reduce.call(funs, (out, f) => f(out), input);
exports.asyncPipeV1 = (...funs) =>
async (input) => await Array.prototype.reduce.call(funs, async (out, f) => await f(out), await input);
/*
const exports = {
someArgsAwaitForMethod,
someArgsAwaitForFunction,
awaitForProperty,
async_bitwiseOr,
async_bitwiseXor,
numToBoolArray,
async_numToBoolArray,
numFromBoolArray,
async_numFromBoolArray,
async_numIsZero,
async_numIsGreaterThan,
async_numIsLessThan,
async_numIsEqual,
};
*/
return exports;
});
moduleFuncs.set("@zarutian/ActiveCapCert/0v1", async () => {
let exports = {};
const { harden } = await require("@agoric/harden");
const { Far } = await require("@endo/eventual-send");
const { makeSeqBlock } = await require("@zarutian/seqBlock");
const { costCalculate } = await require("@zarutian/seqBlock/cost-calculator");
const async_ops = await require("@zarutian/async-ops");
const { JSON } = await require("JSON");
const parse = JSON.parse; // for now but still some tbd
const { base64url_decode } = await require("base64");
const decode = base64url_decode;
const openpgp = await require("openpgp");
const verifySignature = async (certBytes) => {
const [accTag, issuerBytes, bodyBytes, signatureBytes] = certBytes.split(".");
if (accTag !== "ActiveCapCert0v1") {
throw new Error("certBytes did not start with reconized tag");
}
const detachedSignature = decode(signatureBytes);
const publicKeyArmored = decode(issuerBytes);
const verified = await openpgp.verify({
message: openpgp.cleartext.fromText(bodyBytes), // CleartextMessage or Message object
signature: await openpgp.signature.readArmored(detachedSignature), // parse detached signature
publicKeys: (await openpgp.key.readArmored(publicKeyArmored)).keys // for verification
});
if ( verified.signatures.length !== 1 ) {
throw new Error("was only expecting one signiture");
}
const { valid } = verified.signatures[0];
return valid;
};
const makeActiveCapCertInstanceMaker = (opts) => {
const getHandoffTableFacet = opts.getHandoffTableFacet;
const makeActiveCapCertInstance = async (certBytes) => {
const [accTag, issuerBytes, bodyBytes, signatureBytes] = certBytes.split(".");
if (accTag !== "ActiveCapCert0v1") {
throw new Error("certBytes did not start with reconized tag");
}
if (! await verifySignature(certBytes) ) {
throw new Error("signature verification failed");
}
const envelope = parse(decode(bodyBytes));
const { seqBlock } = envelope;
const environ = harden({
...(opts.endowments),
makeActiveCapCertInstance,
handoff: getHandoffTableFacet(issuerBytes),
...async_ops,
Far,
});
return makeSeqBlock(seqBlock, environ);
}
}
exports.makeActiveCapCertInstanceMaker = makeActiveCapCertInstanceMaker;
exports.calculateCostOfACC = (certBytes) => {
const [accTag, issuerBytes, bodyBytes, signatureBytes] = certBytes.split(".");
if (accTag !== "ActiveCapCert0v1") {
throw new Error("certBytes did not start with reconized tag");
}
const envelope = parse(decode(bodyBytes));
const { seqBlock } = envelope;
return costCalculate(seqBlock);
};
return exports;
});
moduleFuncs.set("@zarutian/certCheque/examples", async () => {
let exports = {};
exports.makeSimplePaymentTransferV1 = (opts) => {
const { AliceKeys,
BobPublicKey,
IssuerBoardId,
PaymentNym } = opts;
const seqBlock = [
["applyMethod", "issuerP", ["@env", "board"], "getValue", ["@arr", ["@dat", IssuerBoardId]]],
["applyMethod", "paymentP1", ["@env", "handoff"], "acceptFrom", ["@arr", ["@dat", AliceKeys.publicKey], ["@dat", PaymentNym], ["@dat", null]]],
["applyMethod", "paymentP2", ["@qid", "issuerP"], "claim", ["@arr", ["@qid", "paymentP1"]]],
["applyMethod", "result", ["@env", "handoff"], "provideFor", ["@arr", ["@dat", BobPublicKey], ["@dat", PaymentNym], ["@qid", "paymentP2"]]],
];
return cert;
};
exports.makeSimplePaymentTransferV2 = (opts) => {
const { AliceKeys,
BobPublicKey,
IssuerBoardId,
PaymentNym } = opts;
const seqBlock = [
["applyMethod", "issuerP", ["@env", "board"], "getValue", ["@arr", ["@dat", IssuerBoardId]]],
["assignOnce", "AlicePK", ["@dat", AliceKeys.publicKey]],
["assignOnce", "PaymentNym", ["@dat", PaymentNym]],
["applyMethod", "bool1P", ["@env", "handoff"], "isGiftWaiting", ["@arr", ["@qid", "AlicePK"], ["@qid", "PaymentNym"]]],
["assignOnce", "t", ["@sqb",
["@dat", [
["applyMethod", "p1", ["@env", "handoff"], "acceptFrom", ["@arr", ["@env", "AlicePK"], ["@env", "PaymentNym"]]],
["applyMethod", "p2", ["@env", "issuer"], "claim", ["@arr", ["@qid", "p1"]]],
["applyMethod", "vine", ["@env", "handoff"], "provideFor", ["@arr", ["@dat", BobPublicKey], ["@env", "PaymentNym"]]],
["assignOnce", "result", ["@dat", true]],
]],
["@rec", ["@arr",
["@arr", ["@dat", "handoff"], ["@env", "handoff"]],
["@arr", ["@dat", "issuer"], ["@qid", "issuerP"]],
["@arr", ["@dat", "AlicePK"], ["@qid", "AlicePK"]],
["@arr", ["@dat", "PaymentNym"], ["@qid", "PaymentNym"]],
]],
]],
["assignOnce", "f", ["@sqb", ["@dat",
[
["assignOnce", "result", ["@dat", false]],
]], ["@rec" ["@arr"]]]],
["applyMethod", "branchP", ["@qid", "bool1P"], "pick", ["@arr", ["@qid", "t"], ["@qid", "f"]]],
["applyFunction", "result", ["@qid", "branchP"], ["@arr"]],
];
return cert;
};
return exports;
});
function async getExports() {
let exports = {};
const module = { exports };
const harden = await require("@agoric/harden");
const { E, Far } = await require("@agoric/eventual-send");
const { makeHandoffTable, makeHandoffFacet } = await require("@zarutian/handoff-tables");
// const { workerBundle } = await require("@zarutian/smart-contracts/certChequeExecutor/workerBundle");
const { makeActiveCapCertInstanceMaker, calculateCostOfACC } = await require("@zarutian/ActiveCapCert/0v1");
const start = (zcf, privateArgs) => {
const Zoe = zcf.getZoeService();
// const workerInstallation = E(zoe).install(workerBundle);
const handoffTable = makeHandoffTable();
const getHandoffTableFacet = (ident) => makeHandoffTableFacet(handoffTable, ident);
let board = undefined;
const makeActiveCapCertInstance = makeActiveCapCertInstanceMaker({
getHandoffTableFacet,
endowments: {
get board() { return board },
Zoe,
},
});
let unit_price = zcf.getAmountMathFor(zcf.getTerms().issuers.Fuel).makeEmpty();
const creatorFacet = Far("creatorFacet", {
setBoard: (newBoard) => { board = newBoard; },
setUnitPrice: (newPrice) => { unit_price = newPrice; },
});
const publicFacet = Far("publicFacet", {
makeCertChequeInvitation: (certBytes, resultResolver) => {
return zcf.makeInvitation(seat => {
// do price calculation
const cost = calculateCostOfACC(certBytes); // veikleiki hér?
// todo: check if it is enough
const certInstance = makeActiveCapCertInstance(certBytes);
const result = harden({ certInstance });
if (resultResolver !== undefined) {
E.sendOnly(resultResolver).resolve(result);
}
return result;
}, "CertChequeInvitation");
},
});
return harden({ creatorFacet, publicFacet });
}
exports.start = harden(start);
return module.exports;
}
export { getExports, require };
// A 'chair' is a reoccurring seat in a contract.
//
// when an invitation is used to make an offer via
// const seat = E(zoe).offer(invitation, proposal, payments, custom);
// const offerResult = E(seat).getOfferResult();
// const nextInvitation = E.G(offerResult, "nextInvitation");
// this enables contract parties to trade their 'chairs' via
// other smart contracts.
const makeChair_v1 = (zcf, offerHandler, invitationDesc, customProps) => {
return harden((offerResult) => {
const nextInvitation = zcf.makeInvitation(offerHandler, invitationDesc, customProps);
return harden({ ...offerResult, nextInvitation });
});
};
const makeChair_v2 = zcf => {
return harden((offerResult, offerHandler, invitationDesc, customProps) => {
const nextInvitation = zcf.makeInvitation(offerHandler, invitationDesc, customProps);
return harden({ ...offerResult, nextInvitation });
});
};
/**
* @typedef Chairling
* @property {ZoeInvitation} invitation
* @property {Proposal} proposal
* @property {PaymentsKeywordRecord} payments
*/
/**
* @param {ERef<*>} zoe
* @param {Chairling} A
* @param {Chairling} B
* @returns {*}
*/
const doubleSitter_v1 = (zoe, A, B) => {
const seatA = E(zoe).offer(A.invitation, A.proposal, A.payments);
const seatB = E(zoe).offer(B.invitation, B.proposal, B.payments);
Promise.allSettled([seatA, seatB]).then(settlements => {
settlements.map(s => {
if (s.status == "fullfilled") {
s.value
} else if (s.status == "rejected") {
s.reason
}
});
});
}
const doubleSitter_v2 = (zoe, A, B) => {
const A1 = Object.fromEntries(Object.entries(A)); // FlexRecord
const B1 = Object.fromEntries(Object.entries(B)); // FlexRecord
const ytraFall = () => {
const seatA = E(zoe).offer(A1.invitation, A1.proposal, A1.payments);
const payoutsA = E(seatA).getPayouts();
const resultA = E(seatA).getOfferResult();
A1.invitation = E.G(resultA, "nextInvitation");
{ proposal: B1.proposal, payments: B1.payments } = B1.mapper(A1.proposal, payoutsA);
const seatB = E(zoe).offer(B1.invitation, B1.proposal, B1.payments);
const payoutsB = E(seatB).getPayouts()
const resultB = E(seatB).getOfferResult();
B1.invitation = E.G(resultB, "nextInvitation");
{ proposal: A1.proposal, payments: A1.payments } = A1.mapper(B1.proposal, payoutsB);
const innraFall = () => {
Promise.all([E(seatA).hasExited(), E(seatB).hasExited()]).then(([a, b]) => {
if (a && b) {
ytraFall();
} else {
innraFall();
}
}, (failure) => {});
};
innraFall();
};
ytraFall();
}
// Disclaimer: Use at your own risk! -Zarutian
const Object_map = (obj, cb) => Object.fromEntries(Object.entries(obj).map(cb));
/** @type {ContractStartFn} */
const start = (zcf, privateArgs) => {
var depositSeats = []; // flexList
const IsDeposited = (bling) => {
const keywords = Object.entries([k, v] => k);
const reiknar = Object_map(bling, [k, v] => [k, zcf.getAmountMath(v.brand)]);
const safnarar = Object_map(reiknar, [k, v] => [k, v.makeEmpty()]);
depositSeats.forEach(seat => {
const allocations = seat.getCurrentAllocation();
const subset = Object.entries(allocations).filter([k, v] => keywords.includes(k));
subset.forEach([k, v] => { safnarar[k] = reiknar[k].add(safnarar[k], v); });
});
return keywords.map(k => reiknar[k].isGTE(safnarar[k], bling[k]).reduce((ac, it) => (ac && it), true);
};
const outstandingFlaunts = new WeakSet();
const creatorFacet = harden({
makeDepositInvitation:
/** @type {() => invitation} */
() => zcf.makeInvitation(seat => {
depostSeats.push(seat);
const watch = (upc = undefined) => {
if (seat.hasExited()) {
depositSeats = depositSeats.filter(s => (s !== seat));
return;
}
E.when(E(seat.getNotifier()).getUpdateSince(upc), { value, updateCount } => watch(updateCount));
};
watch();
return undefined;
}, "a flaunt deposit invitation"),
makeFlaunt:
/** @type {(AmountKeywordRecord, Any) => Flaunt} */
( bling, anchillaryInfo ) => {
const flaunt = harden({ bling, anchillaryInfo });
if (isDeposited(bling)) {
outstandingFlaunts.add(flaunt);
}
return flaunt;
},
addIssuer: (issuer, keyword) => E.when(zcf.saveIssuer(issuer, keyword), (_) => undefined)),
shutdown: (completion) => zcf.shutdown(completion),
});
const publicFacet = harden({
verifyFlaunt:
/** @type {(flaunt: Flaunt) => Bool} */
flaunt => {
const r = outstandingFlaunts.has(flaunt);
if (r) { outstandingFlaunts.remove(flaunt); }
return r;
};
});
return harden({ creatorFacet, publicFacet });
};
harden(start);
export { start };
// Disclaimer: Use at your own risk! -Zarutian
import harden from "@agoric/harden";
/** @type {ContractStartFn} */
const start = (zcf) => {
const name = zcf.getTerms().name;
let counter = 0n;
const inventory = new Map();
const addToInventory = (thing) => {
while (inventory.has(counter)) {
counter += 1n;
}
const nr = counter;
inventory.set(nr, thing);
return nr;
};
const creatorFacet = harden({
list: () => harden(new Array(inventory.entries())),
getCounter: () => counter,
fetch: (nr) => inventory.get(nr),
delete: (nr) => inventory.delete(nr),
selfDestruct: () => {
if ((new Array(inventory.entries())).length != 0) {
return false;
};
zcf.vatTerminate("self destructed on creators request");
return true;
},
});
const publicFacet = harden({
dropOff: (thing) => addToInventory(thing),
});
return harden({ creatorFacet, publicFacet });
};
harden(start);
export { start };
// Disclaimer: use at your own risk -Zarutian
import harden from "@agoric/harden";
import { E, Far } from "@agoric/eventual-send";
import { makePromiseKit } from "@agoric/promise";
/** @type {ContractStartFn} */
const start = (zcf) => {
const boxes = [];
const creatorFacet = Far("creatorFacet", {
getProceeds: () => {
},
shutdown: () => {
},
});
const publicFacet = Far("publicFacet", {
makeBox: () => {
return thingsToPutIntoItInvitation;
},
seeBoxes: () => {
},
buyRandomBox: () => {
return buyBoxInvitation;
},
});
const creatorInvitation = undefined;
return harden({ creatorFacet, creatorInvitation, publicFacet });
}
harden(start);
export { start };
// Disclaimer: Use at your own risk! -Zarutian
import { harden } from "@agoric/harden";
import { assert } from "@agoric/assert";
/* This smart contract has the following phases:
1. initialization:
The loaner instanciates the contract
The loaner gives the contract the sum of th fungible
electronic right being loaned out, via the creator
invitation and gets back a payout invitation and a
borrower invitation.
The borrower gives the contract, via the borrower invitation,
the collateral electronic right.
The contract now enters the second phase.
2. Borrower paying the interest and, possibly, the capital down:
Every interval x per timer t, the contract checks if
the borrower has paid in enough to cover the interest.
If it is enough then the loan is not in arreas, and
any excess amount beyond that is needed to cover the
interest payes down the capital of the loan.
If not and this has happened for y many intervals then
exercise the collateral electronic right and terminate
this contract.
If all the interest and capital has been payed then
give the collateral electronic right back to the
borrower.
*/
/** @type {ContractStartFn} */
const start = (zcf) => {
const terms = zcf.getTerms();
assert((terms.timer !== undefined), "no timer given");
assert((terms.repaymentInterval !== undefined), "no repayment interval given");
const creatorInvitation = zcf.makeInvitation(
/* @type {(
(creatorSeat) => {
}, "lenderInitialInvitation", undefined);
const creatorFacet = harden({
});
const publicFacet = harden({
});
return harden({ creatorFacet, creatorInvitation, publicFacet });
}
harden(start);
export { start };
// Disclaimer: use at your own risk! -Zarutian
import { harden } from "@agoric/harden";
import { makeIssuerKit, MathKind } from "@agoric/ERTP";
import { makeStore } from "@agoric/store";
import { E } from "@agoric/eventual-send";
/** @type {ContractStartFn} */
const start = (zcf) => {
const terms = zcf.getTerms();
const zoe = zcf.getZoeService();
var contractInstanceItself = undefined;
// only way I know of to get the instance of this smart contract
(() => {
const invitation = zcf.makeInvitation(seat => seat.exit(), 'thrownAway');
const instance = E(zoe).getInstance(invitation);
instance.then(sci => contractInstanceItself = sci);
const userSeat = E(zoe).offer(invitation, undefined, undefined);
E(userSeat).tryExit();
})();
const { issuer, mint, amountMath, brand } = makeIssuerKit("«".concat(terms.fullname, "» namespace name(s)"), MathKind.STRING_SET);
// Both of these can live in diffrent remote vat, each.
// There is even possibility of sharding.
const name2obj = makeStore();
const name2ctrler = makeStore();
const makeCtrler = (name) => {
return E(E.at(name2ctrler,
(near_name2ctrler, far_name2obj, near_name, far_nsc) => {
"use strict"; "no loops"; "no recursion";
if (near_name2ctrler.has(near_name)) {
// revoke the old controler if any
near_name2ctrler.get(near_name).cell[0] = false;
}
// as ecmascript does not have VarSlots like E has this monstrosity is required:
const cell = [true];
const ctrler = harden({
set: (obj) => {
if (cell[0]) {
return E(far_name2obj).set(near_name, obj);
} else {
throw new Error("this controler for '".concat(near_name, "' has been revoked"));
}
},
get: () => E(far_name2obj).get(near_name),
getNamespaceContract: () => far_nsc,
getName: () => near_name
});
near_name2ctrler.set(near_name, { ctrler, cell });
return ctrler;
}))(name2ctrler, name2obj, name, contractInstanceItself);
};
const creatorFacet = harden({
registerNewName: async (name, obj="«place holder»") => {
if (await E(name2obj).has(name)) {
throw new Error("requested name already registered");
}
const ctrler = makeCtrler(name);
await E(ctrler).set(obj);
return E(mint).mintPayment(amountMath.make(name));
}
});
const publicFacet = harden({
getIssuer: () => issuer,
lookup: (name) => E(E(name2obj).has(name)).pick(E(name2obj).get(name), new Error("no such name registered")),
getInvitationToGetControler: () => zcf.makeInvitation((seat) => {
// We only need to verify that requestor has the token for the name
const name = amountMath.getValue(seat.getAmountAllocated("Name", brand))[0];
seat.exit();
return makeCtrler(name);
}, "invitation to get controler for a spefic name");
});
return harden({ creatorFacet, publicFacet });
};
harden(start);
export { start };
// Disclaimer: use at your own risk -Zarutian
import harden from "@agoric/harden";
import { E } from "@agoric/eventual-send";
import { makePromiseKit } from "@agoric/promise";
import { trade } from "@agoric/zoe/src/contractSupport/";
// The idea is simply a timerService, whose ticks is driven
// onward via payments into it.
// One fungible currency unit drives it one tick onward.
/** @type {ContractStartFn} */
const start = (zcf) => {
const reiknir = zcf.getAmountMath(zcf.getBrandForIssuer(zcf.getTerms().issuers.Currency));
let currentTickNr = 0n;
const wakeups = new Map();
const removeWakeupHandler = (handler) => {
const ts = []; // FlexList which becomes ConstList
wakeups.forEach((v, t) => {
if (v.includes(handler)) {
ts.push(t);
const n = v.filter((i) => (i !== handler));
if (n.length == 0) {
wakeups.delete(t);
} else {
wakeups.set(t, n);
}
}
});
return harden(ts);
};
const doWakeup = (handler) => {
E.sendOnly(handler).wake(currentTickNr);
removeWakeupHandler(handler);
}
const doWakeupsFor = (time) => {
if (!wakeups.has(time)) { return; }
wakeups.get(time).forEach((h) => doWakeup(h));
}
const addWakeup = (time, handler) => {
const t = BigInt(time);
if (t <= currentTickNr) {
doWakeup(handler);
return;
}
if (!wakeups.has(t)) {
wakeups.set(t, [] /* FlexList */);
}
wakeups.get(t).push(handler);
return undefined;
}
const tickOnward = (sinnum) => {
for (let count = 0n; count < sinnum; count = count + 1n) {
doWakeupsFor(currentTickNr);
currentTickNr = currentTickNr + 1n;
}
}
const timerService = harden({
getCurrentTimestamp: () => (currentTickNr),
setWakeup: (baseTime, handler) => {
const t = BigInt(baseTime);
addWakeup(t, handler);
return t;
},
removeWakeup: (handler) => removeWakeupHandler(handler),
createRepeater: (delay, interval) => {
let epoch = currentTickNr + BigInt(delay);
let enabled = true;
const schedule = (handler) => {
timerService.setWakeup(epoch, harden({
wake: (t) => { if(enabled) { schedule(handler); }}
});
return timerService.setWakeup(epoch, handler);
}
schedule(harden({
wake: (t) => { epoch = epoch + BigInt(interval); }
}));
return harden({
schedule: (handler) => {
if (!enabled) {
throw new Error("repeater has been disabled");
}
return schedule(handler);
},
disable: () => { enabled = false; return undefined; }
});
}
});
let payoutSeatPromiseAndResolver = makePromiseKit();
const creatorFacet = harden({
getFacetForPayinInvitation: () => harden({
getPayinInvitation: () => zcf.makeInvitation((payinSeat) => {
return payoutSeatPromiseAndResolver.promise.then((payoutSeat) => {
const amountsRecord = payinSeat.getProposal().give;
const ticks = reiknir.getValue(amountRecord.Currency);
trade(zcf, {
seat: payinSeat, gains: {}, losses: amountsRecord
}, {
seat: payoutSeat, gains: amountsRecord, losses: {}
});
tickOnward(ticks);
return "Done";
});
}, "paymentDrivenCounterPayinInvitation")
})
});
const payoutOfferHandler = (payoutSeat) => {
payoutSeatPromiseAndResolver.resolver.resolve(payoutSeat);
payoutSeatPromiseAndResolver = makePromiseKit();
return harden({
invitation: zcf.makeInvitation(payoutOfferHandler, "payoutInvitation")
});
}
const creatorInvitation = zcf.makeInvitation(payoutOfferHandler, "initialPayoutInvitation");
const publicFacet = harden({
getTimerService: () => timerService;
});
return harden({ creatorFacet, creatorInvitation, publicFacet });
}
harden(start);
export { start };
// @ts-check
import { harden } from '@agoric/harden';
import { E, Far } from '@agoric/eventual-send';
import { AmountMath } from '@agoric/ERTP';
import { withdrawFromSeat } from '@agoric/zoe/src/contractSupport/index.js';
import { verifySigniture, getPayload } from '@zarutian/crypto/publickey';
const signingPublicKey = «insert signing public key here»;
// it is a good idea to specify pricelist in the conracts Terms
// @type {ContractStartFn}
const start = (zcf, privateArgs) => {
const Zoe = zcf.getZoeService();
const feeIssuer = E(Zoe).getFeeIssuer();
const feeBrand = E(feeIssuer).getBrand();
let {
myBudgetFeePurse, // an feePurse to charge when invoking Zoe
myFeePurseDepositFacet,
minimumBudgetAmount = AmountMath.make(feeBrand, 42_000_000n), // in fee Issuer units
} = privateArgs;
if ((myBudgetFeePurse != undefined) &&
(myFeePurseDepositFacet == undefined)) {
myFeePurseDepositFacet = E(myBudgetFeePurse).getDepositFacet();
} else if ((myBudgetFeePurse == undefined) &&
(myFeePurseDepositFacet != undefined)) {
myBudgetFeePurse = E(Zoe).makeFeePurse();
const oldFeePurseDepositFacet = myFeeDepositFacet;
myFeeDepositFacet = Far('fake feePurseDepositFacet', {
recieve: (allegedFeePayment) => E.when(
E(myBudgetFeePurse).getCurrentAmount),
currentBudgetAmount => {
if (AmountMath.isGTE(currentBudgetAmount, minimumBudgetAmount)) {
return E(oldFeePurseDepositFacet).recieve(allegedFeePayment);
} else {
const claimedFeePayment = E(feeIssuer).claim(allegedFeePayment);
return E.when(
E(feeIssuer).getAmountOf(claimedFeePayment),
feePaymentAmount => {
const shortfallAmount = AmountMath.subtract(minimumBudgetAmount, currentBudgetAmount);
const leftoverAmount = AmountMath.subtract(feePaymentAmount, shortfallAmount);
if (AmountMath.isEmpty(leftoverAmount)) {
return E(myBudgetFeePurse).deposit(claimedFeePayment);
} else {
const [shortfallPayment, leftoverPayment] = E.get(E(feeIssuer).split(claimedPayment, shortfallAmount));
const t1 = E(myBudgetFeePurse).deposit(shortfallPayment);
const t2 = E(oldFeePurseDepositFacet).recieve(leftoverPayment);
return Promise.all([t1, t2]);
}
},
);
}
},
),
});
}
E.when(E(board).getId(board), boardIdOfBoard => {
if (boardIdOfBoard != '«boardId of the board itself«') {
zcf.shutdown('the board was not found');
}
});
const chargeFeeToSeat = (zcfSeat, feeAmount) =>
E(myFeePurseDepositFacet).recieve(E.get(withdrawFromSeat(zcf, zcfSeat, { Fee: feeAmount })).Fee);;
const {
board, // todo: ensure that the ui-front end checks that it is the same board as it got from the wallet bridge
} = zcf.getTerms();
// «if applicable put a <at>type declaration here. Would be handy if the typedef is in this same file»
const creatorFacet = Far('creatorFacet', {
});
// «if applicable put a <at>type declaration here. Would be handy if the typedef is in this same file»
const publicFacet = Far('publicFacet', {
donateFee: (feePayment) => E(myFeePurseDepositFacet).recieve(feePayment),
posionPill: (cert) => {
if (verifySigniture(cert, signingPublicKey)) {
const {
contractBoardId,
} = JSON.parse(getPayload(cert));
const myInstance = zcf.getInstance();
return E.when(E(board).getId(myInstance), myBoardId => {
const cond = (contractBoardId != myBoardId);
if (cond) {
const t1 = E(board).getValue(contractBoardId);
const t2 = E(myZoe).getPublicFacet(t1);
const t3 = E(myBudgetFeePurse).getCurrentAmount();
const t4 = E.when(t3, amount => E(myBudgetFeePurse).withdraw(amount));
const t5 = E(t2).donateFee(t4);
E.when(t5, _ => zcf.shutdown('contract instance was posion pilled'));
}
return cond;
});
}
}
});
return harden({ creatorFacet, publicFacet };
};
harden(start);
export { start };
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment