Skip to content

Commit

Permalink
feat: create seperate contract for axelar-gmp
Browse files Browse the repository at this point in the history
  • Loading branch information
rabi-siddique committed Feb 11, 2025
1 parent fdab2d1 commit 08fefad
Show file tree
Hide file tree
Showing 5 changed files with 564 additions and 14 deletions.
3 changes: 2 additions & 1 deletion packages/orchestration/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@
"@endo/far": "^1.1.10",
"@endo/marshal": "^1.6.3",
"@endo/patterns": "^1.4.8",
"@noble/hashes": "^1.5.0"
"@noble/hashes": "^1.5.0",
"ethers": "^5.7.2"
},
"devDependencies": {
"@agoric/swingset-liveslots": "^0.10.2",
Expand Down
101 changes: 101 additions & 0 deletions packages/orchestration/src/examples/axelar-gmp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import { InvitationShape } from '@agoric/zoe/src/typeGuards.js';
import { E } from '@endo/far';
import { M } from '@endo/patterns';
import { prepareChainHubAdmin } from '../exos/chain-hub-admin.js';
import { AnyNatAmountShape } from '../typeGuards.js';
import { withOrchestration } from '../utils/start-helper.js';
import { registerChainsAndAssets } from '../utils/chain-hub-helper.js';
import * as flows from './axelar.flows.js';
import * as sharedFlows from './shared.flows.js';

/**
* @import {Vow} from '@agoric/vow';
* @import {Zone} from '@agoric/zone';
* @import {OrchestrationPowers, OrchestrationTools} from '../utils/start-helper.js';
* @import {CosmosChainInfo, Denom, DenomDetail} from '@agoric/orchestration';
*/

export const SingleNatAmountRecord = M.and(
M.recordOf(M.string(), AnyNatAmountShape, {
numPropertiesLimit: 1,
}),
M.not(harden({})),
);
harden(SingleNatAmountRecord);

/**
* Orchestration contract to be wrapped by withOrchestration for Zoe
*
* @param {ZCF} zcf
* @param {OrchestrationPowers & {
* marshaller: Marshaller;
* chainInfo?: Record<string, CosmosChainInfo>;
* assetInfo?: [Denom, DenomDetail & { brandKey?: string }][];
* }} privateArgs
* @param {Zone} zone
* @param {OrchestrationTools} tools
*/
export const contract = async (
zcf,
privateArgs,
zone,
{ chainHub, orchestrateAll, vowTools, zoeTools },
) => {
const creatorFacet = prepareChainHubAdmin(zone, chainHub);

// UNTIL https://github.com/Agoric/agoric-sdk/issues/9066
const logNode = E(privateArgs.storageNode).makeChildNode('log');
/** @type {(msg: string) => Vow<void>} */
const log = msg => vowTools.watch(E(logNode).setValue(msg));

const { makeLocalAccount } = orchestrateAll(sharedFlows, {});
/**
* Setup a shared local account for use in async-flow functions. Typically,
* exo initState functions need to resolve synchronously, but `makeOnce`
* allows us to provide a Promise. When using this inside a flow, we must
* await it to ensure the account is available for use.
*
* @type {any} sharedLocalAccountP expects a Promise but this is a vow
* https://github.com/Agoric/agoric-sdk/issues/9822
*/
const sharedLocalAccountP = zone.makeOnce('localAccount', () =>
makeLocalAccount(),
);

// orchestrate uses the names on orchestrationFns to do a "prepare" of the associated behavior
const orchFns = orchestrateAll(flows, {
log,
sharedLocalAccountP,
zoeTools,
});

const publicFacet = zone.exo(
'Send PF',
M.interface('Send PF', {
makeSendInvitation: M.callWhen().returns(InvitationShape),
}),
{
makeSendInvitation() {
return zcf.makeInvitation(
orchFns.sendIt,
'send',
undefined,
M.splitRecord({ give: SingleNatAmountRecord }),
);
},
},
);

registerChainsAndAssets(
chainHub,
zcf.getTerms().brands,
privateArgs.chainInfo,
privateArgs.assetInfo,
);

return { publicFacet, creatorFacet };
};
harden(contract);

export const start = withOrchestration(contract);
harden(start);
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { NonNullish } from '@agoric/internal';
import { makeError, q } from '@endo/errors';
import { M, mustMatch } from '@endo/patterns';
import { ethers } from 'ethers';

/**
* @import {GuestInterface, GuestOf} from '@agoric/async-flow';
Expand All @@ -23,6 +24,52 @@ const channels = {
OSMOSIS_TO_AXELAR: 'channel-4118',
};

const getType1Payload = ({ evmContractAddresss, functionSelector, nonce }) => {
const LOGIC_CALL_MSG_ID = 0;
const deadline = Math.floor(Date.now() / 1000) + 3600;
const abiCoder = new ethers.utils.AbiCoder();

const newCountValue = 234;
const encodedArgs = abiCoder.encode(['uint256'], [newCountValue]);

const payload = abiCoder.encode(
['uint256', 'address', 'uint256', 'uint256', 'bytes'],
[
LOGIC_CALL_MSG_ID,
evmContractAddresss,
nonce,
deadline,
ethers.utils.hexlify(
ethers.utils.concat([functionSelector, encodedArgs]),
),
],
);

return Array.from(ethers.utils.arrayify(payload));
};

export const getPayload = ({ type }) => {
const abiCoder = new ethers.utils.AbiCoder();

switch (type) {
case 1:
return getType1Payload();
case 2:
return Array.from(
ethers.utils.arrayify(
abiCoder.encode(
['address'],
['0x20E68F6c276AC6E297aC46c84Ab260928276691D'],
),
),
);
case 3:
return null;
default:
throw new Error('Invalid payload type');
}
};

const { entries } = Object;

// in guest file (the orchestration functions)
Expand All @@ -37,7 +84,6 @@ const { entries } = Object;
* @param {GuestOf<(msg: string) => Vow<void>>} ctx.log
* @param {ZCFSeat} seat
* @param {{
* chainName: string;
* destAddr: string;
* type: number;
* destinationEVMChain: string;
Expand All @@ -60,12 +106,11 @@ export const sendIt = async (
gasAmount: M.number(),
}),
);
const { chainName, destAddr, type, destinationEVMChain, gasAmount } =
offerArgs;
// NOTE the proposal shape ensures that the `give` is a single asset
const { destAddr, type, destinationEVMChain, gasAmount } = offerArgs;

const { give } = seat.getProposal();
const [[_kw, amt]] = entries(give);
void log(`sending {${amt.value}} from ${chainName} to ${destAddr}`);

const agoric = await orch.getChain('agoric');
const assets = await agoric.getVBankAssetInfo();
void log(`got info for denoms: ${assets.map(a => a.denom).join(', ')}`);
Expand All @@ -74,11 +119,11 @@ export const sendIt = async (
`${amt.brand} not registered in vbank`,
);

const chain = await orch.getChain(chainName);
const info = await chain.getChainInfo();
const osmosisChain = await orch.getChain('osmosis');
const info = await osmosisChain.getChainInfo();
const { chainId } = info;
assert(typeof chainId === 'string', 'bad chainId');
void log(`got info for chain: ${chainName} ${chainId}`);
void log(`got info for chain: ${osmosisChain} ${chainId}`);

/**
* @type {any} XXX methods returning vows
Expand Down Expand Up @@ -117,7 +162,7 @@ export const sendIt = async (
try {
await sharedLocalAccount.transfer(
{
value: destAddr,
value: addresses.OSMOSIS,
encoding: 'bech32',
chainId,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { prepareChainHubAdmin } from '../exos/chain-hub-admin.js';
import { AnyNatAmountShape } from '../typeGuards.js';
import { withOrchestration } from '../utils/start-helper.js';
import { registerChainsAndAssets } from '../utils/chain-hub-helper.js';
import * as flows from './send-axelar.flows.js';
import * as flows from './send-anywhere.flows.js';
import * as sharedFlows from './shared.flows.js';

/**
Expand Down
Loading

0 comments on commit 08fefad

Please sign in to comment.