diff --git a/app/genesis.go b/app/genesis.go index fd5dabba..60908a01 100644 --- a/app/genesis.go +++ b/app/genesis.go @@ -18,6 +18,7 @@ import ( govtypesv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + smartaccounttypes "github.com/terra-money/core/v2/x/smartaccount/types" ) // GenesisState - The genesis state of the blockchain is represented here as a map of raw json @@ -79,6 +80,12 @@ func (genState GenesisState) SetDefaultTerraConfig(cdc codec.JSONCodec) GenesisS } genState[icatypes.ModuleName] = cdc.MustMarshalJSON(&icaGenState) + var smartaccountGenState smartaccounttypes.GenesisState + cdc.MustUnmarshalJSON(genState[smartaccounttypes.ModuleName], &smartaccountGenState) + setting := smartaccounttypes.NewSetting("terra1tck9vx8vwu6l83zy76ssdkhnhw8dfcrt80hc6x") + smartaccountGenState.Settings = smartaccounttypes.NewSettings(&setting) + genState[smartaccounttypes.ModuleName] = cdc.MustMarshalJSON(&smartaccountGenState) + return genState } diff --git a/integration-tests/src/contracts/limit_send_only_hooks.wasm b/integration-tests/src/contracts/limit_send_only_hooks.wasm new file mode 100644 index 00000000..b58d3962 Binary files /dev/null and b/integration-tests/src/contracts/limit_send_only_hooks.wasm differ diff --git a/integration-tests/src/contracts/smart_auth_contract.wasm b/integration-tests/src/contracts/smart_auth_contract.wasm new file mode 100644 index 00000000..538a5763 Binary files /dev/null and b/integration-tests/src/contracts/smart_auth_contract.wasm differ diff --git a/integration-tests/src/helpers/mnemonics.ts b/integration-tests/src/helpers/mnemonics.ts index 47a68fbc..05d2ad3f 100644 --- a/integration-tests/src/helpers/mnemonics.ts +++ b/integration-tests/src/helpers/mnemonics.ts @@ -60,7 +60,7 @@ export function getMnemonics() { let mnemonic5 = new MnemonicKey({ mnemonic: "script key fold coyote cage squirrel prevent pole auction slide vintage shoot mirror erosion equip goose capable critic test space sketch monkey eight candy" }) - let mnemonic6 = new MnemonicKey({ + let smartaccountMnemonic = new MnemonicKey({ mnemonic: "work clap clarify edit explain exact depth ramp law hard feel beauty stumble occur prevent crush distance purpose scrap current describe skirt panther skirt" }) @@ -83,6 +83,6 @@ export function getMnemonics() { mnemonic3, mnemonic4, mnemonic5, - mnemonic6, + smartaccountMnemonic, } } \ No newline at end of file diff --git a/integration-tests/src/modules/smartaccount/smartaccount.test.ts b/integration-tests/src/modules/smartaccount/smartaccount.test.ts new file mode 100644 index 00000000..b90a77b5 --- /dev/null +++ b/integration-tests/src/modules/smartaccount/smartaccount.test.ts @@ -0,0 +1,161 @@ +import { Coins, MsgExecuteContract, MsgInstantiateContract, MsgSend, MsgStoreCode, PublicKey } from "@terra-money/feather.js"; +import { AuthorizationMsg, MsgCreateSmartAccount, MsgUpdateAuthorization } from "@terra-money/feather.js/dist/core/smartaccount"; +import fs from "fs"; +import path from 'path'; +import { blockInclusion, getLCDClient, getMnemonics } from "../../helpers"; + +describe("Smartaccount Module (https://github.com/terra-money/core/tree/release/v2.6/x/smartaccount) ", () => { + // Prepare environment clients, accounts and wallets + const LCD = getLCDClient(); + const accounts = getMnemonics(); + const wallet = LCD.chain1.wallet(accounts.mnemonic5); + const controlledAccountAddress = accounts.mnemonic5.accAddress("terra"); + + // const controller = accounts.mnemonic4.publicKey; + const pubkey = accounts.mnemonic4.publicKey; + expect(pubkey).toBeDefined(); + + // TODO: convert pubkey to base64 string similar to golang pubkey.Bytes() + const pubkeybb = pubkey as PublicKey + const ggg = pubkeybb.toAmino() + + const key = ggg.value as string; + console.log(key) + const pubkeyBs = Buffer.from(key); + const initMsg = { + initialization: { + sender: controlledAccountAddress, + account: controlledAccountAddress, + public_key: pubkeyBs, + } + } + // marshal initMsg to bytes similar to json.Marshal in golang + const initMsgBytes = Buffer.from(JSON.stringify(initMsg)).toString('base64'); + + const deployer = LCD.chain1.wallet(accounts.tokenFactoryMnemonic); + const deployerAddress = accounts.tokenFactoryMnemonic.accAddress("terra"); + + let authContractAddress: string; + + test.only('Deploy smart account auth contract and initialize priv key for wallet', async () => { + try { + let tx = await deployer.createAndSignTx({ + msgs: [new MsgStoreCode( + deployerAddress, + fs.readFileSync(path.join(__dirname, "/../../contracts/smart_auth_contract.wasm")).toString("base64"), + )], + chainID: "test-1", + }); + + let result = await LCD.chain1.tx.broadcastSync(tx, "test-1"); + await blockInclusion(); + let txResult = await LCD.chain1.tx.txInfo(result.txhash, "test-1") as any; + let codeId = Number(txResult.logs[0].events[1].attributes[1].value); + expect(codeId).toBeDefined(); + + const msgInstantiateContract = new MsgInstantiateContract( + deployerAddress, + deployerAddress, + codeId, + {}, + Coins.fromString("1uluna"), + "Smart auth contract " + Math.random(), + ); + + tx = await deployer.createAndSignTx({ + msgs: [msgInstantiateContract], + chainID: "test-1", + }); + result = await LCD.chain1.tx.broadcastSync(tx, "test-1"); + await blockInclusion(); + txResult = await LCD.chain1.tx.txInfo(result.txhash, "test-1") as any; + authContractAddress = txResult.logs[0].events[4].attributes[0].value; + expect(authContractAddress).toBeDefined(); + + // add pubkey of controller for smart account + tx = await wallet.createAndSignTx({ + msgs: [new MsgExecuteContract( + controlledAccountAddress, + authContractAddress, + initMsg, + )], + chainID: 'test-1', + gas: '400000', + }); + result = await LCD.chain1.tx.broadcastSync(tx, "test-1"); + await blockInclusion(); + txResult = await LCD.chain1.tx.txInfo(result.txhash, "test-1") as any; + console.log(txResult); + codeId = Number(txResult.logs[0].events[1].attributes[1].value); + expect(codeId).toBeDefined(); + } catch(e: any) { + expect(e).toBeUndefined(); + } + }); + + test('Create new smart account and give control to controller', async () => { + try { + // create the smartaccount + let tx = await wallet.createAndSignTx({ + msgs: [new MsgCreateSmartAccount( + controlledAccountAddress + )], + chainID: 'test-1', + gas: '400000', + }); + let result = await LCD.chain1.tx.broadcastSync(tx, "test-1"); + await blockInclusion(); + let txResult = await LCD.chain1.tx.txInfo(result.txhash, "test-1") as any; + let codeId = Number(txResult.logs[0].events[1].attributes[1].value); + expect(codeId).toBeDefined(); + // Query smartaccount setting for the smart waccount + const setting = await LCD.chain1.smartaccount.setting(controlledAccountAddress); + + expect(setting.toData()) + .toEqual({ + owner: controlledAccountAddress, + authorization: [], + post_transaction: [], + pre_transaction: [], + fallback: true, + }); + + // give control to controller + tx = await wallet.createAndSignTx({ + msgs: [new MsgUpdateAuthorization( + controlledAccountAddress, + false, + [new AuthorizationMsg(authContractAddress, initMsgBytes)], + )], + chainID: 'test-1', + gas: '400000', + }); + result = await LCD.chain1.tx.broadcastSync(tx, "test-1"); + await blockInclusion(); + txResult = await LCD.chain1.tx.txInfo(result.txhash, "test-1") as any; + codeId = Number(txResult.logs[0].events[1].attributes[1].value); + expect(codeId).toBeDefined(); + + // signing with the controlledAccountAddress should now fail + tx = await wallet.createAndSignTx({ + msgs: [ + new MsgSend( + controlledAccountAddress, + controlledAccountAddress, + Coins.fromString("1uluna"), + ), + ], + chainID: "test-1", + }); + result = await LCD.chain1.tx.broadcastSync(tx, "test-1"); + await blockInclusion(); + txResult = await LCD.chain1.tx.txInfo(result.txhash, "test-1") as any; + console.log(txResult); + codeId = Number(txResult.logs[0].events[1].attributes[1].value); + expect(codeId).toBeDefined(); + } catch (e:any) { + console.log(e); + expect(e).toBeUndefined(); + } + }); +}); \ No newline at end of file diff --git a/x/smartaccount/test_helpers/test_data/smart_auth_contract.wasm b/x/smartaccount/test_helpers/test_data/smart_auth_contract.wasm old mode 100755 new mode 100644 index f907b3b8..538a5763 Binary files a/x/smartaccount/test_helpers/test_data/smart_auth_contract.wasm and b/x/smartaccount/test_helpers/test_data/smart_auth_contract.wasm differ diff --git a/x/smartaccount/types/setting.go b/x/smartaccount/types/setting.go index 2a652e94..22063a93 100644 --- a/x/smartaccount/types/setting.go +++ b/x/smartaccount/types/setting.go @@ -10,8 +10,8 @@ func NewSetting(ownerAddr string) Setting { } } -func NewSettings() []*Setting { - return make([]*Setting, 0) +func NewSettings(setting ...*Setting) []*Setting { + return append([]*Setting(nil), setting...) } func DefaultSettings() []*Setting {