# Welcome!

Your go-to resource for Agoric example contracts and components

This GitBook is dedicated to our library of open-source, community-built smart contracts, APIs, and example implementations to build on the Agoric chain. Plus, we've also included a handful of bounties you can browse through!&#x20;

{% hint style="info" %}
**Need Developer Support?**&#x20;

Stuck on a problem? Looking for one-on-one support? Join the Agoric OpCo development team for our weekly Office Hours every Wednesday at 12pm ET.&#x20;

:link: [**Join Office Hours**](https://agoric.com/office-hours)
{% endhint %}

{% hint style="info" %}
**Join Our Community**

Our growing community of developers are always looking to share ideas, help with problems, and showcase their work. Plus - meet the team building Agoric!&#x20;

:link: [**Agoric Discord**](https://agoric.com/discord)
{% endhint %}


# Getting Started

Requirements for setting up your Agoric development environment

{% hint style="warning" %}
**Limited Developer Support**

All assets represented in this library are community built, which means limited support from the Agoric OpCo development team. Please use components, APIs, and front-ends with caution. &#x20;
{% endhint %}

### SDK Installation

Please refer to [documentation page](< https://docs.agoric.com/guides/getting-started/ >) for the steps to get started.

### Helpful Video Tutorials &#x20;

Browse through key developer tutorials to get you started on your journey developing with Agoric's library of components in Hardened JavaScript..&#x20;

### Starter Guide: Code with Agoric JavaScript Smart Contracts

{% embed url="<https://youtu.be/xnxa-G5PFEk>" %}
&#x20;See installation guide at: [https://github.com/RBFLabs/intro-agoric-smart-contracts ](<https://github.com/RBFLabs/intro-agoric-smart-contracts >)\
Note: The video is based on the beta branch of the sdk and it expects the beta branch to be on the version 0.15.0 of the sdk which in fact as of 2023-07-19 beta branch is on 0.16.0.
{% endembed %}

### How To: Build DeFi with Agoric

{% embed url="<https://youtu.be/qudVWjSqDJU>" %}


# DeFi

**Decentralized Finance** (DeFi) refers to a financial system built on blockchain technology that allows for peer-to-peer transactions without intermediaries like banks or traditional financial institutions. In a DeFi system, financial transactions are executed through smart contracts and decentralized applications (dapps) that run on a blockchain network.

DeFi has several key features, including transparency, immutability, security, and accessibility. Transactions are transparent and can be viewed by anyone on the blockchain network, making it difficult to manipulate or falsify data. Smart contracts are self-executing and automate the process of verifying and executing transactions, which reduces the need for intermediaries and ensures that transactions are executed as intended.

Some of the most popular applications of DeFi include cryptocurrency exchanges, lending platforms, and stable tokens. Cryptocurrency exchanges allow users to trade one cryptocurrency for another without the need for a centralized authority, while lending platforms allow users to lend and borrow digital assets without the need for a traditional bank. Stable tokens are digital currencies that are pegged to a stable asset, such as the US dollar, and are used to minimize price volatility in the cryptocurrency market.

Overall, DeFi is an emerging field that has the potential to revolutionize the traditional financial system by creating a more open, transparent, and accessible financial system for everyone.


# Lending Protocol

A pool-based loan contract on Agoric

{% hint style="warning" %}
**Limited Developer Support**

All assets represented in this library are community built, which means limited support from the Agoric OpCo development team. Please use components, APIs, and front-ends with caution. &#x20;
{% endhint %}

## Summary

The LendingPool Protocol component is a pool-based loan protocol on Agoric that offers users five main operations that they can perform: deposit money, borrow money, redeem deposited money, adjust loans, and close loans. These functionalities are distributed among several components that make up the protocol.

## Details

The LendingPool Protocol is based on Compound Finance, with several pools containing underlying assets and accepting multiple collateral types to lend the underlying asset. Liquidity providers fund the pools and receive a protocol token that is minted when they deposit money into the pool. The protocol token is exchanged for the underlying asset at an exchange rate, which increases as interest accrues. The interest rate for borrowers is dynamically calculated using pre-determined parameters and variables within a pool.

Loans lent from this protocol are over-collateralized, meaning that the value of the collateral must be greater than the value of the debt being requested by a predetermined margin called the 'liquidationMargin.' When creating a new pool, the liquidationMargin is passed as a variable. If a loan falls below the liquidationMargin, it gets liquidated by selling the collateral in Agoric's native AMM. Only the amount of collateral sufficient to cover the value of the debt is sold, while the remaining collateral is available for the borrower to withdraw.

LendingPool is similar to the VaultFactory in a way that they both accept a collateral and lend money for that collateral. The difference is that VaultFactory mints IST and lends it whereas LendingPool uses its own liquidity to lend money. Another important difference is that LendingPool lends multiple types of assets whereas VaultFactory only lends IST.&#x20;

Two important modules implemented on the LendingPool are the liquidationObserver and debtsPerCollateral.

The liquidationObserver has a method called checkLiquidation, which detects when the loan's Collateral/Debt ratio exceeds the allowed limit. It uses a generator function to track the latest debt and collateral prices and checks if it triggers a liquidation. If so, it resolves a promise with the specific prices that caused the liquidation and terminates the control flow.

The debtsPerCollateral gathers loans with the same collateral type and provides functions to add new loans and set up a liquidator contract. It also utilizes a liquidationObserver object to schedule and execute liquidation when the closest loan to the liquidation margin reaches its threshold.

## Dependencies

There are some previous considerations to have before instantiating this contract.

The first one is related to the agoric-sdk version used at the moment of its development. The tag returned by running the command git describe --tags --always is agoric-upgrade-8-326-g65d3f14c8, so it is advised to checkout to the same state when exploring this component and test if any major update is required in order to be implemented at the desired agoric-sdk version.

```
git checkout 65d3f14c8102993168d2568eed5e6acbcba0c48a
```

The lendingPool module relies on the Agoric AMM (Automated Market Maker) to have pools like {lending\_pool\_underlying\_currency} / IST in order to facilitate its liquidation process. By having these specific pools available, the lendingPool module can effectively execute its liquidation operations.

When the contract is instantiated, the initialPoserInvitation should be included on the privateArgs, which is accessible through the lendingPoolElectorate creatorFacet.\
The contract terms should specify the following attributes:

```
 const {
   ammPublicFacet,
   priceManager,
   timerService,
   liquidationInstall,
   loanTimingParams,
   compareCurrencyBrand,
   governance: {
     keyword,
     units,
     decimals,
     committeeSize
   },
 } = terms;
```

## Contract Facets

The LendingPool contract exports two remotable objects, publicFacet and the lendingPoolWrapper.

The publicFacet has a list of methods that allows any user to monitor and interact with lending pools, as well as some governance related methods.

The lendingPoolWrapper has multiple methods that are accessible exclusively to the contract owner through the lendingPoolElectionManager contract for monitoring and governance purposes.\
For each method mentioned, a more detailed description will be provided in the next section<br>

```
 const publicFacet = Far('lending pool public facet', {
   helloWorld: () => 'Hello World',
   hasPool,
   hasKeyword,
   getPool: brand => poolTypes.get(brand),
   makeBorrowInvitation,
   makeRedeemInvitation,
   makeDepositInvitation,
   getPoolNotifier: () => poolNotifier,
   getGovernanceBrand: () => govBrand,
   getGovernanceIssuer: () => govIssuer,
   getGovernanceKeyword: () => keyword,
   getTotalSupply: () => totalSupply,
   getProposalTreshold: () => proposalThreshold,
   getGovBalance: () => govSeat.getAmountAllocated(keyword, govBrand),
   getMemberSupplyAmount: () => memberSupplyAmount,
   getCommitteeSize: () => committeeSize,
   getParamsSubscription: underlyingBrand => E(poolParamManagers.get(underlyingBrand)).getSubscription(),
   getCollateralBalance: brand => balanceTracer.getBalance(brand),
 });
 
 const lendingPoolWrapper = Far('powerful lendingPool wrapper', {
   getParamMgrRetriever,
   getLimitedCreatorFacet: () => lendingPool,
   getGovernedApis: () => Far('GovernedApis', { addPoolType }),
   getGovernedApiNames: () => harden(['addPoolType']),
 });
```

## Functionalities

### hasPool

The hasPool function receives a brand as an argument and will verify if a pool was previously created for that brand by checking the poolTypes and poolParamManagers maps.\
It will return true if it exists and false if not.

```
 const hasPool = brand => {
   const result = poolTypes.has(brand) && poolParamManagers.has(brand);
   return result;
 };
```

### hasKeyword

The hasKeyword function receives a keyword as an argument and will check if it is valid and was not already used as a brand in this Instance.

It will return undefined if it is unique or throw an appropriate error if it's not.

```
const hasKeyword = keyword => {
   return zcf.assertUniqueKeyword(keyword);
 };
```

### getPool

The getPool function receives a brand as an argument and it will return the respective poolManager for the brand provided.

```
getPool: brand => poolTypes.get(brand),
```

### makeBorrowInvitation

When the user wishes to borrow an asset in exchange for a collateral, he can do it by exercising the makeBorrowInvitation. The offer proposal needs to define the amount of Debt requested and the amount of Collateral that will be provided, which should correspond to the payment.\
In addition to the proposal and payment, the user needs to specify the collateralUnderlyingBrand in the offerArgs.

A few assertions will be conducted, verifying that the collateralUnderlyingBrand provided on the offerArgs exists on the poolTypes map, if the Collateral and Debt brands are supported and if  the collateral does not exceed the allowed limit.

```
const makeBorrowInvitation = () => {
   /**
    * @type OfferHandler
    * */
   const borrowHook = async (borrowerSeat, offerArgs) => {
     assertProposalShape(borrowerSeat, {
       give: { Collateral: null },
       want: { Debt: null },
     });


     const collateralUnderlyingBrand = assertBorrowOfferArgs(offerArgs, poolTypes);
     /** @type PoolManager */
     const collateralUnderlyingPool = poolTypes.get(collateralUnderlyingBrand);


     const borrowBrand = assertBorrowProposal(poolTypes, borrowerSeat, collateralUnderlyingPool);
     assertColLimitNotExceeded(balanceTracer, getCollateralLimit, borrowerSeat.getProposal(), collateralUnderlyingBrand);


     const currentCollateralExchangeRate = collateralUnderlyingPool.getExchangeRate();
     const pool = poolTypes.get(borrowBrand);
     assertAssetsUsableInLoan(pool, collateralUnderlyingPool);


     return pool.makeBorrowKit(borrowerSeat, currentCollateralExchangeRate);
   };


   return zcf.makeInvitation(borrowHook, 'Borrow');
 };
```

Once all the assertions have been passed, the poolManager's makeBorrowKit method is called. The borrowerSeat and currentCollateralExchangeRate are passed as arguments and upon execution, makeBorrowKit creates a new loan based on the type of collateral and assigns a liquidator contract to handle various types of liquidation behaviors.

Once the new loan has been added, the borrower can monitor and interact with it using the loanKit obtained by exercising the invitation.

```
export const makeLoanKit = (inner, assetNotifier) => {
 const { loan, loanUpdater } = wrapLoan(inner);
 return harden({
   uiNotifier: {
     assetNotifier,
     loanNotifier: loan.getNotifier(),
   },
   invitationMakers: Far('invitation makers', {
     AdjustBalances: loan.makeAdjustBalancesInvitation,
     CloseLoan: loan.makeCloseInvitation,
   }),
   loan,
   loanUpdater,
 });
};
```

### makeDepositInvitation

When the user wishes to deposit an underlying collateral, he will receive in return the corresponding amount of protocolToken. For that purpose the user will call makeDepositInvitation providing as an argument the underlyingBrand and receiving the desired invitation.

When exercising this invitation, the user will define on the proposalShape the Underlying amount he will be giving and the protocolToken he is expecting to receive. The payment should be according to the proposal. No offerArgs are expected for this offer.

The protocolAmountToMint will be calculated based on the amount of underlying asset provided and it will be increased that amount to the totalProtocolSupply

The calculated amount of protocolAmountToMint will be minted and reallocated from the protocolAssetSeat to the fundHolderSeat. The Underlying amount provided is removed from the fundHolderSeat to the underlyingAssetSeat and the asset state is updated.

```
const makeDepositInvitation = () => {
   /**
    * @type {OfferHandler}
    * @param {ZCFSeat} fundHolderSeat*/
   const depositHook = async fundHolderSeat => {
     console.log('[DEPSOSIT]: Icerdeyim');
     assertProposalShape(fundHolderSeat, {
       give: { Underlying: null },
       want: { Protocol: null },
     });


     const {
       give: { Underlying: fundAmount },
     } = fundHolderSeat.getProposal();


     const protocolAmountToMint = shared.getProtocolAmountOut(fundAmount);
     protocolMint.mintGains(
       harden({ Protocol: protocolAmountToMint }),
       protocolAssetSeat,
     );
     totalProtocolSupply = AmountMath.add(
       totalProtocolSupply,
       protocolAmountToMint,
     );
     fundHolderSeat.incrementBy(
       protocolAssetSeat.decrementBy(
         harden({ Protocol: protocolAmountToMint }),
       ),
     );


     underlyingAssetSeat.incrementBy(
       fundHolderSeat.decrementBy(harden({ Underlying: fundAmount })),
     );


     zcf.reallocate(fundHolderSeat, underlyingAssetSeat, protocolAssetSeat);
     fundHolderSeat.exit();


     updateAssetState(UPDATE_ASSET_STATE_OPERATION.DEPOSIT);


     return 'Finished';
   };


   return zcf.makeInvitation(depositHook, 'depositFund');
 }; 
```

### makeRedeemInvitation

When the user that has previously deposited some underlying funds to the lendingPool wishes to redeem his loan, he can do it by calling makeRedeemInvitation. Based on the underlying brand, the respective poolManager is fetched and his redeemHook is called.

When exercising makeRedeemInvitation, the offer needs to define at the offerProposal the amount of protocolTokens to be given and Underlying to be received. The payment should be according to the proposal. No offerArgs are expected for this offer.

The underlying amount to be redeemed is calculated, considering the exchange rate and returned to the user. In exchange, the given redeemProtocolAmount is subtracted from the totalProtocolSupply and burned.

```
const redeemHook = async seat => {
   assertProposalShape(seat, {
     give: { Protocol: null },
     want: { Underlying: null },
   });


   const {
     give: { Protocol: redeemProtocolAmount },
     want: { Underlying: askedAmount },
   } = seat.getProposal();


   const redeemUnderlyingAmount = ceilMultiplyBy(
     redeemProtocolAmount,
     getExchangeRate(),
   );
   trace('RedeemAmounts', {
     redeemProtocolAmount,
     redeemUnderlyingAmount,
     askedAmount,
   });
   assertEnoughLiquidtyExists(
     redeemUnderlyingAmount,
     underlyingAssetSeat,
     underlyingBrand,
   );
   totalProtocolSupply = AmountMath.subtract(
     totalProtocolSupply,
     redeemProtocolAmount,
   );
   seat.decrementBy(
     protocolAssetSeat.incrementBy(harden({ Protocol: redeemProtocolAmount })),
   );
   seat.incrementBy(
     underlyingAssetSeat.decrementBy(
       harden({ Underlying: redeemUnderlyingAmount }),
     ),
   );
   zcf.reallocate(seat, underlyingAssetSeat, protocolAssetSeat);
   seat.exit();
   protocolMint.burnLosses(
     { Protocol: redeemProtocolAmount },
     protocolAssetSeat,
   );


   updateAssetState(UPDATE_ASSET_STATE_OPERATION.REDEEM);


   return 'Success, thanks for doing business with us';
 };
```

### getGovernanceBrand & getGovernanceIssuer & getGovernanceKeyword & getCommitteeSize

The governance object is one of the attributes provided on the contract terms, it has the following structure:

```
  governance: {keyword, units, decimals, committeeSize }
```

The keyword and decimals are used to create a ZCFMint and consequently retrieve the respective brand and issuer. These values, along with the keyword and committeeSize, can be retrieved through the respective methods of the lendingPool publicFacet.

```
const [govMint, electorateParamManager] = await Promise.all([
   zcf.makeZCFMint(keyword, AssetKind.NAT, { decimalPlaces: decimals }),
. . .
 ]);
 const { brand: govBrand, issuer: govIssuer } = govMint.getIssuerRecord();
```

### getTotalSupply & getProposalTreshold

The totalSupply is calculated based on the number of units and decimals defined on the governance object on the contract terms. The proposalThreshold is the round up value of 2% of the previously calculated totalSupply.

These values can be retrieved through the respective methods of the lendingPool publicFacet.

```
const totalSupply = AmountMath.make(govBrand, units * 10n ** BigInt(decimals));
const proposalThreshold = ceilMultiplyBy(totalSupply, makeRatio(2n, govBrand));
```

### getMemberSupplyAmount

The committeeSize is a value passed on the governance object which represents the total number of members of the governance committee, and it is used to calculate the supplyRatio. The memberSupplyAmount is the result of splitting, in equal parts, the totalSupply of governance tokens through the members of the committee.&#x20;

The calculated amount for a single member can be retrieved through the respective method of the lendingPool publicFacet.

```
 const supplyRatio = makeRatio(1n, govBrand, BigInt(committeeSize), govBrand);
 const memberSupplyAmount = floorMultiplyBy(totalSupply, supplyRatio);
```

### getGovBalance

The govSeat is a ZCFSeat instantiated on the lendingPool contract, where it is initially allocated the totalSupply amount of governance tokens. The getGovBalance lets us know, at any given time, the remaining governance tokens allocated on the govSeat.

```
getGovBalance: () => govSeat.getAmountAllocated(keyword, govBrand)  
```

### getCollateralBalance

The getCollateralBalance function receives a brand as an argument and it will return the current balance for the brand provided. The balanceTracer is a component of the lendingPool that keeps track of the balances of all the different protocolBrand

```
getCollateralBalance: brand => balanceTracer.getBalance(brand)
```

### getParamMgrRetriever

The getParamMgrRetriever function, consumed by the lendingPoolElectionManager module, returns a remotable object with one get method, which receives the paramDesc as an argument.&#x20;

If the paramDesc key is 'governedParams' it will return the electorateParamManager, which was instantiated by calling the makeElectorateParamManager function. If not, it will return the poolManager corresponding to the paramDesc respective collateralBrand.

```
const getParamMgrRetriever = () =>
   Far('paramManagerRetriever', {
     get: paramDesc => {
       if (paramDesc.key === 'governedParams') {
         return electorateParamManager;
       } else {
         return poolParamManagers.get(paramDesc.collateralBrand);
       }
     },
   }); 
```

### getLimitedCreatorFacet

The getLimitedCreatorFacet method of the lendingPool returns the lendingPool remote object. The exposed methods of this object will be now described, except for addPoolType method, which will be addressed in the next functionality.

```
const lendingPool = Far('Lending Pool Creator Facet', {
   helloFromCreator: () => 'Hello From the creator',
   addPoolType,
   getGovernanceInvitation: index => governanceInvitations[index],
   makeUpdateRiskControlsInvitation,
 });
```

The getGovernanceInvitation method will receive as an argument an index, which represents a committee member, and return an makeFetchGovInvitation. When this invitation is exercised, the respective committee member receives his corresponding memberSupplyAmount of governance tokens.

```

 const governanceInvitations = harden([...Array(committeeSize)].map(makeFetchGovInvitation));
```

The makeUpdateRiskControlsInvitation method returns an invitation, that when exercised will update the risk controls, provided on the offerArgs, of the paramManager corresponding to the provided underlyingBrand.

```
const makeUpdateRiskControlsInvitation = () => {
   /**
    * @type OfferHandler
    */``
   const updateRiskControls = async (creatorSeat, offerArgs) => {


     const {
       underlyingBrand,
       changes
     } = offerArgs;
     creatorSeat.exit();


     const paramManager = poolParamManagers.get(underlyingBrand);
     await E(paramManager).updateParams(changes);


     return 'Params successfully updated!';
   };


    return zcf.makeInvitation(updateRiskControls, 'UpdateRiskControls');
 };
```

### getGovernedApis

The remote object returned by getGovernedApis encapsulates the function addPoolType, which allows a new pool to be created based on its underlyingBrand. It will also create and return the respective poolManager, after updating the poolTypes map and the pool state.

```
const addPoolType = async (
   underlyingIssuer,
   underlyingKeyword,
   params,
   priceAuthority,
 ) => {
   const {
     poolParamManager,
     underlyingBrand,
     protocolMint
   } = await setUpPoolParams(underlyingIssuer, underlyingKeyword, params);
   poolParamManagers.init(underlyingBrand, poolParamManager);


   const [startTimeStamp, priceAuthNotifier] = await Promise.all([
     E(timerService).getCurrentTimestamp(),
     E(priceManager).addNewWrappedPriceAuthority(
       underlyingBrand,
       priceAuthority,
       compareCurrencyBrand,
     ),
   ]);


   /** @type {ERef<PoolManager>} */
   const pm = makePoolManager(
     zcf,
     protocolMint,
     underlyingBrand,
     underlyingBrand,
     compareCurrencyBrand,
     underlyingKeyword,
     priceAuthority,
     priceAuthNotifier,
     priceManager,
     loanTimingParams,
     poolParamManager.getParams,
     timerService,
     startTimeStamp,
     getExchangeRateForPool,
     makeRedeemInvitation,
     liquidationInstall,
     ammPublicFacet,
     balanceTracer,
     getCollateralLimit,
   );
   poolTypes.init(underlyingBrand, pm);
   updatePoolState();
   return pm;
 };
```

### getGovernedApiNames

This method returns an hardened single entry array with the name of the GovernedApi. It is not being currently used by the lendingPool but it is a requirement of the Agoric governance package.

```
  getGovernedApiNames: () => harden(['addPoolType'])
```

## Notifiers & Subscriptions

The lendingPool contract creates a notifierKit that keeps track of all poolManagers that are created and stored on the poolTypes map. The access to the notifier is exposed on the publicFacet.

```
const updatePoolState = () => {
   poolUpdater.updateState(
     [...poolTypes.values()].map(getPmAttributes),
   );
 };
```

At the lendingPool publicFacet there is also a subscriptionKit, which has the subscriber exposed through the method getParamsSubscription. It returns the state of PoolParamManager to the corresponding underlyingBrand provided.

```
return makeParamManagerSync(getSubscriptionKit(), {
   [LIQUIDATION_MARGIN_KEY]: [ParamTypes.RATIO, rates.liquidationMargin],
   [INITIAL_EXCHANGE_RATE_KEY]: [ParamTypes.RATIO, rates.initialExchangeRate],
   [BASE_RATE_KEY]: [ParamTypes.RATIO, rates.baseRate],
   [MULTIPILIER_RATE_KEY]: [ParamTypes.RATIO, rates.multipilierRate],
   [PENALTY_RATE_KEY]: [ParamTypes.RATIO, rates.penaltyRate],
   [BORROWABLE]: [ParamTypes.UNKNOWN, riskControls.borrowable],
   [USABLE_AS_COLLATERAL]: [ParamTypes.UNKNOWN, riskControls.usableAsCol],
   [COLLATERAL_LIMIT]: [ParamTypes.AMOUNT, riskControls.colLimit],
 })
```

## Usage and Integration

A step-by-step guide on how the contract can be used in practice and the dependencies that must be installed can be found in the README file in the project repository.

There you will find how to setup and run a specific scenario that is executed with the help of pre-built scripts that can be updated according to your preferences.

The list of unit tests built on test-lendingPool.js and test-expandedLendingPool.js is also a good way to understand how to interact with the different features implemented on the lendingProtool contract.

Another source of information where the LendingPool Protocol logic and flow are thoroughly described, with the support of code snippets and UI screenshots, is in the following papers:

[https://bytepitch.com/blog/pool-based-lending-protocol-agoric<br>](https://bytepitch.com/blog/pool-based-lending-protocol-agoric)<https://agoric.com/blog/guest-post/how-a-javascript-novice-won-the-liquidity-pool-bounty>

## **Explore on Github**

<https://github.com/anilhelvaci/dapp-pool-lending-protocol>

<br>

{% hint style="info" %}
Built by [Anil Helvaci](https://github.com/anilhelvaci)
{% endhint %}


# Arbitrage Bot

Off-chain price arb bot between Agoric and Osmosis

{% hint style="warning" %}
**Limited Developer Support**

All assets represented in this library are community built, which means limited support from the Agoric OpCo development team. Please use components, APIs, and front-ends with caution. &#x20;
{% endhint %}

## **Summary**

This component is a bot that is able to arbitrage prices between a pool on Osmosis and a pool on the Agoric AMM. It is an off-chain bot that can make nearly simultaneous off-setting trades on the Agoric AMM and Osmosis DEX given a divergence in price.&#x20;

Note: The Agoric AMM has not been launched in production.

## **Details**

A goal of the Agoric AMM is to maintain prices that are in line with the external market. A tight coupling to external DEXs like Osmosis through arbitrage bots will help achieve this goal.

## Explore on GitHub

<https://github.com/simpletrontdip/agoric-osmosis-bot>

{% hint style="info" %}
Built by [Simpletrontdip](https://github.com/simpletrontdip)
{% endhint %}


# LP Stop Loss

Smart contract for Liquidity Providers on Agoric AMM

{% hint style="warning" %}
**Limited Developer Support**

All assets represented in this library are community built, which means limited support from the Agoric OpCo development team. Please use components, APIs, and front-ends with caution. &#x20;
{% endhint %}

## **Summary**

This contract allows a liquidity provider to the AMM to define a specific price (ratio of supplied assets) at which they would like liquidity removed. This functions as a stop-loss contract which would allow LPs to define liquidity ranges.

## Details

After providing liquidity to a AMM liquidity pool and receiving in return the corresponding amount of LP tokens, the liquidity provider can instantiate a stopLoss contract that will allow him to lock the respective amount of LP tokens and specify the boundaries for a price range.&#x20;

When the price of the respective AMM pool hits one of the boundaries (upper or lower), it will trigger the removal of the user assets (central and secondary tokens) from the AMM pool, in exchange for his LP tokens. Then he will be able to withdraw his assets from this contract to his purse.&#x20;

At any moment the user is allowed to withdraw his locked LP tokens, remove liquidity from the AMM pool and update the price range boundaries.&#x20;

When updating the boundaries, if the user specifies a range outside of the current AMM pool price, it will trigger the removal of the assets from the AMM pool.&#x20;

## Dependencies

There are some previous considerations to have before instantiating this contract.

The first one is related to the agoric-sdk version used at the moment of its development. The tag returned by running the command git describe --tags --always is agoricxnet-7-914-gfedf04943, so it is advised to checkout to the same state when exploring this component and test if any major update is required in order to be implemented at the desired agoric-sdk version.

```
git checkout fedf049435d7307311219fbab1b2b342ec6acce8
```

When the contract is instantiated, the terms should specify the AMM publicFacet, the secondary issuer, the LP token issuer, the central issuer, and the initial boundaries.&#x20;

The issuerKeywordRecord should also be specified with Central, Secondary and LpToken, being each one related to his corresponding issuer.

```
const {
   /** @type XYKAMMPublicFacet */ ammPublicFacet,
   /** @type Issuer */ centralIssuer,
   /** @type Issuer */ secondaryIssuer,
   /** @type Issuer */ lpTokenIssuer,
   boundaries,
   /** @type PriceAuthority */ devPriceAuthority = undefined,
 } = zcf.getTerms();

 assertIssuerKeywords(zcf, ['Central', 'Secondary', 'LpToken']);
```

The third consideration regards one of the contract terms, the ammPublicFacet.&#x20;

For a production environment, the ammPublicFacet should be the respective public facet of a deployed AMM instance on Zoe that the user provided liquidity to.

In a development environment, as a support for your unit tests, you can either create an instance of the AMM contract  @agoric/inter-protocol/src/vpool-xyk-amm/multipoolMarketMaker.js and add the initial liquidity to the pool or you can use Agoric priceAuthority to generate the desired price quotes.

```
/**
*
* @param {XYKAMMPublicFacet} ammPublicFacet
* @param {PriceAuthority} devPriceAuthority
*/
export const assertExecutionMode = (ammPublicFacet, devPriceAuthority) => {
 const checkExecutionModeValid = () => {
   return (ammPublicFacet && !devPriceAuthority) || (!ammPublicFacet && devPriceAuthority);
 };
 tracer('assertExecutionMode', { ammPublicFacet, devPriceAuthority });
 assert(checkExecutionModeValid(),
   X`You can either run this contract with a ammPublicFacet for prod mode or with a priceAuthority for dev mode`);
};
```

## Contract Facets

The stopLoss contract exports two remotable objects, publicFacet and creatorFacet.

The publicFacet has a single method that allows any user with access to a reference of the stopLoss publicFacet to monitor the balance of the assets held by the contract.

The creator facet has multiple methods that are accessible exclusively to the contract owner, which allows him to take advantage of the features implemented by the contract such as implementing a stop-loss condition on a liquidity staking, withdrawing the locked assets and updating the price boundaries.

For each method mentioned, a more detailed description will be provided in the next section

```
   const publicFacet = Far('public facet', {
     getBalanceByBrand,
   });


   const creatorFacet = Far('creator facet', {
     makeUpdateConfigurationInvitation,
     makeLockLPTokensInvitation,
     makeWithdrawLpTokensInvitation,
     makeWithdrawLiquidityInvitation,
     getNotifier: () => notifier,
   });
```

## Functionality

### getBalanceByBrand

When requesting a balance of an asset held by the stopLossSeat, the caller must specify the asset keyword and issuer, which will depend on the terms and IssuerKeywords defined when the contract was instantiated.

```
 const getBalanceByBrand = (keyword, issuer) => {
   return stopLossSeat.getAmountAllocated(
     keyword,
     zcf.getBrandForIssuer(issuer),
   );
 };
```

### makeUpdateConfigurationInvitation&#x20;

The contract owner can update the previously defined boundaries by exercising the invitation returned by makeUpdateConfigurationInvitation().&#x20;

Before implementing the new update, the contract will verify that some conditions are not violated, such as the current allocation phase is set to ACTIVE or SCHEDULED and the offerArgs has the new boundaries object.

```
const makeUpdateConfigurationInvitation = () => {
   /** @type OfferHandler */
   const updateConfiguration = async (seat, offerArgs) => {
     assertScheduledOrActive(phaseSnapshot);
     assertUpdateConfigOfferArgs(offerArgs);
     const { boundaries } = offerArgs;


     const updateBoundaryResult = await updateBoundaries(boundaries);
     assertUpdateSucceeded(updateBoundaryResult);
     boundariesSnapshot = boundaries;
     updateAllocationState(ALLOCATION_PHASE.ACTIVE);


     return UPDATED_BOUNDARY_MESSAGE;
   };


   return zcf.makeInvitation(updateConfiguration, 'Update boundary configuration')
 };
```

The invitation offer needs to include the new lower and upper boundaries in the offerArgs as a price ratio. Note that if the creator specifies a range outside of the current AMM pool price, it will trigger the removal of the assets from the pool.

After the offer result promise is resolved, the price boundaries will be updated, the allocation phase will be set to active and it will return a message confirming the success of the operation.

```
const newBoundaries = {
   lower: boundaries.lower,
   upper: widerBoundaries.upper,
 };
  const userSeat = await E(zoe).offer(
   E(creatorFacet).makeUpdateConfigurationInvitation(),
   undefined,
   undefined,
   harden({ boundaries: newBoundaries }),
 );


 const offerResult = await E(userSeat).getOfferResult();
 t.deepEqual(offerResult, 'Successfully updated boundaries');
```

### makeLockLPTokensInvitation

After the contract owner provides liquidity to a pool and receives its LP tokens in exchange, he can lock them on the contract by exercising the invitation returned by makeLockLPTokensInvitation().&#x20;

After reallocating the assets to the contract seat, the allocation phase will be updated to active.

```
 const makeLockLPTokensInvitation = () => {
   const lockLPTokens = (creatorSeat) => {
     assertProposalShape(creatorSeat, {
       give: { LpToken: null },
     });


     assertScheduledOrActive(phaseSnapshot);


     const {
       give: { LpToken: lpTokenAmount },
     } = creatorSeat.getProposal();


     stopLossSeat.incrementBy(
       creatorSeat.decrementBy(harden({ LpToken: lpTokenAmount })),
     );


     zcf.reallocate(stopLossSeat, creatorSeat);


     creatorSeat.exit();


     updateAllocationState(ALLOCATION_PHASE.ACTIVE);


     return `LP Tokens locked in the value of ${lpTokenAmount.value}`;
   };


   return zcf.makeInvitation(
     lockLPTokens,
     'Lock LP Tokens in stopLoss contract',
   );
 };
```

\
The offer proposal has to specify the LpToken as a keyword identifier and the amount of tokens to be locked, as well as provide the respective payment.\
After the offer result promise is resolved, it will return a message declaring the amount of tokens locked on the contract.

```
const lockLpTokensInvitation =
   E(creatorFacet).makeLockLPTokensInvitation();
 const proposal = harden({ give: { LpToken: lpTokenAmount } });
 const paymentKeywordRecord = harden({ LpToken: lpTokenPayment });


 const lockLpTokenSeat = await E(zoe).offer(
   lockLpTokensInvitation,
   proposal,
   paymentKeywordRecord,
 );
 const lockLpTokensMessage = await E(lockLpTokenSeat).getOfferResult();
 t.deepEqual(lockLpTokensMessage, `LP Tokens locked in the value of ${lpTokenAmount.value}`);
 
```

### makeWithdrawLpTokensInvitation

If at any moment the contract owner wishes to withdraw their locked LP tokens from the stopLoss contract to his seat, he can do it by exercising the invitation returned by makeWithdrawLpTokensInvitation().

When called, the current allocation phase needs to be active or error, being after updated to withdrawn.

```
const makeWithdrawLpTokensInvitation = () => {
   const withdrawLpTokens = (creatorSeat) => {
     assertProposalShape(creatorSeat, {
       want: { LpToken: null },
     });


     assertActiveOrError(phaseSnapshot);


     const lpTokenAmountAllocated = stopLossSeat.getAmountAllocated(
       'LpToken',
       lpTokenBrand,
     );


     creatorSeat.incrementBy(
       stopLossSeat.decrementBy(harden({ LpToken: lpTokenAmountAllocated })),
     );


     zcf.reallocate(creatorSeat, stopLossSeat);


     creatorSeat.exit();


     updateAllocationState(ALLOCATION_PHASE.WITHDRAWN);


     return `LP Tokens withdraw to creator seat`;
   };


   return zcf.makeInvitation(withdrawLpTokens, 'withdraw Lp Tokens');
 };
```

When exercising this invitation, the offer proposal has to specify the LpToken as a keyword identifier. Since the owner will not give anything in this operation, there is no need for a payment.

After the offer result promise is resolved, it will return a message declaring that the tokens were withdrawn to the creator seat.

```
const withdrawLpTokensInvitation = await E(creatorFacet).makeWithdrawLpTokensInvitation();
 const withdrawProposal = harden({want: { LpToken: AmountMath.makeEmpty(lpTokenBrand)}});


 /** @type UserSeat */
 const withdrawLpSeat = E(zoe).offer(
   withdrawLpTokensInvitation,
   withdrawProposal,
 );


 const withdrawLpTokenMessage = await E(withdrawLpSeat).getOfferResult();
 t.deepEqual(withdrawLpTokenMessage, 'LP Tokens withdraw to creator seat');
```

### makeWithdrawLiquidityInvitation

There are two scenarios where the owner would want to call this method to withdraw his assets to his seat.

The first scenario is when the AMM pool price quote went out of the defined boundaries, and the owner assets were removed in exchange for the LP tokens.&#x20;

The second scenario is when the contract owner decides to remove his liquidity from the AMM pool before the price quote of the AMM pool goes outside of any boundary.

```
const makeWithdrawLiquidityInvitation = () => {
   const withdrawLiquidity = async (creatorSeat) => {
     assertProposalShape(creatorSeat, {
       want: {
         Central: null,
         Secondary: null,
       },
     });


     await removeLiquidityFromAmm();
     assertAllocationStatePhase(phaseSnapshot, ALLOCATION_PHASE.REMOVED);


     const centralAmountAllocated = stopLossSeat.getAmountAllocated(
       'Central',
       centralBrand,
     );
     const secondaryAmountAllocated = stopLossSeat.getAmountAllocated(
       'Secondary',
       secondaryBrand,
     );


     creatorSeat.incrementBy(
       stopLossSeat.decrementBy(
         harden({
           Central: centralAmountAllocated,
           Secondary: secondaryAmountAllocated,
         }),
       ),
     );


     zcf.reallocate(creatorSeat, stopLossSeat);


     creatorSeat.exit();


     updateAllocationState(ALLOCATION_PHASE.WITHDRAWN);


     return `Liquidity withdraw to creator seat`;
   };


   return zcf.makeInvitation(withdrawLiquidity, 'withdraw Liquidity');
 };
```

When exercising this invitation, the offer proposal has to specify the keywords identifiers of the assets expected to receive, being Central and Secondary.

After the offer result promise is resolved, the stopLoss contract will no longer hold any asset, and the contract owner will lose his LP tokens in exchange for the asked Central and Secondary tokens. It will return as well a message declaring that the assets were withdrawn to the creator seat.

```
const withdrawLiquidityInvitation = await E(creatorFacet).makeWithdrawLiquidityInvitation();
 const withdrawProposal = harden({
   want: {
     Central: AmountMath.makeEmpty(centralR.brand),
     Secondary: AmountMath.makeEmpty(secondaryR.brand),
   },
 });


 /** @type UserSeat */
 const withdrawSeat = E(zoe).offer(
   withdrawLiquidityInvitation,
   withdrawProposal,
 );


 const withdrawLiquidityMessage = await E(withdrawSeat).getOfferResult();
 t.deepEqual(withdrawLiquidityMessage, 'Liquidity withdraw to creator seat');
```

## Notifiers

The stopLoss contract creates a notifierKit that keeps track of the current allocation phase, balances and boundaries. The contract owner has access to the notifier state through the exposed method on the creatorFacet.

```
const getStateSnapshot = (phase) => {
   return harden({
     phase: phase,
     lpBalance: stopLossSeat.getAmountAllocated('LpToken', lpTokenBrand),
     liquidityBalance: {
       central: stopLossSeat.getAmountAllocated('Central', centralBrand),
       secondary: stopLossSeat.getAmountAllocated('Secondary', secondaryBrand),
     },
     boundaries: boundariesSnapshot,
   });
 };


 const { updater, notifier } = makeNotifierKit(
   getStateSnapshot(ALLOCATION_PHASE.IDLE),
 );
```

## Usage and Integration

A step-by-step guide on how the contract can be used in practice,  and dependencies that must be installed can be found in the README file in the project repository.\
There you will find 5 different scenarios that are executed with the help of pre-built scripts that can be updated according to your preferences.

The list of unit tests built on test-stopLoss.js is also a good way to understand how to interact with the different features implemented on the stopLoss contract.

## **Explore on Github**

<https://github.com/Jorge-Lopes/stop-loss-amm>

{% hint style="info" %}
Built by [Jorge Lopes](https://github.com/Jorge-Lopes)
{% endhint %}


# Like-peg Swap AMM

Minimize slippage for like-asset pairs on Agoric AMM

{% hint style="warning" %}
**Limited Developer Support**

All assets represented in this library are community built, which means limited support from the Agoric OpCo development team. Please use components, APIs, and front-ends with caution. &#x20;
{% endhint %}

## **Summary**

This component implements a curve for Agoric's Automated Market Maker (AMM) which minimizes slippage for like-asset pairs, similar to curve.fi's StableSwap in Ethereum.

It includes:

1. A new version of bondingCurves.js using a new curve structure
2. An update to Agoric's MultiPool Autoswap contract to include a term that chooses which bonding curve to use

## **Details**

Standard X\*Y=K automated market maker (AMM) curves are meant for asset pairs which have relative volatility and require price responses (slippage) based on trades. However, there is a large demand for AMM swaps of like-assets (e.g., USDC-USDT, WBTC-TBTC, ETH-sETH) - particularly stable token pairs - for which the slippage driven by X\*Y=K curves is not desirable. [Curve.Fi](http://curve.fi/)'s StableSwap implementation on Ethereum has had great success driving high volume of these trades. Agoric's stable local currency, IST, will need to trade against other stable tokens with minimal slippage. This adjusted curve implementation will allow for that.

## **Explore on GitHub**

<https://github.com/robor-systems/agoric-amm-curve/>

{% hint style="info" %}
Built by [Robor Systems](https://github.com/robor-systems)
{% endhint %}


# NFTs

**Non-fungible tokens** (NFTs) are types of digital assets that are unique and not interchangeable. Each NFT contains a specific piece of data that distinguishes it from any other NFT, giving it a distinct identity and value. NFTs can be used to represent various types of digital assets, such as artwork, music, videos, and even tweets, and are often bought and sold on blockchain-based marketplaces.

NFTs are created using blockchain technology, which ensures that they are secure and transparent. Each NFT is stored on a blockchain as a digital record that cannot be altered or duplicated, making them valuable as collectibles or investments. NFTs are often bought and sold using cryptocurrencies, and the ownership of an NFT can be easily transferred from one person to another.

NFTs remain a popular and rapidly growing market within the broader world of blockchain and cryptocurrency.


# NFT Marketplace

Basic NFT Marketplace Primitives

{% hint style="warning" %}
**Limited Developer Support**

All assets represented in this library are community built, which means limited support from the Agoric OpCo development team. Please use components, APIs, and front-ends with caution. &#x20;
{% endhint %}

## **Summary**&#x20;

This code implements a basic NFT marketplace Dapp modeled after a baseball card store.&#x20;

## **Details**

Users can buy NFT baseball cards from the store.

After successfully running the Dapp, users can browse available cards by photograph and place bids on cards they want to buy.

## **Explore on GitHub**

<https://github.com/Agoric/dapp-card-store>

## **Advanced Marketplace**

The Advanced Marketplace is a modified version of the baseball card store Dapp that allows for secondary sales with the following modifications to the UI:

* Adds a “My Cards” page which displays the cards owned by the user
* Adds a “Marketplace” page which shows secondary sales listings
* The Dapp page which sells cards to users directly becomes “Primary Sales”

## **Details**

Users are able to list their card for sale. User flow:

1. User navigates to “My Cards” page
2. User selects a card to list for sale
3. User chooses the sale mechanism (currently only one - Fixed price sale)
4. Choose price for listing in RUN
5. Optional for user: Choose end date & time for the listing
6. User confirms choice and creates listing
7. User navigates to “Marketplace” page and can see all marketplace listings and filter to his/her own listing(s)

## **Explore on GitHub**

<https://github.com/robor-systems/agoric-card-store/tree/contract-changes>

{% hint style="info" %}
Built by [Robor Systems](https://robor.systems/)
{% endhint %}


# NFT Character Builder

Composable Hierarchical NFT Builder

{% hint style="warning" %}
**Limited Developer Support**

All assets represented in this library are community built, which means limited support from the Agoric OpCo development team. Please use components, APIs, and front-ends with caution. &#x20;
{% endhint %}

## **Summary**

This Dapp showcases Agoric’s ability to manage hierarchical NFTs, expressed here as a “character builder” in which the character and its equipment are each represented as NFTs that can interact. Developers could modify this code to support their own in-game assets, or to build other NFT-related projects for their communities.

## **Details**

In this tutorial, developers build a Dapp where both the characters as well as the items are NFTs, and will be represented by art assets. Users will have full ownership of their NFTs, meaning that they are able to sell them, trade them, or even burn them. To help users facilitate interacting with their NFTs, a shop will be implemented. This shop will allow users to put their NFTs up for sale or buy NFTs that have been listed for sale at a fixed price.

## **Explore on Kryha**

<https://kryha.academy/protocols/agoric/>

{% hint style="info" %}
Built by [Kryha](https://agoric.kryha.academy/)
{% endhint %}


# NFT Drop

Smart contract for minting NFT collections

{% hint style="warning" %}
**Limited Developer Support**

All assets represented in this library are community built, which means limited support from the Agoric OpCo development team. Please use components, APIs, and front-ends with caution. &#x20;
{% endhint %}

## **Summary**

This is a contract that allows NFT project creators to create a ‘drop’ event similar to popular NFT launches on other chains. Users can mint NFTs up to a count specified by the creator (e.g., 10,000) for a price specified by the creator (e.g., 200 IST). Users mint NFT IDs in a first-come-first-served manner until the full count has completed. The contract allows the contract creator to specify: total count of NFTs in the series to be minted, price per NFT, and the start time (or block) of the offering (before which minting cannot occur).

## **Details**

NFT “drops” have been popularized on Ethereum and other chains. In these drops, an NFT creator will offer a series of NFTs that are tied to their theme, but have differing properties - with the prevalence and desirability of specific properties leading to differing rarities and values for individual NFTs in the series. For example, all Bored Ape Yacht Club (BAYC) NFTs have a value for the “hat” property, but only 65 have the “Trippy Captain’s Hat,” making apes with Trippy Captain’s Hat rarer and more valuable than average BAYCs - currently the lowest offer for a Trippy Hat BAYC is over twice the ‘floor’ BAYC. Actual properties for the specific NFTs minted are typically only updated after the full minting is complete (not covered in this contract). At the time of the launch, users will interact with the contract (either through the creator’s dedicated UI or directly in some other manner) to mint one or multiple NFTs at the specified price.

## **Explore on GitHub**

<https://github.com/simpletrontdip/dapp-nft-drop> &#x20;

{% hint style="info" %}
Built by [Simpletrontdip](https://github.com/simpletrontdip)
{% endhint %}


# Auction Mechanism

First-price auction mechanism for NFT sales

{% hint style="warning" %}
**Limited Developer Support**

All assets represented in this library are community built, which means limited support from the Agoric OpCo development team. Please use components, APIs, and front-ends with caution. &#x20;
{% endhint %}

## **Summary**

This is a smart contract for a modified version of the Baseball Card Store Dapp which uses a first-price auction mechanism. The auction for any individual card starts at the moment the first bid is offered and lasts for a fixed amount of time. At the end of the auction, the highest bidder should win the card and pay the amount of their bid (i.e., first price auction).

## **Details**

This version of the Baseball Card Store features a new user purchase flow:

1. User navigates to dapp-card-store UI
2. User connects wallet
3. User selects a card to purchase
4. User is prompted with information about the card selected
5. User is shown the current bid (if any) for the card, the amount of time remaining on the auction (if applicable), and the history of bids and timestamps for the card
6. If no auction is already in progress, user is notified that an auction will begin at the moment they place a bid and the duration of the auction
7. User may make a bid for the card in IST by selecting the correct purse and providing an amount
8. User is given a visual confirmation of their bid starting or updating the auction
9. At the completion of the auction, winning bidder receives the card in exchange for the IST bid and all other bidders have IST returned

## Explore on GitHub

<https://github.com/Agoric/dapp-card-store/pull/40>

{% hint style="info" %}
Built by [Agoric](https://github.com/Agoric)
{% endhint %}


# Governance

Blockchain governance refers to the set of rules, processes, and decision-making mechanisms that guide how a blockchain network operates. It involves the coordination and management of the different stakeholders in a decentralized network to ensure the system runs smoothly, securely, and transparently. The governance structure typically includes a core development team responsible for maintaining and updating the blockchain software, as well as a community of users and investors who contribute to the network's growth and development. Decisions are made through various mechanisms, including voting systems, consensus algorithms, and stakeholder feedback. The goal of blockchain governance is to ensure the network remains decentralized, secure, and able to adapt to changing circumstances while ensuring the interests of all stakeholders are represented.


# Vote Counter

Evaluate governance results from questions with 2+ options

{% hint style="warning" %}
**Limited Developer Support**

All assets represented in this library are community built, which means limited support from the Agoric OpCo development team. Please use components, APIs, and front-ends with caution. &#x20;
{% endhint %}

## **Summary**

These smart contracts extend Agoric’s governance capabilities to allow using a VoteCounter that correctly evaluates election results from questions with more than two options.

## **Details**

The code includes two separate VoteCounters:

1. VoteCounter evaluates votes for an arbitrary number of options and determines the single winner (plurality of direct votes with a rule for tiebreak)
2. VoteCounter evaluates votes for an arbitrary number of options and determines the top N winners (based on number of direct votes with a rule for tiebreak)

## **Explore on GitHub**

<https://github.com/Agoric/agoric-sdk/pull/6515>


# Governance Committee

Public voting and committee control charter smart contracts

{% hint style="warning" %}
**Limited Developer Support**

All assets represented in this library are community built, which means limited support from the Agoric OpCo development team. Please use components, APIs, and front-ends with caution. &#x20;
{% endhint %}

## **Summary**

An Agoric governance component using a new ElectionType that instantiates a public vote to give voting facets to the election winners. There should be a public registration of the identities of the candidates to make them visible. This contract focuses on creating the committee that will be elected and includes a charter to control the manner of their election and operation. Our existing committee is elected only once, and the membership can't be updated. The biggest open issues are refreshing the membership, and controlling the ability to create new votes. Possible approaches to membership include replacing members who have become unresponsive, scheduling periodic elections, or supporting recalls. There are several plausible ways to limit the ability to open new questions: a chair or subcommittee, require approval from some subset of the members, or require a payment or deposit.

## **Details**

Currently, voters only get a voting facet via an invitation. The electors vote to choose a committee, and the committee members then get the ability to vote. The voters can reliably identify the Electorate by subscribing to get a list of new questions. Voters can use the questionHandle from each update from the subscription to get the questionDetails. They cast their vote by sending their selected position(s) to their electorate, which they know and trust. We want everyone to be able to identify the candidates and winners. Anyone who knows the electorate can get a list of questions, so this includes both the original electorate and the elected committee members for the original election, and then the committee itself will be well-known, so both the public and the committee members can find out what questions the committee is voting on.&#x20;

This structure of Electorates and VoteCounters allows voters and observers to verify how votes will be counted, and who can vote on them but doesn't constrain the process of creating questions. We now have a PSMCharter and EconCommittee Charter, that control aspects of creating questions that those committees can vote on. A charter or electionManager can control the voting threshold, the vote closing time, or the range of parameter values that can be specified.

## **Apply For This Bounty**

Bounty Not Assigned Yet


# Cross-chain


# Price Feed Oracle

Oracle price aggregator smart contract

{% hint style="warning" %}
**Limited Developer Support**

All assets represented in this library are community built, which means limited support from the Agoric OpCo development team. Please use components, APIs, and front-ends with caution. &#x20;
{% endhint %}

## **Summary**

This a smart contract for oracle price aggregation similar to the one that is used in Inter Protocol with some modification.

## **Details**

Inter Protocol Vaults require reliable price feeds for collateral. The aggregator contract is an established method from Chainlink that accepts prices from multiple nodes and eliminates outliers to provide one trusted price per asset pair to the system.

## **Explore on GitHub**

<https://github.com/yashpatel5400/agoric-sdk>


# Akash Lease Management

Agoric Smart Contract for interacting with Akash Leases

{% hint style="warning" %}
**Limited Developer Support**

All assets represented in this library are community built, which means limited support from the Agoric OpCo development team. Please use components, APIs, and front-ends with caution. &#x20;
{% endhint %}

## **Summary**

The Akash Lease Mgmt. module aims to automate the continuous monitoring and funding process for an Akash deployment. It verifies the funding status and triggers the funding process when the available funds fall below a specified threshold. The contract utilizes the AkashClient and Pegasus APIs to interact with the Akash blockchain and maintain the required funding level to ensure the deployment remains functional.

## **Details**

[Akash](https://docs.akash.network/)The [Akash Network](https://akash.network/) is an open-source decentralized cloud computing platform that allows users to bid and lease computing and storage resources. It uses blockchain technology and a marketplace to enable peer-to-peer resource leasing, providing a cost-efficient and decentralized cloud infrastructure for application deployment. To be able to interact with the Akash Network, an [akashClient](https://github.com/simpletrontdip/dapp-akash-controller/blob/main/api/src/akash.js) library was created. The akashClient facilitates deployment management, account balance checks, and depositing uAKT tokens to fund specific deployments.

The Agoric [Pegasus package](https://github.com/Agoric/agoric-sdk/tree/master/packages/pegasus) enables seamless and secure communication and token transfers between different blockchain networks using the [ICS20 standard](https://github.com/cosmos/ibc/blob/main/spec/app/ics-020-fungible-token-transfer/README.md) and [IBC protocol](https://tutorials.cosmos.network/academy/3-ibc/1-what-is-ibc.html). It facilitates the creation and management of pegged fungible tokens, allowing their exchange between local and remote blockchains. Users can create invitations for asset transfers over the network, simplifying cross-chain interactions and enhancing the interoperability and accessibility of assets across various blockchains.

The [AkashController](https://github.com/simpletrontdip/dapp-akash-controller/blob/main/contract/src/contract.js) contract automates the funding process for Akash deployments by monitoring the account balance of the deployed application. The contract implements periodic checks, and if the account balance falls below a specified threshold, the contract automatically triggers the deposit of uAKT tokens to ensure the continuous operation of the application on the Akash Network.

## Dependencies

There are some previous considerations to have before instantiating the akashController contract.\
The first one is related to the agoric-sdk version used at the moment of its development. The tag returned by running the command `git describe --tags --always` is `agoric-upgrade-8-524-gf4143fe13`, so it is advised to checkout to the same state when exploring this component and test if any major update is required in order to be implemented at the desired agoric-sdk version.

`git checkout f4143fe13363a763e37f163225f4684028786663`

The Akash Lease Mgmt. module relies on the Pegasus contract for IBC transactions and an Akash client to monitor and manage the respective Akash deployment. The first step that should be addressed is to create a remote peg for uAKT, using the Pegasus method pegRemote. The second step is to boot an akashClient, for this, you can use the akash.js bootPlugin function and pass your Akash deployment account mnemonic and the Akash network rpcEndpoint as parameters. In return, you will receive a remotable object with the methods detailed in the Contract Facets section. Both objects returned, the uAKT peg and the akashClient, will be required for the contract terms.

```
const akashClient = await installUnsafePlugin("./src/akash.js", {
  mnemonic,
  rpcEndpoint,
}).catch((e) => console.error(`${e}`));
```

Important: the current implementation of the akashClient plugin is not working properly, so we advise to consider this when trying to implement this component into your applications. More details can be found [here](https://github.com/anilhelvaci/dapp-akash-controller/blob/main/README.md).

To instantiate the akashController contract, you need to provide the contract installation, the issuerKeywordRecord and lastly the contract terms.\
For the issuerKeywordRecord you need to specify the keyword 'Fund', being the value of the issuer of the pegged asset, in this case, it is the uAKT.

```
const issuerKeywordRecord = harden({
  Fund: aktIssuer,
});
```

Regarding the contract terms, the snippet below lists all the required attributes that should be included in the terms.\
For the timeAuthority, you can pass the chainTimerService retrieved from the home object. Regarding the Pegasus attribute, you can use the home.agoricNames to lookup for the Pegasus instance, and from there retrieve the contract publicFacet. The deploymentId refers to the Akash deployment sequence identifier (DSEQ).

```
const {
  akashClient,
  timeAuthority,
  checkInterval = 15n,
  deploymentId,
  maxCheck = 2,
  depositValue = 5_000n,
  minimalFundThreshold = 100_000n,
  aktPeg,
  pegasus,
  brands,
} = zcf.getTerms();
```

## Contract Facets

As mentioned in the Dependencies section, an akashClient needs to be provided on the contract terms. The start method of the bootPlugin object returns an akash-client, which is a remotable object that has a set of methods required to interact with the Akash deployment. Those methods are listed bellow, and will be described in more detail in the Functionalities section.

```
return Far('akash-client', {
    initialize(),
    getAddress(),
    async getDeploymentList(),
    async getDeploymentDetail(dseq),
    async getDeploymentFund(dseq),
    async depositDeployment(dseq, amount),
    });
```

The akashController contract returns a creatorInvitation at the moment of its instantiation. The creatorInvitation is a zoe invitation that receives as offerHandler the watchAkashDeployment function. The akashController functions will be described as well on the next section.

```
const creatorInvitation = zcf.makeInvitation(
  watchAkashDeployment,
  "watchAkashDeployment"
);

return harden({
  creatorInvitation,
});
```

## Functionalities

#### Akash Client

**initialize**

The purpose of the initialize method is to ensure that the Akash client is properly set up before any subsequent method calls are made. It initializes the Akash instance and retrieves the account's address, which is required for various operations.\
It first checks if the Akash variable is already set, indicating that the client has already been initialized. If so, it logs a warning message and returns early to avoid re-initialization. If the client has not been initialized, it retrieves the mnemonic and RPC endpoint from the opts object. If not provided, it falls back to the default values specified at the beginning of the code. Then, it calls the initClient function, passing the mnemonic and RPC endpoint as parameters.\
The returned Akash instance and address are assigned to the respective variables.

```
const initialize = async () => {
  if (akash) {
    console.warn("Client initialized, ignoring...");
    return;
  }
  const mnemonic = opts.mnemonic || DEFAULT_MNEMONIC;
  const rpcEndpoint = opts.rpcEndpoint || DEFAULT_AKASH_RPC;
  const result = await initClient(mnemonic, rpcEndpoint);
  akash = result.akash;
  address = result.address;
};
```

The initClient function, called within the initialize method, initiates the Akash client by creating an instance of a DirectSecp256k1HdWallet using the provided mnemonic and connects to the Akash network using the provided rpcEndpoint. It retrieves the address associated with the mnemonic and returns an object containing the Akash instance and the address.

```
const initClient = async (mnemonic, rpcEndpoint) => {
  const offlineSigner = await DirectSecp256k1HdWallet.fromMnemonic(mnemonic, {
    prefix: "akash",
  });
  const accounts = await offlineSigner.getAccounts();
  const address = accounts[0].address;

  const akash = await Akash.connect(rpcEndpoint, offlineSigner);
  console.log("Akash address", address);
  return { akash, address };
};
```

**getAddress**

The getAddress method returns the address associated with the initialized Akash client, derived from the mnemonic phrase.

```
getAddress: () => address,
```

**balance**

The purpose of the balance method is to provide an interface to query the account balance of the Akash client. It relies on the initialized akash instance to query the account balance by sending a request to the Akash network via the query.bank.balance method. It includes the client's address and the token denom (uakt) as parameters in the request.

```
async balance() {
    assert(akash, 'Client need to be initalized');
    return akash.query.bank.balance(address, 'uakt');
},
```

**getDeploymentList**

The getDeploymentList method retrieves a list of deployments associated with the Akash client. It depends on the initialized Akash instance to query the deployment list by sending a request to the Akash network via the query.bank.list.params method, with the client's address as a parameter.

```
async getDeploymentList() {
    assert(akash, 'Client need to be initalized');
    console.log('Getting deployment list');
    return akash.query.deployment.list.params({
    owner: address,
    });
},
```

**getDeploymentDetail**

The getDeploymentDetail method retrieves the detailed information of a specific deployment associated with the Akash client. It relies on the initialized Akash instance to query the deployment detail. The method sends a request to the Akash network, via the query.deployment.get.params method, with the client's address and the dseq parameter as inputs.

```
async getDeploymentDetail(dseq) {
    console.log('Getting deployment detail', dseq);
    assert(akash, 'Client need to be initalized');
    return akash.query.deployment.get.params({
    owner: address,
    dseq,
    });
},
```

**getDeploymentFund**

The getDeploymentFund method retrieves the funding balance of a specific deployment associated with the Akash client. It takes only dseq as a parameter, and relies on the initialized Akash instance and the getDeploymentDetail method to query the deployment funding balance. The method first calls the getDeploymentDetail method internally, passing the dseq parameter, to retrieve the detailed information of the deployment. Once the deployment detail is obtained, the method accesses the escrowAccount.balance property of the detail to retrieve the funding balance.

```
async getDeploymentFund(dseq) {
    console.log('Getting deployment fund', dseq);
    const detail = await this.getDeploymentDetail(dseq);
    return detail.escrowAccount.balance;
},
```

**depositDeployment**

The purpose of the depositDeployment method is to provide an interface for depositing funds into a specific deployment associated with the Akash client. It takes two parameters, the dseq, and the amount of funds to deposit, and relies on the initialized Akash instance to execute the deposit transaction. The method sends a request to the Akash network, via the tx.deployment.deposit.params method, providing the client's address, dseq, and amount as parameters. The result is an asynchronous operation that executes the deposit transaction, transferring the specified amount of funds into the deployment.

```
async depositDeployment(dseq, amount) {
    assert(akash, 'Client need to be initalized');
    console.log('Depositing deployment', dseq, amount);
    return akash.tx.deployment.deposit.params({
    owner: address,
    dseq,
    amount,
    });
},
```

#### Akash Controller

**watchAkashDeployment**

When the creatorInvitation is exercised by the contract owner, the watchAkashDeployment function serves as the entry point for the contract's logic. It starts by verifying the offer proposal shape, ensuring it matches the expected shape. Then, it assigns the ZCFseat parameter to the controllerSeat variable for future reference. Finally, the startWatchingDeployment function is called to initiate the monitoring process for the Akash deployment.\
Upon successful execution, the watchAkashDeployment function returns a default acceptance message: "The offer has been accepted. Once the contract has been completed, please check your payout." This message indicates that the offer has been accepted.

```
const watchAkashDeployment = (seat) => {
  assertProposalShape(seat, {
    give: { Fund: null },
  });

  controllerSeat = seat;
  // start watching deployment
  startWatchingDeployment();

  return defaultAcceptanceMsg;
};
```

**startWatchingDeployment**

The startWatchingDeployment function begins by calling the initialize method on the akashClient, described in the section above, to set up the client and establish the necessary connections. After the client initialization, the function proceeds to register the first wake-up call using the registerNextWakeupCheck function. If an error occurs during the registration process, it is caught and logged.

```
const startWatchingDeployment = async () => {
  // init the client
  await E(akashClient).initialize();

  // register next call
  await registerNextWakeupCheck().catch((err) => {
    controllerSeat.fail(err);
  });
};
```

**registerNextWakeupCheck**

The purpose of the registerNextWakeupCheck function is to calculate the next wake-up time and register a wake-up callback for that specific time, ensuring that the monitoring and funding cycles for the Akash deployment occur at the desired intervals.\
The function begins by incrementing the count variable, which keeps track of the number of monitoring cycles that have occurred. If the value of count exceeds the limit, indicating that the maximum number of checks has been reached, the function logs a message and exits the monitoring process. Otherwise, it retrieves the current timestamp from the timeAuthority, and then it calculates the next wake-up time, checkAfter, and sets the wake-up callback. The callback is defined as a remotable object with a wake function that triggers the next monitoring and funding cycle.\
If an error occurs during the registration process, it is caught and logged.

```
const registerNextWakeupCheck = async () => {
  count += 1;
  if (count > maxCheck) {
    console.log("Max check reached, exiting");
    controllerSeat.exit();
    return;
  }

  const currentTs = await E(timeAuthority).getCurrentTimestamp();
  const checkAfter = currentTs + checkInterval;
  console.log("Registering next wakeup call at", checkAfter);

  E(timeAuthority)
    .setWakeup(
      checkAfter,
      Far("wakeObj", {
        wake: async () => {
          await checkAndFund();
          registerNextWakeupCheck();
        },
      })
    )
    .catch((err) => {
      console.error(
        `Could not schedule the nextWakeupCheck at the deadline ${checkAfter} using this timer ${timeAuthority}`
      );
      console.error(err);
      throw err;
    });
};
```

**checkAndFund**

The checkAndFund function monitors the funding status of the Akash deployment and triggers the funding process when the available funds fall below the specified threshold. This helps to maintain the required funding level for the deployment's operation and ensures its continued functionality.\
First, this function queries the current deployment balance using akashClient's getDeploymentFund method. The balance is represented as a DecCoin object, containing the amount and denomination. Next, it compares the balance amount against the predefined minimalFundThreshold. If it is below the threshold, it proceeds with the funding process by calling fundAkashAccount. If the amount meets or exceeds the threshold, it indicates sufficient funds are available, and the function moves to the next funding cycle without executing the funding process.

```
const checkAndFund = async () => {
  // deployment balance type DecCoin
  const balance = await E(akashClient).getDeploymentFund(deploymentId);
  const amount = BigInt(balance.amount) / 1_000_000_000_000_000_000n;

  console.log("Details here", deploymentId, amount, minimalFundThreshold);

  if (amount < minimalFundThreshold) {
    // funding account and deposit the watch deployment
    await fundAkashAccount();
  }
};
```

**fundAkashAccount**

The fundAkashAccount function is used to fund the Akash account. It first obtains the Akash address using the akashClient.getAddress() function. Then, it creates a transfer invitation using the pegasus makeInvitationToTransfer method, which allows it to transfer tokens from the Pegasus contract to the Akash account. The amount to be transferred is specified as aktDepositAmount, which is a predetermined value in the contract's terms.\
The fundAkashAccount uses the offerTo function, and provides the necessary parameters, including the zcf (Zoe contract facet), the transferInvitation, the keyword mapping, the offer proposal and the from and to Seat.\
To ensure that the deposit is completed before proceeding further, the function calls the waitForPendingDeposit function. Once the deposit is completed, the function logs a message indicating that the transfer has been completed and checks the remaining allocation of the Transfer keyword in the user seat. If the remaining allocation is empty, it signifies that the transfer was successful. In this case, the function proceeds to execute the depositAkashDeployment function, which finalizes the deposit of the Akash deployment. If an error occurs during the offer process or while waiting for the pending deposit, the function catches the error, logs an error message, and handles any necessary error handling or termination of the monitoring process.

```
const fundAkashAccount = async () => {
  console.log("Funding Akash account");
  const akashAddr = await E(akashClient).getAddress();
  const transferInvitation = await E(pegasus).makeInvitationToTransfer(
    aktPeg,
    akashAddr
  );

  console.log("Offering transfer invitation...");
  const { userSeatPromise: transferSeatP, deposited } = await offerTo(
    zcf,
    transferInvitation,
    harden({
      Fund: "Transfer",
    }),
    harden({
      give: {
        Transfer: aktDepositAmount,
      },
    }),
    controllerSeat,
    controllerSeat
  );

  // register callback for deposited promise
  pendingDeposit = deposited.then(async () => {
    console.log("Transfer completed, checking result...");
    const remains = await E(transferSeatP).getCurrentAllocationJig();
    const transferOk = AmountMath.isEmpty(remains.Transfer);

    if (transferOk) {
      console.log("IBC transfer completed");
      // XXX should we recheck the balance?
      await depositAkashDeployment();
    } else {
      console.log("IBC transfer failed");
    }
  });

  const result = await E(transferSeatP)
    .getOfferResult()
    .catch((err) => {
      console.error("Error while offering result", err);
      throw err;
    });
  console.log("Offer completed, result:", result);

  await waitForPendingDeposit();
  console.log("Done");
};
```

**depositAkashDeployment**

The depositAkashDeployment function is responsible for depositing funds into the Akash deployment. It begins by creating a response variable and awaits the result of the depositDeployment method of the akashClient. This method sends a deposit request to the Akash blockchain, specifying the dseq (deploymentId), the amount to be deposited (depositValue), and the token denomination (uakt). After the deposit request is made, the function logs a message indicating that the deposit is completed. The response variable may contain relevant information about the deposit process, which can also be logged for reference if needed.

```
const depositAkashDeployment = async () => {
  console.log("Depositing akash deployment", deploymentId);
  const response = await E(akashClient).depositDeployment(deploymentId, {
    // amount type Coin
    amount: String(depositValue),
    denom: "uakt",
  });
  console.log("Deposit, done", response);
};
```

**waitForPendingDeposit**

After waiting for the pending deposit, which represents the completion of the deposit process, the waitForPendingDeposit function, called in the fundAkashAccount function described above, has two possible outcomes. If the deposit process is successful and the promise resolves, the function completes without any further action. If an error occurs during the deposit process and the promise is rejected, the function logs an error message and calls the exit method on the controllerSeat. This action terminates the monitoring process and exits the contract.\
By awaiting the completion of the deposit, it guarantees that subsequent actions related to the deposit are executed only when the funds are confirmed on the blockchain.

```
const waitForPendingDeposit = async () => {
  try {
    console.log("Waiting for pending deposit");
    await pendingDeposit;
  } catch (err) {
    // always exit if exception occur
    console.log("Error while depositing", err);
    controllerSeat.exit();
  }
};
```

## Usage and Integration

**Usage and Integration Guide**

To help you effectively utilize and integrate the akashController component into your projects, we offer a comprehensive guide that walks you through the necessary steps for setting up the testing environment and running a demonstration scenario. This guide will enable you to better understand the code's functionality, make necessary configurations, and seamlessly integrate it into your existing systems.&#x20;

[Demo](https://github.com/Jorge-Lopes/agoric-components/blob/main/akash-controller/akash-controller_demo.md)

## **Explore on GitHub**

<https://github.com/simpletrontdip/dapp-akash-controller>


# Axelar Transfer

Smart contracts for bridging from Agoric to Ethereum & Avalanche

{% hint style="warning" %}
**Limited Developer Support**

All assets represented in this library are community built, which means limited support from the Agoric OpCo development team. Please use components, APIs, and front-ends with caution. &#x20;
{% endhint %}

## **Summary**

Sending cross-chain messages from Agoric

## **Details**

The Axelar protocol enables decentralised cross-chain communication between different networks, allowing to send arbitrary data and/or tokens.

Axelar decentralisation is achieved by its own proof-of-stake blockchain network built using Cosmos SDK with permissionless set of validators, which constantly produce blocks containing cross-chain transactions info.

This component relies on [Pegasus package](https://github.com/Agoric/dapp-pegasus) that enables pegging of [Agoric](https://agoric.com/) ERTP assets to or from remote assets. This is achieved by using the IBC (Inter-Blockchain Communication) protocol supported by Agoric.

This component allows tokens and/or arbitrary data to EVM chains. This enables a lot of use cases, like token/information bridging, response to Agoric on-chain events on EVM chain and etc.

Check the list of supported EVM chains [here](https://github.com/axelarnetwork/evm-cosmos-gmp-sample/blob/main/native-integration/onboard-devnet.md#supported-chains).

## Dependencies

There are some previous considerations to have before instantiating the Axelar transfer contract.

The first one is related to the agoric-sdk version used, you should use [this](https://github.com/schnetzlerjoe/agoric-sdk/tree/community-dev) version of Agoric SDK.

In order to start an instance of the Axelar-Transfer contract it is not required any issuerKeywordRecord, terms, or privateArgs. Only the installation reference. Although, there is a need to establish an IBC and Pegasus transfer channel between the Agoric and Axelar, prior to the execution of the contract methods.

## Contract Facets

The `publicFacet` of the contract contains only `setupAxelar` method that runs the Axelar setup process and returns a function `sendGMP` that can be used to send arbitrary data to EVM chains. The creator facet is empty and has no methods.

`setupAxelar` requires `pegaus` parameter, which is pegasus service instance.

```javascript
const publicFacet = Far('publicFacet', {
  // Public faucet for anyone to call
  /**
   * This is a contract to interact with Axelar and send messages and tokens from Agoric to EVM's with Axelar
   *
   * @param {import('@agoric/pegasus').Pegasus} pegasus Pegasus public facet
   */
  setupAxelar: async (
    pegasus
  ) => {
    const ret = await setupAxelar(
      pegasus
    );
    return ret;
  },
});
```

## Functionalities

### sendGMP

This function will trigger cross-chain call to EVM chain with specified target address, value and payload. Metadata object should contain information about destination chain, address and payload that will be passed to EVM contract as calldata.

`sendGMP` function creates an invitation to transfer assets over network with all cross-chain info included. The Pegasus package is modified in the required version of Agoric SDK so that it could accept additional `sender` parameter for the Axelar protocol. The offer then is issued and then `sendGMP` returns an offer result.

```javascript
export const setupAxelar = async (
  pegasus,
) => {
  // ...
  return Far('axelar', {
    /**
     * Sends a GMP message to an EVM chain from Agoric.
     *
     * @param {ZoeService} zoe - Zoe service instance
     * @param {Purse} purse - Purse for `amount` payment
     * @param {Peg} peg - Pegasus connection instance
     * @param {string} receiver - Pegasus receceiver address
     * @param {string} sender - Pegasus sender address
     * @param {NatValue} amount - Amount of tokens to be sent (0 if only data is sent)
     * @param {Metadata} metadata - object containing destination chain, address and payload info
     * @returns {Promise<any>}
     */
    sendGMP: async (zoe, purse, peg, receiver, sender, amount, metadata) => {
			/** @type {import('@agoric/pegasus').Pegasus} */
      const pegasus = await storeConnection.get("pegasus");

      const memo = JSON.stringify(metadata);

			// Create a Zoe invitation with cross-chain message info
      // to transfer assets over network to a deposit address
      const [invitation, brand] = await Promise.all([
        E(pegasus).makeInvitationToTransfer(peg, receiver, memo, sender),
        E(peg).getLocalBrand()
      ]);

      const amt = harden({ brand, value: amount });
      const pmt = await E(purse).withdraw(amt);

      const seat = E(zoe).offer(
        invitation,
        harden({ give: { Transfer: amt } }),
        harden({ Transfer: pmt }),
      );

      const result = await E(seat).getOfferResult();

      return result
		}
}
```

For sending only messages without tokens to the remote chain, use `"type": 1` in metadata:

```javascript
// create metadata (note you have to abi encode payload)
let payload = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,185,77,138,47,92,174,154,148,168,212,54,75,162,212,199,126,135,33,159,249]

/** @type {Metadata} */
const metadata = {
    payload,
    "type": 1,
    "destination_chain": "avalanche",
    "destination_address": "0xF4799D77Cc7280fd3Bd9186A7e86B0540243E32d"
}

// Lets send a GMP message
await E(axelar).sendGMP(
    home.zoe,
    localPurseP,
    peg,
    'axelar1dv4u5k73pzqrxlzujxg3qp8kvc3pje7jtdvu72npnt5zhq05ejcsn5qme5',
    'agoric1m26r7lnp422hftlspza6e8pkun3nvddacmu8ta',
    0n,
    metadata
);
```

For sending tokens and the payload to the remote chain, use `"type": 2` in metadata:

```javascript
// create metadata (note you have to abi encode payload)
let payload = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,185,77,138,47,92,174,154,148,168,212,54,75,162,212,199,126,135,33,159,249]

/** @type {Metadata} */
const metadata = {
    payload,
    "type": 2,
    "destination_chain": "avalanche",
    "destination_address": "0xF4799D77Cc7280fd3Bd9186A7e86B0540243E32d"
}

// Lets send a GMP message
await E(axelar).sendGMP(
    home.zoe,
    localPurseP,
    peg,
    'axelar1dv4u5k73pzqrxlzujxg3qp8kvc3pje7jtdvu72npnt5zhq05ejcsn5qme5',
    'agoric1m26r7lnp422hftlspza6e8pkun3nvddacmu8ta',
    1000000n / 4n,
    metadata
);
```

For sending only tokens without payload, use `"type": 3` in metadata and set `"payload": null`:

## Usage and Integration

The initialisation and setup guide can be found in [README.md](https://github.com/pitalco/axelar-transfer/blob/main/README.md) file in project repository. Also check the unit test for the contract to find the testing setup process for `sendGMP` function.

Be aware of specifics of calling EVM contracts - the payload that will be passed to the contract must be decodable by recipient contract. If you are attempting to call a specific function of the contract, make sure to correctly encode the function selector and the function arguments. Otherwise, your payload has to be handled and decoded manually by the `fallback()`function. Check the [official Solidity](https://docs.soliditylang.org/en/v0.8.21/internals/layout_in_calldata.html) documentation for more info about the encoding:

````solidity
```solidity
// function selector: 0x40c10f19
// e.g. if you want to mint 100 tokens (6 decimals) to 
// 0x1234567890123456789012345678901234567890, the payload encoding would be:

// 0x40c10f19 + 0000000000000000000000001234567890123456789012345678901234567890 + 0000000000000000000000000000000000000000000000000000000005f5e100
// ^            ^                                                                  ^
// selector     address argument `to`, padded to 32 bytes                          uint256 argument `amount`, padded to 32 bytes (100000000 converted to hex)
function mint(address to, uint256 amount) public {
    // TODO: check msg.sender
    _mint(to, amount);
}

// for manual data handling
fallback() external payable {
    // TODO: check msg.sender
    (
        // declare variables to store decoded arguments
    ) = abi.decode(msg.data, (/* specify argument types */));
}
```
````

## **Explore on GitHub**

<https://github.com/pitalco/axelar-transfer>


# Cosmos Hub ICA

Smart contracts for interchain account management

{% hint style="warning" %}
**Limited Developer Support**

All assets represented in this library are community built, which means limited support from the Agoric OpCo development team. Please use components, APIs, and front-ends with caution. &#x20;
{% endhint %}

## **Summary**

The Cosmos Hub ICA component provides a seamless solution to establish interchain accounts between Agoric and any desired host chains that support interchain accounts. As well as providing the necessary feature to send messages with data or operations to the interchain account.

## **Details**

The Cosmos Hub ICA component is designed to facilitate the creation of [Interchain Accounts (ICA)](https://ibc.cosmos.network/main/apps/interchain-accounts/overview.html) and execute transactions between Agoric and a different chain, using the [IBC protocol](https://tutorials.cosmos.network/academy/3-ibc/1-what-is-ibc.html).\
With the integration of the [ICS-27 standard](https://github.com/cosmos/ibc/blob/main/spec/app/ics-027-interchain-accounts/README.md) and IBC protocol, interchain accounts can be programmatically controlled via IBC packets, rather than signing transactions with a private key.

The Cosmos Hub ICA component is composed of a [Contract](https://github.com/pitalco/interaccounts/blob/master/contract/src/contract.js) and the [ICA module](https://github.com/pitalco/interaccounts/blob/master/contract/src/ica.js). The contract acts as a proxy for the ICA module, which has its own ICS-27 implementation called ICS27ICAProtocol, that supports methods for establishing connections and sending transaction messages in conformity with the ICS-27 standard.

## Dependencies

There are some previous considerations to have before instantiating the Cosmos Hub ICA contract.\
The first one is related to the agoric-sdk version used at the moment of its development. The tag returned by running the command `git describe --tags --always` is `@agoric/cosmic-swingset@0.41.3`, so it is advised to checkout to the same state when exploring this component and test if any major update is required in order to be implemented at the desired agoric-sdk version.

`git checkout mainnet1B-rc3`

In order to start an instance of the Cosmos Hub ICA contract it is not required any issuerKeywordRecord, terms, or privateArgs. Only the installation reference. Although, there is the need to establish an IBC connection between the two chains in question, prior to the execution of the contract methods.

## Contract Facets

The contract developed for this module exports both creatorFacet and publicFacet. Although, as you can see from the code snippet below, the creatorFacet has no methods. On the other hand, the publicFacet has the createICAAccount and the sendICATxPacket methods.

```
const creatorFacet = Far("creatorFacet", {});

const publicFacet = Far("publicFacet", {
  createICAAccount: () =>
    ICS27ICAProtocol.createICS27Account(
      port,
      connectionHandler,
      controllerConnectionId,
      hostConnectionId
    ),
  sendICATxPacket: () => ICS27ICAProtocol.sendICATx(msgs, connection),
});
```

The contract imports the remotable object ICS27ICAProtocol object from the ICA module, which holds all the logic behind this component. The ICS27ICAProtocol has two methods with the same names as the ones contract publicFacet, createICAAccount and the sendICATxPacket.\
Since the logic behind these methods is implemented in the ICA module, that will be the focus of the next section, Functionalities.

```
export const ICS27ICAProtocol = Far("ics27-1 ICA protocol", {
  sendICATx: sendICAPacket,
  createICS27Account: createICAAccount,
});
```

## Functionalities

#### createICAAccount

The createICAAccount function serves the purpose of creating a new connection to a remote port, returning a promise that resolves to a connection object. The returned connection will then be used by the sendICAPacket function to send information from the controller to the host chain.\
As for parameters, this function expects an IBC listening port, an object acting as the connection handler, and lastly, two connection IDs, one representing the controller chain and the other representing the host chain.

You can access these Port objects in the home.ibcport, which is an array of personal IBC listening ports where each element represents an individual port. The connection handle is a remotable object equipped with a set of methods that are triggered when specific events occur within the connection. The controllerConnectionId and the hostConnectionId can be retrieved from the IBC relayer being used. Using [Hermes](https://hermes.informal.systems/quick-start/installation.html) as an example, when you start the relayer, it will print a message on your console with the connection ID of both clients, and you can also use the command hermes query connection on the Hermes CLI.

```
/**
 * Create an ICA account/channel on the connection provided
 *
 * @param {Port} port
 * @param {object} connectionHandler
 * @param {string} controllerConnectionId
 * @param {string} hostConnectionId
 * @returns {Promise<Connection>}
 */
export const createICAAccount = async (
  port,
  connectionHandler,
  controllerConnectionId,
  hostConnectionId
) => {
  const connString = JSON.stringify({
    version: "ics27-1",
    controllerConnectionId,
    hostConnectionId,
    address: "",
    encoding: "proto3",
    txType: "sdk_multi_msg",
  });

  const connection = await E(port).connect(
    `/ibc-hop/${controllerConnectionId}/ibc-port/icahost/ordered/${connString}`,
    connectionHandler
  );

  return connection;
};
```

One of the available methods of the Port object is the connect, which enables users to establish a connection to a remote IBC port, facilitating communication with other chain-like entities. To establish a connection, one of the parameters you must provide is remote endpoint, which will be a string similar to /ibc-hop/$HOPNAME/ibc-port/$PORTNAME/ordered/$VERSION. For this configuration, the $PORTNAME is already predefined as "icahost".

Note: we recommend reading the Agoric [Network API documentation](https://docs.agoric.com/reference/repl/networking.html#connecting-to-a-remote-port) for a more detailed description.

#### sendICATxPacket

The main purpose of the sendICAPacket function is to send a set of messages through an ICA channel, where the messages represent specific data or operations to be transmitted between chain-like entities. These messages are packaged and transmitted over the IBC channel to a remote endpoint. This function returns a promise that resolves to the acknowledgment data sent by the other side of the connection, represented in the same format as inbound data.\
As parameters, it is expected an array of messages, where each message represents a specific data or operation, and a connection object like the one returned by the above createICAAccount function.

The sendICAPacket starts by validating the messages provided in the msgs array, ensuring that each message contains the required data and typeUrl properties. For each message in the msgs array, the base64 encoded data string is converted into a Uint8Array format to be used in creating the message. Then, it assembles all the converted messages into a single packet conforming to the ICS27 protocol.\
Finally, the packet is sent over the ICA channel using the send method of the connection object, which will be serialized and transmitted to the remote endpoint.

Note: the ica.js module imports some interfaces and functions external to Agoric. from the cosmjs and cosmjs-types packages that provide essential functionalities for handling ICA protocol-related data. TxBody defines transaction body structure, Any enables serialization of protocol buffer messages, toBase64 and fromBase64 encode/decode data in base64 format.

```
/**
 * Provide a connection object and a list of msgs and send them through the ICA channel.
 *
 * @param {[Msg]} msgs
 * @param {Connection} connection
 * @returns {Promise<string>}
 */
export const sendICAPacket = async (msgs, connection) => {
  var allMsgs = [];
  // Asserts/checks
  for (let msg of msgs) {
    assert.typeof(
      msg.data,
      "string",
      X`data within object must be a base64 encoded string`
    );
    assert.typeof(
      msg.typeUrl,
      "string",
      X`typeUrl within object must be a string of the type`
    );

    // Convert the base64 string into a uint8array
    let valueBytes = fromBase64(msg.data);

    // Generate the msg.
    const txmsg = Any.fromPartial({
      typeUrl: msg.typeUrl,
      value: valueBytes,
    });

    // add the new message to all msg array
    allMsgs.push(txmsg);
  }
  const body = TxBody.fromPartial({
    messages: Array.from(allMsgs),
  });

  const buf = TxBody.encode(body).finish();

  // Generate the ics27-1 packet.
  /** @type {ICS27ICAPacket} */
  const ics27 = {
    type: 1,
    data: toBase64(buf),
    memo: "",
  };

  /** @type {Data} */
  const packet = JSON.stringify(ics27);

  const res = await E(connection).send(packet);

  return res;
};
```

In the snippet below, you can see an example of a packet being sent through the sendICATxPacket method. In this scenario, a connection was previously created using the createICAAccount function, and the operation being executed is a transaction of 450000 atoms between two cosmos addresses.

```
  const rawMsg = {
    amount: [{ denom: 'uatom', amount: '450000' }],
    fromAddress: 'cosmos1sdk5kxmjej8yqtcp29murh0xxjl90j7h34s6te',
    toAddress: 'cosmos14y0mj9j2l982dkkl8j9xws9v5vs35u8utj8386',
  };
  const msgType = MsgSend.fromPartial(rawMsg);

  const msgBytes = MsgSend.encode(msgType).finish();

  const bytesBase64 = encodeBase64(msgBytes);

  const res = await E(publicFacet).sendICATxPacket(
    [
      {
        typeUrl: '/cosmos.bank.v1beta1.MsgSend',
        data: bytesBase64,
      },
    ],
    connection,
  );
```

## Usage and Integration

To help you effectively utilize and integrate the Cosmos Hub ICA component into your projects, we offer a comprehensive guide that walks you through the necessary steps for setting up the testing environment and running a demonstration scenario. This guide will enable you to better understand the code's functionality and make the necessary configurations, so you can seamlessly integrate it into your existing applications.

\
[Cosmos Hub ICA Demo](https://github.com/Jorge-Lopes/agoric-components/blob/main/cosmos-hub-ica/cosmos-hub-ica_demo.md)

## **Explore on GitHub**

<https://github.com/pitalco/interaccounts>


# IST & PSM Forwarder

Smart contracts for swapping IST for stable tokens using the PSM

{% hint style="warning" %}
**Limited Developer Support**

All assets represented in this library are community built, which means limited support from the Agoric OpCo development team. Please use components, APIs, and front-ends with caution. &#x20;
{% endhint %}

## **Summary**

The IST & PSM Forwarder is a smart contract for interacting with Inter Protocol's Parity Stability Module (PSM) to exchange stable assets for IST. The contract:

1. Sends the IST received to the destination Agoric address received as an input
2. Trades that ERTP asset to the Agoric Parity Stability Module (PSM) in exchange for IST (assuming the PSM accepts this ERTP asset)
3. Receives an ERTP asset over an IBC transaction and a destination Agoric address as inputs

## **Details**

This contract will act as connective tissue to enable easier onboarding of IST from external stable tokens that are accepted by Inter Protocol's PSM (for example, Axelar\_USDC).

## **Explore on GitHub=**

<https://github.com/pitalco/ist-forward>


# Open Bounties(none at this time)

In our continuous mission to pioneer a more robust JavaScript smart contract platform, we are thrilled to share our bounty program! We invite developers to participate, contribute, and shape the future of web3 with Agoric.&#x20;

### Why participate?

💡 **Innovate**: Dive deep into the world of decentralized programming and contribute to cutting-edge solutions.

💰 **Rewards**: Grab attractive bounties for your innovative solutions, with bonuses for exceptional contributions.

🌏 **Community**: Be a part of an active, global community of like-minded innovators and blockchain enthusiasts.

🚀 **Grow**: Enhance your skills, gain recognition in the web3 community, and potentially collaborate on bigger projects with Agoric.

### How it works

1. **Browse**: Look through our curated list of bounties and find one that sparks your interest.
2. **Develop**: Build your solution using Agoric's platform and tools, ensuring it meets the given requirements.
3. **Submit**: Once done, submit your solution for review.
4. **Review & Reward**: Our team will evaluate submissions and distribute rewards based on quality, innovation, and completeness.

### Rules & Guidelines

* Please ensure you test your bounty submission thoroughly before submission.
* Ensure your bounty is in line with Agoric's platform guidelines and best practices.
* Respect the community: Collaborate, share, and learn from one another.

### Resources

For technical community support, visit our [Community Discord](https://agoric.com/discord)


# Assigned Bounties


# Agoric Swingset Contract Explorer

Join the community of open-source builders at Agoric!

## **Description**

A publicly accessible Agoric chain explorer which exposes detail at the Agoric VM level, in particular:

* Basic Transactions. Cosmos side + Swingset transactions (contract calls)&#x20;
* Contract viewer including interacting with the contract&#x20;
* List contract facets&#x20;
* List assets including ERTP assets&#x20;
* All Swingset based queries

## **Context**

The Agoric chain is supported by several Cosmos-level block explorers. However, these do not do a good job of providing detail on activity that occurs inside the Agoric VM (aka Swingset). This bounty is to provide an explorer that would detail Agoric VM activity. Note: if you need assistance with thinking through the design of this bounty, resources will be provided.

## **Acceptance Criteria**

Bounty acceptance will be based on:

* Functionality in description is provided
* Plan reviewed with Agoric team
* Demo of functionality in page that could be deployed as a webapp
* Be thoroughly documented, including clear instructions on how to use it, its dependencies, and any configuration options.
* Include a short video demonstrating basic usage scenarios&#x20;

## **Time Estimation**

3 weeks(120 hours)

## **Reward**

$9600

Payment will be made in USD (fiat currency) via wire transfer. The developer is responsible for providing their completed tax documents (W9 for US based developers and/or W8 or W8-BEN-E for non-US based developers) and providing their banking details in order to receive payment.&#x20;

## **Applicant Assessment Criteria**

Important: Please provide a clear work plan for how you will approach this bounty.  Use the work plan as an initial demonstration that you would be a good candidate.  Bounties will require coordination with the Agoric team, so unfortunately only plans submitted in English will be considered.

Applicants will be assessed based on the following criteria:&#x20;

\* Issue-specific domain experience

\* Issue-specific technical capability

\* Familiarity with Agoric's platform

\* JavaScript experience

\* Availability and communication

## **Experience Write-up (1000-1500 words)**

As part of completing the bounty, we ask that you write up a short (or long!) summary of your experience building on Agoric. Write-up should:

* Begin with a compelling, relevant introductory hook statement (<50 words).&#x20;
* Clearly explain the specific bounty project (\~100 words).&#x20;
* Describe how the developer approached the problem (\~300 words).&#x20;
* Give a step-by-step description of the solution (>500 words && <1000 words).
* At least three code snippets per write-up. They do not count toward overall word count.&#x20;
* Conclude with clear calls to action on developing with Agoric - specifically how any ambition developer reading this piece could do more themselves (\~100 words).&#x20;

This is important feedback for us as we evolve the platform.

## **Review Process**

1. Agoric team reviews your submitted work plan on Gitcoin
2. It is best to join our Discord and post your gitcoin name in the bounties channel, so that we can follow up with you. Otherwise, we will write on your gitcoin profile wall and say hello!
3. Agoric contacts you to provide reference projects / sample code for engineering review
4. Introductory call to discuss your plans and expected timeline
5. You join the Agoric Discord bounties channel (if you haven’t done so already)&#x20;
6. Agoric accepts you on Gitcoin and you get started!

## **References**

* [Agoric Documentation](https://docs.agoric.com/)


# Inter Protocol Liquidation Bidding Bot

Join the community of open-source builders at Agoric!

## **Description**

Write a reusable off-chain bot for bidding on Inter Protocol liquidations and arbing them against an external market.  The bot should notice pricing differences between active Inter Protocol liquidations (with the price delta a configurable parameter), purchase collateral from the Inter Protocol liquidation, make transfer to external market, and sell collateral at a profit.

## **Example**

* ATOM is trading at 10 IST each on Osmosis
* An active Inter Protocol liquidation is offering 100 ATOM for 9.50 IST
* Bot buys 100 ATOM for 9.5 IST each (950 IST)
* Bot transfers 100 ATOM to Osmosis
* Bot sells 100 ATOM on Osmosis for 10IST each (1000 IST)
* Bot profits 50 IST (ignoring trading fees, transaction fees, price impact, price movement)

## **Context**

Inter Protocol requires a healthy liquidation market to ensure protocol stability.  Bots are the most effective liquidation bidders as they can actively monitor market conditions and drive profit to their owners.  Healthy liquidation markets will converge to bot battles. &#x20;

Inter Protocol doesn’t currently have any active bots bidding on liquidations.  This would be the first!

## **Acceptance Criteria**

* Demo of bot code
* Bot only places bids on active liquidations
* Bot places all bids by price and only places bids when the necessary delta is met
* Bot price delta is configurable
* Bot cancels bids that were not filled
* Bot exits filled or partially filled bids immediately and begins offloading collateral
* Bot understands price impact of its sale on Osmosis and has some method of limiting it (hardcoded limit on individual sale size fine)
* Bot understands the structure of the liquidation auction given governance parameters and knows the price thresholds the auction will offer at and at what time it will offer them

## **Time Estimation**

2 weeks (80 hours)

## **Reward**

$6,400

Payment will be made in USD (fiat currency) via wire transfer. The developer is responsible for providing their completed tax documents (W9 for US based developers and/or W8 or W8-BEN-E for non-US based developers) and providing their banking details in order to receive payment.

## **Applicant Assessment Criteria**

Important: Please provide a clear work plan for how you will approach this bounty.  Use the work plan as an initial demonstration that you would be a good candidate.  Bounties will require coordination with the Agoric team, so unfortunately only plans submitted in English will be considered.

Applicants will be assessed based on the following criteria:&#x20;

\* Issue-specific domain experience

\* Issue-specific technical capability

\* Familiarity with Agoric's platform

\* JavaScript experience

\* Availability and communication

## **Experience Write-up (1000-1500 words)**

As part of completing the bounty, we ask that you write up a short (or long!) summary of your experience building on Agoric. Write-up should:

1. Begin with a compelling, relevant introductory hook statement (<50 words)
2. Clearly explain the specific bounty project (\~100 words)
3. Describe how the developer approached the problem (\~300 words)
4. Give a step-by-step description of the solution (>500 words && <1000 words)
5. At least three code snippets per write-up. They do not count toward overall word count
6. Conclude with clear calls to action on developing with Agoric - specifically how any ambition developer reading this piece could do more themselves (\~100 words).&#x20;

This is important feedback for us as we evolve the platform.

## **Review Process**

1. Agoric team reviews your submitted work plan on Gitcoin
2. It is best to join our Discord and post your gitcoin name in the bounties channel, so that we can follow up with you. Otherwise, we will write on your gitcoin profile wall and say hello!
3. Agoric contacts you to provide reference projects / sample code for engineering review
4. Introductory call to discuss your plans and expected timeline
5. You join the Agoric Discord bounties channel (if you haven’t done so already)&#x20;
6. Agoric accepts you on Gitcoin and you get started!

## **References**

[Agoric Docs](https://docs.agoric.com)

[Agoric Discord](https://agoric.com/discord) (#bounties channel)

[Inter Protocol - Bidding Docs](https://docs.inter.trade/user-how-to/bidding-for-liquidated-collateral)

[Inter Protocol - Auction Execution Docs](https://docs.inter.trade/inter-protocol-system-documentation/liquidation-auction)

[Inter Protocol - Auction Code](https://github.com/Agoric/agoric-sdk/tree/master/packages/inter-protocol/src/auction)

[Additional Bidding Details](https://github.com/Agoric/agoric-sdk/blob/master/packages/inter-protocol/test/auction/README-bidding-cli.md)


# Contract Manages Akash-hosted Front End

Join the community of open-source builders at Agoric!

The goal of this effort is to write an Agoric smart contract that fully manages an Akash compute deployment of an arbitrary front end. This will allow decentralized management of application front ends and could solve a significant industry challenge.

As a result, the smart contract's implementation has the potential to revolutionize how front ends are hosted and operated within decentralized ecosystems, facilitating greater autonomy and self-governance for users and communities and instilling greater trust and confidence in decentralized systems for the general public.

The learnings and insights gained from implementing this Agoric smart contract could pave the way for a fully featured standalone product  in the future.

An initial version of the contract must:

1. On deployment, create an account on the Akash blockchain to manage through Cosmos’s Interchain Accounts (ICA)
2. Be able to receive and hold required payment tokens for the Akash blockchain - $AKT (and if feasible by the time of development - $USDC or even $IST)
3. Transfer those tokens over IBC to the Akash chain to maintain a minimum balance necessary for keeping the deployment running. The contract must use \[agoric-sdk/pegasus package]\(<https://github.com/Agoric/agoric-sdk/tree/release-mainnet1B/packages/pegasus>) to transfer tokens.
4. Create a new Akash deployment of front end code (stored in a public github repository) that showcases a basic blockchain interaction, i.e. connect wallet, read data from a public smart contract, sign a transaction etc.
5. Maintain the deployment including renewing the lease if it expires or is terminated (use Interchain Queries to watch lease status)

## **Context**

Decentralized groups often govern applications but rely on centralized infrastructure for the front end hosting. This contract would offer a more flexible method for hosting infrastructure that would not be reliant on a single person or entity.

This reliance on a single person or entity for hosting introduces vulnerabilities and potential points of failure, contradicting the very essence of decentralization.&#x20;

To address this critical issue, the proposed contract seeks to provide a groundbreaking solution by offering a more flexible approach to hosting infrastructure.&#x20;

By leveraging distributed networks and decentralized technologies, the contract would ensure that hosting responsibilities and deployment decisions are spread across both network nodes and governance groups, eliminating the risk of centralization and enhancing the resilience of the applications.&#x20;

In doing so, it empowers decentralized groups to maintain full control over their applications without compromising on security and reliability, thus embodying the true spirit of decentralization in both governance and infrastructure management.

## **Acceptance Criteria**

* Be deployed on the Agoric testnet
* Include a basic front end for user testing in Beta
* Be able to successfully deploy the front-end application to the target hosting environment
* Be compatible with different front-end frameworks and technologies commonly used in Web3 (React, Angular, Vue)
* Allow for easy configuration and customization of deployment parameters such as target environment, deployment paths, and any environment-specific settings
* Integrate smoothly with version control systems (e.g., Git) and be able to deploy the correct version of the front-end code
* Be capable of pushing updates to a deployed version
* Be capable of rolling back the deployment to the previous stable version in case of critical failures
* Log deployment activities comprehensively, allowing for easy monitoring and debugging of the process. It should also provide a deployment report with relevant details after each successful deployment
* Be thoroughly documented, including clear instructions on how to use it, its dependencies, and any configuration options
* Include a short video demonstrating basic usage scenarios&#x20;

## **Time Estimation**

3 weeks(120 hours)

## **Reward**

$9600

Payment will be made in USD (fiat currency) via wire transfer. The developer is responsible for providing their completed tax documents (W9 for US based developers and/or W8 or W8-BEN-E for non-US based developers) and providing their banking details in order to receive payment.&#x20;

## **Applicant Assessment Criteria**

Important: Please provide a clear work plan for how you will approach this bounty.  Use the work plan as an initial demonstration that you would be a good candidate.  Bounties will require coordination with the Agoric team, so unfortunately only plans submitted in English will be considered.

Applicants will be assessed based on the following criteria:&#x20;

\* Issue-specific domain experience

\* Issue-specific technical capability

\* Familiarity with Agoric's platform

\* JavaScript experience

\* Availability and communication

## **Experience Write-up (1000-1500 words)**

As part of completing the bounty, we ask that you write up a short (or long!) summary of your experience building on Agoric. Write-up should:

* Begin with a compelling, relevant introductory hook statement (<50 words).&#x20;
* Clearly explain the specific bounty project (\~100 words).&#x20;
* Describe how the developer approached the problem (\~300 words).&#x20;
* Give a step-by-step description of the solution (>500 words && <1000 words).
* At least three code snippets per write-up. They do not count toward overall word count.&#x20;
* Conclude with clear calls to action on developing with Agoric - specifically how any ambition developer reading this piece could do more themselves (\~100 words).&#x20;

This is important feedback for us as we evolve the platform.

## **Review Process**

1. Agoric team reviews your submitted work plan on Gitcoin
2. It is best to join our Discord and post your gitcoin name in the bounties channel, so that we can follow up with you. Otherwise, we will write on your gitcoin profile wall and say hello!
3. Agoric contacts you to provide reference projects / sample code for engineering review
4. Introductory call to discuss your plans and expected timeline
5. You join the Agoric Discord bounties channel (if you haven’t done so already)&#x20;
6. Agoric accepts you on Gitcoin and you get started!

## **References**

* [Agoric Documentation](https://docs.agoric.com/)
* [Akash Documentation](https://docs.akash.network/)

## Non-Interchain Version

An initial version of this Agoric smart-contract must:

1. On startup, create an account on the Akash blockchain
2. Be able to receive and hold required payment tokens for the Akash blockchain - $AKT. Have a flexible design so that the contract can keep functioning when Akash governance decides to accept new tokens as payment.
3. Transfer the tokens escrowed in the Agoric smart-contract to the Akash account that has been created on the contract startup over IBC. Use \[agoric-sdk/pegasus package] for transferring tokens over IBC.
4. 4\. Manage the Akash compute deployment's lifecycle.

## **Technical Infrastructure**

Ideally we would like to implement all the functionalities above using Interchain tech stack like ICA (Interchain Accounts) and ICQ (Interchain Queries). However, given the Akash network not supporting these Interchain technologies yet, we are not able to use them for the purposes of this bounty.&#x20;

So as an alternative, we encourage the bounty developer to use \[Official akash-network/akashjs library] to build a Hardened JS module and export a remotable object containing the methods required for this bounty so that the Agoric smart-contract can use it. Please contact the Agoric team for technical support on how to implement this module.

## Acceptance Criteria

1. Manage the Akash compute deployment's lifecycle performing below operations;
2. &#x20; Create new Akash compute deployment
   1. &#x20; View bids from providers
   2. &#x20; Chose a bid
   3. Create a lease using the chosen bid. Sending a manifest to the provider as an additional step might be required for the contract to take care of depending on the capability of the sdk used for interacting with the Akash network.
   4. Query and display the lease information
   5. Upgrade/redeploy the running code by updating the deployment configuration
   6. Close lease
   7. Close Akash compute deployment
3. Use \`pegasus\` for IBC transfers
4. Include a basic front end for user testing in Beta.
5. Be able to successfully deploy the front-end application to the target hosting environment.
6. Be compatible with different front-end frameworks and technologies commonly used in Web3 (React, Angular, Vue).
7. Be thoroughly documented, including clear instructions on how to use it, its dependencies, and any configuration options.
8. Showcase a demo scenario where all the operations mentioned in clause 1 are clearly shown. The setup of this demo should also be clearly documented with a walkthrough and another dev should be able to successfully run the demo in their environment by following the instructions from the walkthrough.
9. Record the demo.


# Disclaimer

This website may provide access and use of certain applications and services (“Applications”). You will only use the Applications as directed and reasonably intended by this website. Certain Applications are provided as free, public, or open-source software, and those Applications are governed by separate terms. As between you and the website providers, the website providers retain all right, title, and interest in and to the Applications except as set forth in this Disclaimer. You are responsible for any fees, including blockchain transaction fees, related to your use of the Applications.

Your use of the Applications involves various risks, including, but not limited to, losses while digital assets are being supplied to or used with the Applications. Additionally, access to Applications through other web or mobile interfaces is at your own risk. You are responsible for conducting your own diligence on those interfaces to understand the fees and risks they present.

THE APPLICATIONS ARE PROVIDED “AS IS”, AT YOUR OWN RISK, AND WITHOUT WARRANTIES OF ANY KIND. To the maximum extent permitted by law, no individual, entity, provider, developer, or community member involved in creating, operating, providing, or maintaining the Applications or this website (“Providers”) will be liable for any claims or damages whatsoever associated with your use, inability to use, or your interaction with other users of the Applications, including but not limited to any direct, indirect, incidental, special, exemplary, punitive or consequential damages, or loss of profits, cryptocurrencies, tokens, or anything else of value. Solely to the extent the previous sentence is not permitted by applicable law, THE MAXIMUM LIABILITY OF THE PROVIDERS TO YOU IN CONNECTION WITH THE APPLICATIONS AND THIS DISCLAIMER WILL BE THE TOTAL OF ALL AMOUNTS ACTUALLY PAID BY YOU TO A PROVIDER IN CONNECTION WITH THE APPLICATIONS IN THE 3 MONTHS IMMEDIATELY PRECEDING THE EVENT GIVING RISE TO THE LIABILITY.

NOTHING ON THIS WEBSITE OR THE APPLICATIONS IS INVESTMENT ADVICE, FINANCIAL ADVICE, TRADING ADVICE, OR ANY OTHER SORT OF ADVICE, AND YOU WILL NOT TREAT ANYTHING ON THIS WEBSITE OR THE APPLICATIONS AS SUCH. The Providers do not recommend the buying, selling, or holding of any digital asset. You will conduct your own diligence and consult a licensed financial advisor before making any and all investment decisions. Any investments, trades, speculation, or decisions made on the basis of any information found on this website or the Applications, express or implied, are committed at your own risk.

You acknowledge that use of digital assets, cryptocurrencies, and blockchain technology involve a high degree of risk, and that digital assets may have no present or future value. The use or accessing of digital assets may result in a loss of part or all of their value. Digital assets, and the blockchain technology on which they are based, are new and rapidly changing, and therefore may contain technical flaws and may be susceptible to malicious cyberattacks. The Providers are not responsible for any such risks, and are not responsible for any loss or theft of, inability to use, or loss of value related to any digital assets.


