@indigo-labs/indigo-sdk 0.1.7 → 0.1.8
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/.github/workflows/ci.yml +62 -0
- package/.github/workflows/test.yml +44 -0
- package/.husky/pre-commit +1 -0
- package/.nvmrc +1 -0
- package/.prettierrc +6 -0
- package/dist/index.d.mts +11 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +15 -0
- package/dist/index.mjs +14 -0
- package/eslint.config.mjs +36 -0
- package/package.json +2 -5
- package/src/contracts/cdp.ts +741 -0
- package/src/contracts/collector.ts +98 -0
- package/src/contracts/gov.ts +1 -0
- package/src/contracts/interest-oracle.ts +149 -0
- package/src/contracts/lrp.ts +315 -0
- package/src/contracts/one-shot.ts +67 -0
- package/src/contracts/stability-pool.ts +684 -0
- package/src/contracts/staking.ts +348 -0
- package/src/contracts/treasury.ts +112 -0
- package/src/helpers/asset-helpers.ts +57 -0
- package/src/helpers/helper-txs.ts +30 -0
- package/src/helpers/helpers.ts +38 -0
- package/src/helpers/indigo-helpers.ts +19 -0
- package/src/helpers/interest-oracle.ts +57 -0
- package/src/helpers/lucid-utils.ts +70 -0
- package/src/helpers/price-oracle-helpers.ts +36 -0
- package/src/helpers/stability-pool-helpers.ts +207 -0
- package/src/helpers/staking-helpers.ts +94 -0
- package/src/helpers/time-helpers.ts +4 -0
- package/src/helpers/value-helpers.ts +27 -0
- package/src/index.ts +34 -0
- package/src/scripts/always-fail-validator.ts +7 -0
- package/src/scripts/auth-token-policy.ts +23 -0
- package/src/scripts/cdp-creator-validator.ts +53 -0
- package/src/scripts/cdp-validator.ts +9 -0
- package/src/scripts/collector-validator.ts +8 -0
- package/src/scripts/execute-validator.ts +52 -0
- package/src/scripts/gov-validator.ts +44 -0
- package/src/scripts/iasset-policy.ts +22 -0
- package/src/scripts/interest-oracle-validator.ts +23 -0
- package/src/scripts/lrp-validator.ts +40 -0
- package/src/scripts/one-shot-policy.ts +62 -0
- package/src/scripts/poll-manager-validator.ts +52 -0
- package/src/scripts/poll-shard-validator.ts +47 -0
- package/src/scripts/price-oracle-validator.ts +26 -0
- package/src/scripts/stability-pool-validator.ts +60 -0
- package/src/scripts/staking-validator.ts +8 -0
- package/src/scripts/treasury-validator.ts +8 -0
- package/src/scripts/version-record-policy.ts +26 -0
- package/src/scripts/version-registry.ts +15 -0
- package/src/types/generic.ts +106 -0
- package/src/types/indigo/cdp-creator.ts +46 -0
- package/src/types/indigo/cdp.ts +88 -0
- package/src/types/indigo/execute.ts +21 -0
- package/src/types/indigo/gov.ts +51 -0
- package/src/types/indigo/interest-oracle.ts +55 -0
- package/src/types/indigo/lrp.ts +59 -0
- package/src/types/indigo/poll-manager.ts +21 -0
- package/src/types/indigo/poll-shard.ts +16 -0
- package/src/types/indigo/price-oracle.ts +38 -0
- package/src/types/indigo/stability-pool.ts +233 -0
- package/src/types/indigo/staking.ts +99 -0
- package/src/types/indigo/version-record.ts +17 -0
- package/src/types/on-chain-decimal.ts +23 -0
- package/src/types/one-shot.ts +22 -0
- package/src/types/system-params.ts +256 -0
- package/tests/data/system-params.json +1012 -0
- package/tests/datums.test.ts +286 -0
- package/tests/endpoints/initialize.ts +1013 -0
- package/tests/hash-checks.test.ts +80 -0
- package/tests/indigo-test-helpers.ts +115 -0
- package/tests/initialize.test.ts +27 -0
- package/tests/interest-calculations.test.ts +120 -0
- package/tests/interest-oracle.test.ts +90 -0
- package/tests/lrp.test.ts +777 -0
- package/tests/queries/governance-queries.ts +31 -0
- package/tests/queries/iasset-queries.ts +39 -0
- package/tests/queries/interest-oracle-queries.ts +13 -0
- package/tests/queries/lrp-queries.ts +39 -0
- package/tests/queries/price-oracle-queries.ts +27 -0
- package/tests/queries/stability-pool-queries.ts +75 -0
- package/tests/queries/staking-queries.ts +43 -0
- package/tests/stability-pool.test.ts +364 -0
- package/tests/staking.test.ts +105 -0
- package/tests/test-helpers.ts +38 -0
- package/tsconfig.build.json +4 -0
- package/tsconfig.json +17 -0
- package/vitest.config.ts +9 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Address,
|
|
3
|
+
applyParamsToScript,
|
|
4
|
+
Constr,
|
|
5
|
+
Data,
|
|
6
|
+
fromText,
|
|
7
|
+
LucidEvolution,
|
|
8
|
+
OutRef,
|
|
9
|
+
SpendingValidator,
|
|
10
|
+
TxBuilder,
|
|
11
|
+
UTxO,
|
|
12
|
+
validatorToAddress,
|
|
13
|
+
validatorToScriptHash,
|
|
14
|
+
} from '@lucid-evolution/lucid';
|
|
15
|
+
import { _collectorValidator } from '../scripts/collector-validator';
|
|
16
|
+
import {
|
|
17
|
+
CollectorParams,
|
|
18
|
+
ScriptReferences,
|
|
19
|
+
SystemParams,
|
|
20
|
+
} from '../types/system-params';
|
|
21
|
+
import { scriptRef } from '../helpers/lucid-utils';
|
|
22
|
+
import { getRandomElement } from '../helpers/helpers';
|
|
23
|
+
|
|
24
|
+
export class CollectorContract {
|
|
25
|
+
static async feeTx(
|
|
26
|
+
fee: bigint,
|
|
27
|
+
lucid: LucidEvolution,
|
|
28
|
+
params: SystemParams,
|
|
29
|
+
tx: TxBuilder,
|
|
30
|
+
collectorRef?: OutRef,
|
|
31
|
+
): Promise<void> {
|
|
32
|
+
const collectorUtxo: UTxO = collectorRef
|
|
33
|
+
? getRandomElement(await lucid.utxosByOutRef([collectorRef]))
|
|
34
|
+
: getRandomElement(
|
|
35
|
+
await lucid.utxosAt(
|
|
36
|
+
CollectorContract.address(params.collectorParams, lucid),
|
|
37
|
+
),
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const collectorScriptRefUtxo = await CollectorContract.scriptRef(
|
|
41
|
+
params.scriptReferences,
|
|
42
|
+
lucid,
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
tx.collectFrom([collectorUtxo], Data.to(new Constr(0, [])))
|
|
46
|
+
.pay.ToContract(
|
|
47
|
+
collectorUtxo.address,
|
|
48
|
+
{ kind: 'inline', value: Data.to(new Constr(0, [])) },
|
|
49
|
+
{
|
|
50
|
+
...collectorUtxo.assets,
|
|
51
|
+
lovelace: collectorUtxo.assets.lovelace + fee,
|
|
52
|
+
},
|
|
53
|
+
)
|
|
54
|
+
.readFrom([collectorScriptRefUtxo]);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Collector Validator
|
|
58
|
+
static validator(params: CollectorParams): SpendingValidator {
|
|
59
|
+
return {
|
|
60
|
+
type: 'PlutusV2',
|
|
61
|
+
script: applyParamsToScript(_collectorValidator.cborHex, [
|
|
62
|
+
new Constr(0, [
|
|
63
|
+
new Constr(0, [
|
|
64
|
+
params.stakingManagerNFT[0].unCurrencySymbol,
|
|
65
|
+
fromText(params.stakingManagerNFT[1].unTokenName),
|
|
66
|
+
]),
|
|
67
|
+
new Constr(0, [
|
|
68
|
+
params.stakingToken[0].unCurrencySymbol,
|
|
69
|
+
fromText(params.stakingToken[1].unTokenName),
|
|
70
|
+
]),
|
|
71
|
+
new Constr(0, [
|
|
72
|
+
params.versionRecordToken[0].unCurrencySymbol,
|
|
73
|
+
fromText(params.versionRecordToken[1].unTokenName),
|
|
74
|
+
]),
|
|
75
|
+
]),
|
|
76
|
+
]),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
static validatorHash(params: CollectorParams): string {
|
|
81
|
+
return validatorToScriptHash(CollectorContract.validator(params));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
static address(params: CollectorParams, lucid: LucidEvolution): Address {
|
|
85
|
+
const network = lucid.config().network;
|
|
86
|
+
if (!network) {
|
|
87
|
+
throw new Error('Network configuration is undefined');
|
|
88
|
+
}
|
|
89
|
+
return validatorToAddress(network, CollectorContract.validator(params));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
static async scriptRef(
|
|
93
|
+
params: ScriptReferences,
|
|
94
|
+
lucid: LucidEvolution,
|
|
95
|
+
): Promise<UTxO> {
|
|
96
|
+
return scriptRef(params.collectorValidatorRef, lucid);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export class GovContract {}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import {
|
|
2
|
+
fromText,
|
|
3
|
+
LucidEvolution,
|
|
4
|
+
OutRef,
|
|
5
|
+
toUnit,
|
|
6
|
+
TxBuilder,
|
|
7
|
+
UTxO,
|
|
8
|
+
validatorToAddress,
|
|
9
|
+
} from '@lucid-evolution/lucid';
|
|
10
|
+
import { AssetClass } from '../types/generic';
|
|
11
|
+
import {
|
|
12
|
+
InterestOracleParams,
|
|
13
|
+
parseInterestOracleDatum,
|
|
14
|
+
serialiseFeedInterestOracleRedeemer,
|
|
15
|
+
serialiseInterestOracleDatum,
|
|
16
|
+
} from '../types/indigo/interest-oracle';
|
|
17
|
+
import { oneShotMintTx } from './one-shot';
|
|
18
|
+
import { mkInterestOracleValidator } from '../scripts/interest-oracle-validator';
|
|
19
|
+
import { findInterestOracle } from '../../tests/queries/interest-oracle-queries';
|
|
20
|
+
import { ONE_SECOND } from '../helpers/time-helpers';
|
|
21
|
+
import { calculateUnitaryInterestSinceOracleLastUpdated } from '../helpers/interest-oracle';
|
|
22
|
+
|
|
23
|
+
export class InterestOracleContract {
|
|
24
|
+
static async startInterestOracle(
|
|
25
|
+
initialUnitaryInterest: bigint,
|
|
26
|
+
initialInterestRate: bigint,
|
|
27
|
+
initialLastInterestUpdate: bigint,
|
|
28
|
+
oracleParams: InterestOracleParams,
|
|
29
|
+
lucid: LucidEvolution,
|
|
30
|
+
withScriptRef: boolean = false,
|
|
31
|
+
refOutRef?: OutRef,
|
|
32
|
+
interestTokenName?: string,
|
|
33
|
+
): Promise<[TxBuilder, AssetClass]> {
|
|
34
|
+
const tokenName = interestTokenName ?? 'INTEREST_ORACLE';
|
|
35
|
+
if (!refOutRef) {
|
|
36
|
+
refOutRef = (await lucid.wallet().getUtxos())[0];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const [tx, policyId] = await oneShotMintTx(lucid, {
|
|
40
|
+
referenceOutRef: {
|
|
41
|
+
txHash: refOutRef.txHash,
|
|
42
|
+
outputIdx: BigInt(refOutRef.outputIndex),
|
|
43
|
+
},
|
|
44
|
+
mintAmounts: [
|
|
45
|
+
{
|
|
46
|
+
tokenName: fromText(tokenName),
|
|
47
|
+
amount: 1n,
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const validator = mkInterestOracleValidator(oracleParams);
|
|
53
|
+
|
|
54
|
+
tx.pay.ToContract(
|
|
55
|
+
validatorToAddress(lucid.config().network, validator),
|
|
56
|
+
{
|
|
57
|
+
kind: 'inline',
|
|
58
|
+
value: serialiseInterestOracleDatum({
|
|
59
|
+
unitaryInterest: initialUnitaryInterest,
|
|
60
|
+
interestRate: {
|
|
61
|
+
getOnChainInt: initialInterestRate,
|
|
62
|
+
},
|
|
63
|
+
lastUpdated: initialLastInterestUpdate,
|
|
64
|
+
}),
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
lovelace: 2_500_000n,
|
|
68
|
+
[toUnit(policyId, fromText(tokenName))]: 1n,
|
|
69
|
+
},
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
if (withScriptRef) {
|
|
73
|
+
tx.pay.ToAddressWithData(
|
|
74
|
+
validatorToAddress(lucid.config().network, validator),
|
|
75
|
+
undefined,
|
|
76
|
+
undefined,
|
|
77
|
+
validator,
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return [
|
|
82
|
+
tx,
|
|
83
|
+
{
|
|
84
|
+
currencySymbol: policyId,
|
|
85
|
+
tokenName: fromText(tokenName),
|
|
86
|
+
},
|
|
87
|
+
];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
static async feedInterestOracle(
|
|
91
|
+
params: InterestOracleParams,
|
|
92
|
+
newInterestRate: bigint,
|
|
93
|
+
lucid: LucidEvolution,
|
|
94
|
+
assetClass?: AssetClass,
|
|
95
|
+
utxo?: UTxO,
|
|
96
|
+
scriptRef?: UTxO,
|
|
97
|
+
): Promise<TxBuilder> {
|
|
98
|
+
if (!assetClass && !utxo)
|
|
99
|
+
throw new Error('Either interest oracle nft or utxo must be provided');
|
|
100
|
+
if (assetClass && !utxo) {
|
|
101
|
+
const [ioUtxo, _datum] = await findInterestOracle(lucid, assetClass);
|
|
102
|
+
utxo = ioUtxo;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const now = BigInt(Date.now());
|
|
106
|
+
const tx = lucid.newTx();
|
|
107
|
+
const datum = parseInterestOracleDatum(utxo.datum);
|
|
108
|
+
|
|
109
|
+
if (scriptRef) {
|
|
110
|
+
tx.readFrom([scriptRef]);
|
|
111
|
+
} else {
|
|
112
|
+
tx.attach.Script(mkInterestOracleValidator(params));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
tx.collectFrom(
|
|
116
|
+
[utxo],
|
|
117
|
+
serialiseFeedInterestOracleRedeemer({
|
|
118
|
+
newInterestRate: {
|
|
119
|
+
getOnChainInt: newInterestRate,
|
|
120
|
+
},
|
|
121
|
+
currentTime: now,
|
|
122
|
+
}),
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
tx.pay.ToContract(
|
|
126
|
+
utxo.address,
|
|
127
|
+
{
|
|
128
|
+
kind: 'inline',
|
|
129
|
+
value: serialiseInterestOracleDatum({
|
|
130
|
+
unitaryInterest:
|
|
131
|
+
datum.unitaryInterest +
|
|
132
|
+
calculateUnitaryInterestSinceOracleLastUpdated(now, datum),
|
|
133
|
+
interestRate: {
|
|
134
|
+
getOnChainInt: newInterestRate,
|
|
135
|
+
},
|
|
136
|
+
lastUpdated: now,
|
|
137
|
+
}),
|
|
138
|
+
},
|
|
139
|
+
utxo.assets,
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
tx.validFrom(Number(now) - ONE_SECOND);
|
|
143
|
+
tx.validTo(Number(now + params.biasTime) - ONE_SECOND);
|
|
144
|
+
|
|
145
|
+
tx.addSignerKey(params.owner);
|
|
146
|
+
|
|
147
|
+
return tx;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LucidEvolution,
|
|
3
|
+
Network,
|
|
4
|
+
ScriptHash,
|
|
5
|
+
TxBuilder,
|
|
6
|
+
Credential,
|
|
7
|
+
OutRef,
|
|
8
|
+
UTxO,
|
|
9
|
+
addAssets,
|
|
10
|
+
} from '@lucid-evolution/lucid';
|
|
11
|
+
import {
|
|
12
|
+
addrDetails,
|
|
13
|
+
createScriptAddress,
|
|
14
|
+
getInlineDatumOrThrow,
|
|
15
|
+
} from '../helpers/lucid-utils';
|
|
16
|
+
import { match, P } from 'ts-pattern';
|
|
17
|
+
import { unzip, zip } from 'fp-ts/lib/Array';
|
|
18
|
+
import { reduceWithIndex } from 'fp-ts/lib/Array';
|
|
19
|
+
import {
|
|
20
|
+
LRPDatum,
|
|
21
|
+
LRPParams,
|
|
22
|
+
parseLrpDatum,
|
|
23
|
+
serialiseLrpDatum,
|
|
24
|
+
serialiseLrpRedeemer,
|
|
25
|
+
} from '../types/indigo/lrp';
|
|
26
|
+
import {
|
|
27
|
+
parsePriceOracleDatum,
|
|
28
|
+
PriceOracleParams,
|
|
29
|
+
} from '../types/indigo/price-oracle';
|
|
30
|
+
import { ocdMul, OnChainDecimal } from '../types/on-chain-decimal';
|
|
31
|
+
import { parseIAssetDatum } from '../types/indigo/cdp';
|
|
32
|
+
import {
|
|
33
|
+
assetClassValueOf,
|
|
34
|
+
mkAssetsOf,
|
|
35
|
+
mkLovelacesOf,
|
|
36
|
+
} from '../helpers/value-helpers';
|
|
37
|
+
import { oracleExpirationAwareValidity } from '../helpers/price-oracle-helpers';
|
|
38
|
+
import { calculateFeeFromPercentage } from '../helpers/indigo-helpers';
|
|
39
|
+
import { matchSingle } from '../helpers/helpers';
|
|
40
|
+
import { AssetClass } from '../types/generic';
|
|
41
|
+
|
|
42
|
+
const MIN_UTXO_COLLATERAL_AMT = 2_000_000n;
|
|
43
|
+
|
|
44
|
+
export async function openLrp(
|
|
45
|
+
assetTokenName: string,
|
|
46
|
+
lovelacesAmt: bigint,
|
|
47
|
+
maxPrice: OnChainDecimal,
|
|
48
|
+
lucid: LucidEvolution,
|
|
49
|
+
lrpScriptHash: ScriptHash,
|
|
50
|
+
network: Network,
|
|
51
|
+
lrpStakeCredential?: Credential,
|
|
52
|
+
): Promise<TxBuilder> {
|
|
53
|
+
const [ownPkh, _] = await addrDetails(lucid);
|
|
54
|
+
|
|
55
|
+
const newDatum: LRPDatum = {
|
|
56
|
+
owner: ownPkh.hash,
|
|
57
|
+
iasset: assetTokenName,
|
|
58
|
+
maxPrice: maxPrice,
|
|
59
|
+
lovelacesToSpend: lovelacesAmt,
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
return lucid.newTx().pay.ToContract(
|
|
63
|
+
createScriptAddress(network, lrpScriptHash, lrpStakeCredential),
|
|
64
|
+
{
|
|
65
|
+
kind: 'inline',
|
|
66
|
+
value: serialiseLrpDatum(newDatum),
|
|
67
|
+
},
|
|
68
|
+
{ lovelace: lovelacesAmt + MIN_UTXO_COLLATERAL_AMT },
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export async function cancelLrp(
|
|
73
|
+
lrpOutRef: OutRef,
|
|
74
|
+
lrpRefScriptOutRef: OutRef,
|
|
75
|
+
lucid: LucidEvolution,
|
|
76
|
+
): Promise<TxBuilder> {
|
|
77
|
+
const ownAddr = await lucid.wallet().address();
|
|
78
|
+
// TODO: use Promise.all
|
|
79
|
+
const lrpScriptRefUtxo = matchSingle(
|
|
80
|
+
await lucid.utxosByOutRef([lrpRefScriptOutRef]),
|
|
81
|
+
(_) => new Error('Expected a single LRP Ref Script UTXO'),
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const lrpUtxo = matchSingle(
|
|
85
|
+
await lucid.utxosByOutRef([lrpOutRef]),
|
|
86
|
+
(_) => new Error('Expected a single LRP UTXO.'),
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
return lucid
|
|
90
|
+
.newTx()
|
|
91
|
+
.readFrom([lrpScriptRefUtxo])
|
|
92
|
+
.collectFrom([lrpUtxo], serialiseLrpRedeemer('Cancel'))
|
|
93
|
+
.addSigner(ownAddr);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export async function redeemLrp(
|
|
97
|
+
/** The tuple represents the LRP outref and the amount of iAssets to redeem against it. */
|
|
98
|
+
redemptionLrpsData: [OutRef, bigint][],
|
|
99
|
+
lrpRefScriptOutRef: OutRef,
|
|
100
|
+
priceOracleOutRef: OutRef,
|
|
101
|
+
iassetOutRef: OutRef,
|
|
102
|
+
lucid: LucidEvolution,
|
|
103
|
+
lrpParams: LRPParams,
|
|
104
|
+
priceOracleParams: PriceOracleParams,
|
|
105
|
+
network: Network,
|
|
106
|
+
currentSlot: number,
|
|
107
|
+
): Promise<TxBuilder> {
|
|
108
|
+
const lrpScriptRefUtxo = matchSingle(
|
|
109
|
+
await lucid.utxosByOutRef([lrpRefScriptOutRef]),
|
|
110
|
+
(_) => new Error('Expected a single LRP Ref Script UTXO'),
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
const priceOracleUtxo = matchSingle(
|
|
114
|
+
await lucid.utxosByOutRef([priceOracleOutRef]),
|
|
115
|
+
(_) => new Error('Expected a single price oracle UTXO'),
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
const iassetUtxo = matchSingle(
|
|
119
|
+
await lucid.utxosByOutRef([iassetOutRef]),
|
|
120
|
+
(_) => new Error('Expected a single IAsset UTXO'),
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
const iassetDatum = parseIAssetDatum(getInlineDatumOrThrow(iassetUtxo));
|
|
124
|
+
|
|
125
|
+
const [lrpsToRedeemOutRefs, lrpRedemptionIAssetAmt] =
|
|
126
|
+
unzip(redemptionLrpsData);
|
|
127
|
+
|
|
128
|
+
const priceOracleDatum = parsePriceOracleDatum(
|
|
129
|
+
getInlineDatumOrThrow(priceOracleUtxo),
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
const redemptionLrps = await lucid
|
|
133
|
+
.utxosByOutRef(lrpsToRedeemOutRefs)
|
|
134
|
+
.then((val) => zip(val, lrpRedemptionIAssetAmt));
|
|
135
|
+
|
|
136
|
+
const [[mainLrpUtxo, _], __] = match(redemptionLrps)
|
|
137
|
+
.with(
|
|
138
|
+
[P._, ...P.array()],
|
|
139
|
+
([[firstLrp, _], ...rest]): [[UTxO, bigint], [UTxO, bigint][]] => [
|
|
140
|
+
[firstLrp, _],
|
|
141
|
+
rest,
|
|
142
|
+
],
|
|
143
|
+
)
|
|
144
|
+
.otherwise(() => {
|
|
145
|
+
throw new Error('Expects at least 1 UTXO to redeem.');
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
const mainLrpDatum = parseLrpDatum(getInlineDatumOrThrow(mainLrpUtxo));
|
|
149
|
+
|
|
150
|
+
const tx = reduceWithIndex<[UTxO, bigint], TxBuilder>(
|
|
151
|
+
lucid.newTx(),
|
|
152
|
+
(idx, acc, [lrpUtxo, redeemIAssetAmt]) => {
|
|
153
|
+
const lovelacesForRedemption = ocdMul(
|
|
154
|
+
{
|
|
155
|
+
getOnChainInt: redeemIAssetAmt,
|
|
156
|
+
},
|
|
157
|
+
priceOracleDatum.price,
|
|
158
|
+
).getOnChainInt;
|
|
159
|
+
const reimburstmentLovelaces = calculateFeeFromPercentage(
|
|
160
|
+
iassetDatum.redemptionReimbursementPercentage,
|
|
161
|
+
lovelacesForRedemption,
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
const lrpDatum = parseLrpDatum(getInlineDatumOrThrow(lrpUtxo));
|
|
165
|
+
|
|
166
|
+
return acc
|
|
167
|
+
.collectFrom(
|
|
168
|
+
[lrpUtxo],
|
|
169
|
+
serialiseLrpRedeemer(
|
|
170
|
+
idx === 0
|
|
171
|
+
? { Redeem: { continuingOutputIdx: 0n } }
|
|
172
|
+
: {
|
|
173
|
+
RedeemAuxiliary: {
|
|
174
|
+
continuingOutputIdx: BigInt(idx),
|
|
175
|
+
mainRedeemOutRef: {
|
|
176
|
+
txHash: { hash: mainLrpUtxo.txHash },
|
|
177
|
+
outputIndex: BigInt(mainLrpUtxo.outputIndex),
|
|
178
|
+
},
|
|
179
|
+
asset: mainLrpDatum.iasset,
|
|
180
|
+
assetPrice: priceOracleDatum.price,
|
|
181
|
+
redemptionReimbursementPercentage:
|
|
182
|
+
iassetDatum.redemptionReimbursementPercentage,
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
),
|
|
186
|
+
)
|
|
187
|
+
.pay.ToContract(
|
|
188
|
+
lrpUtxo.address,
|
|
189
|
+
{
|
|
190
|
+
kind: 'inline',
|
|
191
|
+
value: serialiseLrpDatum({
|
|
192
|
+
...lrpDatum,
|
|
193
|
+
lovelacesToSpend:
|
|
194
|
+
lrpDatum.lovelacesToSpend - lovelacesForRedemption,
|
|
195
|
+
}),
|
|
196
|
+
},
|
|
197
|
+
addAssets(
|
|
198
|
+
lrpUtxo.assets,
|
|
199
|
+
mkLovelacesOf(-(lovelacesForRedemption - reimburstmentLovelaces)),
|
|
200
|
+
mkAssetsOf(
|
|
201
|
+
{
|
|
202
|
+
currencySymbol: lrpParams.iassetPolicyId,
|
|
203
|
+
tokenName: mainLrpDatum.iasset,
|
|
204
|
+
},
|
|
205
|
+
redeemIAssetAmt,
|
|
206
|
+
),
|
|
207
|
+
),
|
|
208
|
+
);
|
|
209
|
+
},
|
|
210
|
+
)(redemptionLrps);
|
|
211
|
+
|
|
212
|
+
const txValidity = oracleExpirationAwareValidity(
|
|
213
|
+
currentSlot,
|
|
214
|
+
Number(priceOracleParams.biasTime),
|
|
215
|
+
Number(priceOracleDatum.expiration),
|
|
216
|
+
network,
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
return (
|
|
220
|
+
lucid
|
|
221
|
+
.newTx()
|
|
222
|
+
.validFrom(txValidity.validFrom)
|
|
223
|
+
.validTo(txValidity.validTo)
|
|
224
|
+
// Ref script
|
|
225
|
+
.readFrom([lrpScriptRefUtxo])
|
|
226
|
+
// Ref inputs
|
|
227
|
+
.readFrom([iassetUtxo, priceOracleUtxo])
|
|
228
|
+
.compose(tx)
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Create Tx adjusting the LRP and claiming the received iAssets
|
|
234
|
+
*/
|
|
235
|
+
export async function adjustLrp(
|
|
236
|
+
lucid: LucidEvolution,
|
|
237
|
+
lrpOutRef: OutRef,
|
|
238
|
+
/**
|
|
239
|
+
* A positive amount increases the lovelaces in the LRP,
|
|
240
|
+
* and a negative amount takes lovelaces from the LRP.
|
|
241
|
+
*/
|
|
242
|
+
lovelacesAdjustAmt: bigint,
|
|
243
|
+
lrpRefScriptOutRef: OutRef,
|
|
244
|
+
lrpParams: LRPParams,
|
|
245
|
+
): Promise<TxBuilder> {
|
|
246
|
+
const ownAddr = await lucid.wallet().address();
|
|
247
|
+
|
|
248
|
+
const lrpScriptRefUtxo = matchSingle(
|
|
249
|
+
await lucid.utxosByOutRef([lrpRefScriptOutRef]),
|
|
250
|
+
(_) => new Error('Expected a single LRP Ref Script UTXO'),
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
const lrpUtxo = matchSingle(
|
|
254
|
+
await lucid.utxosByOutRef([lrpOutRef]),
|
|
255
|
+
(_) => new Error('Expected a single LRP UTXO.'),
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
const lrpDatum = parseLrpDatum(getInlineDatumOrThrow(lrpUtxo));
|
|
259
|
+
|
|
260
|
+
const rewardAssetClass: AssetClass = {
|
|
261
|
+
currencySymbol: lrpParams.iassetPolicyId,
|
|
262
|
+
tokenName: lrpDatum.iasset,
|
|
263
|
+
};
|
|
264
|
+
const rewardAssetsAmt = assetClassValueOf(lrpUtxo.assets, rewardAssetClass);
|
|
265
|
+
|
|
266
|
+
// The claim case
|
|
267
|
+
if (lovelacesAdjustAmt === 0n && lrpDatum.lovelacesToSpend === 0n) {
|
|
268
|
+
throw new Error(
|
|
269
|
+
"When there's no more lovelaces to spend, use close instead of claim.",
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Negative adjust case
|
|
274
|
+
if (
|
|
275
|
+
lovelacesAdjustAmt < 0 &&
|
|
276
|
+
lrpDatum.lovelacesToSpend <= lovelacesAdjustAmt
|
|
277
|
+
) {
|
|
278
|
+
throw new Error(
|
|
279
|
+
"Can't adjust negatively by more than available. Also, for adjusting by exactly the amount deposited, a close action should be used instead.",
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return lucid
|
|
284
|
+
.newTx()
|
|
285
|
+
.readFrom([lrpScriptRefUtxo])
|
|
286
|
+
.collectFrom([lrpUtxo], serialiseLrpRedeemer('Cancel'))
|
|
287
|
+
.pay.ToContract(
|
|
288
|
+
lrpUtxo.address,
|
|
289
|
+
{
|
|
290
|
+
kind: 'inline',
|
|
291
|
+
value: serialiseLrpDatum({
|
|
292
|
+
...lrpDatum,
|
|
293
|
+
lovelacesToSpend: lrpDatum.lovelacesToSpend + lovelacesAdjustAmt,
|
|
294
|
+
}),
|
|
295
|
+
},
|
|
296
|
+
addAssets(
|
|
297
|
+
lrpUtxo.assets,
|
|
298
|
+
mkAssetsOf(rewardAssetClass, -rewardAssetsAmt),
|
|
299
|
+
mkLovelacesOf(lovelacesAdjustAmt),
|
|
300
|
+
),
|
|
301
|
+
)
|
|
302
|
+
.addSigner(ownAddr);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Create Tx claiming the received iAssets.
|
|
307
|
+
*/
|
|
308
|
+
export async function claimLrp(
|
|
309
|
+
lucid: LucidEvolution,
|
|
310
|
+
lrpOutRef: OutRef,
|
|
311
|
+
lrpRefScriptOutRef: OutRef,
|
|
312
|
+
lrpParams: LRPParams,
|
|
313
|
+
): Promise<TxBuilder> {
|
|
314
|
+
return adjustLrp(lucid, lrpOutRef, 0n, lrpRefScriptOutRef, lrpParams);
|
|
315
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import {
|
|
2
|
+
addAssets,
|
|
3
|
+
Assets,
|
|
4
|
+
Constr,
|
|
5
|
+
Data,
|
|
6
|
+
LucidEvolution,
|
|
7
|
+
mintingPolicyToId,
|
|
8
|
+
PolicyId,
|
|
9
|
+
toUnit,
|
|
10
|
+
TxBuilder,
|
|
11
|
+
} from '@lucid-evolution/lucid';
|
|
12
|
+
import { OneShotParams } from '../types/one-shot';
|
|
13
|
+
import { matchSingle } from '../helpers/helpers';
|
|
14
|
+
import { mkOneShotPolicy } from '../scripts/one-shot-policy';
|
|
15
|
+
import { reduce } from 'fp-ts/lib/Array';
|
|
16
|
+
|
|
17
|
+
export async function oneShotMintTx(
|
|
18
|
+
lucid: LucidEvolution,
|
|
19
|
+
params: OneShotParams,
|
|
20
|
+
): Promise<[TxBuilder, PolicyId]> {
|
|
21
|
+
const oneShotPolicy = mkOneShotPolicy(params);
|
|
22
|
+
const policyId = mintingPolicyToId(oneShotPolicy);
|
|
23
|
+
|
|
24
|
+
const refUtxo = matchSingle(
|
|
25
|
+
await lucid.utxosByOutRef([
|
|
26
|
+
{
|
|
27
|
+
txHash: params.referenceOutRef.txHash,
|
|
28
|
+
outputIndex: Number(params.referenceOutRef.outputIdx),
|
|
29
|
+
},
|
|
30
|
+
]),
|
|
31
|
+
(_) => {
|
|
32
|
+
throw new Error('Cannot find the reference UTXO for one-shot.');
|
|
33
|
+
},
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
return [
|
|
37
|
+
lucid
|
|
38
|
+
.newTx()
|
|
39
|
+
.collectFrom([refUtxo])
|
|
40
|
+
.mintAssets(
|
|
41
|
+
reduce<{ tokenName: string; amount: bigint }, Assets>(
|
|
42
|
+
{},
|
|
43
|
+
(acc, entry) =>
|
|
44
|
+
addAssets(acc, {
|
|
45
|
+
[toUnit(policyId, entry.tokenName)]: entry.amount,
|
|
46
|
+
}),
|
|
47
|
+
)(params.mintAmounts),
|
|
48
|
+
Data.to(new Constr(0, [])),
|
|
49
|
+
)
|
|
50
|
+
.attach.MintingPolicy(oneShotPolicy),
|
|
51
|
+
policyId,
|
|
52
|
+
];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export async function runOneShotMintTx(
|
|
56
|
+
lucid: LucidEvolution,
|
|
57
|
+
params: OneShotParams,
|
|
58
|
+
): Promise<PolicyId> {
|
|
59
|
+
const [tx, policyId] = await oneShotMintTx(lucid, params);
|
|
60
|
+
const txHash = await tx
|
|
61
|
+
.complete()
|
|
62
|
+
.then((tx) => tx.sign.withWallet().complete())
|
|
63
|
+
.then((tx) => tx.submit());
|
|
64
|
+
|
|
65
|
+
await lucid.awaitTx(txHash);
|
|
66
|
+
return policyId;
|
|
67
|
+
}
|